From 9200df7842b7bf874c25e2055142c2863f858933 Mon Sep 17 00:00:00 2001 From: ouyangyouzhang Date: Fri, 28 Nov 2025 10:12:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=A2=E6=9C=8D=E9=87=8D?= =?UTF-8?q?=E5=AE=9A=E5=90=91=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rag2_0/api/intent_recognition_api.py | 4 ++ rag2_0/api/kefu_redirect_url.py | 92 ++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 rag2_0/api/kefu_redirect_url.py diff --git a/rag2_0/api/intent_recognition_api.py b/rag2_0/api/intent_recognition_api.py index 72adc4e..62a91fe 100755 --- a/rag2_0/api/intent_recognition_api.py +++ b/rag2_0/api/intent_recognition_api.py @@ -16,6 +16,7 @@ load_dotenv() import sys from rag2_0.intent_recognition import AsyncIntentRecognizer +from rag2_0.api.kefu_redirect_url import router as kefu_router # 确保日志目录存在 os.makedirs('data/logs', exist_ok=True) @@ -84,6 +85,9 @@ app.add_middleware( allow_headers=["*"], ) +# 注册外部路由 +app.include_router(kefu_router) + # 全局变量存储AsyncIntentRecognizer实例 _instance = None diff --git a/rag2_0/api/kefu_redirect_url.py b/rag2_0/api/kefu_redirect_url.py new file mode 100644 index 0000000..5605e78 --- /dev/null +++ b/rag2_0/api/kefu_redirect_url.py @@ -0,0 +1,92 @@ +from fastapi import APIRouter +from fastapi.responses import RedirectResponse +import os +import sqlite3 +import threading +import time +from queue import Queue, Full + + +router = APIRouter() + +# 以当前文件为基准的相对路径:../../data/db +PROJECT_ROOT = os.getcwd() +DB_DIR = os.path.join(PROJECT_ROOT, "data", "db") +DB_FILE = os.path.join(DB_DIR, "redirects.sqlite3") +TABLE_SQL = ( + "CREATE TABLE IF NOT EXISTS redirects (" + " msg_id TEXT PRIMARY KEY," + " url TEXT NOT NULL" + ")" +) + + +def _ensure_db(): + """确保数据库与表存在。""" + os.makedirs(DB_DIR, exist_ok=True) + with sqlite3.connect(DB_FILE) as conn: + cur = conn.cursor() + cur.execute(TABLE_SQL) + conn.commit() + + +def save_redirect(msg_id: str, url: str) -> None: + """将 msg_id 与 url 写入 SQLite,若已存在则忽略。 + + 使用 INSERT OR IGNORE 结合 PRIMARY KEY(msg_id) 来避免重复写入。 + """ + _ensure_db() + with sqlite3.connect(DB_FILE) as conn: + cur = conn.cursor() + cur.execute( + "INSERT OR IGNORE INTO redirects (msg_id, url) VALUES (?, ?)", + (msg_id, url), + ) + conn.commit() + + +# ========= 异步写库队列与后台线程 ========= +_write_queue: "Queue[tuple[str, str]]" = Queue(maxsize=10000) + + +def _write_worker(): + _ensure_db() + while True: + try: + msg_id, url = _write_queue.get() + try: + with sqlite3.connect(DB_FILE) as conn: + cur = conn.cursor() + cur.execute( + "INSERT OR IGNORE INTO redirects (msg_id, url) VALUES (?, ?)", + (msg_id, url), + ) + conn.commit() + except Exception: + # 失败忽略,避免阻断工作线程 + pass + finally: + _write_queue.task_done() + except Exception: + # 防御性 sleep,避免异常导致CPU空转 + time.sleep(0.1) + + +_worker_thread = threading.Thread(target=_write_worker, daemon=True) +_worker_thread.start() + + +@router.get("/kefu_login", summary="客服登录页重定向") +async def kefu_redirect(msg_id:str): + """重定向到客服登录页。""" + target_url = "https://www.booway.com.cn/kefu/toLoginPage" + # 写入 SQLite:若 msg_id 已存在将不会重复写入 + try: + if msg_id: + # 走异步队列 + _write_queue.put_nowait((msg_id, target_url)) + except Exception: + # 出于稳健性考虑,即使写库失败也不影响重定向 + pass + return RedirectResponse(target_url, status_code=302) +