808 lines
32 KiB
HTML
808 lines
32 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>设置 - TXT版轻量NotebookLM</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.container {
|
|
background-color: white;
|
|
padding: 30px;
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
text-align: center;
|
|
}
|
|
.nav {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
}
|
|
.nav a {
|
|
display: inline-block;
|
|
padding: 10px 20px;
|
|
margin: 0 10px;
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
text-decoration: none;
|
|
border-radius: 5px;
|
|
}
|
|
.nav a:hover {
|
|
background-color: #45a049;
|
|
}
|
|
.nav a.settings {
|
|
background-color: #2196F3;
|
|
}
|
|
.nav a.settings:hover {
|
|
background-color: #0b7dda;
|
|
}
|
|
.section {
|
|
margin-bottom: 30px;
|
|
padding: 20px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
}
|
|
.section h2 {
|
|
margin-top: 0;
|
|
color: #333;
|
|
border-bottom: 2px solid #4CAF50;
|
|
padding-bottom: 5px;
|
|
}
|
|
.form-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
font-weight: bold;
|
|
}
|
|
input, select, textarea {
|
|
width: 100%;
|
|
padding: 10px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
box-sizing: border-box;
|
|
}
|
|
button {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
margin: 5px;
|
|
}
|
|
button:hover {
|
|
background-color: #45a049;
|
|
}
|
|
.btn-secondary {
|
|
background-color: #2196F3;
|
|
}
|
|
.btn-secondary:hover {
|
|
background-color: #0b7dda;
|
|
}
|
|
.btn-danger {
|
|
background-color: #f44336;
|
|
}
|
|
.btn-danger:hover {
|
|
background-color: #d32f2f;
|
|
}
|
|
.alert {
|
|
padding: 15px;
|
|
margin: 15px 0;
|
|
border-radius: 5px;
|
|
}
|
|
.alert.info {
|
|
background-color: #e3f2fd;
|
|
border-left: 4px solid #2196F3;
|
|
color: #0d47a1;
|
|
}
|
|
.alert.success {
|
|
background-color: #e8f5e9;
|
|
border-left: 4px solid #4CAF50;
|
|
color: #1b5e20;
|
|
}
|
|
.alert.warning {
|
|
background-color: #fff3e0;
|
|
border-left: 4px solid #FF9800;
|
|
color: #e65100;
|
|
}
|
|
.alert.error {
|
|
background-color: #ffebee;
|
|
border-left: 4px solid #f44336;
|
|
color: #b71c1c;
|
|
}
|
|
.hidden {
|
|
display: none !important;
|
|
}
|
|
@media (max-width: 768px) {
|
|
body {
|
|
padding: 10px;
|
|
}
|
|
.container {
|
|
padding: 15px;
|
|
}
|
|
.nav a {
|
|
display: block;
|
|
margin: 5px 0;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>TXT版轻量NotebookLM 设置</h1>
|
|
|
|
<div class="nav">
|
|
<a href="/">主页面</a>
|
|
<a href="/settings" class="settings active">设置</a>
|
|
<a href="/knowledge_bases" class="kb">知识库管理</a>
|
|
</div>
|
|
|
|
<div id="messageArea" class="alert hidden"></div>
|
|
|
|
<div id="messageArea" class="hidden"></div>
|
|
|
|
<!-- 系统配置 -->
|
|
<div class="section">
|
|
<h2>系统配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="maxFiles">最大上传文件数:</label>
|
|
<input type="number" id="maxFiles" min="1" max="100" value="20">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="topK">检索返回结果数量 (Top-K):</label>
|
|
<input type="number" id="topK" min="1" max="50" value="8">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="batchSize">批处理大小:</label>
|
|
<input type="number" id="batchSize" min="1" max="100" value="50">
|
|
</div>
|
|
|
|
<button id="saveSystemConfig">保存系统配置</button>
|
|
</div>
|
|
|
|
<!-- 生成配置 -->
|
|
<div class="section">
|
|
<h2>生成配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="defaultStyle">默认文案风格:</label>
|
|
<select id="defaultStyle">
|
|
<option value="通用文案">通用文案</option>
|
|
<option value="小红书种草风">小红书种草风</option>
|
|
<option value="官方通告">官方通告</option>
|
|
<option value="知乎科普">知乎科普</option>
|
|
<option value="微博热点">微博热点</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="defaultMinLength">默认最小字数:</label>
|
|
<input type="number" id="defaultMinLength" min="10" max="1000" value="50">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="defaultMaxLength">默认最大字数:</label>
|
|
<input type="number" id="defaultMaxLength" min="50" max="2000" value="200">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="temperature">生成温度 (0.0-1.0):</label>
|
|
<input type="number" id="temperature" min="0" max="1" step="0.01" value="0.25">
|
|
</div>
|
|
|
|
<button id="saveGenerationConfig">保存生成配置</button>
|
|
</div>
|
|
|
|
<!-- 检索配置 -->
|
|
<div class="section">
|
|
<h2>检索配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="defaultSearchType">默认检索方式:</label>
|
|
<select id="defaultSearchType">
|
|
<option value="hybrid">混合检索(BM25+向量)</option>
|
|
<option value="vector">仅向量检索</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="bm25Weight">BM25权重 (混合检索时):</label>
|
|
<input type="number" id="bm25Weight" min="0" max="1" step="0.01" value="0.5">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" id="includeContext" checked> 默认包含上下文
|
|
</label>
|
|
</div>
|
|
|
|
<button id="saveRetrievalConfig">保存检索配置</button>
|
|
</div>
|
|
|
|
<!-- 导出配置 -->
|
|
<div class="section">
|
|
<h2>导出配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="defaultExportFormat">默认导出格式:</label>
|
|
<select id="defaultExportFormat">
|
|
<option value="markdown">Markdown</option>
|
|
<option value="docx">DOCX</option>
|
|
</select>
|
|
</div>
|
|
|
|
<button id="saveExportConfig">保存导出配置</button>
|
|
</div>
|
|
|
|
<!-- 日志配置 -->
|
|
<div class="section">
|
|
<h2>日志配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" id="enableLogging" checked> 启用生成日志记录
|
|
</label>
|
|
</div>
|
|
|
|
<button id="clearLogs" class="btn-danger">清空所有日志</button>
|
|
<button id="viewLogs" class="btn-secondary">查看日志</button>
|
|
<button id="saveLogConfig">保存日志配置</button>
|
|
</div>
|
|
|
|
<!-- API配置 -->
|
|
<div class="section">
|
|
<h2>API配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="embeddingProvider">嵌入模型提供商:</label>
|
|
<select id="embeddingProvider">
|
|
<option value="openai">OpenAI</option>
|
|
<option value="anthropic">Anthropic</option>
|
|
<option value="qwen">通义千问</option>
|
|
<option value="openrouter">OpenRouter</option>
|
|
<option value="siliconflow">硅基流动</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="embeddingModel">嵌入模型:</label>
|
|
<select id="embeddingModel">
|
|
<!-- 模型选项将根据提供商动态更新 -->
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="embeddingApiBase">嵌入模型API地址:</label>
|
|
<input type="text" id="embeddingApiBase" value="https://api.openai.com/v1">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="generationProvider">生成模型提供商:</label>
|
|
<select id="generationProvider">
|
|
<option value="openai">OpenAI</option>
|
|
<option value="anthropic">Anthropic</option>
|
|
<option value="qwen">通义千问</option>
|
|
<option value="openrouter">OpenRouter</option>
|
|
<option value="siliconflow">硅基流动</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="generationModel">生成模型:</label>
|
|
<select id="generationModel">
|
|
<!-- 模型选项将根据提供商动态更新 -->
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="generationApiBase">生成模型API地址:</label>
|
|
<input type="text" id="generationApiBase" value="https://api.openai.com/v1">
|
|
</div>
|
|
|
|
<button id="testModelConnection" class="btn-secondary">测试模型连接</button>
|
|
<div id="modelTestResult" class="alert hidden"></div>
|
|
|
|
<button id="saveApiConfig">保存API配置</button>
|
|
</div>
|
|
|
|
<!-- 第三方API密钥配置 -->
|
|
<div class="section">
|
|
<h2>第三方API密钥配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="generationApiBase">生成模型API地址:</label>
|
|
<input type="text" id="generationApiBase" value="https://api.openai.com/v1">
|
|
</div>
|
|
|
|
<button id="saveApiKeyConfig">保存API密钥配置</button>
|
|
</div>
|
|
|
|
<!-- 第三方API密钥配置 -->
|
|
<div class="section">
|
|
<h2>第三方API密钥配置</h2>
|
|
|
|
<div class="form-group">
|
|
<label for="openrouterApiKey">OpenRouter API密钥:</label>
|
|
<input type="password" id="openrouterApiKey" placeholder="请输入OpenRouter API密钥">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="siliconflowApiKey">硅基流动API密钥:</label>
|
|
<input type="password" id="siliconflowApiKey" placeholder="请输入硅基流动API密钥">
|
|
</div>
|
|
|
|
<button id="saveApiKeyConfig">保存API密钥配置</button>
|
|
</div>
|
|
|
|
<!-- 模型管理 -->
|
|
<div class="section">
|
|
<h2>模型管理</h2>
|
|
|
|
<div class="form-group">
|
|
<p>当前支持的模型提供商:</p>
|
|
<ul>
|
|
<li><strong>OpenAI</strong>: 支持GPT系列模型</li>
|
|
<li><strong>Anthropic</strong>: 支持Claude系列模型</li>
|
|
<li><strong>通义千问</strong>: 支持Qwen系列模型</li>
|
|
<li><strong>OpenRouter</strong>: 支持数百种AI模型的统一API网关</li>
|
|
<li><strong>硅基流动</strong>: 支持国内新兴的模型服务提供商</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<p>推荐模型配置:</p>
|
|
<ul>
|
|
<li><strong>嵌入模型</strong>: text-embedding-ada-002 (OpenAI) 或 SiliconFlow/deepseek-ai/DeepSeek-V3</li>
|
|
<li><strong>生成模型</strong>: gpt-3.5-turbo (OpenAI) 或 openrouter/anthropic/claude-3.5-sonnet</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<button id="loadModelConfig">加载推荐模型配置</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// 定义模型映射关系
|
|
const modelMapping = {
|
|
'openai': {
|
|
'embedding': ['text-embedding-ada-002'],
|
|
'generation': ['gpt-3.5-turbo', 'gpt-4', 'gpt-4o']
|
|
},
|
|
'anthropic': {
|
|
'embedding': [],
|
|
'generation': ['claude-3-haiku', 'claude-3-sonnet', 'claude-3-opus']
|
|
},
|
|
'qwen': {
|
|
'embedding': [],
|
|
'generation': ['qwen-turbo', 'qwen-plus', 'qwen-max']
|
|
},
|
|
'openrouter': {
|
|
'embedding': [],
|
|
'generation': ['openai/gpt-4o', 'anthropic/claude-3.5-sonnet', 'google/gemini-pro', 'meta-llama/llama-3.1-70b-instruct']
|
|
},
|
|
'siliconflow': {
|
|
'embedding': ['deepseek-ai/DeepSeek-V3'],
|
|
'generation': ['deepseek-ai/DeepSeek-R1', 'Qwen/Qwen3-72B', 'Qwen/Qwen3-14B']
|
|
}
|
|
};
|
|
|
|
// 更新模型下拉框选项
|
|
function updateModelOptions(providerSelectId, modelSelectId, modelType) {
|
|
const provider = document.getElementById(providerSelectId).value;
|
|
const modelSelect = document.getElementById(modelSelectId);
|
|
|
|
// 清空现有选项
|
|
modelSelect.innerHTML = '';
|
|
|
|
// 添加新选项
|
|
const models = modelMapping[provider][modelType] || [];
|
|
models.forEach(model => {
|
|
const option = document.createElement('option');
|
|
option.value = model;
|
|
option.textContent = model;
|
|
modelSelect.appendChild(option);
|
|
});
|
|
}
|
|
|
|
// 更新API地址
|
|
function updateApiBase(providerSelectId, apiBaseId) {
|
|
const provider = document.getElementById(providerSelectId).value;
|
|
const apiBaseInput = document.getElementById(apiBaseId);
|
|
|
|
// 根据提供商设置默认API地址
|
|
const defaultApiBases = {
|
|
'openai': 'https://api.openai.com/v1',
|
|
'anthropic': 'https://api.anthropic.com/v1',
|
|
'qwen': 'https://dashscope.aliyuncs.com/api/v1',
|
|
'openrouter': 'https://openrouter.ai/api/v1',
|
|
'siliconflow': 'https://api.siliconflow.cn/v1'
|
|
};
|
|
|
|
apiBaseInput.value = defaultApiBases[provider] || '';
|
|
}
|
|
|
|
// 页面加载时获取当前配置
|
|
document.addEventListener('DOMContentLoaded', async function() {
|
|
try {
|
|
const response = await fetch('/api/config');
|
|
if (response.ok) {
|
|
const config = await response.json();
|
|
// 填充表单字段
|
|
document.getElementById('maxFiles').value = config.max_files;
|
|
document.getElementById('topK').value = config.top_k;
|
|
document.getElementById('batchSize').value = config.batch_size;
|
|
document.getElementById('defaultStyle').value = config.default_style;
|
|
document.getElementById('defaultMinLength').value = config.default_min_length;
|
|
document.getElementById('defaultMaxLength').value = config.default_max_length;
|
|
document.getElementById('temperature').value = config.temperature;
|
|
document.getElementById('defaultSearchType').value = config.default_search_type;
|
|
document.getElementById('bm25Weight').value = config.bm25_weight;
|
|
document.getElementById('includeContext').checked = config.include_context;
|
|
document.getElementById('defaultExportFormat').value = config.default_export_format;
|
|
document.getElementById('enableLogging').checked = config.enable_logging;
|
|
document.getElementById('embeddingProvider').value = config.embedding_provider || 'openai';
|
|
document.getElementById('generationProvider').value = config.generation_provider || 'openai';
|
|
document.getElementById('openrouterApiKey').value = config.openrouter_api_key || '';
|
|
document.getElementById('siliconflowApiKey').value = config.siliconflow_api_key || '';
|
|
|
|
// 更新模型选项
|
|
updateModelOptions('embeddingProvider', 'embeddingModel', 'embedding');
|
|
updateModelOptions('generationProvider', 'generationModel', 'generation');
|
|
|
|
// 设置模型值
|
|
document.getElementById('embeddingModel').value = config.embedding_model || 'text-embedding-ada-002';
|
|
document.getElementById('generationModel').value = config.generation_model || 'gpt-3.5-turbo';
|
|
|
|
// 更新API地址
|
|
updateApiBase('embeddingProvider', 'embeddingApiBase');
|
|
updateApiBase('generationProvider', 'generationApiBase');
|
|
|
|
// 设置API地址值
|
|
document.getElementById('embeddingApiBase').value = config.openai_api_base || 'https://api.openai.com/v1';
|
|
document.getElementById('generationApiBase').value = config.openai_api_base || 'https://api.openai.com/v1';
|
|
} else {
|
|
throw new Error('获取配置失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('加载配置失败: ' + error.message, 'error');
|
|
}
|
|
|
|
// 添加提供商选择事件监听器
|
|
document.getElementById('embeddingProvider').addEventListener('change', function() {
|
|
updateModelOptions('embeddingProvider', 'embeddingModel', 'embedding');
|
|
updateApiBase('embeddingProvider', 'embeddingApiBase');
|
|
});
|
|
|
|
document.getElementById('generationProvider').addEventListener('change', function() {
|
|
updateModelOptions('generationProvider', 'generationModel', 'generation');
|
|
updateApiBase('generationProvider', 'generationApiBase');
|
|
});
|
|
});
|
|
|
|
// 保存系统配置
|
|
document.getElementById('saveSystemConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
maxFiles: parseInt(document.getElementById('maxFiles').value),
|
|
topK: parseInt(document.getElementById('topK').value),
|
|
batchSize: parseInt(document.getElementById('batchSize').value)
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
max_files: config.maxFiles,
|
|
top_k: config.topK,
|
|
batch_size: config.batchSize
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('系统配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存系统配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 保存生成配置
|
|
document.getElementById('saveGenerationConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
defaultStyle: document.getElementById('defaultStyle').value,
|
|
defaultMinLength: parseInt(document.getElementById('defaultMinLength').value),
|
|
defaultMaxLength: parseInt(document.getElementById('defaultMaxLength').value),
|
|
temperature: parseFloat(document.getElementById('temperature').value)
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
default_style: config.defaultStyle,
|
|
default_min_length: config.defaultMinLength,
|
|
default_max_length: config.defaultMaxLength,
|
|
temperature: config.temperature
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('生成配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存生成配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 保存检索配置
|
|
document.getElementById('saveRetrievalConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
defaultSearchType: document.getElementById('defaultSearchType').value,
|
|
bm25Weight: parseFloat(document.getElementById('bm25Weight').value),
|
|
includeContext: document.getElementById('includeContext').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
default_search_type: config.defaultSearchType,
|
|
bm25_weight: config.bm25Weight,
|
|
include_context: config.includeContext
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('检索配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存检索配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 保存导出配置
|
|
document.getElementById('saveExportConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
defaultExportFormat: document.getElementById('defaultExportFormat').value
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
default_export_format: config.defaultExportFormat
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('导出配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存导出配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 保存日志配置
|
|
document.getElementById('saveLogConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
enableLogging: document.getElementById('enableLogging').checked
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
enable_logging: config.enableLogging
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('日志配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存日志配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 清空日志
|
|
document.getElementById('clearLogs').addEventListener('click', async function() {
|
|
if (confirm('确定要清空所有日志吗?此操作不可恢复。')) {
|
|
try {
|
|
const response = await fetch('/logs', {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('日志已清空', 'success');
|
|
} else {
|
|
throw new Error('清空日志失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('清空日志失败: ' + error.message, 'error');
|
|
}
|
|
}
|
|
});
|
|
|
|
// 查看日志
|
|
document.getElementById('viewLogs').addEventListener('click', function() {
|
|
// 这里应该跳转到日志查看页面或显示日志模态框
|
|
alert('查看日志功能待实现');
|
|
});
|
|
|
|
// 保存API配置
|
|
document.getElementById('saveApiConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
embeddingProvider: document.getElementById('embeddingProvider').value,
|
|
embeddingModel: document.getElementById('embeddingModel').value,
|
|
embeddingApiBase: document.getElementById('embeddingApiBase').value,
|
|
generationProvider: document.getElementById('generationProvider').value,
|
|
generationModel: document.getElementById('generationModel').value,
|
|
generationApiBase: document.getElementById('generationApiBase').value,
|
|
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
embedding_provider: config.embeddingProvider,
|
|
embedding_model: config.embeddingModel,
|
|
openai_api_base: config.embeddingApiBase, // 注意:这里应该根据提供商设置正确的配置项
|
|
generation_provider: config.generationProvider,
|
|
generation_model: config.generationModel,
|
|
openai_api_base: config.generationApiBase, // 注意:这里应该根据提供商设置正确的配置项
|
|
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('API配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存API配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 测试模型连接
|
|
document.getElementById('testModelConnection').addEventListener('click', async function() {
|
|
// 获取表单数据
|
|
const providerType = document.getElementById('generationProvider').value;
|
|
const modelName = document.getElementById('generationModel').value;
|
|
// 根据提供商获取对应的API密钥
|
|
let apiKey = '';
|
|
if (providerType === 'openrouter') {
|
|
apiKey = document.getElementById('openrouterApiKey').value;
|
|
} else if (providerType === 'siliconflow') {
|
|
apiKey = document.getElementById('siliconflowApiKey').value;
|
|
} else {
|
|
// 对于其他提供商,可能需要从环境变量获取
|
|
// 这里暂时留空,实际应用中可能需要其他处理方式
|
|
}
|
|
const apiBase = document.getElementById('generationApiBase').value;
|
|
|
|
// 显示测试中状态
|
|
const testResult = document.getElementById('modelTestResult');
|
|
testResult.textContent = '测试中...';
|
|
testResult.className = 'alert info';
|
|
testResult.classList.remove('hidden');
|
|
|
|
try {
|
|
// 发送测试请求
|
|
const formData = new FormData();
|
|
formData.append('provider_type', providerType);
|
|
formData.append('model_name', modelName);
|
|
formData.append('api_key', apiKey);
|
|
formData.append('api_base', apiBase);
|
|
|
|
const response = await fetch('/test_model_connection', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (response.ok && result.success) {
|
|
testResult.textContent = result.message;
|
|
testResult.className = 'alert success';
|
|
} else {
|
|
throw new Error(result.detail || '测试失败');
|
|
}
|
|
} catch (error) {
|
|
testResult.textContent = '测试失败: ' + error.message;
|
|
testResult.className = 'alert error';
|
|
}
|
|
});
|
|
|
|
// 保存API密钥配置
|
|
document.getElementById('saveApiKeyConfig').addEventListener('click', async function() {
|
|
const config = {
|
|
openrouterApiKey: document.getElementById('openrouterApiKey').value,
|
|
siliconflowApiKey: document.getElementById('siliconflowApiKey').value
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/config', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
openrouter_api_key: config.openrouterApiKey,
|
|
siliconflow_api_key: config.siliconflowApiKey
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('API密钥配置保存成功', 'success');
|
|
} else {
|
|
throw new Error('保存失败');
|
|
}
|
|
} catch (error) {
|
|
showMessage('保存API密钥配置失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
// 加载推荐模型配置
|
|
document.getElementById('loadModelConfig').addEventListener('click', function() {
|
|
// 这里可以实现加载推荐模型配置的逻辑
|
|
alert('推荐模型配置加载功能待实现');
|
|
});
|
|
|
|
// 显示消息
|
|
function showMessage(message, type) {
|
|
const messageArea = document.getElementById('messageArea');
|
|
messageArea.textContent = message;
|
|
messageArea.className = type;
|
|
messageArea.classList.remove('hidden');
|
|
|
|
// 3秒后自动隐藏消息
|
|
setTimeout(() => {
|
|
messageArea.classList.add('hidden');
|
|
}, 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |