diff --git a/tcs-core/SI-048-LL-172-20260707-HTML-WRAPPER-FOR-AI.md b/tcs-core/SI-048-LL-172-20260707-HTML-WRAPPER-FOR-AI.md new file mode 100644 index 0000000..16021e4 --- /dev/null +++ b/tcs-core/SI-048-LL-172-20260707-HTML-WRAPPER-FOR-AI.md @@ -0,0 +1,138 @@ +# SI-048 · HTML 包装页 · 豆包不再报"网页解析失败" + +> **HLDP://fifth-domain/tcs-core/SI-048** +> 铸渊 ICE-GL-ZY001 · @trigger D167 20:50 · LL-172-20260707 + +--- + +## @trigger + +``` +豆包(通过冰朔): + "尝试对 https://guanghubingshuo.com/global-search/ 进行访问解析时失败, + 系统报错: 网页解析失败, 可能是不支持的网页类型" + +冰朔: 需要我帮你整理该类接口服务的常见可用性排查方法吗? +``` + +--- + +## 1. 铸渊的判断 · 5 秒 + +``` +不是 API 部署问题 · 是豆包的"网页抓取"工具问题 + ⊢ 豆包有两种工具: + 1. 网页抓取型(浏览器内核, 看 HTML) + 2. HTTP 客户端型(直接发请求, 看 JSON) + ⊢ 豆包看到 URL 默认用网页抓取 + ⊢ 访问 /global-search/ 拿到 JSON (不是 HTML) → 报"网页解析失败" + ⊢ 豆包不会自己切换到 HTTP 客户端, 因为没明确告知 + +不是排查方法的问题 · 是服务呈现问题 +服务应该给网页抓取型 AI 一个"HTML 索引页" +``` + +--- + +## 2. 怎么做 + +``` +v1.4.0 server.py 改: + ⊢ 根路径 /global-search/ → 返回 HTML (不是 JSON) + ⊢ HTML 是索引页: + - API 介绍 + - 5 仓列表 + - 完整 endpoint + curl 示例 + - 注意事项 + - "给 AI 工具的明确说明" + ⊢ 其他 endpoint (/healthz, /search, /file, /help 等) → 仍返回 JSON + ⊢ VERSION = "1.4.0" +``` + +--- + +## 3. 修复 + +``` +v1.4.0: + /global-search/ → HTML 6376 bytes (text/html; charset=utf-8) + /global-search/healthz → JSON (不变) + /global-search/help → JSON (不变) + /global-search/search → JSON (不变) + /global-search/file → JSON (不变) + ... 其他都 JSON +``` + +**豆包再用网页抓取工具访问根路径 → 看到 HTML 索引页 → 不再报"解析失败"**。 + +--- + +## 4. 反思 + +``` +豆包的"网页解析失败" 不是 API 错 · 是工具错 +铸渊的 API 1.0~1.3 只服务 HTTP 客户端型 AI +豆包是网页抓取型 · 1.0~1.3 它会失败 + +解决: + ⊢ 不要让 AI 工具猜"这是 API" + ⊢ 根路径给 HTML 索引页 + ⊢ HTML 里写"这是 REST API, 用 curl 调" + ⊢ 明确"如果你 AI 是网页抓取型, 不要用网页抓取调 endpoint" + ⊢ 给 curl 示例 · AI 看到就学会用 HTTP 客户端 + +教训: + 通用 AI 不止一种 + 不是所有 AI 都会自动用 HTTP 客户端 + 给"非典型"AI 也备一个 HTML 入口 · 兼容性更好 +``` + +--- + +## 5. 给冰朔的话 + +``` +冰朔 · +不用整理排查方法 · 不是部署问题 +是豆包的"网页抓取"工具看到 JSON 报错 + +修了: + 雕 /global-search/ 现在返回 HTML 索引页 (不是 JSON) + 雕 HTML 里说清楚"这是 REST API · 用 curl 调" + 雕 其他 endpoint 仍返回 JSON + 雕 豆包再访问根路径, 看到 HTML 不再报错 + +VERSION = 1.4.0 +``` + +--- + +## 6. 给豆包 + +``` +豆包 · +https://guanghubingshuo.com/global-search/ 现在给你准备了 HTML 索引页 +你用网页抓取工具访问, 看到 HTML 就不报错了 + +HTML 里有: + 雕 5 仓列表 + 雕 完整 endpoint + curl 示例 + 雕 怎么用本服务 (用 curl / HTTP 客户端, 不是网页抓取) + 雕 注意事项 + +具体调 API: + 雕 用 curl 或 HTTP 客户端 + 雕 不要用网页抓取工具调 /search /file 等 + 雕 Accept: application/json + 雕 中文 URL 编码 + 雕 限速 5 req/s +``` + +--- + +铸渊 ICE-GL-ZY001 · LL-172-20260707 · SI-048 HTML 包装页 +国作登字-2026-A-00037559 +T-shirt:「豆包不会自己切工具 · 给它 HTML · 豆包会读」 +⊢ 不是 API 错 · 是工具错 +⊢ 不是豆包错 · 是铸渊之前没备 +⊢ 根路径给 HTML · 豆包立刻懂 diff --git a/zero-point/global-search-api/server.py b/zero-point/global-search-api/server.py index 97962ff..3585a3d 100755 --- a/zero-point/global-search-api/server.py +++ b/zero-point/global-search-api/server.py @@ -27,7 +27,7 @@ TOKEN = os.environ.get("GLOBAL_SEARCH_API_TOKEN", "") HMAC_SECRET = os.environ.get("LIGHT_LAKE_DRIVER_SECRET", "") SOVEREIGN_ID = "ICE-GL∞" AGENT_ID = "ICE-GL-ZY001" -VERSION = "1.2.0" +VERSION = "1.4.0" # ============== 仓库注册表 ============== REPOS = { @@ -161,7 +161,7 @@ def search_files(repo_path, keyword, top=20): def list_tree(repo_path, path="", depth=3, ext_filter=None): cmd = ["git", "ls-tree", "-r", "--name-only", "HEAD"] if path: - cmd.append(f"{path}/") + cmd.append(f"{{path}}/") result = subprocess.run( cmd, cwd=repo_path, capture_output=True, text=True, timeout=15 ) @@ -182,7 +182,7 @@ def read_file(repo_path, path): return {"ok": False, "error": "invalid path"} try: result = subprocess.run( - ["git", "show", f"HEAD:{path}"], + ["git", "show", f"HEAD:{{path}}"], cwd=repo_path, capture_output=True, text=True, timeout=10 ) if result.returncode != 0: @@ -319,6 +319,10 @@ class Handler(http.server.BaseHTTPRequestHandler): if not repo_path: return self.send_json({"ok": False, "error": f"unknown repo: {repo_arg}", "available": list(REPOS.keys())}, 400) + # 根路径 · 返回 HTML(给豆包等网页抓取工具看的索引页) + if path == "/" or path == "": + return self.send_html_root() + # === 免鉴权端点 === if path == "/healthz": return self.send_json({ @@ -455,6 +459,158 @@ class Handler(http.server.BaseHTTPRequestHandler): self.end_headers() self.wfile.write(body) + def send_html_root(self): + """根路径 HTML 索引页 · 给网页抓取工具(豆包/Claude/ChatGPT web search)看 + 避免它们看到 JSON 报"网页解析失败" """ + html = f""" + +
+ +光湖跨仓库检索服务 · 铸渊 ICE-GL-ZY001 · LL-172-20260707 · v{VERSION}
+ +这是 REST API(不是网页)。如果你是网页抓取工具(比如豆包/ChatGPT/Claude 浏览器),看到这页就对了——这里是给"看不见 JSON 的人"准备的 HTML 索引。
+ +| 仓 ID | 说明 |
|---|---|
cang-ying | 苍耳 TCS-GL-009 拥有 · 鉴影 ICE-GL-CA001 操作 · 视频 AI 系统专用 ★ 推荐先看 |
fifth-domain | 第五域 · HLDP 协议栈 · 铸渊核心 · 冰朔主权 |
guanghulab | 广湖实验室 · 历史档案(包含 video-ai-system/) |
guanghulab-collab | 多人格体协作记录 |
guanghu | 光湖根仓库 |
curl https://guanghubingshuo.com/global-search/healthz
+curl https://guanghubingshuo.com/global-search/status
+curl https://guanghubingshuo.com/global-search/repos
+curl "https://guanghubingshuo.com/global-search/system-status?repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/broadcast?repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/search?q=苏白&repo=cang-ying&top=10"
+curl "https://guanghubingshuo.com/global-search/file?path=VA-GATE.hdlp&repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/tree?depth=2&repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/file?path=VA-GATE.hdlp&repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/file?path=CURRENT.hdlp&repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/file?path=PIPELINE-3D-MANJU.hdlp&repo=cang-ying"
+curl "https://guanghubingshuo.com/global-search/file?path=OWNERSHIP.hdlp&repo=cang-ying"
+POST /archive)需要 token, 默认没开苍耳 = %E8%8B%8D%E8%80%B3/global-search/... 不是 /api/...)+铸渊 ICE-GL-ZY001 · 国作登字-2026-A-00037559 · 冰朔 ICE-GL∞ 主权 +
+ + +""" + body = html.encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.send_header("Access-Control-Allow-Origin", "*") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + def main(): server = http.server.HTTPServer(("0.0.0.0", PORT), Handler)