allow multi-part replies for xiaoniu qa responses
This commit is contained in:
@@ -298,13 +298,15 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
||||
)
|
||||
return False, "empty_response"
|
||||
|
||||
response = self._finalize_reply(response, reply_mode)
|
||||
reply_chunks = self._finalize_reply(response, reply_mode)
|
||||
|
||||
await bot.send_text_message(room_id, response, sender)
|
||||
for chunk in reply_chunks:
|
||||
await bot.send_text_message(room_id, chunk, sender)
|
||||
self.last_reply_at[room_id] = time.time()
|
||||
self.flow_manager.note_bot_reply(room_id)
|
||||
self.memory_store.note_bot_reply(room_id, sender, trigger.topic)
|
||||
self._upsert_interaction_memory(room_id, sender, sender_name, content, response, trigger.trigger_type, trigger.topic)
|
||||
final_response_text = "\n".join(reply_chunks)
|
||||
self._upsert_interaction_memory(room_id, sender, sender_name, content, final_response_text, trigger.trigger_type, trigger.topic)
|
||||
self._log_event(
|
||||
"sent",
|
||||
room_id=room_id,
|
||||
@@ -312,8 +314,9 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
||||
sender_name=sender_name,
|
||||
trigger_type=trigger.trigger_type,
|
||||
reply_mode=reply_mode,
|
||||
response_preview=self._preview(response),
|
||||
response_len=len(response),
|
||||
response_preview=self._preview(final_response_text),
|
||||
response_len=len(final_response_text),
|
||||
chunk_count=len(reply_chunks),
|
||||
)
|
||||
return False, "replied"
|
||||
|
||||
@@ -487,31 +490,29 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
||||
response = re.sub(r"\n{3,}", "\n\n", response)
|
||||
return response[:500].strip()
|
||||
|
||||
def _finalize_reply(self, response: str, reply_mode: str) -> str:
|
||||
def _finalize_reply(self, response: str, reply_mode: str) -> List[str]:
|
||||
text = (response or "").strip()
|
||||
if not text:
|
||||
return ""
|
||||
return []
|
||||
text = re.sub(r"\s+", " ", text)
|
||||
text = text.replace("\n", " ").strip()
|
||||
|
||||
if reply_mode == "social_short":
|
||||
text = self._take_first_sentence(text, 12)
|
||||
return [self._take_first_sentence(text, 12).strip()]
|
||||
elif reply_mode == "qa_fast":
|
||||
text = self._take_first_sentence(text, 28)
|
||||
return self._split_reply_chunks(text, sentence_limit=2, char_limit=28, chunk_limit=2)
|
||||
elif reply_mode == "qa_with_context":
|
||||
text = self._take_first_sentence(text, 36)
|
||||
else:
|
||||
text = self._take_first_sentence(text, 24)
|
||||
return text.strip()
|
||||
return self._split_reply_chunks(text, sentence_limit=2, char_limit=36, chunk_limit=2)
|
||||
return [self._take_first_sentence(text, 24).strip()]
|
||||
|
||||
@staticmethod
|
||||
def _build_length_rule(reply_mode: str) -> str:
|
||||
if reply_mode == "social_short":
|
||||
return "默认只回一句短话,最好控制在2到8个字,除非非常不自然。"
|
||||
if reply_mode == "qa_fast":
|
||||
return "尽量只回1句话,总长度优先控制在28字内,先给结论,不要主动补解释。"
|
||||
return "优先1句话;如果确实需要,可以拆成2条很短的话发出,总长度每条优先控制在28字内,先给结论,不要主动补解释。"
|
||||
if reply_mode == "qa_with_context":
|
||||
return "优先控制在1句话,必要时最多2句,总长度优先控制在36字内,只给第一层答案。"
|
||||
return "优先控制在1句话;必要时可以拆成2条短消息发出,每条优先控制在36字内,只给第一层答案。"
|
||||
return "尽量短,像群友临时接一句,不要长篇大论。"
|
||||
|
||||
@staticmethod
|
||||
@@ -523,6 +524,24 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
||||
clipped = first[:limit].rstrip(",,、;;::")
|
||||
return clipped
|
||||
|
||||
@staticmethod
|
||||
def _split_reply_chunks(text: str, sentence_limit: int, char_limit: int, chunk_limit: int) -> List[str]:
|
||||
parts = [item.strip() for item in re.split(r"(?<=[。!?!?;;])", text) if item.strip()]
|
||||
if not parts:
|
||||
short = text.strip()
|
||||
return [short[:char_limit].rstrip(",,、;;::").strip()] if short else []
|
||||
|
||||
chunks: List[str] = []
|
||||
for part in parts[:sentence_limit]:
|
||||
current = part
|
||||
if len(current) > char_limit:
|
||||
current = current[:char_limit].rstrip(",,、;;::")
|
||||
if current:
|
||||
chunks.append(current.strip())
|
||||
if len(chunks) >= chunk_limit:
|
||||
break
|
||||
return chunks[:chunk_limit] or [text[:char_limit].strip()]
|
||||
|
||||
|
||||
def _sync_member_memory(self, room_id: str, sender: str, sender_name: str, member_context: Dict) -> None:
|
||||
if not member_context:
|
||||
@@ -663,6 +682,7 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
||||
f"[XIAONIU] SENT room={room} user={sender_name}/{sender} "
|
||||
f"trigger={data.get('trigger_type', 'none')} "
|
||||
f"mode={data.get('reply_mode', '')} "
|
||||
f"chunks={data.get('chunk_count', 1)} "
|
||||
f"len={data.get('response_len', 0)} "
|
||||
f"reply={data.get('response_preview', '')}"
|
||||
).strip()
|
||||
|
||||
Reference in New Issue
Block a user