Restore provider selection, model selection, and context/glossary in file uploader

This commit is contained in:
Sepehr 2025-11-30 22:57:21 +01:00
parent dfd45d9f07
commit 721b18dbbd
2 changed files with 133 additions and 3 deletions

View File

@ -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() {
<CardHeader>
<CardTitle className="text-white">Translation Options</CardTitle>
<CardDescription>
Select your target language and start translating
Configure your translation settings
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
@ -351,6 +352,133 @@ export function FileUploader() {
</Select>
</div>
{/* Provider Selection */}
<div className="space-y-2">
<Label htmlFor="provider" className="text-zinc-300">Translation Provider</Label>
<Select value={provider} onValueChange={(v) => setProvider(v as ProviderType)}>
<SelectTrigger id="provider" className="bg-zinc-800 border-zinc-700 text-white">
<SelectValue placeholder="Select provider" />
</SelectTrigger>
<SelectContent className="bg-zinc-800 border-zinc-700">
{providers.map((p) => (
<SelectItem
key={p.id}
value={p.id}
className="text-white hover:bg-zinc-700"
>
<span className="flex items-center gap-2">
<span>{p.icon}</span>
<span>{p.name}</span>
</span>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* OpenAI Model Selection */}
{provider === "openai" && (
<div className="space-y-2">
<Label htmlFor="openai-model" className="text-zinc-300">OpenAI Model</Label>
<Select
value={settings.openaiModel}
onValueChange={(v) => useTranslationStore.getState().updateSettings({ openaiModel: v })}
>
<SelectTrigger id="openai-model" className="bg-zinc-800 border-zinc-700 text-white">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent className="bg-zinc-800 border-zinc-700">
{openaiModels.map((m) => (
<SelectItem
key={m.id}
value={m.id}
className="text-white hover:bg-zinc-700"
>
<div className="flex flex-col">
<span>{m.name}</span>
<span className="text-xs text-zinc-500">{m.description}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{!settings.openaiApiKey && (
<p className="text-xs text-amber-400"> API key required in Settings</p>
)}
</div>
)}
{/* OpenRouter Model Selection */}
{provider === "openrouter" && (
<div className="space-y-2">
<Label htmlFor="openrouter-model" className="text-zinc-300">OpenRouter Model</Label>
<Select
value={settings.openrouterModel}
onValueChange={(v) => useTranslationStore.getState().updateSettings({ openrouterModel: v })}
>
<SelectTrigger id="openrouter-model" className="bg-zinc-800 border-zinc-700 text-white">
<SelectValue placeholder="Select model" />
</SelectTrigger>
<SelectContent className="bg-zinc-800 border-zinc-700">
{openrouterModels.map((m) => (
<SelectItem
key={m.id}
value={m.id}
className="text-white hover:bg-zinc-700"
>
<div className="flex flex-col">
<span>{m.name}</span>
<span className="text-xs text-zinc-500">{m.description}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{!settings.openrouterApiKey && (
<p className="text-xs text-amber-400"> API key required in Settings</p>
)}
</div>
)}
{/* Context Section - Only for LLM providers */}
{(provider === "openai" || provider === "openrouter" || provider === "ollama") && (
<div className="space-y-4 p-4 bg-zinc-800/50 rounded-lg border border-zinc-700">
<div className="flex items-center justify-between">
<Label className="text-zinc-300 flex items-center gap-2">
<Brain className="h-4 w-4 text-teal-400" />
Translation Context
</Label>
<Badge variant="outline" className="border-teal-500/50 text-teal-400 text-xs">
LLM Only
</Badge>
</div>
{/* System Prompt */}
<div className="space-y-2">
<Label htmlFor="system-prompt" className="text-zinc-400 text-sm">Instructions for the AI</Label>
<Textarea
id="system-prompt"
value={settings.systemPrompt}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => 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"
/>
</div>
{/* Glossary */}
<div className="space-y-2">
<Label htmlFor="glossary" className="text-zinc-400 text-sm">Glossary (term=translation, one per line)</Label>
<Textarea
id="glossary"
value={settings.glossary}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => useTranslationStore.getState().updateSettings({ glossary: e.target.value })}
placeholder="compressor=compresseur&#10;evaporator=évaporateur&#10;condenser=condenseur"
className="bg-zinc-900 border-zinc-700 text-white placeholder:text-zinc-600 min-h-[80px] text-sm font-mono"
/>
</div>
</div>
)}
{/* Translate Button */}
<Button
onClick={handleTranslate}

View File

@ -10,6 +10,8 @@ import {
LogIn,
Crown,
LogOut,
Settings,
BookOpen,
} from "lucide-react";
import {
Tooltip,