Lora-trainer / CreateProject.jsx
Allex21's picture
Upload 24 files
5bb2330 verified
import React, { useState, useEffect } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Slider } from '@/components/ui/slider';
import { ArrowLeft, Upload, Save } from 'lucide-react';
import '../App.css';
const CreateProject = ({ onBack, onProjectCreated }) => {
const [formData, setFormData] = useState({
name: '',
description: '',
base_model: '',
rank: 4,
alpha: 32,
dropout: 0.1,
learning_rate: 0.0001,
batch_size: 1,
num_epochs: 10,
use_8bit_optimizer: true,
use_gradient_checkpointing: true,
mixed_precision: 'fp16'
});
const [availableModels, setAvailableModels] = useState([]);
const [loading, setLoading] = useState(false);
const [datasetFile, setDatasetFile] = useState(null);
useEffect(() => {
fetchAvailableModels();
}, []);
const fetchAvailableModels = async () => {
try {
const response = await fetch('/api/models');
const data = await response.json();
setAvailableModels(data);
} catch (error) {
console.error('Erro ao buscar modelos:', error);
}
};
const handleInputChange = (field, value) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
const handleFileChange = (event) => {
const file = event.target.files[0];
setDatasetFile(file);
};
const handleSubmit = async (event) => {
event.preventDefault();
setLoading(true);
try {
// Create project
const response = await fetch('/api/projects', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
if (!response.ok) {
throw new Error('Erro ao criar projeto');
}
const project = await response.json();
// Upload dataset if provided
if (datasetFile) {
const formDataUpload = new FormData();
formDataUpload.append('dataset', datasetFile);
const uploadResponse = await fetch(`/api/projects/${project.id}/upload-dataset`, {
method: 'POST',
body: formDataUpload,
});
if (!uploadResponse.ok) {
throw new Error('Erro ao fazer upload do dataset');
}
}
onProjectCreated(project);
} catch (error) {
console.error('Erro ao criar projeto:', error);
alert('Erro ao criar projeto: ' + error.message);
} finally {
setLoading(false);
}
};
return (
<div className="space-y-6">
{/* Header */}
<div className="flex items-center gap-4">
<Button variant="outline" onClick={onBack} className="flex items-center gap-2">
<ArrowLeft className="w-4 h-4" />
Voltar
</Button>
<div>
<h1 className="text-3xl font-bold">Criar Novo Projeto LoRA</h1>
<p className="text-gray-600 mt-2">
Configure os parâmetros para seu novo projeto de treinamento
</p>
</div>
</div>
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Basic Information */}
<Card>
<CardHeader>
<CardTitle>Informações Básicas</CardTitle>
<CardDescription>
Configure as informações básicas do seu projeto
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div>
<Label htmlFor="name">Nome do Projeto *</Label>
<Input
id="name"
value={formData.name}
onChange={(e) => handleInputChange('name', e.target.value)}
placeholder="Ex: Meu Primeiro LoRA"
required
/>
</div>
<div>
<Label htmlFor="description">Descrição</Label>
<Textarea
id="description"
value={formData.description}
onChange={(e) => handleInputChange('description', e.target.value)}
placeholder="Descreva o objetivo do seu projeto..."
rows={3}
/>
</div>
<div>
<Label htmlFor="base_model">Modelo Base *</Label>
<Select
value={formData.base_model}
onValueChange={(value) => handleInputChange('base_model', value)}
required
>
<SelectTrigger>
<SelectValue placeholder="Selecione um modelo base" />
</SelectTrigger>
<SelectContent>
{availableModels.map((model) => (
<SelectItem key={model.id} value={model.id}>
{model.name} ({model.size})
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="dataset">Dataset</Label>
<Input
id="dataset"
type="file"
onChange={handleFileChange}
accept=".zip,.tar,.tar.gz"
className="cursor-pointer"
/>
<p className="text-sm text-gray-500 mt-1">
Formatos aceitos: ZIP, TAR, TAR.GZ
</p>
</div>
</CardContent>
</Card>
{/* LoRA Parameters */}
<Card>
<CardHeader>
<CardTitle>Parâmetros LoRA</CardTitle>
<CardDescription>
Configure os parâmetros específicos do LoRA
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div>
<Label htmlFor="rank">Rank: {formData.rank}</Label>
<Slider
id="rank"
min={1}
max={128}
step={1}
value={[formData.rank]}
onValueChange={(value) => handleInputChange('rank', value[0])}
className="mt-2"
/>
<p className="text-sm text-gray-500 mt-1">
Menor rank = menos parâmetros, mais eficiente
</p>
</div>
<div>
<Label htmlFor="alpha">Alpha: {formData.alpha}</Label>
<Slider
id="alpha"
min={1}
max={128}
step={1}
value={[formData.alpha]}
onValueChange={(value) => handleInputChange('alpha', value[0])}
className="mt-2"
/>
<p className="text-sm text-gray-500 mt-1">
Controla a força da adaptação LoRA
</p>
</div>
<div>
<Label htmlFor="dropout">Dropout: {formData.dropout}</Label>
<Slider
id="dropout"
min={0}
max={0.5}
step={0.01}
value={[formData.dropout]}
onValueChange={(value) => handleInputChange('dropout', value[0])}
className="mt-2"
/>
<p className="text-sm text-gray-500 mt-1">
Previne overfitting durante o treinamento
</p>
</div>
</CardContent>
</Card>
{/* Training Parameters */}
<Card>
<CardHeader>
<CardTitle>Parâmetros de Treinamento</CardTitle>
<CardDescription>
Configure como o treinamento será executado
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div>
<Label htmlFor="learning_rate">Taxa de Aprendizado</Label>
<Input
id="learning_rate"
type="number"
step="0.00001"
value={formData.learning_rate}
onChange={(e) => handleInputChange('learning_rate', parseFloat(e.target.value))}
/>
</div>
<div>
<Label htmlFor="batch_size">Tamanho do Batch</Label>
<Select
value={formData.batch_size.toString()}
onValueChange={(value) => handleInputChange('batch_size', parseInt(value))}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1 (Mais eficiente em memória)</SelectItem>
<SelectItem value="2">2</SelectItem>
<SelectItem value="4">4</SelectItem>
<SelectItem value="8">8</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="num_epochs">Número de Épocas: {formData.num_epochs}</Label>
<Slider
id="num_epochs"
min={1}
max={50}
step={1}
value={[formData.num_epochs]}
onValueChange={(value) => handleInputChange('num_epochs', value[0])}
className="mt-2"
/>
</div>
</CardContent>
</Card>
{/* Optimization Settings */}
<Card>
<CardHeader>
<CardTitle>Otimizações de GPU</CardTitle>
<CardDescription>
Configure otimizações para reduzir o uso de GPU
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<Label htmlFor="use_8bit_optimizer">Otimizador 8-bit</Label>
<p className="text-sm text-gray-500">
Reduz uso de memória em ~50%
</p>
</div>
<Switch
id="use_8bit_optimizer"
checked={formData.use_8bit_optimizer}
onCheckedChange={(checked) => handleInputChange('use_8bit_optimizer', checked)}
/>
</div>
<div className="flex items-center justify-between">
<div>
<Label htmlFor="use_gradient_checkpointing">Gradient Checkpointing</Label>
<p className="text-sm text-gray-500">
Troca velocidade por menos memória
</p>
</div>
<Switch
id="use_gradient_checkpointing"
checked={formData.use_gradient_checkpointing}
onCheckedChange={(checked) => handleInputChange('use_gradient_checkpointing', checked)}
/>
</div>
<div>
<Label htmlFor="mixed_precision">Precisão Mista</Label>
<Select
value={formData.mixed_precision}
onValueChange={(value) => handleInputChange('mixed_precision', value)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="fp16">FP16 (Recomendado)</SelectItem>
<SelectItem value="bf16">BF16 (Para GPUs mais novas)</SelectItem>
<SelectItem value="fp32">FP32 (Sem otimização)</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
</div>
{/* Submit Button */}
<div className="flex justify-end">
<Button type="submit" disabled={loading} className="flex items-center gap-2">
<Save className="w-4 h-4" />
{loading ? 'Criando...' : 'Criar Projeto'}
</Button>
</div>
</form>
</div>
);
};
export default CreateProject;