Merge branch 'main' into KnowledgeBase_fix

This commit is contained in:
hrz
2025-11-13 16:51:01 +08:00
committed by GitHub
10 changed files with 62 additions and 42 deletions
@@ -0,0 +1,11 @@
UPDATE `ai_model_config` SET
`doc_link` = 'https://github.com/infiniflow/ragflow/blob/main/README_zh.md',
`remark` = '详细部署教程参考:https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/ragflow-integration.md
部署成功,注冊登录后,点击右上角头像,获得RAGFlow的API KEY和API服务器地址。使用RAGFlow前请在Model Provider中添加模型和设置默认模型。' WHERE `id` = 'RAG_RAGFlow';
update `ai_model_config` set `model_name` = '外挂的大模型意图识别' where `id` = 'Intent_intent_llm';
update `ai_model_config` set `model_name` = '大模型自主函数调用' where `id` = 'Intent_function_call';
update `ai_model_provider` set `name` = '外挂的大模型意图识别' , `fields` = '[{"key":"llm","label":"引用的LLM模型","type":"string"}]' where id = 'SYSTEM_Intent_intent_llm';
update `ai_model_provider` set `name` = '大模型自主函数调用' where id = 'SYSTEM_Intent_function_call';
@@ -416,3 +416,10 @@ databaseChangeLog:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202510251150.sql
- changeSet:
id: 202511131020
author: hrz
changes:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202511131020.sql
@@ -13,7 +13,9 @@
<div class="function-column">
<div class="column-header">
<h4 class="column-title">{{ $t('functionDialog.unselectedFunctions') }}</h4>
<el-button type="text" @click="selectAll" class="select-all-btn">{{ $t('functionDialog.selectAll') }}</el-button>
<el-button type="text" @click="selectAll" class="select-all-btn">
{{ $t('functionDialog.selectAll') }}
</el-button>
</div>
<div class="function-list">
<div v-if="unselected.length">
@@ -21,7 +23,7 @@
<el-checkbox :label="func.name" v-model="selectedNames" @change="(val) => handleCheckboxChange(func, val)"
@click.native.stop></el-checkbox>
<div class="func-tag" @click="handleFunctionClick(func)">
<div class="color-dot" :style="{ backgroundColor: getFunctionColor(func.name) }"></div>
<div class="color-dot"></div>
<span>{{ func.name }}</span>
</div>
</div>
@@ -36,7 +38,9 @@
<div class="function-column">
<div class="column-header">
<h4 class="column-title">{{ $t('functionDialog.selectedFunctions') }}</h4>
<el-button type="text" @click="deselectAll" class="select-all-btn">{{ $t('functionDialog.selectAll') }}</el-button>
<el-button type="text" @click="deselectAll" class="select-all-btn">
{{ $t('functionDialog.selectAll') }}
</el-button>
</div>
<div class="function-list">
<div v-if="selectedList.length > 0">
@@ -44,7 +48,7 @@
<el-checkbox :label="func.name" v-model="selectedNames" @change="(val) => handleCheckboxChange(func, val)"
@click.native.stop></el-checkbox>
<div class="func-tag" @click="handleFunctionClick(func)">
<div class="color-dot" :style="{ backgroundColor: getFunctionColor(func.name) }"></div>
<div class="color-dot"></div>
<span>{{ func.name }}</span>
</div>
</div>
@@ -57,7 +61,9 @@
<!-- 右侧参数配置 -->
<div class="params-column">
<h4 v-if="currentFunction" class="column-title">{{ $t('functionDialog.paramConfig') }} - {{ currentFunction.name }}</h4>
<h4 v-if="currentFunction" class="column-title">
{{ $t('functionDialog.paramConfig') }} - {{ currentFunction.name }}
</h4>
<div v-if="currentFunction" class="params-container">
<el-form :model="currentFunction" class="param-form">
<!-- 遍历 fieldsMeta而不是 params keys -->
@@ -119,8 +125,8 @@
<el-input v-model="mcpUrl" readonly class="url-input">
<template #suffix>
<el-button @click="copyUrl" class="inner-copy-btn" icon="el-icon-document-copy">
{{ $t('functionDialog.copy') }}
</el-button>
{{ $t('functionDialog.copy') }}
</el-button>
</template>
</el-input>
</div>
@@ -191,10 +197,6 @@ export default {
selectedNames: [],
currentFunction: null,
modifiedFunctions: {},
functionColorMap: [
'#FF6B6B', '#4ECDC4', '#45B7D1',
'#96CEB4', '#FFEEAD', '#D4A5A5', '#A2836E'
],
tempFunctions: {},
// 添加一个标志位来跟踪是否已经保存
hasSaved: false,
@@ -405,10 +407,6 @@ export default {
// 通知父组件对话框已关闭且已保存
this.$emit('dialog-closed', true);
},
getFunctionColor(name) {
const hash = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0);
return this.functionColorMap[hash % this.functionColorMap.length];
},
fieldRemark(field) {
let description = (field && field.label) ? field.label : '';
if (field.default) {
@@ -527,6 +525,7 @@ export default {
flex-shrink: 0;
width: 8px;
height: 8px;
background-color: #5778ff;
margin-right: 8px;
border-radius: 50%;
}
+5 -12
View File
@@ -104,7 +104,7 @@
<div slot="content">
<div><strong>功能名称:</strong> {{ func.name }}</div>
</div>
<div class="icon-dot" :style="{ backgroundColor: getFunctionColor(func.name) }">
<div class="icon-dot">
{{ getFunctionDisplayChar(func.name) }}
</div>
</el-tooltip>
@@ -189,10 +189,6 @@ export default {
voiceOptions: [],
showFunctionDialog: false,
currentFunctions: [],
functionColorMap: [
'#FF6B6B', '#4ECDC4', '#45B7D1',
'#96CEB4', '#FFEEAD', '#D4A5A5', '#A2836E'
],
allFunctions: [],
originalFunctions: [],
}
@@ -428,20 +424,16 @@ export default {
}
});
},
getFunctionColor(name) {
const hash = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0);
return this.functionColorMap[hash % this.functionColorMap.length];
},
getFunctionDisplayChar(name) {
if (!name || name.length === 0) return '';
for (let i = 0; i < name.length; i++) {
const char = name[i];
if (/[\u4e00-\u9fa5a-zA-Z0-9]/.test(char)) {
return char;
}
}
// 如果没有找到有效字符,返回第一个字符
return name.charAt(0);
},
@@ -768,11 +760,12 @@ export default {
display: inline-flex;
align-items: center;
justify-content: center;
color: white;
color: #5778ff;
font-weight: bold;
font-size: 12px;
margin-right: 8px;
position: relative;
background-color: #e6ebff;
}
::v-deep .el-form-item__label {
@@ -55,7 +55,6 @@ class IntentProvider(IntentProviderBase):
prompt = (
"【严格格式要求】你必须只能返回JSON格式,绝对不能返回任何自然语言!\n\n"
"你是一个意图识别助手。请分析用户的最后一句话,判断用户意图并调用相应的函数。\n\n"
"【重要规则】以下类型的查询请直接返回result_for_context,无需调用函数:\n"
"- 询问当前时间(如:现在几点、当前时间、查询时间等)\n"
"- 询问今天日期(如:今天几号、今天星期几、今天是什么日期等)\n"
@@ -202,7 +201,7 @@ class IntentProvider(IntentProviderBase):
# 记录LLM调用完成时间
llm_time = time.time() - llm_start_time
logger.bind(tag=TAG).debug(
f"LLM意图识别完成, 模型: {model_info}, 调用耗时: {llm_time:.4f}"
f"外挂的大模型意图识别完成, 模型: {model_info}, 调用耗时: {llm_time:.4f}"
)
# 记录后处理开始时间
@@ -238,8 +237,10 @@ class IntentProvider(IntentProviderBase):
# 处理不同类型的意图
if function_name == "result_for_context":
# 处理基础信息查询,直接从context构建结果
logger.bind(tag=TAG).info("检测到result_for_context意图,将使用上下文信息直接回答")
logger.bind(tag=TAG).info(
"检测到result_for_context意图,将使用上下文信息直接回答"
)
elif function_name == "continue_chat":
# 处理普通对话
# 保留非工具相关的消息
@@ -249,7 +250,7 @@ class IntentProvider(IntentProviderBase):
if msg.role not in ["tool", "function"]
]
conn.dialogue.dialogue = clean_history
else:
# 处理函数调用
logger.bind(tag=TAG).info(f"检测到函数调用意图: {function_name}")
@@ -240,7 +240,7 @@ class TTSProvider(TTSProviderBase):
self.conn.sentence_id = uuid.uuid4().hex
logger.bind(tag=TAG).debug(f"自动生成新的 会话ID: {self.conn.sentence_id}")
logger.bind(tag=TAG).debu("开始启动TTS会话...")
logger.bind(tag=TAG).debug("开始启动TTS会话...")
future = asyncio.run_coroutine_threadsafe(
self.start_session(self.conn.sentence_id),
loop=self.conn.loop,
+12
View File
@@ -1430,6 +1430,13 @@
};
log('使用AudioWorklet处理音频', 'success');
// 需要连接输出,否则不会触发处理
// 我们创建一个静音通道
const silent = audioContext.createGain();
silent.gain.value = 0;
audioProcessor.connect(silent);
silent.connect(audioContext.destination);
return { node: audioProcessor, type: 'worklet' };
} else {
// 使用旧版ScriptProcessorNode作为回退方案
@@ -1604,6 +1611,11 @@
// 创建音频上下文和分析器
audioContext = getAudioContextInstance();
// 浏览器出于安全和性能考虑,新创建的 AudioContext 默认处于 suspended 状态,必须显式调用 resume() 才会开始处理音频。
if (audioContext.state === 'suspended') {
await audioContext.resume();
}
// 创建音频处理器
const processorResult = await createAudioProcessor();
if (!processorResult) {