Feat: 新增自定义选择模型功能
This commit is contained in:
parent
b71de1f5c9
commit
83e826e034
|
|
@ -25,6 +25,7 @@ type Props = {
|
|||
languages: string[];
|
||||
paths: string[];
|
||||
prompt: string | undefined;
|
||||
model?: string | undefined;
|
||||
initialSelectedLanguages?: string[];
|
||||
getExistingByPath?: (path: string) => Record<string, string>;
|
||||
onConfirm: (
|
||||
|
|
@ -33,7 +34,7 @@ type Props = {
|
|||
) => Promise<void> | void;
|
||||
};
|
||||
|
||||
function AiTranslateModalImpl({ open, onOpenChange, languages, paths, prompt, initialSelectedLanguages, getExistingByPath, onConfirm }: Props) {
|
||||
function AiTranslateModalImpl({ open, onOpenChange, languages, paths, prompt, model, initialSelectedLanguages, getExistingByPath, onConfirm }: Props) {
|
||||
const [inputsByKey, setInputsByKey] = useState<Record<string, string>>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
@ -92,7 +93,7 @@ function AiTranslateModalImpl({ open, onOpenChange, languages, paths, prompt, in
|
|||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await requestTranslations({ items, languages: selectedLangs, prompt });
|
||||
const result = await requestTranslations({ items, languages: selectedLangs, prompt, model });
|
||||
await onConfirm(result, { overwrite, selectedLanguages: selectedLangs });
|
||||
setInputsByKey({});
|
||||
onOpenChange(false);
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@ type Props = {
|
|||
open: boolean;
|
||||
onOpenChange: (v: boolean) => void;
|
||||
project: Project | null;
|
||||
onSave: (update: { name: string; preferences: { aiPrompt?: string } }) => Promise<void> | void;
|
||||
onSave: (update: { name: string; preferences: { aiPrompt?: string; aiModel?: string } }) => Promise<void> | void;
|
||||
onDelete: () => Promise<void> | void;
|
||||
};
|
||||
|
||||
function ProjectSettingsModalImpl({ open, onOpenChange, project, onSave, onDelete }: Props) {
|
||||
const [name, setName] = useState("");
|
||||
const [aiPrompt, setAiPrompt] = useState<string>("");
|
||||
const [aiModel, setAiModel] = useState<string>("");
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ function ProjectSettingsModalImpl({ open, onOpenChange, project, onSave, onDelet
|
|||
if (open) {
|
||||
setName(project?.name ?? "");
|
||||
setAiPrompt(project?.preferences?.aiPrompt ?? "");
|
||||
setAiModel(project?.preferences?.aiModel ?? "");
|
||||
setSaving(false);
|
||||
setErr(null);
|
||||
}
|
||||
|
|
@ -35,7 +37,7 @@ function ProjectSettingsModalImpl({ open, onOpenChange, project, onSave, onDelet
|
|||
try {
|
||||
await onSave({
|
||||
name: trimmed,
|
||||
preferences: { aiPrompt },
|
||||
preferences: { aiPrompt, aiModel },
|
||||
});
|
||||
onOpenChange(false);
|
||||
} catch (e) {
|
||||
|
|
@ -69,6 +71,22 @@ function ProjectSettingsModalImpl({ open, onOpenChange, project, onSave, onDelet
|
|||
<label className="block text-sm text-muted-foreground">项目名称</label>
|
||||
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="输入项目名称" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-muted-foreground">AI 模型</label>
|
||||
<Input
|
||||
list="ai-model-options"
|
||||
value={aiModel}
|
||||
onChange={(e) => setAiModel(e.target.value)}
|
||||
placeholder="例如:openai/gpt-5"
|
||||
/>
|
||||
<datalist id="ai-model-options">
|
||||
<option value="openai/gpt-5" />
|
||||
<option value="gpt-4o-mini" />
|
||||
<option value="gpt-4o" />
|
||||
<option value="gpt-4.1-mini" />
|
||||
<option value="o4-mini" />
|
||||
</datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-muted-foreground">翻译偏好设置(AI Prompt)</label>
|
||||
<textarea
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export type Project = {
|
|||
updatedAt: number; // ms timestamp
|
||||
preferences?: {
|
||||
aiPrompt?: string;
|
||||
aiModel?: string;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ export default function Editor() {
|
|||
/>
|
||||
</td>
|
||||
<td className="px-3 py-2 font-mono wrap-break-word">
|
||||
<button type="button" className="w-full text-left min-h-8 leading-8 px-2 rounded hover:bg-accent" onClick={handleCopy} title="点击复制">
|
||||
<button type="button" className="w-full text-left min-h-8 leading-normal px-2 rounded hover:bg-accent" onClick={handleCopy} title="点击复制">
|
||||
{entry.path}
|
||||
</button>
|
||||
</td>
|
||||
|
|
@ -251,12 +251,12 @@ export default function Editor() {
|
|||
onBlur={inline.saveEdit}
|
||||
onKeyDown={inline.handleKeyDown}
|
||||
disabled={isSaving}
|
||||
className="leading-8 px-2 py-0"
|
||||
className="leading-normal px-2 py-0"
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="w-full text-left min-h-8 leading-8 px-2 rounded hover:bg-accent"
|
||||
className="w-full text-left min-h-8 leading-normal px-2 rounded hover:bg-accent"
|
||||
onClick={() => inline.startEdit(entry.path, lang)}
|
||||
title="点击编辑"
|
||||
>
|
||||
|
|
@ -517,6 +517,7 @@ export default function Editor() {
|
|||
initialSelectedLanguages={aiModal?.path ? computeSuggestedLanguages([aiModal.path]) : []}
|
||||
getExistingByPath={getExistingByPath}
|
||||
prompt={project?.preferences?.aiPrompt}
|
||||
model={project?.preferences?.aiModel}
|
||||
onConfirm={async (translations, options) => {
|
||||
if (!projectId || !aiModal) return;
|
||||
const updates: Record<string, Record<string, string>> = {};
|
||||
|
|
@ -554,6 +555,7 @@ export default function Editor() {
|
|||
initialSelectedLanguages={computeSuggestedLanguages(Array.from(selected))}
|
||||
getExistingByPath={getExistingByPath}
|
||||
prompt={project?.preferences?.aiPrompt}
|
||||
model={project?.preferences?.aiModel}
|
||||
onConfirm={async (translations, options) => {
|
||||
if (!projectId || selected.size === 0) return;
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue