Compare commits

...

3 Commits

2 changed files with 90 additions and 9 deletions

View File

@@ -1345,10 +1345,20 @@ def get_frontend_config():
conn = get_db()
cursor = conn.cursor()
# 获取默认LLM配置
cursor.execute('SELECT * FROM llm_configs WHERE is_default=1 AND is_active=1 LIMIT 1')
# 获取默认对话配置
cursor.execute('SELECT * FROM chat_configs WHERE is_default=1 LIMIT 1')
chat_config = cursor.fetchone()
# 根据对话配置中的 llm_config_id 获取对应的 LLM 配置
llm_config_id = chat_config['llm_config_id'] if chat_config else 1
cursor.execute('SELECT * FROM llm_configs WHERE id=?', (llm_config_id,))
llm = cursor.fetchone()
# 如果找不到对应的LLM配置使用默认的
if not llm:
cursor.execute('SELECT * FROM llm_configs WHERE is_default=1 LIMIT 1')
llm = cursor.fetchone()
# 获取默认工具配置(搜索等)
cursor.execute('SELECT * FROM tool_configs WHERE is_default=1 AND is_active=1')
tools = [dict(row) for row in cursor.fetchall()]
@@ -1361,10 +1371,6 @@ def get_frontend_config():
cursor.execute('SELECT agent_id, name, avatar, category, description, system_prompt, heat, tags, enable_tools FROM agents WHERE is_online=1 AND is_active=1')
agents = [dict(row) for row in cursor.fetchall()]
# 获取默认对话配置
cursor.execute('SELECT * FROM chat_configs WHERE is_default=1 LIMIT 1')
chat_config = cursor.fetchone()
# 获取系统配置
cursor.execute('SELECT key, value FROM system_configs')
system = {row['key']: row['value'] for row in cursor.fetchall()}

View File

@@ -140,7 +140,13 @@ async function loadBackendConfig() {
// 将后台 LLM 配置赋值到 CONFIG
if (backendConfig.llm) {
CONFIG.apiUrl = backendConfig.llm.api_url;
// 自动拼接 /chat/completions如果不是完整URL
let apiUrl = backendConfig.llm.api_url;
if (apiUrl && !apiUrl.includes('/chat/completions')) {
// 确保URL以/结尾再拼接,或直接拼接
apiUrl = apiUrl.endsWith('/') ? apiUrl + 'chat/completions' : apiUrl + '/chat/completions';
}
CONFIG.apiUrl = apiUrl;
CONFIG.apiKey = backendConfig.llm.api_key;
CONFIG.model = backendConfig.llm.model;
CONFIG.maxTokens = backendConfig.llm.max_tokens || 2048;
@@ -4790,6 +4796,66 @@ function renderMessages() {
// ==================== TTS 队列播放 ====================
// 清理 TTS 文本过滤Markdown特殊字符和表情
function cleanTTSText(text) {
if (!text) return '';
let cleaned = text;
// 移除代码块(```code```
cleaned = cleaned.replace(/```[\s\S]*?```/g, '');
// 移除行内代码(`code`
cleaned = cleaned.replace(/`[^`]+`/g, '');
// 移除标题符号(#、##、###等)
cleaned = cleaned.replace(/^#{1,6}\s*/gm, '');
// 移除列表符号(-、*、+
cleaned = cleaned.replace(/^[\-\*\+]\s+/gm, '');
// 移除数字列表1.、2.等)
cleaned = cleaned.replace(/^\d+\.\s+/gm, '');
// 处理链接 [text](url) -> 只保留text
cleaned = cleaned.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
// 移除粗体/斜体符号(**text**、*text*、__text__、_text_
cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1');
cleaned = cleaned.replace(/\*([^*]+)\*/g, '$1');
cleaned = cleaned.replace(/__([^_]+)__/g, '$1');
cleaned = cleaned.replace(/_([^_]+)_/g, '$1');
// 移除引用符号(>
cleaned = cleaned.replace(/^>\s*/gm, '');
// 移除分割线(---、***
cleaned = cleaned.replace(/^[\-\*]{3,}$/gm, '');
// 移除表情符号常见emoji范围
cleaned = cleaned.replace(/[\u{1F600}-\u{1F64F}]/gu, ''); // 表情
cleaned = cleaned.replace(/[\u{1F300}-\u{1F5FF}]/gu, ''); // 符号和图形
cleaned = cleaned.replace(/[\u{1F680}-\u{1F6FF}]/gu, ''); // 交通和地图
cleaned = cleaned.replace(/[\u{1F700}-\u{1F77F}]/gu, ''); // 占星术
cleaned = cleaned.replace(/[\u{1F780}-\u{1F7FF}]/gu, ''); // 几何图形
cleaned = cleaned.replace(/[\u{1F800}-\u{1F8FF}]/gu, ''); // 补充箭头
cleaned = cleaned.replace(/[\u{1F900}-\u{1F9FF}]/gu, ''); // 补充符号
cleaned = cleaned.replace(/[\u{1FA00}-\u{1FA6F}]/gu, ''); // 游戏符号
cleaned = cleaned.replace(/[\u{1FA70}-\u{1FAFF}]/gu, ''); // 补充符号B
cleaned = cleaned.replace(/[\u{2600}-\u{26FF}]/gu, ''); // 杂项符号
cleaned = cleaned.replace(/[\u{2700}-\u{27BF}]/gu, ''); // 装饰符号
cleaned = cleaned.replace(/[\u{FE00}-\u{FE0F}]/gu, ''); // 变体选择符
cleaned = cleaned.replace(/[\u{1F1E0}-\u{1F1FF}]/gu, ''); // 旗帜
// 移除HTML实体
cleaned = cleaned.replace(/&[a-zA-Z]+;/g, '');
// 清理多余空白
cleaned = cleaned.replace(/\s+/g, ' ').trim();
return cleaned;
}
// 添加文本到 TTS 队列
async function addToTTSQueue(text) {
if (!text || !enableTTS) return;
@@ -4812,7 +4878,10 @@ async function playTTSQueue() {
isTTSPlaying = true;
while (ttsQueue.length > 0 && enableTTS) {
const text = ttsQueue.shift();
const rawText = ttsQueue.shift();
const text = cleanTTSText(rawText); // 清理文本
if (!text) continue; // 跳过空文本
try {
const response = await fetch('/api/tts', {
@@ -4866,7 +4935,13 @@ async function playTTS(index) {
const msg = currentConversation.messages[index];
if (!msg || msg.role !== 'assistant') return;
const text = msg.content;
const rawText = msg.content;
if (!rawText) {
showToast('没有可播放的内容');
return;
}
const text = cleanTTSText(rawText); // 清理文本
if (!text) {
showToast('没有可播放的内容');
return;