276 lines
7.2 KiB
TypeScript
276 lines
7.2 KiB
TypeScript
/**
|
||
* 翻译模块类型定义。
|
||
*
|
||
* 与 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: '未知错误,详见下方原始响应'
|
||
}
|