更新 static/js/api.js

This commit is contained in:
2025-06-06 16:49:13 +08:00
parent e9c3b8cac8
commit d7c238de03

View File

@ -1,265 +1,265 @@
// static/js/api.js // static/js/api.js
/* /*
* 通用的API请求函数 * 通用的API请求函数
* @param { string } endpoint API端点不包含 / api前缀 * @param { string } endpoint API端点不包含 / api前缀
* @param { string } method HTTP方法'GET', 'POST', 'DELETE' * @param { string } method HTTP方法'GET', 'POST', 'DELETE'
* @param { Object } [data = null] 请求体数据GET请求时转换为查询参数 * @param { Object } [data = null] 请求体数据GET请求时转换为查询参数
* @param { string } [baseUrl = ''] 可选的基础URL如果提供则覆盖默认的API_BASE_URL * @param { string } [baseUrl = ''] 可选的基础URL如果提供则覆盖默认的API_BASE_URL
* @returns { Promise < Object >} API响应数据 * @returns { Promise < Object >} API响应数据
*/ */
export async function apiRequest(endpoint, method = 'GET', data = null, baseUrl = '') { export async function apiRequest(endpoint, method = 'GET', data = null, baseUrl = '') {
let url; let url;
if (baseUrl && (baseUrl.startsWith('http://') || baseUrl.startsWith('https://'))) { if (baseUrl && (baseUrl.startsWith('http://') || baseUrl.startsWith('https://'))) {
// 如果baseUrl是完整的URL则直接拼接endpoint // 如果baseUrl是完整的URL则直接拼接endpoint
url = `${baseUrl}${endpoint}`; url = `${baseUrl}${endpoint}`;
} else { } else {
// 否则,使用默认的 /api 前缀或提供的相对baseUrl // 否则,使用默认的 /api 前缀或提供的相对baseUrl
url = `${baseUrl || '/api'}${endpoint}`; url = `${baseUrl || '/api'}${endpoint}`;
} }
const options = { const options = {
method: method, method: method,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}; };
if (method === 'GET' && data) { if (method === 'GET' && data) {
const query = new URLSearchParams(data).toString(); const query = new URLSearchParams(data).toString();
url = `${url}?${query}`; url = `${url}?${query}`;
} else if (data) { } else if (data) {
options.body = JSON.stringify(data); options.body = JSON.stringify(data);
} }
try { try {
const response = await fetch(url, options); const response = await fetch(url, options);
if (!response.ok) { if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: response.statusText })); const errorData = await response.json().catch(() => ({ message: response.statusText }));
throw new Error(errorData.error || errorData.message || `API请求失败: ${response.status}`); throw new Error(errorData.error || errorData.message || `API请求失败: ${response.status}`);
} }
// 根据Content-Type判断返回JSON还是文本 // 根据Content-Type判断返回JSON还是文本
const contentType = response.headers.get('Content-Type'); const contentType = response.headers.get('Content-Type');
if (contentType && contentType.includes('application/json')) { if (contentType && contentType.includes('application/json')) {
return await response.json(); return await response.json();
} else { } else {
// 假设是纯文本,例如日志文件 // 假设是纯文本,例如日志文件
return await response.text(); return await response.text();
} }
} catch (error) { } catch (error) {
console.error(`API请求 (${method} ${url}) 失败:`, error); console.error(`API请求 (${method} ${url}) 失败:`, error);
throw error; // 重新抛出错误以便调用方处理 throw error; // 重新抛出错误以便调用方处理
} }
} }
// --- 配置管理 API --- // --- 配置管理 API ---
export async function fetchConfig() { export async function fetchConfig() {
return apiRequest('/config', 'GET'); return apiRequest('/config', 'GET');
} }
export async function saveConfig(configData) { export async function saveConfig(configData) {
return apiRequest('/config', 'POST', configData); return apiRequest('/config', 'POST', configData);
} }
// --- 角色管理 API --- // --- 角色管理 API ---
export async function fetchRoles() { export async function fetchRoles() {
return apiRequest('/roles', 'GET'); return apiRequest('/roles', 'GET');
} }
export async function createRole(roleId, roleName) { export async function createRole(roleId, roleName) {
return apiRequest('/roles', 'POST', { id: roleId, name: roleName }); return apiRequest('/roles', 'POST', { id: roleId, name: roleName });
} }
export async function deleteRole(roleId) { export async function deleteRole(roleId) {
return apiRequest(`/roles/${roleId}`, 'DELETE'); return apiRequest(`/roles/${roleId}`, 'DELETE');
} }
// --- 记忆管理 API --- // --- 记忆管理 API ---
export async function fetchMemories() { export async function fetchMemories() {
return apiRequest('/memories', 'GET'); return apiRequest('/memories', 'GET');
} }
export async function createMemory(memoryId, memoryName) { export async function createMemory(memoryId, memoryName) {
return apiRequest('/memories', 'POST', { id: memoryId, name: memoryName }); return apiRequest('/memories', 'POST', { id: memoryId, name: memoryName });
} }
export async function deleteMemory(memoryId) { export async function deleteMemory(memoryId) {
return apiRequest(`/memories/${memoryId}`, 'DELETE'); return apiRequest(`/memories/${memoryId}`, 'DELETE');
} }
// --- 会话管理 API --- // --- 会话管理 API ---
export async function fetchActiveSession() { export async function fetchActiveSession() {
return apiRequest('/active_session', 'GET'); return apiRequest('/active_session', 'GET');
} }
export async function setActiveSession(roleId, memoryId) { export async function setActiveSession(roleId, memoryId) {
return apiRequest('/active_session', 'POST', { role_id: roleId, memory_id: memoryId }); return apiRequest('/active_session', 'POST', { role_id: roleId, memory_id: memoryId });
} }
// --- 特征内容 API --- // --- 特征内容 API ---
export async function fetchFeaturesContent() { export async function fetchFeaturesContent() {
return apiRequest('/features_content', 'GET'); return apiRequest('/features_content', 'GET');
} }
export async function saveFeaturesContent(content) { export async function saveFeaturesContent(content) {
return apiRequest('/features_content', 'POST', content); return apiRequest('/features_content', 'POST', content);
} }
// --- 记忆内容 API --- // --- 记忆内容 API ---
export async function fetchMemoryContent() { export async function fetchMemoryContent() {
return apiRequest('/memory_content', 'GET'); return apiRequest('/memory_content', 'GET');
} }
export async function saveMemoryContent(content) { export async function saveMemoryContent(content) {
return apiRequest('/memory_content', 'POST', content); return apiRequest('/memory_content', 'POST', content);
} }
export async function triggerMemoryUpdate() { export async function triggerMemoryUpdate() {
return apiRequest('/memory/trigger_update', 'POST'); return apiRequest('/memory/trigger_update', 'POST');
} }
// --- 聊天与日志 API --- // --- 聊天与日志 API ---
export async function sendMessage(message, useStream = false) { export async function sendMessage(message, useStream = false) {
if (!useStream) { if (!useStream) {
// 使用标准响应方式 // 使用标准响应方式
return apiRequest('/chat', 'POST', { message: message }); return apiRequest('/chat', 'POST', { message: message });
} else { } else {
// 使用流式响应方式 // 使用流式响应方式
const url = '/api/chat?stream=true'; const url = '/api/chat?stream=true';
const options = { const options = {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ message: message }), body: JSON.stringify({ message: message }),
}; };
try { try {
const response = await fetch(url, options); const response = await fetch(url, options);
if (!response.ok) { if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: response.statusText })); const errorData = await response.json().catch(() => ({ message: response.statusText }));
throw new Error(errorData.error || errorData.message || `API请求失败: ${response.status}`); throw new Error(errorData.error || errorData.message || `API请求失败: ${response.status}`);
} }
// 检查是否返回了流 // 检查是否返回了流
if (response.body) { if (response.body) {
const reader = response.body.getReader(); const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8'); const decoder = new TextDecoder('utf-8');
// 创建一个更强健的处理SSE的异步迭代器 // 创建一个更强健的处理SSE的异步迭代器
return { return {
[Symbol.asyncIterator]() { [Symbol.asyncIterator]() {
let buffer = ''; let buffer = '';
return { return {
async next() { async next() {
try { try {
// 读取新数据块 // 读取新数据块
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (done) { if (done) {
console.log('流已结束'); console.log('流已结束');
// 处理buffer中剩余的数据 // 处理buffer中剩余的数据
if (buffer.trim().length > 0) { if (buffer.trim().length > 0) {
console.log('处理buffer中剩余数据:', buffer); console.log('处理buffer中剩余数据:', buffer);
const finalValue = buffer; const finalValue = buffer;
buffer = ''; buffer = '';
return { done: false, value: finalValue }; return { done: false, value: finalValue };
} }
return { done: true, value: undefined }; return { done: true, value: undefined };
} }
// 解码二进制数据并添加到缓冲区 // 解码二进制数据并添加到缓冲区
buffer += decoder.decode(value, { stream: true }); buffer += decoder.decode(value, { stream: true });
// 检查是否有完整的SSE消息 (以"data: "开头的行) // 检查是否有完整的SSE消息 (以"data: "开头的行)
// 注意SSE消息格式为 "data: {...}\n\n" // 注意SSE消息格式为 "data: {...}\n\n"
const lines = buffer.split('\n\n'); const lines = buffer.split('\n\n');
// 如果没有完整的消息,继续读取 // 如果没有完整的消息,继续读取
if (lines.length < 2) { if (lines.length < 2) {
return this.next(); return this.next();
} }
// 提取完整的消息并更新buffer // 提取完整的消息并更新buffer
const completeMessage = lines[0]; const completeMessage = lines[0];
buffer = lines.slice(1).join('\n\n'); buffer = lines.slice(1).join('\n\n');
// 移除 "data: " 前缀并解析 JSON // 移除 "data: " 前缀并解析 JSON
if (completeMessage.startsWith('data: ')) { if (completeMessage.startsWith('data: ')) {
try { try {
const jsonString = completeMessage.substring(6); // 移除 "data: " const jsonString = completeMessage.substring(6); // 移除 "data: "
const parsedData = JSON.parse(jsonString); const parsedData = JSON.parse(jsonString);
if (parsedData.end) { if (parsedData.end) {
// 如果收到结束标记,则流结束 // 如果收到结束标记,则流结束
console.log('收到流结束标记。'); console.log('收到流结束标记。');
return { done: true, value: undefined }; return { done: true, value: undefined };
} else if (parsedData.chunk !== undefined) { } else if (parsedData.chunk !== undefined) {
// 返回 chunk 内容 // 返回 chunk 内容
console.log('解析并返回 chunk:', parsedData.chunk.substring(0, 50) + '...'); console.log('解析并返回 chunk:', parsedData.chunk.substring(0, 50) + '...');
return { done: false, value: parsedData.chunk }; return { done: false, value: parsedData.chunk };
} }
} catch (parseError) { } catch (parseError) {
console.error('解析SSE数据失败:', parseError, '原始数据:', completeMessage); console.error('解析SSE数据失败:', parseError, '原始数据:', completeMessage);
// 如果解析失败,可以返回原始数据抛出错误,这里选择返回原始数据 // 如果解析失败,可以返回原始数据抛出错误,这里选择返回原始数据
return { done: false, value: completeMessage }; return { done: false, value: completeMessage };
} }
} }
// 如果不是有效的SSE数据行继续读取 // 如果不是有效的SSE数据行继续读取
return this.next(); return this.next();
} catch (error) { } catch (error) {
console.error('读取流时出错:', error); console.error('读取流时出错:', error);
return { done: true, value: undefined }; return { done: true, value: undefined };
} }
} }
}; };
} }
}; };
} else { } else {
throw new Error('服务器未返回流响应'); throw new Error('服务器未返回流响应');
} }
} catch (error) { } catch (error) {
console.error(`流式API请求 (POST ${url}) 失败:`, error); console.error(`流式API请求 (POST ${url}) 失败:`, error);
throw error; throw error;
} }
} }
} }
export async function fetchChatLog(limit = null) { export async function fetchChatLog(limit = null) {
return apiRequest('/chat_log', 'GET', limit ? { limit: limit } : null); return apiRequest('/chat_log', 'GET', limit ? { limit: limit } : null);
} }
export async function clearChatLog() { export async function clearChatLog() {
return apiRequest('/chat_log', 'DELETE'); return apiRequest('/chat_log', 'DELETE');
} }
// --- 模型列表 API --- // --- 模型列表 API ---
export async function fetchModels() { export async function fetchModels() {
try { try {
// 始终通过后端代理获取模型列表 // 始终通过后端代理获取模型列表
const data = await apiRequest('/proxy_models', 'GET'); const data = await apiRequest('/proxy_models', 'GET');
if (data && Array.isArray(data.models)) { if (data && Array.isArray(data.models)) {
return data.models.map(model => { return data.models.map(model => {
if (typeof model === 'string') { if (typeof model === 'string') {
return model; return model;
} else if (model && typeof model.name === 'string') { } else if (model && typeof model.name === 'string') {
return model.name; return model.name;
} }
return null; return null;
}).filter(model => model !== null); }).filter(model => model !== null);
} }
return []; return [];
} catch (error) { } catch (error) {
console.error("获取模型列表失败:", error); console.error("获取模型列表失败:", error);
throw error; throw error;
} }
} }
// --- 日志 API --- // --- 日志 API ---
export async function fetchLogs() { export async function fetchLogs() {
return apiRequest('/logs', 'GET'); return apiRequest('/logs', 'GET');
} }
console.log("api.js loaded. Type of fetchConfig:", typeof fetchConfig); console.log("api.js loaded. Type of fetchConfig:", typeof fetchConfig);