Restore provider selection, model selection, and context/glossary in file uploader
This commit is contained in:
parent
dfd45d9f07
commit
721b18dbbd
@ -2,15 +2,16 @@
|
|||||||
|
|
||||||
import { useState, useCallback, useEffect } from "react";
|
import { useState, useCallback, useEffect } from "react";
|
||||||
import { useDropzone } from "react-dropzone";
|
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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Progress } from "@/components/ui/progress";
|
import { Progress } from "@/components/ui/progress";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Switch } from "@/components/ui/switch";
|
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 { translateDocument, languages, providers, extractTextsFromDocument, reconstructDocument, TranslatedText } from "@/lib/api";
|
||||||
import { useWebLLM } from "@/lib/webllm";
|
import { useWebLLM } from "@/lib/webllm";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
@ -323,7 +324,7 @@ export function FileUploader() {
|
|||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-white">Translation Options</CardTitle>
|
<CardTitle className="text-white">Translation Options</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Select your target language and start translating
|
Configure your translation settings
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-6">
|
<CardContent className="space-y-6">
|
||||||
@ -351,6 +352,133 @@ export function FileUploader() {
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</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 evaporator=évaporateur 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 */}
|
{/* Translate Button */}
|
||||||
<Button
|
<Button
|
||||||
onClick={handleTranslate}
|
onClick={handleTranslate}
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import {
|
|||||||
LogIn,
|
LogIn,
|
||||||
Crown,
|
Crown,
|
||||||
LogOut,
|
LogOut,
|
||||||
|
Settings,
|
||||||
|
BookOpen,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user