diff --git a/frontend/src/components/file-uploader.tsx b/frontend/src/components/file-uploader.tsx index 6ac3081..bc7db24 100644 --- a/frontend/src/components/file-uploader.tsx +++ b/frontend/src/components/file-uploader.tsx @@ -2,15 +2,16 @@ import { useState, useCallback, useEffect } from "react"; import { useDropzone } from "react-dropzone"; -import { Upload, FileText, FileSpreadsheet, Presentation, X, Download, Loader2, Cpu, AlertTriangle } from "lucide-react"; +import { Upload, FileText, FileSpreadsheet, Presentation, X, Download, Loader2, Cpu, AlertTriangle, Brain } from "lucide-react"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Progress } from "@/components/ui/progress"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Label } from "@/components/ui/label"; +import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; -import { useTranslationStore } from "@/lib/store"; +import { useTranslationStore, openaiModels, openrouterModels } from "@/lib/store"; import { translateDocument, languages, providers, extractTextsFromDocument, reconstructDocument, TranslatedText } from "@/lib/api"; import { useWebLLM } from "@/lib/webllm"; import { cn } from "@/lib/utils"; @@ -323,7 +324,7 @@ export function FileUploader() { Translation Options - Select your target language and start translating + Configure your translation settings @@ -351,6 +352,133 @@ export function FileUploader() { + {/* Provider Selection */} + + Translation Provider + setProvider(v as ProviderType)}> + + + + + {providers.map((p) => ( + + + {p.icon} + {p.name} + + + ))} + + + + + {/* OpenAI Model Selection */} + {provider === "openai" && ( + + OpenAI Model + useTranslationStore.getState().updateSettings({ openaiModel: v })} + > + + + + + {openaiModels.map((m) => ( + + + {m.name} + {m.description} + + + ))} + + + {!settings.openaiApiKey && ( + ⚠️ API key required in Settings + )} + + )} + + {/* OpenRouter Model Selection */} + {provider === "openrouter" && ( + + OpenRouter Model + useTranslationStore.getState().updateSettings({ openrouterModel: v })} + > + + + + + {openrouterModels.map((m) => ( + + + {m.name} + {m.description} + + + ))} + + + {!settings.openrouterApiKey && ( + ⚠️ API key required in Settings + )} + + )} + + {/* Context Section - Only for LLM providers */} + {(provider === "openai" || provider === "openrouter" || provider === "ollama") && ( + + + + + Translation Context + + + LLM Only + + + + {/* System Prompt */} + + Instructions for the AI + ) => useTranslationStore.getState().updateSettings({ systemPrompt: e.target.value })} + placeholder="E.g., You are translating technical HVAC documentation. Keep unit measurements unchanged. Use formal language..." + className="bg-zinc-900 border-zinc-700 text-white placeholder:text-zinc-600 min-h-[80px] text-sm" + /> + + + {/* Glossary */} + + Glossary (term=translation, one per line) + ) => useTranslationStore.getState().updateSettings({ glossary: e.target.value })} + placeholder="compressor=compresseur evaporator=évaporateur condenser=condenseur" + className="bg-zinc-900 border-zinc-700 text-white placeholder:text-zinc-600 min-h-[80px] text-sm font-mono" + /> + + + )} + {/* Translate Button */}
⚠️ API key required in Settings