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 @@
+
+