Files
baiyue-logistics-chat/logistics_chat/human_service.py
T
ouyangxq 805675f8db 重构物流客服模块并完善会话接待工作台
- 拆分应用工厂、业务服务与路由,保留原有 HTTP/SSE 和存储入口
- 分离页面资源,重排客服工作台并完善响应式导航、草稿和附件交互
- 整理维护脚本、请求示例和贡献指南,移除启动脚本中的密钥配置
- 上传文件改为仅本地保留,补充隔离的后端与前端回归验证

验证:46 项 Python 测试通过,含 14 个已有子测试;12 个 Node 前端场景通过。
2026-10-29 10:59:29 +08:00

103 lines
3.2 KiB
Python

"""Human conversation lifecycle; typing state is supplied by the app."""
import time
from datetime import datetime
from .db import connect
def human_request(data):
conv_id = data.get('conv_id')
if not conv_id:
return ({'ok': False, 'error': 'no conv'}, 400)
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
conn = connect()
row = conn.execute("SELECT id FROM human_sessions WHERE conv_id=? AND status!='closed' ORDER BY id DESC LIMIT 1", (conv_id,)).fetchone()
if row:
sid = row[0]
else:
cur = conn.execute('INSERT INTO human_sessions(conv_id, status, ctime) VALUES(?,?,?)', (conv_id, 'waiting', now))
sid = cur.lastrowid
conn.commit()
conn.close()
return {'ok': True, 'session_id': sid}
def human_poll(sid, after, typing_map):
conn = connect()
msgs = conn.execute('SELECT id, side, content, ctime, read_at FROM human_messages WHERE session_id=? AND id>? ORDER BY id', (sid, after)).fetchall()
st = conn.execute('SELECT status FROM human_sessions WHERE id=?', (sid,)).fetchone()
conn.close()
is_typing = False
ts = typing_map.get(str(sid))
if ts and time.time() - ts < 5:
is_typing = True
return {'status': st[0] if st else 'closed', 'typing': is_typing, 'messages': [{'id': m[0], 'side': m[1], 'content': m[2], 'ctime': m[3], 'read': bool(m[4])} for m in msgs]}
def human_send(data):
sid = data.get('sid')
side = data.get('side', 'customer')
content = (data.get('content') or '').strip()
if not sid or not content:
return ({'ok': False}, 400)
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
conn = connect()
conn.execute('INSERT INTO human_messages(session_id, side, content, ctime) VALUES(?,?,?,?)', (sid, side, content, now))
conn.commit()
conn.close()
return {'ok': True}
def human_queue():
conn = connect()
rows = conn.execute("SELECT id, conv_id, status, ctime FROM human_sessions WHERE status='waiting' ORDER BY id").fetchall()
conn.close()
return [{'id': r[0], 'conv_id': r[1], 'ctime': r[3]} for r in rows]
def human_active():
conn = connect()
rows = conn.execute("SELECT id, conv_id FROM human_sessions WHERE status='active' ORDER BY id").fetchall()
conn.close()
return [{'id': r[0], 'conv_id': r[1]} for r in rows]
def human_accept(data):
sid = data.get('sid')
conn = connect()
conn.execute("UPDATE human_sessions SET status='active' WHERE id=?", (sid,))
conn.commit()
conn.close()
return {'ok': True}
def human_close(data):
sid = data.get('sid')
conn = connect()
conn.execute("UPDATE human_sessions SET status='closed' WHERE id=?", (sid,))
conn.commit()
conn.close()
return {'ok': True}
def human_typing(data, typing_map):
sid = data.get('sid')
typing_map[str(sid)] = time.time()
return {'ok': True}
def human_stop_typing(data, typing_map):
sid = data.get('sid')
typing_map.pop(str(sid), None)
return {'ok': True}
def human_read(data):
sid = data.get('sid')
conn = connect()
conn.execute("UPDATE human_messages SET read_at=? WHERE session_id=? AND side='customer' AND read_at IS NULL", (datetime.now().strftime('%Y-%m-%d %H:%M:%S'), sid))
conn.commit()
conn.close()
return {'ok': True}