update at 2025-10-14 21:52:11
This commit is contained in:
218
web/public/debug-modelstore.html
Normal file
218
web/public/debug-modelstore.html
Normal file
@@ -0,0 +1,218 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ModelStore Debug</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
padding: 20px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1 { color: #333; }
|
||||
.section {
|
||||
background: #f5f5f5;
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
pre {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
button {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
}
|
||||
button:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
.error { color: red; }
|
||||
.success { color: green; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ModelStore 调试工具</h1>
|
||||
|
||||
<div class="section">
|
||||
<h2>LocalStorage 数据</h2>
|
||||
<button onclick="checkLocalStorage()">检查 LocalStorage</button>
|
||||
<button onclick="clearLocalStorage()">清空 model-providers</button>
|
||||
<pre id="localStorage-data">点击"检查 LocalStorage"查看数据</pre>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>测试添加模型服务</h2>
|
||||
<button onclick="addTestProvider()">添加测试 OpenAI 服务</button>
|
||||
<button onclick="addTestOllama()">添加测试 Ollama 服务</button>
|
||||
<pre id="add-result"></pre>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>当前配置</h2>
|
||||
<button onclick="showCurrentConfig()">显示当前配置</button>
|
||||
<pre id="current-config"></pre>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function checkLocalStorage() {
|
||||
const data = {
|
||||
'model-providers': localStorage.getItem('model-providers'),
|
||||
'global-model-settings': localStorage.getItem('global-model-settings'),
|
||||
'all-keys': Object.keys(localStorage)
|
||||
}
|
||||
|
||||
document.getElementById('localStorage-data').textContent = JSON.stringify(data, null, 2)
|
||||
|
||||
if (data['model-providers']) {
|
||||
try {
|
||||
const providers = JSON.parse(data['model-providers'])
|
||||
console.log('Parsed providers:', providers)
|
||||
} catch (e) {
|
||||
console.error('Parse error:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearLocalStorage() {
|
||||
localStorage.removeItem('model-providers')
|
||||
document.getElementById('localStorage-data').textContent = 'model-providers 已清空'
|
||||
setTimeout(checkLocalStorage, 500)
|
||||
}
|
||||
|
||||
function addTestProvider() {
|
||||
const providers = []
|
||||
|
||||
// 添加 OpenAI 测试配置
|
||||
const openaiProvider = {
|
||||
id: 'openai-test-' + Date.now(),
|
||||
name: 'OpenAI 测试',
|
||||
type: 'openai',
|
||||
enabled: true,
|
||||
apiKey: 'sk-test-key',
|
||||
baseUrl: 'https://api.openai.com/v1',
|
||||
models: [
|
||||
{
|
||||
id: 'gpt-4',
|
||||
name: 'GPT-4',
|
||||
maxTokens: 8192,
|
||||
temperature: 0.7
|
||||
},
|
||||
{
|
||||
id: 'gpt-3.5-turbo',
|
||||
name: 'GPT-3.5 Turbo',
|
||||
maxTokens: 4096,
|
||||
temperature: 0.7
|
||||
}
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
// 读取现有配置
|
||||
const existing = localStorage.getItem('model-providers')
|
||||
if (existing) {
|
||||
try {
|
||||
const existingProviders = JSON.parse(existing)
|
||||
providers.push(...existingProviders)
|
||||
} catch (e) {
|
||||
console.error('Parse existing error:', e)
|
||||
}
|
||||
}
|
||||
|
||||
providers.push(openaiProvider)
|
||||
|
||||
localStorage.setItem('model-providers', JSON.stringify(providers))
|
||||
document.getElementById('add-result').innerHTML = '<span class="success">✓ 已添加 OpenAI 测试服务</span>'
|
||||
setTimeout(checkLocalStorage, 500)
|
||||
}
|
||||
|
||||
function addTestOllama() {
|
||||
const providers = []
|
||||
|
||||
// 添加 Ollama 测试配置
|
||||
const ollamaProvider = {
|
||||
id: 'ollama-test-' + Date.now(),
|
||||
name: 'Ollama 本地',
|
||||
type: 'ollama',
|
||||
enabled: true,
|
||||
baseUrl: 'http://localhost:11434',
|
||||
models: [
|
||||
{
|
||||
id: 'llama2',
|
||||
name: 'Llama 2',
|
||||
maxTokens: 4096,
|
||||
temperature: 0.7
|
||||
},
|
||||
{
|
||||
id: 'mistral',
|
||||
name: 'Mistral',
|
||||
maxTokens: 8192,
|
||||
temperature: 0.7
|
||||
}
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
// 读取现有配置
|
||||
const existing = localStorage.getItem('model-providers')
|
||||
if (existing) {
|
||||
try {
|
||||
const existingProviders = JSON.parse(existing)
|
||||
providers.push(...existingProviders)
|
||||
} catch (e) {
|
||||
console.error('Parse existing error:', e)
|
||||
}
|
||||
}
|
||||
|
||||
providers.push(ollamaProvider)
|
||||
|
||||
localStorage.setItem('model-providers', JSON.stringify(providers))
|
||||
document.getElementById('add-result').innerHTML = '<span class="success">✓ 已添加 Ollama 测试服务</span>'
|
||||
setTimeout(checkLocalStorage, 500)
|
||||
}
|
||||
|
||||
function showCurrentConfig() {
|
||||
const providers = localStorage.getItem('model-providers')
|
||||
if (providers) {
|
||||
try {
|
||||
const parsed = JSON.parse(providers)
|
||||
const summary = {
|
||||
总数: parsed.length,
|
||||
已启用: parsed.filter(p => p.enabled).length,
|
||||
服务列表: parsed.map(p => ({
|
||||
名称: p.name,
|
||||
类型: p.type,
|
||||
启用: p.enabled,
|
||||
模型数: p.models?.length || 0,
|
||||
模型列表: p.models?.map(m => m.name) || []
|
||||
}))
|
||||
}
|
||||
document.getElementById('current-config').textContent = JSON.stringify(summary, null, 2)
|
||||
} catch (e) {
|
||||
document.getElementById('current-config').innerHTML = '<span class="error">解析错误: ' + e.message + '</span>'
|
||||
}
|
||||
} else {
|
||||
document.getElementById('current-config').textContent = '暂无配置'
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时自动检查
|
||||
window.onload = function() {
|
||||
checkLocalStorage()
|
||||
showCurrentConfig()
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
292
web/public/diagnose-storage.html
Normal file
292
web/public/diagnose-storage.html
Normal file
@@ -0,0 +1,292 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LocalStorage 诊断工具</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
padding: 20px;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
h1 {
|
||||
color: #4ec9b0;
|
||||
border-bottom: 2px solid #4ec9b0;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
h2 {
|
||||
color: #dcdcaa;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.section {
|
||||
background: #252526;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin: 15px 0;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
.key-name {
|
||||
color: #9cdcfe;
|
||||
font-weight: bold;
|
||||
}
|
||||
.value {
|
||||
color: #ce9178;
|
||||
}
|
||||
pre {
|
||||
background: #1e1e1e;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
button {
|
||||
background: #0e639c;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
button:hover {
|
||||
background: #1177bb;
|
||||
}
|
||||
.success { color: #4ec9b0; }
|
||||
.error { color: #f48771; }
|
||||
.warning { color: #dcdcaa; }
|
||||
.info { color: #9cdcfe; }
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 15px 0;
|
||||
}
|
||||
th, td {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #3c3c3c;
|
||||
}
|
||||
th {
|
||||
background: #1e1e1e;
|
||||
color: #4ec9b0;
|
||||
}
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔍 LocalStorage 完整诊断</h1>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button onclick="diagnose()">🔄 重新诊断</button>
|
||||
<button onclick="fixData()">🔧 修复数据</button>
|
||||
<button onclick="clearAll()">🗑️ 清空所有</button>
|
||||
<button onclick="exportData()">💾 导出数据</button>
|
||||
</div>
|
||||
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function diagnose() {
|
||||
const output = document.getElementById('output')
|
||||
let html = ''
|
||||
|
||||
// 1. 显示所有 LocalStorage 键
|
||||
html += '<div class="section">'
|
||||
html += '<h2>📋 所有 LocalStorage 键值对</h2>'
|
||||
html += '<table>'
|
||||
html += '<tr><th>键名</th><th>大小</th><th>数据类型</th><th>操作</th></tr>'
|
||||
|
||||
const allKeys = Object.keys(localStorage).sort()
|
||||
|
||||
if (allKeys.length === 0) {
|
||||
html += '<tr><td colspan="4" class="warning">⚠️ LocalStorage 为空</td></tr>'
|
||||
} else {
|
||||
allKeys.forEach(key => {
|
||||
const value = localStorage.getItem(key)
|
||||
const size = new Blob([value]).size
|
||||
let type = 'string'
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
type = Array.isArray(parsed) ? 'array' : typeof parsed
|
||||
} catch (e) {
|
||||
type = 'string'
|
||||
}
|
||||
|
||||
html += `<tr>
|
||||
<td class="key-name">${key}</td>
|
||||
<td>${(size / 1024).toFixed(2)} KB</td>
|
||||
<td>${type}</td>
|
||||
<td><button onclick="viewKey('${key}')">查看</button></td>
|
||||
</tr>`
|
||||
})
|
||||
}
|
||||
|
||||
html += '</table></div>'
|
||||
|
||||
// 2. 重点检查模型相关的键
|
||||
html += '<div class="section">'
|
||||
html += '<h2>🎯 模型服务相关键检查</h2>'
|
||||
|
||||
const modelKeys = [
|
||||
'model-services',
|
||||
'model-providers',
|
||||
'model-service-config',
|
||||
'services',
|
||||
'providers'
|
||||
]
|
||||
|
||||
modelKeys.forEach(key => {
|
||||
const value = localStorage.getItem(key)
|
||||
html += `<h3 class="key-name">${key}:</h3>`
|
||||
|
||||
if (!value) {
|
||||
html += `<p class="error">✗ 不存在</p>`
|
||||
} else {
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
if (Array.isArray(parsed)) {
|
||||
html += `<p class="success">✓ 找到 ${parsed.length} 项</p>`
|
||||
html += '<pre>' + JSON.stringify(parsed, null, 2) + '</pre>'
|
||||
} else {
|
||||
html += '<pre>' + JSON.stringify(parsed, null, 2) + '</pre>'
|
||||
}
|
||||
} catch (e) {
|
||||
html += `<p class="warning">⚠️ 非JSON格式</p>`
|
||||
html += '<pre>' + value.substring(0, 500) + '...</pre>'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
html += '</div>'
|
||||
|
||||
// 3. 诊断建议
|
||||
html += '<div class="section">'
|
||||
html += '<h2>💡 诊断结果与建议</h2>'
|
||||
|
||||
const modelServices = localStorage.getItem('model-services')
|
||||
const modelProviders = localStorage.getItem('model-providers')
|
||||
|
||||
if (!modelServices && !modelProviders) {
|
||||
html += '<p class="error">❌ 未找到任何模型服务数据</p>'
|
||||
html += '<p class="info">原因可能:</p>'
|
||||
html += '<ul>'
|
||||
html += '<li>数据保存失败(检查浏览器控制台是否有错误)</li>'
|
||||
html += '<li>使用了不同的存储方式(sessionStorage、IndexedDB等)</li>'
|
||||
html += '<li>页面域名不同导致 LocalStorage 隔离</li>'
|
||||
html += '</ul>'
|
||||
html += '<p class="warning">🔧 建议:点击"修复数据"按钮创建测试数据</p>'
|
||||
} else if (modelServices && !modelProviders) {
|
||||
html += '<p class="warning">⚠️ 找到 model-services 但缺少 model-providers</p>'
|
||||
html += '<p class="info">需要同步数据到 model-providers</p>'
|
||||
} else if (!modelServices && modelProviders) {
|
||||
html += '<p class="success">✓ model-providers 有数据(正确的键)</p>'
|
||||
html += '<p class="info">可以清理旧的 model-services 键</p>'
|
||||
} else {
|
||||
html += '<p class="info">ℹ️ 两个键都存在,需要判断哪个是最新的</p>'
|
||||
}
|
||||
|
||||
html += '</div>'
|
||||
|
||||
output.innerHTML = html
|
||||
}
|
||||
|
||||
function viewKey(key) {
|
||||
const value = localStorage.getItem(key)
|
||||
const newWindow = window.open('', '_blank')
|
||||
newWindow.document.write('<pre>' + JSON.stringify(JSON.parse(value), null, 2) + '</pre>')
|
||||
}
|
||||
|
||||
function fixData() {
|
||||
// 检查是否有 model-services 数据
|
||||
const modelServices = localStorage.getItem('model-services')
|
||||
|
||||
if (modelServices) {
|
||||
// 复制到 model-providers
|
||||
localStorage.setItem('model-providers', modelServices)
|
||||
alert('✓ 已将 model-services 同步到 model-providers')
|
||||
} else {
|
||||
// 创建测试数据
|
||||
const testData = [
|
||||
{
|
||||
id: 'test-dashscope',
|
||||
name: '阿里大模型',
|
||||
type: 'dashscope',
|
||||
url: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
||||
apiKey: 'sk-test',
|
||||
enabled: true,
|
||||
connected: true,
|
||||
status: 'connected',
|
||||
models: [
|
||||
{ id: 'qwen-max', name: 'Qwen Max' },
|
||||
{ id: 'qwen-plus', name: 'Qwen Plus' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'test-volcengine',
|
||||
name: '火山大模型',
|
||||
type: 'volcengine',
|
||||
url: 'https://ark.cn-beijing.volces.com/api/v3',
|
||||
apiKey: 'test-key',
|
||||
enabled: true,
|
||||
connected: true,
|
||||
status: 'connected',
|
||||
models: [
|
||||
{ id: 'doubao-pro-4k', name: 'Doubao Pro 4K' },
|
||||
{ id: 'doubao-pro-32k', name: 'Doubao Pro 32K' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
localStorage.setItem('model-providers', JSON.stringify(testData))
|
||||
localStorage.setItem('model-services', JSON.stringify(testData))
|
||||
alert('✓ 已创建测试数据')
|
||||
}
|
||||
|
||||
diagnose()
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
if (confirm('确定要清空所有 LocalStorage 数据吗?')) {
|
||||
localStorage.clear()
|
||||
alert('✓ 已清空')
|
||||
diagnose()
|
||||
}
|
||||
}
|
||||
|
||||
function exportData() {
|
||||
const data = {}
|
||||
Object.keys(localStorage).forEach(key => {
|
||||
try {
|
||||
data[key] = JSON.parse(localStorage.getItem(key))
|
||||
} catch (e) {
|
||||
data[key] = localStorage.getItem(key)
|
||||
}
|
||||
})
|
||||
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'localStorage-backup.json'
|
||||
a.click()
|
||||
}
|
||||
|
||||
// 页面加载时自动诊断
|
||||
window.onload = diagnose
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
318
web/public/sync-data.html
Normal file
318
web/public/sync-data.html
Normal file
@@ -0,0 +1,318 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>数据同步工具</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
padding: 40px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.description {
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.btn-primary {
|
||||
background: #18a058;
|
||||
color: white;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background: #16915e;
|
||||
}
|
||||
.btn-secondary {
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
.btn-danger {
|
||||
background: #d03050;
|
||||
color: white;
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background: #b02848;
|
||||
}
|
||||
.result {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
display: none;
|
||||
}
|
||||
.result.show {
|
||||
display: block;
|
||||
}
|
||||
.result.success {
|
||||
background: #f0f9ff;
|
||||
border: 1px solid #18a058;
|
||||
color: #18a058;
|
||||
}
|
||||
.result.error {
|
||||
background: #fff0f0;
|
||||
border: 1px solid #d03050;
|
||||
color: #d03050;
|
||||
}
|
||||
.result.info {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #909399;
|
||||
color: #606266;
|
||||
}
|
||||
pre {
|
||||
background: #f5f5f5;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.step {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin: 15px 0;
|
||||
border-left: 4px solid #18a058;
|
||||
}
|
||||
.step-title {
|
||||
font-weight: bold;
|
||||
color: #18a058;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔄 数据同步工具</h1>
|
||||
<p class="description">
|
||||
由于系统使用了不同的 LocalStorage 键名,需要将数据从 <code>model-services</code> 同步到 <code>model-providers</code>。
|
||||
<br>点击下方按钮完成一键同步。
|
||||
</p>
|
||||
|
||||
<div class="button-group">
|
||||
<button class="btn-primary" onclick="syncData()">
|
||||
✓ 一键同步数据
|
||||
</button>
|
||||
<button class="btn-secondary" onclick="checkData()">
|
||||
🔍 检查当前数据
|
||||
</button>
|
||||
<button class="btn-danger" onclick="clearOldData()">
|
||||
🗑️ 清理旧数据
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="result" class="result"></div>
|
||||
|
||||
<div class="step">
|
||||
<div class="step-title">📋 同步步骤说明:</div>
|
||||
<ol>
|
||||
<li>点击"检查当前数据"查看两个键的数据状态</li>
|
||||
<li>点击"一键同步数据"将 model-services 的数据复制到 model-providers</li>
|
||||
<li>刷新聊天页面,模型列表将显示正确的数据</li>
|
||||
<li>(可选) 同步完成后可以点击"清理旧数据"删除 model-services</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showResult(message, type = 'info') {
|
||||
const resultDiv = document.getElementById('result')
|
||||
resultDiv.innerHTML = message
|
||||
resultDiv.className = `result ${type} show`
|
||||
}
|
||||
|
||||
function syncData() {
|
||||
try {
|
||||
// 读取旧数据
|
||||
const oldData = localStorage.getItem('model-services')
|
||||
const newData = localStorage.getItem('model-providers')
|
||||
|
||||
if (!oldData) {
|
||||
showResult('⚠️ 未找到 model-services 数据,无需同步', 'info')
|
||||
return
|
||||
}
|
||||
|
||||
// 解析并验证数据
|
||||
let services
|
||||
try {
|
||||
services = JSON.parse(oldData)
|
||||
if (!Array.isArray(services)) {
|
||||
throw new Error('数据格式不正确')
|
||||
}
|
||||
} catch (e) {
|
||||
showResult(`❌ 数据解析失败: ${e.message}`, 'error')
|
||||
return
|
||||
}
|
||||
|
||||
// 保存到新的键
|
||||
localStorage.setItem('model-providers', oldData)
|
||||
|
||||
// 验证同步结果
|
||||
const synced = localStorage.getItem('model-providers')
|
||||
const syncedData = JSON.parse(synced)
|
||||
|
||||
let summary = `
|
||||
<div style="font-size: 16px; font-weight: bold; margin-bottom: 10px;">
|
||||
✓ 同步成功!
|
||||
</div>
|
||||
<div style="margin-bottom: 10px;">
|
||||
已将 ${services.length} 个服务从 model-services 同步到 model-providers
|
||||
</div>
|
||||
<div style="margin-top: 15px;">
|
||||
<strong>同步的服务:</strong>
|
||||
<ul style="margin: 10px 0; padding-left: 20px;">
|
||||
`
|
||||
|
||||
services.forEach(service => {
|
||||
const modelCount = service.models?.length || 0
|
||||
summary += `<li>${service.name} (${service.type}) - ${modelCount} 个模型</li>`
|
||||
})
|
||||
|
||||
summary += `
|
||||
</ul>
|
||||
</div>
|
||||
<div style="margin-top: 15px; padding: 10px; background: #fff3cd; border-radius: 4px;">
|
||||
⚡ <strong>下一步:</strong> 请刷新聊天页面查看效果
|
||||
</div>
|
||||
`
|
||||
|
||||
showResult(summary, 'success')
|
||||
|
||||
// 自动刷新页面提示
|
||||
setTimeout(() => {
|
||||
if (confirm('数据同步成功!是否立即打开聊天页面查看效果?')) {
|
||||
window.open('/', '_blank')
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
} catch (error) {
|
||||
showResult(`❌ 同步失败: ${error.message}`, 'error')
|
||||
console.error('Sync error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function checkData() {
|
||||
try {
|
||||
const oldData = localStorage.getItem('model-services')
|
||||
const newData = localStorage.getItem('model-providers')
|
||||
|
||||
let report = '<div style="font-size: 16px; font-weight: bold; margin-bottom: 15px;">📊 数据检查报告</div>'
|
||||
|
||||
// 检查 model-services
|
||||
report += '<div style="margin-bottom: 20px;">'
|
||||
report += '<strong>model-services (旧键):</strong><br>'
|
||||
if (oldData) {
|
||||
try {
|
||||
const services = JSON.parse(oldData)
|
||||
report += `✓ 找到数据 (${services.length} 个服务)<br>`
|
||||
report += '<ul style="margin: 5px 0; padding-left: 20px;">'
|
||||
services.forEach(s => {
|
||||
report += `<li>${s.name} - ${s.models?.length || 0} 个模型</li>`
|
||||
})
|
||||
report += '</ul>'
|
||||
} catch (e) {
|
||||
report += `⚠️ 数据格式错误: ${e.message}`
|
||||
}
|
||||
} else {
|
||||
report += '✗ 无数据'
|
||||
}
|
||||
report += '</div>'
|
||||
|
||||
// 检查 model-providers
|
||||
report += '<div style="margin-bottom: 20px;">'
|
||||
report += '<strong>model-providers (新键):</strong><br>'
|
||||
if (newData) {
|
||||
try {
|
||||
const providers = JSON.parse(newData)
|
||||
report += `✓ 找到数据 (${providers.length} 个服务)<br>`
|
||||
report += '<ul style="margin: 5px 0; padding-left: 20px;">'
|
||||
providers.forEach(p => {
|
||||
report += `<li>${p.name} - ${p.models?.length || 0} 个模型</li>`
|
||||
})
|
||||
report += '</ul>'
|
||||
} catch (e) {
|
||||
report += `⚠️ 数据格式错误: ${e.message}`
|
||||
}
|
||||
} else {
|
||||
report += '✗ 无数据'
|
||||
}
|
||||
report += '</div>'
|
||||
|
||||
// 建议
|
||||
report += '<div style="padding: 10px; background: #f0f9ff; border-radius: 4px; border-left: 4px solid #18a058;">'
|
||||
if (oldData && !newData) {
|
||||
report += '💡 建议: 点击"一键同步数据"将旧数据迁移到新键'
|
||||
} else if (oldData && newData) {
|
||||
const oldServices = JSON.parse(oldData)
|
||||
const newProviders = JSON.parse(newData)
|
||||
if (oldServices.length > newProviders.length) {
|
||||
report += '💡 建议: model-services 的数据更新,建议重新同步'
|
||||
} else {
|
||||
report += '✓ 数据已同步,可以点击"清理旧数据"删除 model-services'
|
||||
}
|
||||
} else if (!oldData && newData) {
|
||||
report += '✓ 数据正常,新键已有数据'
|
||||
} else {
|
||||
report += '⚠️ 未找到任何模型服务数据,请先在"模型服务"页面添加服务'
|
||||
}
|
||||
report += '</div>'
|
||||
|
||||
showResult(report, 'info')
|
||||
} catch (error) {
|
||||
showResult(`❌ 检查失败: ${error.message}`, 'error')
|
||||
console.error('Check error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function clearOldData() {
|
||||
if (!confirm('确定要删除 model-services 的旧数据吗?\n\n请确保已经完成数据同步!')) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const oldData = localStorage.getItem('model-services')
|
||||
if (!oldData) {
|
||||
showResult('ℹ️ model-services 中没有数据', 'info')
|
||||
return
|
||||
}
|
||||
|
||||
localStorage.removeItem('model-services')
|
||||
showResult('✓ 旧数据已清理完成', 'success')
|
||||
} catch (error) {
|
||||
showResult(`❌ 清理失败: ${error.message}`, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时自动检查
|
||||
window.onload = function() {
|
||||
checkData()
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user