Files
baiyue-logistics-chat/logistics_chat/business_service.py
T

136 lines
5.3 KiB
Python

"""Feedback, reporting, login, orders and offline tickets."""
from datetime import datetime
from .db import connect, now_str
from .tracking import card_to_text
def feedback(data):
"""收集 👍/👎 反馈,存到 feedback 表"""
conn = connect()
conn.execute('INSERT INTO feedback(question, answer, vote, ctime) VALUES (?,?,?,?)', (str(data.get('question', ''))[:500], str(data.get('answer', ''))[:2000], str(data.get('vote', '')), now_str()))
conn.commit()
conn.close()
return {'ok': True}
def admin_stats():
conn = connect()
total_conv = conn.execute('SELECT COUNT(*) FROM chat_history').fetchone()[0]
total_msg = conn.execute('SELECT COUNT(*) FROM messages').fetchone()[0]
good = conn.execute('SELECT COUNT(*) FROM feedback WHERE vote=1').fetchone()[0]
bad = conn.execute('SELECT COUNT(*) FROM feedback WHERE vote=-1').fetchone()[0]
today = datetime.now().strftime('%Y-%m-%d')
today_conv = conn.execute('SELECT COUNT(*) FROM chat_history WHERE date(ctime)=date(?)', (today,)).fetchone()[0]
rating_avg, rating_count = conn.execute('SELECT COALESCE(AVG(stars), 0), COUNT(*) FROM ratings').fetchone()
conn.close()
return {'total_conv': total_conv, 'total_msg': total_msg, 'good': good, 'bad': bad, 'today_conv': today_conv,
'rating_avg': round(rating_avg, 1), 'rating_count': rating_count}
def my_orders(phone):
if not phone:
return {'orders': []}
conn = connect()
rows = conn.execute('SELECT track_no, status, created FROM orders WHERE phone=? ORDER BY id DESC', (phone,)).fetchall()
conn.close()
return {'orders': [{'track_no': r[0], 'status': r[1], 'created': r[2]} for r in rows]}
def add_ticket(data):
conn = connect()
conn.execute('INSERT INTO tickets(content, phone, ctime, status) VALUES(?,?,?,?)', (data.get('content', ''), data.get('phone', ''), datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'pending'))
conn.commit()
conn.close()
return {'ok': True}
def list_tickets():
conn = connect()
rows = conn.execute("SELECT id, content, phone, ctime FROM tickets WHERE status='pending' ORDER BY id DESC").fetchall()
conn.close()
return [{'id': r[0], 'content': r[1], 'phone': r[2], 'ctime': r[3]} for r in rows]
def admin_login(data):
u = data.get('username', '')
p = data.get('password', '')
conn = connect()
row = conn.execute('SELECT name FROM agents WHERE username=? AND password=?', (u, p)).fetchone()
conn.close()
if row:
return {'ok': True, 'name': row[0]}
return ({'ok': False}, 401)
def agents_list():
conn = connect()
# rowid also works with the legacy agents table that has an explicit INTEGER id.
rows = conn.execute('SELECT rowid, username, name FROM agents ORDER BY rowid').fetchall()
conn.close()
return [{'id': row[0], 'username': row[1], 'name': row[2]} for row in rows]
def rate_chat(data):
sid, stars = data.get('sid'), data.get('stars', 0)
comment = data.get('comment', '')
if not sid or type(stars) is not int or not 1 <= stars <= 5 or not isinstance(comment, str):
return ({'ok': False}, 400)
conn = connect()
if not conn.execute('SELECT 1 FROM human_sessions WHERE id=?', (sid,)).fetchone():
conn.close()
return ({'ok': False}, 404)
conn.execute('INSERT INTO ratings(sid, stars, comment, ctime) VALUES(?,?,?,?)',
(sid, stars, comment, datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
conn.commit()
conn.close()
return {'ok': True}
def search_chat(keyword):
if not keyword:
return {'results': []}
conn = connect()
rows = conn.execute('''SELECT h.title, m.role, m.content, m.ctime FROM messages m
JOIN chat_history h ON m.conv_id=h.id WHERE m.content LIKE ? ORDER BY m.id DESC LIMIT 50''',
('%' + keyword + '%',)).fetchall()
conn.close()
return [{'title': row[0], 'role': row[1], 'content': card_to_text(row[2]), 'ctime': row[3]} for row in rows]
def export_chat(format='xlsx'):
conn = connect()
rows = conn.execute('SELECT h.title, m.role, m.content, m.ctime FROM messages m JOIN chat_history h ON m.conv_id=h.id ORDER BY m.id').fetchall()
conn.close()
import io
if format == 'csv':
import csv
buf = io.StringIO()
w = csv.writer(buf)
w.writerow(['标题', '角色', '内容', '时间'])
for r in rows:
w.writerow([r[0], r[1], r[2] or '', r[3]])
return buf.getvalue()
from openpyxl import Workbook
from openpyxl.styles import Alignment, Font, PatternFill
workbook = Workbook()
sheet = workbook.active
sheet.title = '聊天记录'
sheet.append(['对话标题', '角色', '内容', '时间'])
for cell in sheet[1]:
cell.font = Font(bold=True, color='FFFFFF')
cell.fill = PatternFill('solid', fgColor='315FD5')
cell.alignment = Alignment(horizontal='center')
roles = {'user': '客户', 'assistant': '客服', 'system': '系统'}
for title, role, content, ctime in rows:
sheet.append([title, roles.get(role, role), content or '', ctime])
for cell in sheet[sheet.max_row]:
cell.data_type = 's'
for column, width in zip('ABCD', (20, 8, 80, 20)):
sheet.column_dimensions[column].width = width
buf = io.BytesIO()
workbook.save(buf)
return buf.getvalue()