/** * 翻译模块类型定义。 * * 与 Rust 侧 `src-tauri/src/translate/` 的 specta 类型一一对应(字段名 camelCase)。 * * 为什么手写而非直接引用 `@/lib/bindings`:specta 的绑定只在 **debug 构建启动时** * 重新生成(见 `lib.rs::export_bindings`),新增命令后需先以 `bun run tauri dev` * 跑一次才会出现在 bindings.ts 里。在那之前若直接写 `commands.translateRun`, * `vue-tsc` 会因属性不存在而报错。因此 P0 先用原生 `invoke` + 本文件的类型, * 待首次 dev 启动生成绑定后,可平滑替换为 `commands.*`(调用点集中在 translateStore)。 */ /** 引擎类型:AI(OpenAI 兼容)| 免密钥网络源 | 需签名的云厂商 */ export type EngineKind = 'ai' | 'free' | 'cloud' /** 错误分类。前端据此决定给出「改 Key」「查网络」还是「稍后重试」的提示 */ export type TranslateErrorKind = | 'config' | 'auth' | 'rateLimit' | 'network' | 'timeout' | 'parse' | 'unsupported' | 'empty' | 'captcha' | 'unknown' export interface TranslateError { kind: TranslateErrorKind message: string detail: string | null } export interface TokenUsage { promptTokens: number completionTokens: number totalTokens: number } export interface TranslateResult { text: string detected: string | null engineId: string engineName: string latencyMs: number usage: TokenUsage | null } export interface PromptTemplates { translate: string polish: string explain: string summarize: string } export interface TranslateEngineConfig { id: string name: string kind: EngineKind preset: string enabled: boolean priority: number baseUrl: string model: string temperature: number maxTokens: number timeoutMs: number systemPrompt: string extraBody: string | null /** 是否支持图像输入(截图翻译的视觉直译模式只发给勾选了此项的引擎) */ supportsVision: boolean } export interface SelectionSettings { enabled: boolean /** 打开翻译面板的全局快捷键(默认 Ctrl+2) */ panelShortcut: string mode: string restoreClipboard: boolean maxChars: number blacklist: string[] } export interface PopupSettings { fontSize: number opacity: number positionPreference: string showOriginal: boolean } export interface ScreenshotSettings { ocrMode: string ocrLang: string autoTranslate: boolean } export interface HistorySettings { enabled: boolean maxItems: number } export interface TranslateSettings { version: number defaultTarget: string defaultEngineId: string autoFallback: boolean useProxy: boolean engines: TranslateEngineConfig[] selection: SelectionSettings popup: PopupSettings screenshot: ScreenshotSettings history: HistorySettings promptTemplates: PromptTemplates } /** 引擎实例的前端视图:配置 + 后端派生的密钥/可用性状态 */ export interface EngineView { config: TranslateEngineConfig hasApiKey: boolean apiKeyMasked: string ready: boolean issue: string | null } /** 连通性自检结果(失败也是 Ok 返回,细节在 message/detail 里) */ export interface EngineTestResult { ok: boolean latencyMs: number message: string errorKind: TranslateErrorKind | null detail: string | null } export interface TranslateRunParams { text: string from?: string | null to?: string | null toLabel?: string | null fromLabel?: string | null engineId?: string | null mode?: string | null /** 记入历史时的来源:"manual" | "selection" | "clipboard" | "screenshot" */ via?: string | null /** 是否写入历史,默认 true;对比 / 预览必须传 false */ record?: boolean | null } /** 一条翻译历史记录(与 Rust translate::history::HistoryItem 对应) */ export interface HistoryItem { id: number ts: number fromLang: string toLang: string engineId: string engineName: string sourceText: string resultText: string via: string favorited: boolean latencyMs: number } /** 引擎预设:用于「新增引擎」时给出可直接用的起点 */ export interface EnginePreset { key: string label: string description: string template: Partial } export const ENGINE_PRESETS: EnginePreset[] = [ { key: 'deepseek', label: 'DeepSeek', description: 'OpenAI 兼容 · 默认引擎,翻译场景用非思考模式,低延迟低成本', template: { kind: 'ai', baseUrl: 'https://api.deepseek.com', model: 'deepseek-flash', temperature: 0.3, maxTokens: 4096, timeoutMs: 30000 } }, { key: 'openai', label: 'OpenAI', description: 'OpenAI 兼容 · 官方端点', template: { kind: 'ai', baseUrl: 'https://api.openai.com/v1', model: 'gpt-4o-mini', temperature: 0.3, maxTokens: 4096, timeoutMs: 30000 } }, { key: 'ollama', label: 'Ollama(本地)', description: '本地推理,数据不出机器;需先在 Ollama 中拉取模型', template: { kind: 'ai', baseUrl: 'http://localhost:11434/v1', model: 'qwen2.5:7b', temperature: 0.3, maxTokens: 4096, timeoutMs: 120000 } }, { key: 'proxy-gateway', label: '中转 / one-api', description: '任意 OpenAI 兼容中转服务,自行填写 Base URL 与模型名', template: { kind: 'ai', baseUrl: '', model: '', temperature: 0.3, maxTokens: 4096, timeoutMs: 30000 } }, { key: 'deepl', label: 'DeepL(云厂商)', description: '质量口碑最好的传统机翻之一。免费 Key 用 api-free 端点,目标语言仅简体中文', template: { kind: 'cloud', preset: 'deepl', baseUrl: 'https://api-free.deepl.com/v2', model: '', timeoutMs: 20000 } }, { key: 'libretranslate', label: 'LibreTranslate(自部署)', description: '开源自托管翻译服务。需自行填写服务地址;API Key 可选(部署启用密钥校验时需要)', template: { kind: 'free', preset: 'libretranslate', baseUrl: '', model: '', timeoutMs: 20000 } }, { key: 'mymemory', label: 'MyMemory(免密钥)', description: '国内可直接访问的免密兜底。需显式指定源语言,单次约 500 字节内有免费额度', template: { kind: 'free', preset: 'mymemory', baseUrl: '', model: '', timeoutMs: 15000 } } ] /** 错误分类 → 用户可执行的动作提示 */ export const ERROR_HINTS: Record = { config: '检查引擎配置:Base URL、模型名是否填对', auth: '检查 API Key 是否正确、账户是否有该模型权限', rateLimit: '上游限流,稍后重试即可', network: '网络不可达:检查网络连接,若该服务在境外请开启代理模块', timeout: '请求超时:可调大该引擎的超时时间', parse: '上游返回格式异常,可能是接口变更', unsupported: '该引擎类型尚未接入', empty: '没有可翻译的内容:请先输入文本', captcha: '被上游风控拦截,稍后重试或更换引擎', unknown: '未知错误,详见下方原始响应' }