Files
Thing/src/types/translate.ts
T
2026-09-17 17:32:20 +08:00

276 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 翻译模块类型定义。
*
* 与 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<TranslateEngineConfig>
}
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<TranslateErrorKind, string> = {
config: '检查引擎配置:Base URL、模型名是否填对',
auth: '检查 API Key 是否正确、账户是否有该模型权限',
rateLimit: '上游限流,稍后重试即可',
network: '网络不可达:检查网络连接,若该服务在境外请开启代理模块',
timeout: '请求超时:可调大该引擎的超时时间',
parse: '上游返回格式异常,可能是接口变更',
unsupported: '该引擎类型尚未接入',
empty: '没有可翻译的内容:请先输入文本',
captcha: '被上游风控拦截,稍后重试或更换引擎',
unknown: '未知错误,详见下方原始响应'
}