From c832edfab1c659aa6490f15647f29d63613af3a5 Mon Sep 17 00:00:00 2001 From: MT-Fire <798521692@qq.com> Date: Tue, 10 Mar 2026 13:30:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BB=9F=E4=B8=80=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=89=80=E6=9C=89=E7=9A=84baseURL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 + js/api/api.js | 40 ++- js/chatbot/core/api-config-builder.js | 3 +- js/chatbot/core/llm-caller.js | 4 +- js/chatbot/core/message-sender.js | 8 +- js/config/proxy-config.js | 358 ++++++++++++++++++++ js/history/history_detail_scripts.js | 5 +- js/process/main.js | 4 +- js/process/mineru-structured-translation.js | 10 +- js/process/ocr-adapters/mistral-adapter.js | 11 +- js/process/ocr-manager.js | 12 +- js/process/translation.js | 4 +- test.html | 2 + 13 files changed, 441 insertions(+), 22 deletions(-) create mode 100644 js/config/proxy-config.js diff --git a/index.html b/index.html index f93f766..c31faea 100644 --- a/index.html +++ b/index.html @@ -1484,6 +1484,8 @@ + + diff --git a/js/api/api.js b/js/api/api.js index 2ceb26c..c41d4f7 100644 --- a/js/api/api.js +++ b/js/api/api.js @@ -63,7 +63,12 @@ async function uploadToMistral(fileToProcess, mistralKey) { formData.append('file', fileToProcess); formData.append('purpose', 'ocr'); - const response = await fetch('http://localhost:3456/api/mistral/v1/files', { + // 使用统一配置获取代理地址 + const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getMistralUrl('/v1/files') + : 'http://localhost:3456/api/mistral/v1/files'; + + const response = await fetch(proxyUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}` }, body: formData @@ -91,11 +96,12 @@ async function uploadFileToOssViaProxy(fileToProcess, fileName) { const formData = new FormData(); formData.append('file', fileToProcess, fileName); - // 假设 local-proxy 运行在 3456 端口,如果部署到线上可能需要改相对路径或读取配置 - // 这里采用跟 Mistral API 相同的基础写法 - const proxyUrl = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1' - ? 'http://localhost:3456/api/upload/oss' - : '/api/upload/oss'; + // 使用统一配置获取代理地址 + const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getOssUploadUrl() + : (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1' + ? 'http://localhost:3456/api/upload/oss' + : '/api/upload/oss'); const response = await fetch(proxyUrl, { method: 'POST', @@ -124,8 +130,12 @@ async function uploadFileToOssViaProxy(fileToProcess, fileName) { * @throws {Error} 如果获取签名 URL 失败(例如文件 ID 无效、认证失败),则抛出错误。 */ async function getMistralSignedUrl(fileId, mistralKey) { - const urlEndpoint = `http://localhost:3456/api/mistral/v1/files/${fileId}/url?expiry=24`; - const response = await fetch(urlEndpoint, { + // 使用统一配置获取代理地址 + const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getMistralUrl(`/v1/files/${fileId}/url?expiry=24`) + : `http://localhost:3456/api/mistral/v1/files/${fileId}/url?expiry=24`; + + const response = await fetch(proxyUrl, { method: 'GET', headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}`, 'Accept': 'application/json' } }); @@ -149,7 +159,12 @@ async function getMistralSignedUrl(fileId, mistralKey) { * @throws {Error} 如果 OCR 处理失败(例如 URL 无效、API Key 错误、处理超时),则抛出错误。 */ async function callMistralOcr(signedUrl, mistralKey) { - const response = await fetch('http://localhost:3456/api/mistral/v1/ocr', { + // 使用统一配置获取代理地址 + const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getMistralUrl('/v1/ocr') + : 'http://localhost:3456/api/mistral/v1/ocr'; + + const response = await fetch(proxyUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}`, @@ -183,7 +198,12 @@ async function callMistralOcr(signedUrl, mistralKey) { */ async function deleteMistralFile(fileId, apiKey) { if (!fileId) return; // 参数校验 - const deleteUrl = `http://localhost:3456/api/mistral/v1/files/${fileId}`; + + // 使用统一配置获取代理地址 + const deleteUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getMistralUrl(`/v1/files/${fileId}`) + : `http://localhost:3456/api/mistral/v1/files/${fileId}`; + try { const response = await fetch(deleteUrl, { method: 'DELETE', diff --git a/js/chatbot/core/api-config-builder.js b/js/chatbot/core/api-config-builder.js index daeac54..018e1dc 100644 --- a/js/chatbot/core/api-config-builder.js +++ b/js/chatbot/core/api-config-builder.js @@ -160,7 +160,8 @@ options.proxyMode === 'proxy' || (options.proxyMode !== 'direct' && globalProxyMode === 'proxy'); const proxyBaseUrl = options.proxyBaseUrl || - (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL) || + (typeof window !== 'undefined' && window.ProxyConfig ? window.ProxyConfig.getProxyUrl() : null) || + (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL ? window.PBX_PROXY_BASE_URL : null) || 'http://localhost:3456'; const provider = options.provider || 'openai'; diff --git a/js/chatbot/core/llm-caller.js b/js/chatbot/core/llm-caller.js index c301f3e..e0a75b4 100644 --- a/js/chatbot/core/llm-caller.js +++ b/js/chatbot/core/llm-caller.js @@ -138,7 +138,9 @@ // 检测是否使用代理服务器 const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const useProxy = globalProxyMode === 'proxy'; - const proxyBaseUrl = (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL) || 'http://localhost:3456'; + const proxyBaseUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'); // 确定提供商(从模型 ID 或配置推断) let provider = 'openai'; diff --git a/js/chatbot/core/message-sender.js b/js/chatbot/core/message-sender.js index 0e629f4..2fefbbf 100644 --- a/js/chatbot/core/message-sender.js +++ b/js/chatbot/core/message-sender.js @@ -445,7 +445,9 @@ async function sendChatbotMessage(userInput, updateChatbotUI, externalConfig = n // 检测是否使用代理服务器模式 const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const useProxy = globalProxyMode === 'proxy'; - const proxyBaseUrl = (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL) || 'http://localhost:3456'; + const proxyBaseUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'); // 在使用代理服务器模式时,API Key 在后端配置,前端可以没有 API Key // 否则,检查前端是否配置了有效的 API Key @@ -1736,7 +1738,9 @@ async function singleChunkSummary(sysPrompt, userInput, config, apiKey) { // 代理服务器配置(与 buildCustomApiConfig 保持一致) const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const useProxy = globalProxyMode === 'proxy'; - const proxyBaseUrl = (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL) || 'http://localhost:3456'; + const proxyBaseUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'); // 只做单轮整理,不带历史 let apiConfig; diff --git a/js/config/proxy-config.js b/js/config/proxy-config.js new file mode 100644 index 0000000..f25086f --- /dev/null +++ b/js/config/proxy-config.js @@ -0,0 +1,358 @@ +/** + * @file js/config/proxy-config.js + * @description + * 代理服务器地址统一配置文件 + * + * 集中管理所有代理服务器地址、API 端点和端口配置。 + * + * 使用方式: + * 1. 前端代码:window.ProxyConfig.getProxyUrl() + * 2. 支持环境变量覆盖:window.ENV_PROXY_URL + * 3. 支持 localStorage 用户自定义 + */ + +(function () { + 'use strict'; + + // ==================== 默认配置 ==================== + + const DEFAULT_CONFIG = { + // 本地代理服务器端口 + LOCAL_PROXY_PORT: 3456, + + // 前端静态服务端口 + FRONTEND_PORT: 8080, + + // 后端 API 服务端口(Docker 部署时) + BACKEND_API_PORT: 3000, + + // 本地代理服务器地址 + LOCAL_PROXY_URL: 'http://localhost:3456', + + // 生产环境代理地址(相对路径,由 Nginx 等代理) + PROD_PROXY_URL: '/api', + + // 各服务端点路径 + ENDPOINTS: { + // OCR 相关 + MISTRAL_BASE: '/api/mistral', + MINERU_BASE: '/mineru', + DOC2X_BASE: '/doc2x', + + // LLM 代理 + LLM_PROXY: '/api/llm', + + // OSS 上传 + OSS_UPLOAD: '/api/upload/oss', + + // 学术搜索 + SEMANTIC_SCHOLAR: '/api/semanticscholar', + PUBMED: '/api/pubmed', + CROSSREF: '/api/crossref', + OPENALEX: '/api/openalex', + ARXIV: '/api/arxiv', + + // PDF 下载代理 + PDF_DOWNLOAD: '/api/pdf/download', + + // 健康检查 + HEALTH: '/health', + + // 后端 API + BACKEND_API: '/api' + }, + + // 外部服务直连地址(供参考,实际通过代理访问) + EXTERNAL_SERVICES: { + MINERU_API: 'https://mineru.net/api/v4', + DOC2X_API: 'https://v2.doc2x.noedgeai.com', + MISTRAL_API: 'https://api.mistral.ai', + OPENAI_API: 'https://api.openai.com', + DEEPSEEK_API: 'https://api.deepseek.com', + ANTHROPIC_API: 'https://api.anthropic.com', + GEMINI_API: 'https://generativelanguage.googleapis.com', + ALIYUN_DASHSCOPE: 'https://dashscope.aliyuncs.com/compatible-mode', + ZHIPU_API: 'https://open.bigmodel.cn/api/paas/v4' + } + }; + + // ==================== 配置管理类 ==================== + + class ProxyConfig { + constructor() { + this.config = { ...DEFAULT_CONFIG }; + this._loadUserConfig(); + } + + /** + * 加载用户自定义配置 + * 优先级:环境变量 > localStorage > 默认值 + */ + _loadUserConfig() { + // 1. 检查环境变量覆盖 + if (typeof window !== 'undefined') { + if (window.ENV_PROXY_URL) { + this.config.LOCAL_PROXY_URL = window.ENV_PROXY_URL; + } + if (window.ENV_API_BASE_URL) { + this.config.PROD_PROXY_URL = window.ENV_API_BASE_URL; + } + if (window.ENV_LOCAL_PROXY_PORT) { + this.config.LOCAL_PROXY_PORT = parseInt(window.ENV_LOCAL_PROXY_PORT, 10); + } + } + + // 2. 检查 localStorage 用户配置 + try { + const savedProxyUrl = localStorage.getItem('proxyUrl'); + if (savedProxyUrl) { + this.config.LOCAL_PROXY_URL = savedProxyUrl; + } + + const savedPort = localStorage.getItem('proxyPort'); + if (savedPort) { + this.config.LOCAL_PROXY_PORT = parseInt(savedPort, 10); + } + } catch (e) { + // localStorage 不可用时忽略 + } + } + + /** + * 判断是否为本地开发环境 + * @returns {boolean} + */ + isLocalDevelopment() { + if (typeof window === 'undefined') return false; + + const hostname = window.location.hostname; + return hostname === 'localhost' || + hostname === '127.0.0.1' || + hostname.startsWith('192.168.') || + hostname.startsWith('10.') || + hostname.endsWith('.local'); + } + + /** + * 判断是否为 file:// 协议(纯本地文件访问) + * @returns {boolean} + */ + isFileProtocol() { + if (typeof window === 'undefined') return false; + return window.location.protocol === 'file:'; + } + + /** + * 获取代理服务器基础 URL + * @returns {string} + */ + getProxyUrl() { + // file:// 协议无法访问本地服务器 + if (this.isFileProtocol()) { + console.warn('[ProxyConfig] file:// 协议无法访问代理服务器'); + return ''; + } + + // 本地开发环境使用完整 URL + if (this.isLocalDevelopment()) { + return this.config.LOCAL_PROXY_URL; + } + + // 生产环境使用相对路径 + return this.config.PROD_PROXY_URL; + } + + /** + * 获取本地代理服务器端口 + * @returns {number} + */ + getLocalProxyPort() { + return this.config.LOCAL_PROXY_PORT; + } + + /** + * 获取前端服务端口 + * @returns {number} + */ + getFrontendPort() { + return this.config.FRONTEND_PORT; + } + + /** + * 获取指定端点的完整 URL + * @param {string} endpointName - 端点名称(ENDPOINTS 中的 key) + * @param {string} [suffix=''] - 路径后缀 + * @returns {string} + */ + getEndpointUrl(endpointName, suffix = '') { + const basePath = this.config.ENDPOINTS[endpointName]; + if (!basePath) { + console.warn(`[ProxyConfig] Unknown endpoint: ${endpointName}`); + return ''; + } + return `${this.getProxyUrl()}${basePath}${suffix}`; + } + + // ==================== 便捷方法:各服务 URL ==================== + + /** + * Mistral OCR 服务 URL + * @param {string} [path=''] - 路径后缀 + * @returns {string} + */ + getMistralUrl(path = '') { + const base = this.config.ENDPOINTS.MISTRAL_BASE; + return `${this.getProxyUrl()}${base}${path}`; + } + + /** + * MinerU OCR 服务 URL + * @param {string} [path=''] - 路径后缀 + * @returns {string} + */ + getMinerUUrl(path = '') { + const base = this.config.ENDPOINTS.MINERU_BASE; + return `${this.getProxyUrl()}${base}${path}`; + } + + /** + * Doc2X OCR 服务 URL + * @param {string} [path=''] - 路径后缀 + * @returns {string} + */ + getDoc2XUrl(path = '') { + const base = this.config.ENDPOINTS.DOC2X_BASE; + return `${this.getProxyUrl()}${base}${path}`; + } + + /** + * LLM 代理服务 URL + * @param {string} provider - 提供商名称(openai, deepseek, anthropic 等) + * @param {string} [path=''] - 路径后缀 + * @returns {string} + */ + getLLMProxyUrl(provider, path = '') { + const base = this.config.ENDPOINTS.LLM_PROXY; + return `${this.getProxyUrl()}${base}/${provider}${path}`; + } + + /** + * OSS 上传服务 URL + * @returns {string} + */ + getOssUploadUrl() { + return `${this.getProxyUrl()}${this.config.ENDPOINTS.OSS_UPLOAD}`; + } + + /** + * 健康检查 URL + * @returns {string} + */ + getHealthCheckUrl() { + return `${this.getProxyUrl()}${this.config.ENDPOINTS.HEALTH}`; + } + + /** + * 后端 API URL(用于后端模式) + * @param {string} [path=''] - 路径后缀 + * @returns {string} + */ + getBackendApiUrl(path = '') { + return `${this.config.PROD_PROXY_URL}${path}`; + } + + // ==================== 配置更新方法 ==================== + + /** + * 更新代理服务器 URL + * @param {string} url - 新的代理 URL + */ + setProxyUrl(url) { + this.config.LOCAL_PROXY_URL = url.replace(/\/+$/, ''); // 移除末尾斜杠 + try { + localStorage.setItem('proxyUrl', this.config.LOCAL_PROXY_URL); + console.log(`[ProxyConfig] 代理地址已更新为: ${this.config.LOCAL_PROXY_URL}`); + } catch (e) { + console.warn('[ProxyConfig] 无法保存代理地址到 localStorage'); + } + } + + /** + * 更新代理服务器端口 + * @param {number} port - 新的端口 + */ + setProxyPort(port) { + this.config.LOCAL_PROXY_PORT = port; + this.config.LOCAL_PROXY_URL = `http://localhost:${port}`; + try { + localStorage.setItem('proxyPort', String(port)); + localStorage.setItem('proxyUrl', this.config.LOCAL_PROXY_URL); + console.log(`[ProxyConfig] 代理端口已更新为: ${port}`); + } catch (e) { + console.warn('[ProxyConfig] 无法保存代理端口到 localStorage'); + } + } + + /** + * 重置为默认配置 + */ + resetToDefault() { + this.config = { ...DEFAULT_CONFIG }; + try { + localStorage.removeItem('proxyUrl'); + localStorage.removeItem('proxyPort'); + console.log('[ProxyConfig] 已重置为默认配置'); + } catch (e) { + // 忽略 + } + } + + /** + * 获取完整配置对象(只读) + * @returns {Object} + */ + getConfig() { + return Object.freeze({ ...this.config }); + } + + /** + * 获取默认配置(只读) + * @returns {Object} + */ + getDefaultConfig() { + return Object.freeze({ ...DEFAULT_CONFIG }); + } + } + + // ==================== 初始化并导出 ==================== + + const proxyConfig = new ProxyConfig(); + + // 导出到全局 + if (typeof window !== 'undefined') { + window.ProxyConfig = proxyConfig; + + // 同时暴露类定义,方便扩展 + window.ProxyConfigClass = ProxyConfig; + + // 兼容旧代码:设置全局代理地址变量 + // 这些变量会被其他模块引用 + if (!window.PBX_PROXY_BASE_URL) { + window.PBX_PROXY_BASE_URL = proxyConfig.getProxyUrl(); + } + if (!window.PBX_PROXY_MODE) { + window.PBX_PROXY_MODE = 'auto'; + } + } + + // 兼容 CommonJS + if (typeof module !== 'undefined' && module.exports) { + module.exports = { ProxyConfig, proxyConfig, DEFAULT_CONFIG }; + } + + // 初始化日志 + console.log(`[ProxyConfig] 已初始化`); + console.log(`[ProxyConfig] 本地开发环境: ${proxyConfig.isLocalDevelopment()}`); + console.log(`[ProxyConfig] 代理地址: ${proxyConfig.getProxyUrl()}`); + +})(); \ No newline at end of file diff --git a/js/history/history_detail_scripts.js b/js/history/history_detail_scripts.js index d55b086..abb91de 100644 --- a/js/history/history_detail_scripts.js +++ b/js/history/history_detail_scripts.js @@ -807,7 +807,10 @@ async function triggerReprocessWithMinerU() { */ async function executeMinerUStructuredTranslation() { const logPrefix = '[MinerU结构化翻译]'; - const PROXY_BASE = 'http://localhost:3456'; + // 使用统一配置获取代理地址 + const PROXY_BASE = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'); // 获取翻译配置 const settings = typeof loadSettings === 'function' ? loadSettings() : {}; diff --git a/js/process/main.js b/js/process/main.js index 6703cd3..b22f945 100644 --- a/js/process/main.js +++ b/js/process/main.js @@ -798,7 +798,9 @@ const fileType = fileToProcess.name.split('.').pop().toLowerCase(); ...translationOptions, useBackendProxy, provider: selectedTranslationModelName, - proxyBase: 'http://localhost:3456', + proxyBase: (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'), // 允许从设置自定义重试,若无则用默认 maxRetries: (typeof loadSettings === 'function' ? (loadSettings().structuredMaxRetries || undefined) : undefined), retryDelay: (typeof loadSettings === 'function' ? (loadSettings().structuredRetryDelayMs || undefined) : undefined) diff --git a/js/process/mineru-structured-translation.js b/js/process/mineru-structured-translation.js index b5d9e41..73ba5f2 100644 --- a/js/process/mineru-structured-translation.js +++ b/js/process/mineru-structured-translation.js @@ -714,7 +714,10 @@ ${jsonContent} // 后端代理模式 - API Key 由后端管理 if (options.useBackendProxy) { - const proxyBase = options.proxyBase || 'http://localhost:3456'; + const proxyBase = options.proxyBase || + (typeof window !== 'undefined' && window.ProxyConfig ? window.ProxyConfig.getProxyUrl() : null) || + (typeof window !== 'undefined' && window.PBX_PROXY_BASE_URL ? window.PBX_PROXY_BASE_URL : null) || + 'http://localhost:3456'; const provider = options.provider || 'aliyun'; // 后端代理端点映射 @@ -831,9 +834,12 @@ ${jsonContent} // 预设模型 - 从 translation.js 获取配置 // 简化:仅支持常用模型 // 前端发出的请求源头 + const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : (window.PBX_PROXY_BASE_URL || 'http://localhost:3456'); const predefinedConfigs = { 'proxy': { - endpoint: 'http://localhost:3456/api/llm/aliyun/v1/chat/completions', + endpoint: `${proxyUrl}/api/llm/aliyun/v1/chat/completions`, modelName: '通义百炼 (via local proxy)', headers: { 'Content-Type': 'application/json' }, bodyBuilder: (sys, user) => ({ diff --git a/js/process/ocr-adapters/mistral-adapter.js b/js/process/ocr-adapters/mistral-adapter.js index e729423..8e4f711 100644 --- a/js/process/ocr-adapters/mistral-adapter.js +++ b/js/process/ocr-adapters/mistral-adapter.js @@ -10,7 +10,16 @@ class MistralOcrAdapter extends OcrAdapter { super(config); this.keys = config.keys && config.keys.length > 0 ? config.keys : ['sk-local-proxy']; this.currentKeyIndex = 0; - this.baseUrl = (config.baseUrl && config.baseUrl !== 'https://api.mistral.ai' ? config.baseUrl : 'http://localhost:3456/api/mistral').replace(/\/+$/, ''); // 移除尾部斜杠 + + // 使用统一配置获取代理地址 + // 优先级:config.baseUrl > window.ProxyConfig > 默认值 + if (config.baseUrl && config.baseUrl !== 'https://api.mistral.ai') { + this.baseUrl = config.baseUrl.replace(/\/+$/, ''); + } else if (typeof window !== 'undefined' && window.ProxyConfig) { + this.baseUrl = window.ProxyConfig.getMistralUrl(); + } else { + this.baseUrl = 'http://localhost:3456/api/mistral'; + } } /** diff --git a/js/process/ocr-manager.js b/js/process/ocr-manager.js index 4731852..a55453b 100644 --- a/js/process/ocr-manager.js +++ b/js/process/ocr-manager.js @@ -94,10 +94,14 @@ class OcrManager { } case 'mineru': + // 使用统一配置获取默认 workerUrl + const mineruDefaultUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : 'http://localhost:3456'; return { engine: 'mineru', token: localStorage.getItem('ocrMinerUToken') || '', - workerUrl: (localStorage.getItem('ocrMinerUWorkerUrl') || '').replace(/\/+$/, ''), // 去掉末尾斜杠 + workerUrl: (localStorage.getItem('ocrMinerUWorkerUrl') || mineruDefaultUrl).replace(/\/+$/, ''), // 去掉末尾斜杠 authKey: localStorage.getItem('ocrWorkerAuthKey') || '', tokenMode: localStorage.getItem('ocrMinerUTokenMode') || 'frontend', enableOcr: localStorage.getItem('ocrMinerUEnableOcr') !== 'false', @@ -106,10 +110,14 @@ class OcrManager { }; case 'doc2x': + // 使用统一配置获取默认 workerUrl + const doc2xDefaultUrl = (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getProxyUrl() + : 'http://localhost:3456'; return { engine: 'doc2x', token: localStorage.getItem('ocrDoc2XToken') || '', - workerUrl: (localStorage.getItem('ocrDoc2XWorkerUrl') || '').replace(/\/+$/, ''), // 去掉末尾斜杠 + workerUrl: (localStorage.getItem('ocrDoc2XWorkerUrl') || doc2xDefaultUrl).replace(/\/+$/, ''), // 去掉末尾斜杠 authKey: localStorage.getItem('ocrWorkerAuthKey') || '', tokenMode: localStorage.getItem('ocrDoc2XTokenMode') || 'frontend' // 注意:不再需要 exportFormat,因为我们总是导出 Markdown + 图片 diff --git a/js/process/translation.js b/js/process/translation.js index 970fc04..af517ec 100644 --- a/js/process/translation.js +++ b/js/process/translation.js @@ -703,7 +703,9 @@ async function translateMarkdown( const predefinedConfigs = { 'aliyun': { // 所有翻译请求都指向后端代理,由后端决定使用哪个模型 - endpoint: 'http://localhost:3456/api/llm/tongyi/v1/chat/completions', + endpoint: (typeof window !== 'undefined' && window.ProxyConfig) + ? window.ProxyConfig.getLLMProxyUrl('tongyi', '/v1/chat/completions') + : ((window.PBX_PROXY_BASE_URL || 'http://localhost:3456') + '/api/llm/tongyi/v1/chat/completions'), modelName: '通义百炼', headers: { 'Content-Type': 'application/json' }, bodyBuilder: (sys, user) => { diff --git a/test.html b/test.html index a320e55..9d72ff3 100644 --- a/test.html +++ b/test.html @@ -97,6 +97,8 @@ + +