Files
tw/core/ai_reply_flow.py

136 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from core.pydantic_ai_agent import AgentDeps, ConversationState, CustomerMessage, CustomerServiceAgent
def select_target_agent(agent: "CustomerServiceAgent", message: "CustomerMessage", state: "ConversationState"):
msg_lower = message.msg.lower()
pricing_kw = ["多少钱", "多少一张", "报价", "给个价", "几块", "价位", "能便宜点吗"]
processing_kw = ["安排", "处理一下", "开始做", "做一下", "尽快", "加急", "付款了", "已付款"]
similar_kw = ["有一样的", "有一样吗", "一样的吗", "类似的", "类似的吗", "同款", "相似", "类似吗"]
order_markers = ["[系统订单信息]", "订单状态", "买家已付款"]
risk_kw = [
"黄色",
"擦边",
"色情",
"涉黄",
"涉政",
"政治",
"",
"不雅",
"天安门",
"政治人物",
"政治事件",
"领导人",
"党政",
"习近平",
"毛泽东",
"邓小平",
"江泽民",
"胡锦涛",
"特朗普",
"拜登",
"普京",
"泽连斯基",
"地图",
"地形图",
"行政区划图",
"卫星地图",
]
target_agent = agent.agent_after_sale if state.stage == "售后" else agent.agent
risk_hit = any(k in msg_lower for k in risk_kw) or agent._is_political_inquiry(message.msg) or agent._is_map_inquiry(message.msg)
if risk_hit:
return agent.agent_risk
if any(k in message.msg for k in order_markers):
return agent.agent_order
if any(k in msg_lower for k in processing_kw):
return agent.agent_processing
if any(k in msg_lower for k in pricing_kw):
return agent.agent_pricing
if any(k in msg_lower for k in similar_kw):
return agent.agent_similar
return target_agent
async def execute_ai_turn(
agent: "CustomerServiceAgent",
*,
message: "CustomerMessage",
state: "ConversationState",
user_prompt: str,
deps: "AgentDeps",
history: list,
) -> str:
target_agent = select_target_agent(agent, message, state)
result = await target_agent.run(user_prompt, deps=deps, message_history=history)
agent.message_histories[message.from_id] = result.all_messages()[-30:]
reply_text = agent._colloquialize_reply(agent._normalize_reply_text(result.output))
strategy_reply = agent._negotiation_strategy_reply(message.msg, state)
if strategy_reply:
reply_text = strategy_reply
try:
from config.config import MIN_PRICE_FLOOR
import re
offer = None
m = re.search(r"(\d{1,4})\s*(?:元|块|块钱|元钱)\b", message.msg)
if m:
offer = int(m.group(1))
else:
m2 = re.search(r"(?:能|可以|可否|能否)\s*(\d{1,4})\b", message.msg)
offer = int(m2.group(1)) if m2 else None
st = agent._get_conversation_state(message.from_id)
floor = st.last_min_price if isinstance(st.last_min_price, int) and st.last_min_price > 0 else MIN_PRICE_FLOOR
if offer is not None and offer < floor:
reply_text = "不好意思"
except Exception:
pass
try:
from config.config import MIN_PRICE_FLOOR
import re
st = agent._get_conversation_state(message.from_id)
floor = st.last_min_price if isinstance(st.last_min_price, int) and st.last_min_price > 0 else MIN_PRICE_FLOOR
def _adjust(text: str) -> str:
def _repl(m: Any):
num = int(m.group(1))
adj = max(floor, round(num / 5) * 5)
return m.group(0).replace(str(num), str(adj))
patterns = [
r"按(\d{1,4})元",
r"报价[:]\s*(\d{1,4})\s*元",
r"(\d{1,4})\s*元一张",
r"打包(\d{1,4})\s*元",
]
t = text
for p in patterns:
t = re.sub(p, _repl, t)
return t
reply_text = _adjust(reply_text or "")
except Exception:
pass
for msg in result.new_messages():
for part in getattr(msg, "parts", []):
part_type = type(part).__name__
if "ToolCall" in part_type:
print(
f"{agent.C_TOOL}[THINK/TOOL_CALL]{agent.C_RESET} "
f"{getattr(part, 'tool_name', '')}({getattr(part, 'args', '')})"
)
elif "ToolReturn" in part_type:
ret = str(getattr(part, "content", ""))[:120]
print(f"{agent.C_TOOL}[THINK/TOOL_RETURN]{agent.C_RESET} {ret}")
print(f"{agent.C_THINK}[THINK/RAW_OUTPUT]{agent.C_RESET} {repr(reply_text)}")
return reply_text