mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-23 15:43:54 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
942d55118b | ||
|
|
f47f3b050b | ||
|
|
e3453b1a87 | ||
|
|
6e92d169ec | ||
|
|
ed89c05245 |
@@ -33,6 +33,7 @@
|
|||||||
<aliyun-sms-version>4.1.0</aliyun-sms-version>
|
<aliyun-sms-version>4.1.0</aliyun-sms-version>
|
||||||
<okio-version>3.4.0</okio-version>
|
<okio-version>3.4.0</okio-version>
|
||||||
<skipTests>true</skipTests>
|
<skipTests>true</skipTests>
|
||||||
|
<argLine></argLine>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -287,6 +288,7 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<skipTests>${skipTests}</skipTests>
|
<skipTests>${skipTests}</skipTests>
|
||||||
|
<argLine>@{argLine} -Xshare:off -javaagent:"${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar"</argLine>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.function.BiFunction;
|
|||||||
|
|
||||||
import org.apache.ibatis.binding.MapperMethod;
|
import org.apache.ibatis.binding.MapperMethod;
|
||||||
import org.apache.ibatis.executor.BatchResult;
|
import org.apache.ibatis.executor.BatchResult;
|
||||||
|
import org.apache.ibatis.logging.nologging.NoLoggingImpl;
|
||||||
import org.apache.ibatis.mapping.MappedStatement;
|
import org.apache.ibatis.mapping.MappedStatement;
|
||||||
import org.apache.ibatis.session.ExecutorType;
|
import org.apache.ibatis.session.ExecutorType;
|
||||||
import org.apache.ibatis.session.SqlSession;
|
import org.apache.ibatis.session.SqlSession;
|
||||||
@@ -184,6 +185,10 @@ class BaseServiceImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class TestService extends BaseServiceImpl<TestMapper, TestEntity> {
|
private static class TestService extends BaseServiceImpl<TestMapper, TestEntity> {
|
||||||
|
private TestService() {
|
||||||
|
log = new NoLoggingImpl(TestService.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getSqlStatement(SqlMethod sqlMethod) {
|
protected String getSqlStatement(SqlMethod sqlMethod) {
|
||||||
return switch (sqlMethod) {
|
return switch (sqlMethod) {
|
||||||
|
|||||||
@@ -118,8 +118,17 @@ async def process_intent_result(
|
|||||||
|
|
||||||
请根据以上信息回答用户的问题:{original_text}"""
|
请根据以上信息回答用户的问题:{original_text}"""
|
||||||
|
|
||||||
response = conn.intent.replyResult(context_prompt, original_text)
|
# 使用异步调用避免阻塞事件循环,影响其他设备的音频播放
|
||||||
speak_txt(conn, response)
|
try:
|
||||||
|
response = asyncio.run_coroutine_threadsafe(
|
||||||
|
conn.intent.replyResult(context_prompt, original_text),
|
||||||
|
conn.loop,
|
||||||
|
).result()
|
||||||
|
except Exception as e:
|
||||||
|
conn.logger.bind(tag=TAG).error(f"LLM生成回复失败: {e}")
|
||||||
|
response = None
|
||||||
|
if response:
|
||||||
|
speak_txt(conn, response)
|
||||||
|
|
||||||
conn.executor.submit(process_context_result)
|
conn.executor.submit(process_context_result)
|
||||||
return True
|
return True
|
||||||
@@ -184,7 +193,15 @@ async def process_intent_result(
|
|||||||
elif result.action == Action.REQLLM: # 调用函数后再请求llm生成回复
|
elif result.action == Action.REQLLM: # 调用函数后再请求llm生成回复
|
||||||
text = result.result
|
text = result.result
|
||||||
conn.dialogue.put(Message(role="tool", content=text))
|
conn.dialogue.put(Message(role="tool", content=text))
|
||||||
llm_result = conn.intent.replyResult(text, original_text)
|
# 使用异步调用避免阻塞事件循环,影响其他设备的音频播放
|
||||||
|
try:
|
||||||
|
llm_result = asyncio.run_coroutine_threadsafe(
|
||||||
|
conn.intent.replyResult(text, original_text),
|
||||||
|
conn.loop,
|
||||||
|
).result()
|
||||||
|
except Exception as e:
|
||||||
|
conn.logger.bind(tag=TAG).error(f"LLM生成回复失败: {e}")
|
||||||
|
llm_result = text
|
||||||
if llm_result is None:
|
if llm_result is None:
|
||||||
llm_result = text
|
llm_result = text
|
||||||
speak_txt(conn, llm_result)
|
speak_txt(conn, llm_result)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
from typing import List, Dict, TYPE_CHECKING
|
from typing import List, Dict, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@@ -120,12 +121,18 @@ class IntentProvider(IntentProviderBase):
|
|||||||
)
|
)
|
||||||
return prompt
|
return prompt
|
||||||
|
|
||||||
def replyResult(self, text: str, original_text: str):
|
async def replyResult(self, text: str, original_text: str):
|
||||||
|
"""使用 asyncio.to_thread 避免阻塞事件循环"""
|
||||||
try:
|
try:
|
||||||
llm_result = self.llm.response_no_stream(
|
user_prompt = (
|
||||||
|
"请根据以上内容,像人类一样说话的口吻回复用户,要求简洁,请直接返回结果。用户现在说:"
|
||||||
|
+ original_text
|
||||||
|
)
|
||||||
|
# 使用 to_thread 将同步阻塞调用放到线程池中执行,不阻塞事件循环
|
||||||
|
llm_result = await asyncio.to_thread(
|
||||||
|
self.llm.response_no_stream,
|
||||||
system_prompt=text,
|
system_prompt=text,
|
||||||
user_prompt="请根据以上内容,像人类一样说话的口吻回复用户,要求简洁,请直接返回结果。用户现在说:"
|
user_prompt=user_prompt,
|
||||||
+ original_text,
|
|
||||||
)
|
)
|
||||||
return llm_result
|
return llm_result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -207,8 +214,11 @@ class IntentProvider(IntentProviderBase):
|
|||||||
logger.bind(tag=TAG).debug(f"开始LLM意图识别调用, 模型: {model_info}")
|
logger.bind(tag=TAG).debug(f"开始LLM意图识别调用, 模型: {model_info}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
intent = self.llm.response_no_stream(
|
# 使用 to_thread 将同步阻塞调用放到线程池中,避免阻塞事件循环
|
||||||
system_prompt=prompt_music, user_prompt=user_prompt
|
intent = await asyncio.to_thread(
|
||||||
|
self.llm.response_no_stream,
|
||||||
|
system_prompt=prompt_music,
|
||||||
|
user_prompt=user_prompt,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.bind(tag=TAG).error(f"Error in intent detection LLM call: {e}")
|
logger.bind(tag=TAG).error(f"Error in intent detection LLM call: {e}")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
import httpx
|
import httpx
|
||||||
from markitdown import MarkItDown
|
from io import BytesIO
|
||||||
|
from markitdown import MarkItDown, StreamInfo
|
||||||
from config.logger import setup_logging
|
from config.logger import setup_logging
|
||||||
from plugins_func.register import register_function, ToolType, ActionResponse, Action
|
from plugins_func.register import register_function, ToolType, ActionResponse, Action
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
@@ -144,7 +145,14 @@ async def fetch_news_detail(url):
|
|||||||
|
|
||||||
# 使用MarkItDown清理HTML内容
|
# 使用MarkItDown清理HTML内容
|
||||||
md = MarkItDown(enable_plugins=False)
|
md = MarkItDown(enable_plugins=False)
|
||||||
result = md.convert(response)
|
result = md.convert_stream(
|
||||||
|
BytesIO(response.content),
|
||||||
|
stream_info=StreamInfo(
|
||||||
|
mimetype="text/html",
|
||||||
|
extension=".html",
|
||||||
|
charset=response.encoding or "utf-8",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
# 获取清理后的文本内容
|
# 获取清理后的文本内容
|
||||||
clean_text = result.text_content
|
clean_text = result.text_content
|
||||||
|
|||||||
Reference in New Issue
Block a user