add banbanmini backend
This commit is contained in:
184
talkingq-url/handlers/response_coordinator.py
Normal file
184
talkingq-url/handlers/response_coordinator.py
Normal file
@@ -0,0 +1,184 @@
|
||||
import asyncio
|
||||
from typing import Dict, List
|
||||
from config import settings
|
||||
from utils.logger import session_logger
|
||||
from services.audio_session import AudioSession
|
||||
from services.conversation_history import conversation_history_manager
|
||||
from services.interrupt_handler import interrupt_handler
|
||||
from services.task_manager import task_manager
|
||||
from services.text_generator import TextGenerator
|
||||
from services.tts_synthesizer import TTSSynthesizer
|
||||
from services.audio_sender import AudioSender
|
||||
from services.interruption_helper import InterruptionHelper
|
||||
|
||||
import re
|
||||
|
||||
|
||||
async def _cleanup_queues(text_queue: asyncio.Queue, url_queue: asyncio.Queue, device_id: str, session_id: str):
|
||||
"""清理响应处理中使用的队列"""
|
||||
try:
|
||||
# 清理text_queue
|
||||
text_count = 0
|
||||
while not text_queue.empty():
|
||||
try:
|
||||
item = text_queue.get_nowait()
|
||||
text_queue.task_done()
|
||||
text_count += 1
|
||||
del item
|
||||
except asyncio.QueueEmpty:
|
||||
break
|
||||
|
||||
# 清理url_queue
|
||||
url_count = 0
|
||||
while not url_queue.empty():
|
||||
try:
|
||||
item = url_queue.get_nowait()
|
||||
url_queue.task_done()
|
||||
url_count += 1
|
||||
del item
|
||||
except asyncio.QueueEmpty:
|
||||
break
|
||||
|
||||
session_logger.info(
|
||||
device_id, session_id,
|
||||
f"队列清理完成 - text_queue: {text_count}项, url_queue: {url_count}项"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
device_id, session_id, f"队列清理时出错: {e}"
|
||||
)
|
||||
|
||||
|
||||
SENSITIVE_RESPONSES = [
|
||||
"你好,我无法给到相关内容",
|
||||
"我无法给到相关内容",
|
||||
"Sorry, I didn't catch that",
|
||||
"I didn't catch that",
|
||||
"让我们换一个话题",
|
||||
"Let's change the topic",
|
||||
"Changeons de sujet",
|
||||
"Lassen Sie uns das Thema wechseln",
|
||||
"Cambiemos de tema",
|
||||
"Mari kita tukar topik"
|
||||
]
|
||||
|
||||
def is_sensitive_response(reply: str) -> bool:
|
||||
"""
|
||||
检查回复是否为敏感话题回复,考虑不同语言的标点符号差异
|
||||
"""
|
||||
def normalize_text(text):
|
||||
text = text.lower()
|
||||
punctuations = r'[!"#$%&\'()*+,-./:;<=>?@\[\\\]^_`{|}~""''、。,!?:;()【】「」『』〈〉《》〔〕…—¥€£¥]'
|
||||
text = re.sub(punctuations, '', text)
|
||||
text = re.sub(r'\s+', '', text)
|
||||
full_to_half = str.maketrans({
|
||||
'0': '0', '1': '1', '2': '2', '3': '3', '4': '4',
|
||||
'5': '5', '6': '6', '7': '7', '8': '8', '9': '9',
|
||||
'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd', 'E': 'e',
|
||||
'F': 'f', 'G': 'g', 'H': 'h', 'I': 'i', 'J': 'j',
|
||||
'K': 'k', 'L': 'l', 'M': 'm', 'N': 'n', 'O': 'o',
|
||||
'P': 'p', 'Q': 'q', 'R': 'r', 'S': 's', 'T': 't',
|
||||
'U': 'u', 'V': 'v', 'W': 'w', 'X': 'x', 'Y': 'y',
|
||||
'Z': 'z', 'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd',
|
||||
'e': 'e', 'f': 'f', 'g': 'g', 'h': 'h', 'i': 'i',
|
||||
'j': 'j', 'k': 'k', 'l': 'l', 'm': 'm', 'n': 'n',
|
||||
'o': 'o', 'p': 'p', 'q': 'q', 'r': 'r', 's': 's',
|
||||
't': 't', 'u': 'u', 'v': 'v', 'w': 'w', 'x': 'x',
|
||||
'y': 'y', 'z': 'z', ' ': ''
|
||||
})
|
||||
text = text.translate(full_to_half)
|
||||
return text
|
||||
|
||||
normalized_reply = normalize_text(reply)
|
||||
|
||||
for sensitive_reply in SENSITIVE_RESPONSES:
|
||||
normalized_sensitive = normalize_text(sensitive_reply)
|
||||
if normalized_sensitive in normalized_reply:
|
||||
return True
|
||||
return False
|
||||
|
||||
async def process_response(
|
||||
transcript: str,
|
||||
history: List[Dict[str, str]],
|
||||
selected_role: dict,
|
||||
device_id: str,
|
||||
session_id: str,
|
||||
device_history,
|
||||
session: AudioSession,
|
||||
language: str = None,
|
||||
):
|
||||
|
||||
text_queue = asyncio.Queue() # 从LLM到TTS传递文本
|
||||
url_queue = asyncio.Queue() # 从TTS到发送任务传递音频URL
|
||||
session_key = (device_id, session_id)
|
||||
await InterruptionHelper.register_queue_cleanup(session_key, url_queue)
|
||||
await InterruptionHelper.register_queue_cleanup(session_key, text_queue)
|
||||
text_generator = TextGenerator(device_id, session_id)
|
||||
tts_synthesizer = TTSSynthesizer(device_id, session_id)
|
||||
audio_sender = AudioSender(device_id, session_id, session.websocket)
|
||||
llm_service = session.llm_service
|
||||
tts_service = session.tts_service
|
||||
|
||||
if isinstance(tts_service.__class__.__name__, str) and tts_service.__class__.__name__ == "AliyunTTS":
|
||||
tts_service = await get_tts(selected_role, language)
|
||||
session.tts_service = tts_service
|
||||
session_logger.warning(
|
||||
device_id, session_id, "检测到AliyunTTS已不再支持,自动切换到MiniMaxTTS"
|
||||
)
|
||||
|
||||
text_gen_task = await task_manager.create_task(
|
||||
text_generator.generate_text(
|
||||
llm_service, transcript, history, selected_role, text_queue
|
||||
),
|
||||
device_id=device_id,
|
||||
session_key=(device_id, session_id),
|
||||
task_type="text_generation"
|
||||
)
|
||||
tts_task = await task_manager.create_task(
|
||||
tts_synthesizer.synthesize_audio(
|
||||
tts_service, text_queue, url_queue, selected_role, language # 传递语言参数到TTS
|
||||
),
|
||||
device_id=device_id,
|
||||
session_key=(device_id, session_id),
|
||||
task_type="tts_synthesis"
|
||||
)
|
||||
sender_task = await task_manager.create_task(
|
||||
audio_sender.send_audio_urls(url_queue),
|
||||
device_id=device_id,
|
||||
session_key=(device_id, session_id),
|
||||
task_type="audio_sender"
|
||||
)
|
||||
reply = ""
|
||||
try:
|
||||
reply = await text_gen_task
|
||||
await asyncio.gather(tts_task, sender_task)
|
||||
except Exception as e:
|
||||
session_logger.error(
|
||||
device_id, session_id, f"响应处理过程中出错: {e}", exc_info=True
|
||||
)
|
||||
finally:
|
||||
# 清理队列
|
||||
await _cleanup_queues(text_queue, url_queue, device_id, session_id)
|
||||
if not interrupt_handler.is_interrupted(session_key):
|
||||
if is_sensitive_response(reply):
|
||||
session_logger.info(
|
||||
device_id, session_id, "检测到敏感话题回复,该轮对话将不被添加到历史记录"
|
||||
)
|
||||
else:
|
||||
device_history.history.append({"user": transcript, "assistant": reply})
|
||||
|
||||
if len(device_history.history) > settings.max_conversation_history:
|
||||
device_history.history = device_history.history[-settings.max_conversation_history:]
|
||||
|
||||
role_key = selected_role.get("role_key", settings.selected_role_key)
|
||||
device_history.role_key = role_key
|
||||
await conversation_history_manager.set_history(device_id, device_history, role_key)
|
||||
|
||||
session_logger.info(
|
||||
device_id,
|
||||
session_id,
|
||||
f"已将本轮对话添加到角色 {role_key} 的历史记录并保存到数据库"
|
||||
)
|
||||
|
||||
return reply
|
||||
Reference in New Issue
Block a user