فهرست منبع

perf(mode_workflow): 帖列表瘦身——fetch_posts 不再拉 llm_evaluation/body(78MB→123KB),详情按需 /api/post

刘文武 6 روز پیش
والد
کامیت
a14d0c8ae3
3فایلهای تغییر یافته به همراه31 افزوده شده و 7 حذف شده
  1. 12 5
      examples/mode_workflow/db.py
  2. 14 2
      examples/mode_workflow/index.html
  3. 5 0
      examples/mode_workflow/server.py

+ 12 - 5
examples/mode_workflow/db.py

@@ -532,12 +532,19 @@ def fetch_queries(mode="process"):
 
 
 def fetch_posts(query_id, mode="process"):
-    """某方向搜索表里某 query 的全部帖子(JSON 列已解析),带 has_process/has_tools 标记。"""
+    """列表用:只取列表所需列 + SQL 直取 adopted 标量,**不拉 body/videos/llm_evaluation 大字段**
+    (llm_evaluation ~1.5MB/帖,旧版 SELECT * 切 tab/选 query 要几十 MB 过远程 RDS,故慢)。
+    正文/评分等详情按需走 fetch_post。带 adopted/has_process/has_tools;adopted 口径用
+    is_adopted_rel(与 is_adopted 完全一致,rel/repro 由 _REL_SQL/_REPRO_SQL 直取标量)。"""
     table = _search_table(mode)
     conn = _conn()
     try:
         with conn.cursor() as cur:
-            cur.execute(f"""SELECT * FROM {table} WHERE query_id=%s
+            cur.execute(f"""SELECT id, query_id, query_text, case_id, platform, channel_content_id,
+                                   title, url, content_type, images, like_count, publish_time,
+                                   quality_score, quality_grade, found_by, knowledge_type, overall_score,
+                                   {_REL_SQL} AS rel, {_REPRO_SQL} AS repro
+                            FROM {table} WHERE query_id=%s
                             ORDER BY overall_score DESC, id""", (query_id,))
             rows = cur.fetchall()
             cur.execute("SELECT DISTINCT case_id FROM mode_process WHERE query_id=%s", (query_id,))
@@ -547,12 +554,12 @@ def fetch_posts(query_id, mode="process"):
     finally:
         conn.close()
     for r in rows:
-        for col in ("images", "videos", "found_by", "knowledge_type", "llm_evaluation"):
+        for col in ("images", "found_by", "knowledge_type"):
             r[col] = _loads(r[col])
-        r["adopted"] = is_adopted(r["overall_score"], r["llm_evaluation"], r["publish_time"])
+        r["adopted"] = is_adopted_rel(r["overall_score"], r.pop("rel", None),
+                                      r["publish_time"], r.pop("repro", None))
         r["has_process"] = r["case_id"] in hp
         r["has_tools"] = r["case_id"] in ht
-        r.pop("created_at", None); r.pop("updated_at", None)
     return rows
 
 

+ 14 - 2
examples/mode_workflow/index.html

@@ -2469,7 +2469,7 @@
           <button class="qr-x" id="qr-close" title="关闭">✕</button>
         </div>
         <div class="qr-bar">
-          <button class="btn seal" id="qr-score">生成正交表 &amp; 评估高亮</button>
+          <button class="btn seal" id="qr-score">生成正交表</button>
           <button class="btn" id="qr-search-all" hidden>搜全部达标</button>
           <label class="qr-thr-lab">达标分 ≥ <input id="qr-thr" class="qr-thr" type="number" min="0" max="10" step="0.5" value="7"></label>
           <span id="qr-hint" class="qr-hint"></span>
@@ -3125,9 +3125,10 @@
         // Esc 由 <dialog> 原生处理(触发 close)
       });
 
-      function openPostDetail(cid) {
+      async function openPostDetail(cid) {
         const p = state.posts.find((x) => x.case_id === cid);
         if (!p) return;
+        await ensurePostDetail(p);   // 列表瘦身,弹框前补全正文/评估
         const e = p.llm_evaluation || {};
         const meta = [];
         meta.push(`${PLAT_LOGO(p.platform)}<span style="font-weight:600">${esc(PLAT_NAME(p.platform))}</span>`);
@@ -3208,8 +3209,19 @@
         state.version = null;
         state.post = state.posts.find((p) => p.case_id === cid) || null;
         renderPosts();
+        await ensurePostDetail(state.post);   // 列表瘦身,补全正文/评估再渲染右侧详情
         await loadExtract();
       }
+      // 列表是瘦身数据(无 body/llm_evaluation/videos);详情按需取单帖并合并到对象上(合并后再点 0 往返)
+      async function ensurePostDetail(p) {
+        if (!p || p.body !== undefined) return p;
+        try {
+          const full = await api(`/api/post?mode=${state.mode}&query_id=`
+            + encodeURIComponent(state.queryId) + "&case_id=" + encodeURIComponent(p.case_id));
+          if (full) Object.assign(p, full);
+        } catch (e) { /* 详情取不到不阻断,正文/评分留空 */ }
+        return p;
+      }
 
       /* ── 解构结果:客户端缓存 + 请求竞态守卫(解决「多次点击卡顿 / 残留上一帖」)──
          · _extractCache:解构数据只在「重新解构」时变(由本页 startExtract 触发,届时清缓存),

+ 5 - 0
examples/mode_workflow/server.py

@@ -497,6 +497,11 @@ class Handler(BaseHTTPRequestHandler):
                 self._json(db.fetch_queries(qs.get("mode", "process")))
             elif u.path == "/api/posts":
                 self._json(db.fetch_posts(qs.get("query_id", ""), qs.get("mode", "process")))
+            elif u.path == "/api/post":
+                # 单帖详情(正文/配图/评估全量):列表已瘦身,详情按需取;带 ETag/304
+                r = db.fetch_post(qs.get("query_id", ""), qs.get("case_id", ""),
+                                  qs.get("mode", "process"))
+                self._json_etag(r) if r else self._err("无此帖", 404)
             elif u.path == "/api/extract":
                 # 一次点击合一:单连接同时取版本列表 + 解构详情,前端少一次往返。
                 self._json_etag(db.fetch_extract(