翻译模块
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
* 翻译模块类型定义。
|
||||
*
|
||||
* 与 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: '未知错误,详见下方原始响应'
|
||||
}
|
||||
Reference in New Issue
Block a user