- Added a new visitor chat API endpoint (`/api/chat/visitor`) to allow unauthenticated users to engage in conversations without requiring customer data. - Introduced a visitor context dependency to manage visitor interactions seamlessly. - Enhanced the chat API to support explicit session termination and improved response handling for customer service interactions. - Updated the database configuration to include Redis client support for caching visitor data. - Added a new customer note repository to persist user notes independently of the L1 profile slots. This update significantly improves the customer service experience by enabling visitor interactions and ensuring efficient data handling for both registered and unregistered users.
101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
"""客户显式备注持久化(jinrong_agent 库,Wave 5)。
|
|
|
|
职责:用户主动要求记忆的自由文本("你要记住我每天看净值"),独立于 L1 画像槽位。
|
|
触发:keyword_route 命中"记住/记一下/帮我记" → save_note 意图 → note_service 调 LLM 抽取 content+category → 写入此表。
|
|
|
|
铁律:
|
|
1. content 为 LLM 抽取后的纯净文本(剥掉"你要记住"等指令词),长度 ≤500;
|
|
2. 软删除(is_active=0)保留审计痕,用户可"忘掉我之前的备注";
|
|
3. 一会话可多条备注(无 uk_session_id)。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from sqlalchemy import text
|
|
from sqlalchemy.engine import Engine
|
|
|
|
from app.config.database import get_agent_engine
|
|
|
|
|
|
class CustomerNoteRepository:
|
|
def __init__(self, engine: Engine | None = None) -> None:
|
|
self._engine = engine or get_agent_engine()
|
|
|
|
def insert_note(
|
|
self,
|
|
*,
|
|
customer_id: str,
|
|
session_id: str,
|
|
trace_id: str,
|
|
content: str,
|
|
category: str | None = None,
|
|
source_text: str | None = None,
|
|
) -> int:
|
|
"""写入备注,返回自增 id。"""
|
|
sql = text(
|
|
"""
|
|
INSERT INTO customer_notes
|
|
(customer_id, session_id, trace_id, content, category, source_text)
|
|
VALUES
|
|
(:cid, :sid, :trace_id, :content, :category, :source_text)
|
|
"""
|
|
)
|
|
with self._engine.begin() as conn:
|
|
result = conn.execute(
|
|
sql,
|
|
{
|
|
"cid": customer_id,
|
|
"sid": session_id,
|
|
"trace_id": trace_id,
|
|
"content": content,
|
|
"category": category,
|
|
"source_text": source_text,
|
|
},
|
|
)
|
|
return int(result.lastrowid)
|
|
|
|
def list_active_notes(self, customer_id: str, limit: int = 5) -> list[dict]:
|
|
"""读最近 N 条 active 备注按 created_at DESC。"""
|
|
sql = text(
|
|
"""
|
|
SELECT id, content, category, source_text, created_at
|
|
FROM customer_notes
|
|
WHERE customer_id = :cid AND is_active = 1
|
|
ORDER BY created_at DESC
|
|
LIMIT :limit
|
|
"""
|
|
)
|
|
with self._engine.connect() as conn:
|
|
rows = conn.execute(
|
|
sql, {"cid": customer_id, "limit": limit}
|
|
).mappings().all()
|
|
return [dict(r) for r in rows]
|
|
|
|
def deactivate(self, note_id: int, customer_id: str) -> bool:
|
|
"""软删除单条备注(is_active=0),返回是否成功。"""
|
|
sql = text(
|
|
"""
|
|
UPDATE customer_notes
|
|
SET is_active = 0
|
|
WHERE id = :note_id AND customer_id = :cid AND is_active = 1
|
|
"""
|
|
)
|
|
with self._engine.begin() as conn:
|
|
result = conn.execute(sql, {"note_id": note_id, "cid": customer_id})
|
|
return result.rowcount == 1
|
|
|
|
def deactivate_all(self, customer_id: str) -> int:
|
|
"""软删除客户所有 active 备注,返回删除条数。"""
|
|
sql = text(
|
|
"""
|
|
UPDATE customer_notes
|
|
SET is_active = 0
|
|
WHERE customer_id = :cid AND is_active = 1
|
|
"""
|
|
)
|
|
with self._engine.begin() as conn:
|
|
result = conn.execute(sql, {"cid": customer_id})
|
|
return int(result.rowcount)
|