feat: 统一管理所有的baseURL

This commit is contained in:
肖应宇 2026-03-10 13:30:28 +08:00
parent 05b130b5a8
commit c832edfab1
13 changed files with 441 additions and 22 deletions

View File

@ -1484,6 +1484,8 @@
<script src="js/utils/github-stars.js"></script> <script src="js/utils/github-stars.js"></script>
<!-- 自动探测后端:若 /api/健康检查通过将切换为 backend也可用 ?mode=backend 强制 --> <!-- 自动探测后端:若 /api/健康检查通过将切换为 backend也可用 ?mode=backend 强制 -->
<script>window.ENV_DEPLOYMENT_MODE = 'auto';</script> <script>window.ENV_DEPLOYMENT_MODE = 'auto';</script>
<!-- 代理服务器地址统一配置(必须在其他 API 相关脚本之前加载) -->
<script src="js/config/proxy-config.js"></script>
<script src="js/api/api.js?v=2"></script> <script src="js/api/api.js?v=2"></script>
<script src="js/storage/storage.js"></script> <script src="js/storage/storage.js"></script>
<!-- 先初始化存储适配器(提供 isFrontendMode 标记) --> <!-- 先初始化存储适配器(提供 isFrontendMode 标记) -->

View File

@ -63,7 +63,12 @@ async function uploadToMistral(fileToProcess, mistralKey) {
formData.append('file', fileToProcess); formData.append('file', fileToProcess);
formData.append('purpose', 'ocr'); 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', method: 'POST',
headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}` }, headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}` },
body: formData body: formData
@ -91,11 +96,12 @@ async function uploadFileToOssViaProxy(fileToProcess, fileName) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', fileToProcess, fileName); formData.append('file', fileToProcess, fileName);
// 假设 local-proxy 运行在 3456 端口,如果部署到线上可能需要改相对路径或读取配置 // 使用统一配置获取代理地址
// 这里采用跟 Mistral API 相同的基础写法 const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig)
const proxyUrl = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1' ? window.ProxyConfig.getOssUploadUrl()
? 'http://localhost:3456/api/upload/oss' : (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
: '/api/upload/oss'; ? 'http://localhost:3456/api/upload/oss'
: '/api/upload/oss');
const response = await fetch(proxyUrl, { const response = await fetch(proxyUrl, {
method: 'POST', method: 'POST',
@ -124,8 +130,12 @@ async function uploadFileToOssViaProxy(fileToProcess, fileName) {
* @throws {Error} 如果获取签名 URL 失败例如文件 ID 无效认证失败则抛出错误 * @throws {Error} 如果获取签名 URL 失败例如文件 ID 无效认证失败则抛出错误
*/ */
async function getMistralSignedUrl(fileId, mistralKey) { 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', method: 'GET',
headers: { 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}`, 'Accept': 'application/json' } 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 错误处理超时则抛出错误 * @throws {Error} 如果 OCR 处理失败例如 URL 无效API Key 错误处理超时则抛出错误
*/ */
async function callMistralOcr(signedUrl, mistralKey) { 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', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}`, 'Authorization': `Bearer ${mistralKey || 'sk-local-proxy'}`,
@ -183,7 +198,12 @@ async function callMistralOcr(signedUrl, mistralKey) {
*/ */
async function deleteMistralFile(fileId, apiKey) { async function deleteMistralFile(fileId, apiKey) {
if (!fileId) return; // 参数校验 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 { try {
const response = await fetch(deleteUrl, { const response = await fetch(deleteUrl, {
method: 'DELETE', method: 'DELETE',

View File

@ -160,7 +160,8 @@
options.proxyMode === 'proxy' || options.proxyMode === 'proxy' ||
(options.proxyMode !== 'direct' && globalProxyMode === 'proxy'); (options.proxyMode !== 'direct' && globalProxyMode === 'proxy');
const proxyBaseUrl = options.proxyBaseUrl || 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'; 'http://localhost:3456';
const provider = options.provider || 'openai'; const provider = options.provider || 'openai';

View File

@ -138,7 +138,9 @@
// 检测是否使用代理服务器 // 检测是否使用代理服务器
const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto';
const useProxy = globalProxyMode === 'proxy'; 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 或配置推断) // 确定提供商(从模型 ID 或配置推断)
let provider = 'openai'; let provider = 'openai';

View File

@ -445,7 +445,9 @@ async function sendChatbotMessage(userInput, updateChatbotUI, externalConfig = n
// 检测是否使用代理服务器模式 // 检测是否使用代理服务器模式
const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto';
const useProxy = globalProxyMode === 'proxy'; 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 在后端配置,前端可以没有 API Key
// 否则,检查前端是否配置了有效的 API Key // 否则,检查前端是否配置了有效的 API Key
@ -1736,7 +1738,9 @@ async function singleChunkSummary(sysPrompt, userInput, config, apiKey) {
// 代理服务器配置(与 buildCustomApiConfig 保持一致) // 代理服务器配置(与 buildCustomApiConfig 保持一致)
const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto'; const globalProxyMode = (typeof window !== 'undefined' && window.PBX_PROXY_MODE) || 'auto';
const useProxy = globalProxyMode === 'proxy'; 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; let apiConfig;

358
js/config/proxy-config.js Normal file
View File

@ -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()}`);
})();

View File

@ -807,7 +807,10 @@ async function triggerReprocessWithMinerU() {
*/ */
async function executeMinerUStructuredTranslation() { async function executeMinerUStructuredTranslation() {
const logPrefix = '[MinerU结构化翻译]'; 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() : {}; const settings = typeof loadSettings === 'function' ? loadSettings() : {};

View File

@ -798,7 +798,9 @@ const fileType = fileToProcess.name.split('.').pop().toLowerCase();
...translationOptions, ...translationOptions,
useBackendProxy, useBackendProxy,
provider: selectedTranslationModelName, 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), maxRetries: (typeof loadSettings === 'function' ? (loadSettings().structuredMaxRetries || undefined) : undefined),
retryDelay: (typeof loadSettings === 'function' ? (loadSettings().structuredRetryDelayMs || undefined) : undefined) retryDelay: (typeof loadSettings === 'function' ? (loadSettings().structuredRetryDelayMs || undefined) : undefined)

View File

@ -714,7 +714,10 @@ ${jsonContent}
// 后端代理模式 - API Key 由后端管理 // 后端代理模式 - API Key 由后端管理
if (options.useBackendProxy) { 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'; const provider = options.provider || 'aliyun';
// 后端代理端点映射 // 后端代理端点映射
@ -831,9 +834,12 @@ ${jsonContent}
// 预设模型 - 从 translation.js 获取配置 // 预设模型 - 从 translation.js 获取配置
// 简化:仅支持常用模型 // 简化:仅支持常用模型
// 前端发出的请求源头 // 前端发出的请求源头
const proxyUrl = (typeof window !== 'undefined' && window.ProxyConfig)
? window.ProxyConfig.getProxyUrl()
: (window.PBX_PROXY_BASE_URL || 'http://localhost:3456');
const predefinedConfigs = { const predefinedConfigs = {
'proxy': { 'proxy': {
endpoint: 'http://localhost:3456/api/llm/aliyun/v1/chat/completions', endpoint: `${proxyUrl}/api/llm/aliyun/v1/chat/completions`,
modelName: '通义百炼 (via local proxy)', modelName: '通义百炼 (via local proxy)',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
bodyBuilder: (sys, user) => ({ bodyBuilder: (sys, user) => ({

View File

@ -10,7 +10,16 @@ class MistralOcrAdapter extends OcrAdapter {
super(config); super(config);
this.keys = config.keys && config.keys.length > 0 ? config.keys : ['sk-local-proxy']; this.keys = config.keys && config.keys.length > 0 ? config.keys : ['sk-local-proxy'];
this.currentKeyIndex = 0; 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';
}
} }
/** /**

View File

@ -94,10 +94,14 @@ class OcrManager {
} }
case 'mineru': case 'mineru':
// 使用统一配置获取默认 workerUrl
const mineruDefaultUrl = (typeof window !== 'undefined' && window.ProxyConfig)
? window.ProxyConfig.getProxyUrl()
: 'http://localhost:3456';
return { return {
engine: 'mineru', engine: 'mineru',
token: localStorage.getItem('ocrMinerUToken') || '', token: localStorage.getItem('ocrMinerUToken') || '',
workerUrl: (localStorage.getItem('ocrMinerUWorkerUrl') || '').replace(/\/+$/, ''), // 去掉末尾斜杠 workerUrl: (localStorage.getItem('ocrMinerUWorkerUrl') || mineruDefaultUrl).replace(/\/+$/, ''), // 去掉末尾斜杠
authKey: localStorage.getItem('ocrWorkerAuthKey') || '', authKey: localStorage.getItem('ocrWorkerAuthKey') || '',
tokenMode: localStorage.getItem('ocrMinerUTokenMode') || 'frontend', tokenMode: localStorage.getItem('ocrMinerUTokenMode') || 'frontend',
enableOcr: localStorage.getItem('ocrMinerUEnableOcr') !== 'false', enableOcr: localStorage.getItem('ocrMinerUEnableOcr') !== 'false',
@ -106,10 +110,14 @@ class OcrManager {
}; };
case 'doc2x': case 'doc2x':
// 使用统一配置获取默认 workerUrl
const doc2xDefaultUrl = (typeof window !== 'undefined' && window.ProxyConfig)
? window.ProxyConfig.getProxyUrl()
: 'http://localhost:3456';
return { return {
engine: 'doc2x', engine: 'doc2x',
token: localStorage.getItem('ocrDoc2XToken') || '', token: localStorage.getItem('ocrDoc2XToken') || '',
workerUrl: (localStorage.getItem('ocrDoc2XWorkerUrl') || '').replace(/\/+$/, ''), // 去掉末尾斜杠 workerUrl: (localStorage.getItem('ocrDoc2XWorkerUrl') || doc2xDefaultUrl).replace(/\/+$/, ''), // 去掉末尾斜杠
authKey: localStorage.getItem('ocrWorkerAuthKey') || '', authKey: localStorage.getItem('ocrWorkerAuthKey') || '',
tokenMode: localStorage.getItem('ocrDoc2XTokenMode') || 'frontend' tokenMode: localStorage.getItem('ocrDoc2XTokenMode') || 'frontend'
// 注意:不再需要 exportFormat因为我们总是导出 Markdown + 图片 // 注意:不再需要 exportFormat因为我们总是导出 Markdown + 图片

View File

@ -703,7 +703,9 @@ async function translateMarkdown(
const predefinedConfigs = { const predefinedConfigs = {
'aliyun': { '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: '通义百炼', modelName: '通义百炼',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
bodyBuilder: (sys, user) => { bodyBuilder: (sys, user) => {

View File

@ -97,6 +97,8 @@
<!-- 引入必要的库 --> <!-- 引入必要的库 -->
<script src="js/lib/jszip.min.js"></script> <script src="js/lib/jszip.min.js"></script>
<!-- 代理服务器地址统一配置(必须在其他 API 相关脚本之前加载) -->
<script src="js/config/proxy-config.js"></script>
<script src="js/storage/storage.js"></script> <script src="js/storage/storage.js"></script>
<script src="js/api/api.js"></script> <script src="js/api/api.js"></script>
<script src="js/ui/ocr-settings.js"></script> <script src="js/ui/ocr-settings.js"></script>