argo-search 1.0.1 → 2.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. package/LICENSE +201 -21
  2. package/README.en.md +735 -0
  3. package/README.es.md +777 -0
  4. package/README.ja.md +777 -0
  5. package/README.ko.md +777 -0
  6. package/README.md +778 -320
  7. package/SKILL.md +135 -0
  8. package/assets/readme/hero.svg +121 -0
  9. package/assets/readme/made-with-beautify.svg +10 -0
  10. package/assets/readme/proof-routes.svg +73 -0
  11. package/assets/readme/why-better.svg +104 -0
  12. package/assets/readme/workflow.svg +83 -0
  13. package/backends/domain_profiles.json +2356 -96
  14. package/backends/engine_registry.yaml +3428 -503
  15. package/backends/query_synonyms_cn.json +35 -0
  16. package/backends/quota_profiles.json +2488 -160
  17. package/backends/source_types_cn.json +109 -0
  18. package/backends/text_lexicon.json +44 -0
  19. package/bin/argo +772 -0
  20. package/bin/argo.js +102 -39
  21. package/config.yaml +5139 -367
  22. package/cordis.patch.yml +21 -0
  23. package/data/countries.json +40 -0
  24. package/data/lang_matrix/lang_capability.json +842 -0
  25. package/data/lang_matrix/matrix_2026-09-10.json +11921 -0
  26. package/data/regions_cn.json +1 -0
  27. package/docs/ADDING_NEW_ENGINE.md +184 -0
  28. package/docs/ARGO_INTRO.md +124 -0
  29. package/docs/DATA_SOURCE_GAPS.md +81 -0
  30. package/docs/DESIGN_LOCAL_DATA_FUSION.md +90 -0
  31. package/docs/ENGINE_CATALOG.md +575 -0
  32. package/docs/MCP_SETUP.md +108 -0
  33. package/docs/PLATFORM_PATHS.md +111 -0
  34. package/docs/RELEASE_NOTES_v2.8.0.md +71 -0
  35. package/docs/RELEASE_NOTES_v2.8.2.md +63 -0
  36. package/docs/RELEASE_NOTES_v2.8.3.md +55 -0
  37. package/docs/RELEASE_NOTES_v2.8.4.md +79 -0
  38. package/docs/RELEASE_NOTES_v2.8.5.md +102 -0
  39. package/docs/RELEASE_NOTES_v2.8.6.md +66 -0
  40. package/docs/RELEASE_NOTES_v2.8.7.md +65 -0
  41. package/docs/RELEASE_NOTES_v2.8.8.md +67 -0
  42. package/docs/RELEASE_NOTES_v2.8.9.md +67 -0
  43. package/docs/RELEASE_NOTES_v2.9.0.md +64 -0
  44. package/docs/RELEASE_NOTES_v2.9.8.md +73 -0
  45. package/docs/SEARCH_ARCHIVE.md +115 -0
  46. package/docs/assets/architecture.svg +104 -0
  47. package/docs/assets/hero.svg +98 -0
  48. package/docs/engines/bangumi.md +27 -0
  49. package/docs/engines/biorxiv.md +27 -0
  50. package/docs/engines/clawhub.md +27 -0
  51. package/docs/engines/crt_sh.md +27 -0
  52. package/docs/engines/datacite.md +27 -0
  53. package/docs/engines/deps_dev.md +27 -0
  54. package/docs/engines/douban_movie.md +27 -0
  55. package/docs/engines/endoflife.md +27 -0
  56. package/docs/engines/flk_law.md +27 -0
  57. package/docs/engines/fxtwitter.md +27 -0
  58. package/docs/engines/google_news.md +27 -0
  59. package/docs/engines/gov_regulations.md +27 -0
  60. package/docs/engines/guqian.md +27 -0
  61. package/docs/engines/hackernews.md +27 -0
  62. package/docs/engines/iplant.md +27 -0
  63. package/docs/engines/keenable.md +27 -0
  64. package/docs/engines/met_museum.md +27 -0
  65. package/docs/engines/nasa_images.md +27 -0
  66. package/docs/engines/netease_music.md +27 -0
  67. package/docs/engines/npm.md +27 -0
  68. package/docs/engines/nvd.md +27 -0
  69. package/docs/engines/openreview.md +27 -0
  70. package/docs/engines/openstd.md +27 -0
  71. package/docs/engines/parallel_free.md +27 -0
  72. package/docs/engines/people_daily.md +27 -0
  73. package/docs/engines/realtime_index.md +27 -0
  74. package/docs/engines/sec_edgar.md +27 -0
  75. package/docs/engines/seltz.md +27 -0
  76. package/docs/engines/skillsmp.md +27 -0
  77. package/docs/engines/sspai.md +27 -0
  78. package/docs/engines/std_samr.md +27 -0
  79. package/docs/engines/train.md +27 -0
  80. package/docs/engines/un_comtrade.md +27 -0
  81. package/docs/engines/wikisource.md +27 -0
  82. package/docs/engines/zdic.md +27 -0
  83. package/docs/engines/zenodo.md +27 -0
  84. package/docs/engines/zhihu_hot_app.md +27 -0
  85. package/docs//344/270/272/344/273/200/344/271/210/351/200/211/346/213/251argo.md +176 -0
  86. package/engines/README.md +10 -0
  87. package/engines/_template_cli.yaml +39 -0
  88. package/engines/_template_http.yaml +37 -0
  89. package/engines/plugins/_template_plugin.py +50 -0
  90. package/engines/specs/_cisa_kev.yaml +54 -0
  91. package/engines/specs/_osv.yaml +63 -0
  92. package/engines/specs/aljazeera.yaml +43 -0
  93. package/engines/specs/antara.yaml +43 -0
  94. package/engines/specs/artic.yaml +20 -0
  95. package/engines/specs/aviation_weather.yaml +39 -0
  96. package/engines/specs/bangumi.yaml +21 -0
  97. package/engines/specs/biorxiv.yaml +24 -0
  98. package/engines/specs/carbon_intensity.yaml +32 -0
  99. package/engines/specs/cfets.yaml +41 -0
  100. package/engines/specs/cinii.yaml +44 -0
  101. package/engines/specs/clawhub.yaml +49 -0
  102. package/engines/specs/cleveland.yaml +19 -0
  103. package/engines/specs/cn_ai_news.yaml +43 -0
  104. package/engines/specs/core.yaml +35 -0
  105. package/engines/specs/crt_sh.yaml +38 -0
  106. package/engines/specs/ct24.yaml +43 -0
  107. package/engines/specs/datacite.yaml +27 -0
  108. package/engines/specs/datagov_uk.yaml +41 -0
  109. package/engines/specs/ddgs_images.yaml +45 -0
  110. package/engines/specs/deepseek_search.yaml +74 -0
  111. package/engines/specs/deezer.yaml +20 -0
  112. package/engines/specs/defillama.yaml +38 -0
  113. package/engines/specs/deps_dev.yaml +21 -0
  114. package/engines/specs/digup.yaml +36 -0
  115. package/engines/specs/doi.yaml +39 -0
  116. package/engines/specs/douban_movie.yaml +22 -0
  117. package/engines/specs/dw_news.yaml +47 -0
  118. package/engines/specs/egov_law.yaml +21 -0
  119. package/engines/specs/elpais.yaml +43 -0
  120. package/engines/specs/endoflife.yaml +21 -0
  121. package/engines/specs/energy_charts.yaml +21 -0
  122. package/engines/specs/factcheck_org.yaml +52 -0
  123. package/engines/specs/faz.yaml +43 -0
  124. package/engines/specs/federal_register.yaml +57 -0
  125. package/engines/specs/firecrawl.yaml +53 -0
  126. package/engines/specs/flk_law.yaml +24 -0
  127. package/engines/specs/folha.yaml +43 -0
  128. package/engines/specs/france24.yaml +44 -0
  129. package/engines/specs/full_fact.yaml +47 -0
  130. package/engines/specs/fxtwitter.yaml +36 -0
  131. package/engines/specs/gbfs_nyc.yaml +32 -0
  132. package/engines/specs/gdacs.yaml +21 -0
  133. package/engines/specs/gdelt.yaml +64 -0
  134. package/engines/specs/gleif.yaml +55 -0
  135. package/engines/specs/google_news.yaml +22 -0
  136. package/engines/specs/gov_regulations.yaml +38 -0
  137. package/engines/specs/guardian_rss.yaml +59 -0
  138. package/engines/specs/hkex.yaml +40 -0
  139. package/engines/specs/hurriyet.yaml +43 -0
  140. package/engines/specs/iplant.yaml +25 -0
  141. package/engines/specs/jikan.yaml +24 -0
  142. package/engines/specs/jolpica.yaml +20 -0
  143. package/engines/specs/k10plus.yaml +20 -0
  144. package/engines/specs/keenable.yaml +44 -0
  145. package/engines/specs/keenable_free.yaml +36 -0
  146. package/engines/specs/lefigaro.yaml +43 -0
  147. package/engines/specs/listenbrainz.yaml +19 -0
  148. package/engines/specs/matichon.yaml +43 -0
  149. package/engines/specs/met_museum.yaml +21 -0
  150. package/engines/specs/nasa_images.yaml +45 -0
  151. package/engines/specs/netease_music.yaml +38 -0
  152. package/engines/specs/nhk.yaml +43 -0
  153. package/engines/specs/nhtsa_vpic.yaml +20 -0
  154. package/engines/specs/noaa_swpc.yaml +20 -0
  155. package/engines/specs/nvd.yaml +38 -0
  156. package/engines/specs/obis.yaml +20 -0
  157. package/engines/specs/opencitations.yaml +52 -0
  158. package/engines/specs/openf1.yaml +21 -0
  159. package/engines/specs/openfoodfacts.yaml +45 -0
  160. package/engines/specs/openligadb.yaml +20 -0
  161. package/engines/specs/openreview.yaml +37 -0
  162. package/engines/specs/openstd.yaml +21 -0
  163. package/engines/specs/people_daily.yaml +22 -0
  164. package/engines/specs/realtime_index.yaml +34 -0
  165. package/engines/specs/ror.yaml +20 -0
  166. package/engines/specs/satnogs.yaml +20 -0
  167. package/engines/specs/sec_edgar.yaml +46 -0
  168. package/engines/specs/shfe.yaml +39 -0
  169. package/engines/specs/skillsmp.yaml +50 -0
  170. package/engines/specs/sogou_weixin_browser.yaml +30 -0
  171. package/engines/specs/soilgrids.yaml +25 -0
  172. package/engines/specs/sspai.yaml +36 -0
  173. package/engines/specs/stackexchange.yaml +46 -0
  174. package/engines/specs/std_samr.yaml +21 -0
  175. package/engines/specs/tass.yaml +43 -0
  176. package/engines/specs/tavily_free.yaml +56 -0
  177. package/engines/specs/tle_mirror.yaml +21 -0
  178. package/engines/specs/train.yaml +37 -0
  179. package/engines/specs/tvmaze.yaml +20 -0
  180. package/engines/specs/twitter_syndication.yaml +31 -0
  181. package/engines/specs/un_comtrade.yaml +23 -0
  182. package/engines/specs/unpaywall.yaml +54 -0
  183. package/engines/specs/vnpress.yaml +43 -0
  184. package/engines/specs/weather.yaml +32 -0
  185. package/engines/specs/who_don.yaml +21 -0
  186. package/engines/specs/who_gho.yaml +20 -0
  187. package/engines/specs/wikimedia_commons.yaml +34 -0
  188. package/engines/specs/wikisource.yaml +22 -0
  189. package/engines/specs/worms.yaml +19 -0
  190. package/engines/specs/x_trending.yaml +34 -0
  191. package/engines/specs/yna.yaml +43 -0
  192. package/engines/specs/ynet.yaml +43 -0
  193. package/engines/specs/yuanbao.yaml +93 -0
  194. package/engines/specs/zbmath.yaml +40 -0
  195. package/engines/specs/zdic.yaml +22 -0
  196. package/engines/specs/zenodo.yaml +27 -0
  197. package/engines/specs/zhihu_hot_app.yaml +35 -0
  198. package/mcp/clients.yaml +106 -0
  199. package/package.json +55 -12
  200. package/packages/dsh-plugin/README.md +152 -0
  201. package/packages/dsh-plugin/cordis.patch.yml +48 -0
  202. package/packages/dsh-plugin/dsh/client.js +1533 -0
  203. package/packages/dsh-plugin/dsh/diagnostics.js +54 -0
  204. package/packages/dsh-plugin/dsh/index.js +527 -0
  205. package/packages/dsh-plugin/dsh/native-tools.mjs +749 -0
  206. package/packages/dsh-plugin/dsh/runner.js +666 -0
  207. package/packages/dsh-plugin/dsh/wide-research.js +878 -0
  208. package/packages/dsh-plugin/package.json +38 -0
  209. package/packages/dsh-plugin/scripts/sync-local.sh +70 -0
  210. package/packages/dsh-plugin/test/client.test.js +406 -0
  211. package/packages/dsh-plugin/test/config.test.js +30 -0
  212. package/packages/dsh-plugin/test/diagnostics.test.js +28 -0
  213. package/packages/dsh-plugin/test/index.test.js +1382 -0
  214. package/references/query-templates.md +96 -0
  215. package/references/query-templates.yaml +118 -0
  216. package/scripts/ab_eval.py +219 -0
  217. package/scripts/ab_eval_p0p1.py +266 -0
  218. package/scripts/adaptive.py +294 -70
  219. package/scripts/answer.py +154 -0
  220. package/scripts/archive_run.py +591 -0
  221. package/scripts/argo_engine_registry.py +172 -0
  222. package/scripts/argo_paths.py +728 -0
  223. package/scripts/article.py +136 -0
  224. package/scripts/article_meta.py +131 -0
  225. package/scripts/arxiv_source.py +201 -0
  226. package/scripts/badcase_ledger.py +252 -0
  227. package/scripts/batch_probe.py +241 -0
  228. package/scripts/benchmark.py +19 -0
  229. package/scripts/bounded_run.py +144 -0
  230. package/scripts/browser_auth.py +323 -0
  231. package/scripts/budget.py +247 -0
  232. package/scripts/budget_cli.py +93 -0
  233. package/scripts/build_release_assets.sh +65 -0
  234. package/scripts/burstiness_detector.py +147 -0
  235. package/scripts/cache.py +1066 -67
  236. package/scripts/cache_guard.py +271 -0
  237. package/scripts/cache_key_vdom.py +56 -0
  238. package/scripts/cache_similarity.py +170 -0
  239. package/scripts/caliber_isolation.py +195 -0
  240. package/scripts/calibrate_lowquality.py +210 -0
  241. package/scripts/candidate_envelope.py +366 -0
  242. package/scripts/chrome_cdp.py +871 -0
  243. package/scripts/ci_drift_gate.py +90 -0
  244. package/scripts/circuit_breaker.py +389 -0
  245. package/scripts/citations.py +334 -0
  246. package/scripts/cite_cli.py +59 -0
  247. package/scripts/cjk_tokens.py +95 -0
  248. package/scripts/clarify.py +47 -24
  249. package/scripts/cli_io.py +240 -0
  250. package/scripts/config.py +683 -45
  251. package/scripts/config_cache.py +402 -0
  252. package/scripts/conn_pool.py +220 -0
  253. package/scripts/content_boundary.py +46 -0
  254. package/scripts/content_security.py +685 -0
  255. package/scripts/content_signals.py +751 -0
  256. package/scripts/crawl.py +74 -35
  257. package/scripts/cross_lingual_trace.py +293 -0
  258. package/scripts/daemon.py +866 -0
  259. package/scripts/digup_bridge.py +214 -0
  260. package/scripts/dispatch_result.py +98 -0
  261. package/scripts/engine_admission.py +366 -0
  262. package/scripts/engine_dispatch.py +982 -0
  263. package/scripts/engine_env.py +539 -0
  264. package/scripts/engine_failure.py +411 -0
  265. package/scripts/engine_families.py +738 -0
  266. package/scripts/engine_policy.py +218 -0
  267. package/scripts/engine_requires.py +190 -0
  268. package/scripts/engine_status.py +322 -0
  269. package/scripts/engine_validate.py +638 -0
  270. package/scripts/engines.py +799 -294
  271. package/scripts/engines_base.py +1521 -0
  272. package/scripts/engines_builders.py +310 -0
  273. package/scripts/engines_builders_batch10.py +204 -0
  274. package/scripts/engines_builders_batch11.py +174 -0
  275. package/scripts/engines_builders_batch12.py +103 -0
  276. package/scripts/engines_builders_batch13.py +340 -0
  277. package/scripts/engines_builders_batch14.py +656 -0
  278. package/scripts/engines_builders_batch15.py +249 -0
  279. package/scripts/engines_builders_batch9.py +1468 -0
  280. package/scripts/engines_builders_cn.py +2283 -0
  281. package/scripts/engines_builders_data.py +2923 -0
  282. package/scripts/engines_builders_data_macro.py +775 -0
  283. package/scripts/engines_builders_feeds.py +255 -0
  284. package/scripts/engines_builders_intl.py +1239 -0
  285. package/scripts/engines_builders_keyless.py +111 -0
  286. package/scripts/engines_builders_search.py +440 -0
  287. package/scripts/engines_builders_tech.py +1359 -0
  288. package/scripts/evidence.py +620 -166
  289. package/scripts/evidence_loop.py +624 -0
  290. package/scripts/evidence_tier.py +298 -0
  291. package/scripts/except_sets.py +25 -0
  292. package/scripts/extract.py +55 -16
  293. package/scripts/fact_align.py +207 -0
  294. package/scripts/fact_crosscheck.py +230 -0
  295. package/scripts/fetch.py +25 -12
  296. package/scripts/fetch_browser.py +87 -0
  297. package/scripts/fetch_jsrun.py +122 -0
  298. package/scripts/fetch_quality.py +225 -0
  299. package/scripts/fetch_render_tinyfish.py +117 -0
  300. package/scripts/fetch_v3.py +1804 -0
  301. package/scripts/focus_extract.py +350 -0
  302. package/scripts/fulltext_store.py +169 -0
  303. package/scripts/fxtwitter_api.py +325 -0
  304. package/scripts/gen_engine_catalog.py +364 -0
  305. package/scripts/gen_native_tools.py +91 -0
  306. package/scripts/gen_routing_snapshot.py +195 -0
  307. package/scripts/health_check.py +140 -402
  308. package/scripts/health_probe.py +23 -8
  309. package/scripts/hot_state.py +134 -0
  310. package/scripts/http_client.py +1053 -0
  311. package/scripts/image_ops.py +430 -0
  312. package/scripts/image_vision/vision_probe.swift +126 -0
  313. package/scripts/install.ps1 +166 -0
  314. package/scripts/install.sh +221 -0
  315. package/scripts/job.py +1186 -0
  316. package/scripts/jump_resolver.py +235 -0
  317. package/scripts/lang_capability.py +150 -0
  318. package/scripts/lang_detect.py +289 -0
  319. package/scripts/lang_matrix_probe.py +329 -0
  320. package/scripts/lang_pref.py +311 -0
  321. package/scripts/link_source.py +340 -0
  322. package/scripts/local_image.py +970 -0
  323. package/scripts/local_seek.py +402 -0
  324. package/scripts/macro_countries.py +97 -0
  325. package/scripts/matrix_search_eval.py +1187 -0
  326. package/scripts/mcp_compact.py +234 -0
  327. package/scripts/mcp_diag.py +8 -3
  328. package/scripts/mcp_handlers.py +492 -0
  329. package/scripts/mcp_handlers_surface.py +157 -0
  330. package/scripts/mcp_launch.sh +124 -0
  331. package/scripts/mcp_local.py +241 -0
  332. package/scripts/mcp_server.py +125 -419
  333. package/scripts/mcp_setup.py +431 -0
  334. package/scripts/mcp_tools.py +331 -0
  335. package/scripts/mcp_transport.py +191 -0
  336. package/scripts/mcp_warm.py +127 -0
  337. package/scripts/min_version_scan.py +335 -0
  338. package/scripts/net_proxy.py +258 -0
  339. package/scripts/network_aware.py +152 -0
  340. package/scripts/output_transparency.py +200 -0
  341. package/scripts/paid_policy.py +98 -0
  342. package/scripts/paper.py +274 -0
  343. package/scripts/pdf_extract.py +518 -0
  344. package/scripts/phrase_filter.py +66 -0
  345. package/scripts/plan.py +422 -0
  346. package/scripts/postprocess_signals.py +150 -0
  347. package/scripts/pre-commit +48 -0
  348. package/scripts/query_enhance.py +157 -0
  349. package/scripts/query_operators.py +196 -0
  350. package/scripts/query_rewriter.py +116 -7
  351. package/scripts/query_signals.py +300 -0
  352. package/scripts/query_templates.py +167 -0
  353. package/scripts/query_understanding.py +411 -0
  354. package/scripts/query_variants.py +298 -0
  355. package/scripts/quota.py +633 -76
  356. package/scripts/rank_signals.py +775 -0
  357. package/scripts/ranking_eval.py +319 -0
  358. package/scripts/readability_extract.py +433 -0
  359. package/scripts/recompute.py +415 -0
  360. package/scripts/recovery.py +616 -0
  361. package/scripts/recovery_l0.py +160 -0
  362. package/scripts/recovery_runner.py +150 -0
  363. package/scripts/redskill/redskill_engine.py +332 -0
  364. package/scripts/regression_p0p1.py +318 -0
  365. package/scripts/replay_eval.py +658 -0
  366. package/scripts/rerank_tfidf.py +225 -0
  367. package/scripts/research.py +607 -403
  368. package/scripts/research_cli.py +361 -0
  369. package/scripts/research_dossier.py +492 -0
  370. package/scripts/research_expand.py +169 -0
  371. package/scripts/research_gates.py +272 -0
  372. package/scripts/research_report.py +209 -0
  373. package/scripts/research_strategy.py +37 -0
  374. package/scripts/research_work_packages.py +195 -0
  375. package/scripts/result_lang.py +311 -0
  376. package/scripts/retry_policy.py +76 -0
  377. package/scripts/robots_guard.py +259 -0
  378. package/scripts/route.py +921 -254
  379. package/scripts/route_bangs.py +40 -0
  380. package/scripts/route_cache.py +243 -0
  381. package/scripts/route_combo.py +917 -0
  382. package/scripts/route_domains.py +341 -0
  383. package/scripts/route_lang.py +605 -0
  384. package/scripts/route_log.py +63 -0
  385. package/scripts/route_policy.py +250 -0
  386. package/scripts/rrf_classic.py +66 -0
  387. package/scripts/screenshot.py +73 -0
  388. package/scripts/search.py +886 -406
  389. package/scripts/search_attribution.py +185 -0
  390. package/scripts/search_benchmark.py +407 -0
  391. package/scripts/search_cli.py +640 -0
  392. package/scripts/search_entry.py +395 -0
  393. package/scripts/search_output.py +690 -0
  394. package/scripts/search_pipeline.py +926 -0
  395. package/scripts/search_rank.py +991 -0
  396. package/scripts/search_types.py +129 -16
  397. package/scripts/seek_locator.py +68 -0
  398. package/scripts/semantic_evidence.py +391 -0
  399. package/scripts/serp_guard.py +336 -0
  400. package/scripts/serp_kill_log.py +74 -0
  401. package/scripts/single_flight.py +120 -0
  402. package/scripts/social_engines/__init__.py +10 -0
  403. package/scripts/social_engines/bilibili_engine.py +131 -0
  404. package/scripts/social_engines/hackernews_engine.py +113 -0
  405. package/scripts/social_engines/reddit_engine.py +172 -0
  406. package/scripts/social_engines/twitter_engine.py +397 -0
  407. package/scripts/social_engines/v2ex_engine.py +101 -0
  408. package/scripts/social_engines/weibo_engine.py +128 -0
  409. package/scripts/social_engines/xiaohongshu_engine.py +137 -0
  410. package/scripts/social_engines/zhihu_engine.py +139 -0
  411. package/scripts/social_research.py +201 -0
  412. package/scripts/sogou_weixin_browser.py +318 -0
  413. package/scripts/source_ledger.py +249 -0
  414. package/scripts/stage_timing.py +58 -0
  415. package/scripts/stats_cli.py +107 -0
  416. package/scripts/straggler_policy.py +60 -0
  417. package/scripts/stylometry_detector.py +231 -0
  418. package/scripts/sync_backends.py +353 -0
  419. package/scripts/sync_installs.py +29 -0
  420. package/scripts/template_cli.py +127 -0
  421. package/scripts/text_lexicon.py +72 -0
  422. package/scripts/tfidf_router.py +109 -37
  423. package/scripts/time_utils.py +233 -0
  424. package/scripts/topic_research_profiles.py +643 -0
  425. package/scripts/train.py +737 -0
  426. package/scripts/tweet.py +596 -0
  427. package/scripts/url_canon.py +217 -0
  428. package/scripts/url_optimize.py +56 -0
  429. package/scripts/url_safety.py +236 -0
  430. package/scripts/usage_log.py +116 -0
  431. package/scripts/usage_log_clean.py +113 -0
  432. package/scripts/v2ex_nodes.py +311 -0
  433. package/scripts/variant_recall.py +188 -0
  434. package/scripts/watch.py +205 -0
  435. package/scripts/wechat_article.py +258 -0
  436. package/scripts/wide_research.py +447 -0
  437. package/scripts/wx.py +349 -0
  438. package/scripts/x_article_fetch.py +141 -0
  439. package/scripts/x_search.py +234 -0
  440. package/scripts/x_trending.py +189 -0
  441. package/scripts/yaml_load.py +67 -0
  442. package/scripts/zhihu_quota.py +139 -0
  443. package/sub-skills/ego-search/SKILL.md +253 -0
  444. package/sub-skills/ego-search/scripts/ego_search.py +800 -0
  445. package/sub-skills/ego-search/scripts/merge.py +226 -0
  446. package/sub-skills/ego-search/scripts/quality.py +64 -0
  447. package/sub-skills/ego-search/scripts/runtime.py +172 -0
  448. package/sub-skills/ego-search/scripts/safety.py +109 -0
  449. package/sub-skills/ego-search/scripts/serp_spec.py +109 -0
  450. package/sub-skills/ego-search/scripts/webbridge_adapter.py +374 -0
  451. package/sub-skills/js-run/SKILL.md +67 -0
  452. package/sub-skills/js-run/scripts/jsrun.py +112 -0
  453. package/sub-skills/js-run/scripts/shim.js +188 -0
  454. package/sub-skills/local-search/SKILL.md +50 -53
  455. package/sub-skills/local-search/bm25.py +186 -0
  456. package/sub-skills/local-search/cli_runner.py +331 -0
  457. package/sub-skills/local-search/config.yaml +152 -55
  458. package/sub-skills/local-search/engine_registry.py +91 -26
  459. package/sub-skills/local-search/{health_check.py → local_health_check.py} +140 -10
  460. package/sub-skills/local-search/local_search_adapter.py +13 -2
  461. package/sub-skills/local-search/parse_maps.yaml +40 -42
  462. package/sub-skills/local-search/parsers.py +328 -0
  463. package/sub-skills/local-search/search_v3.py +716 -242
  464. package/sub-skills/local-search/smart_router.py +47 -7
  465. package/sub-skills/local-seek/SKILL.md +110 -0
  466. package/sub-skills/local-seek/config/domains.yaml +20 -0
  467. package/sub-skills/local-seek/scripts/eval_rank.py +216 -0
  468. package/sub-skills/local-seek/scripts/eval_seek.py +224 -0
  469. package/sub-skills/local-seek/scripts/seek.py +1465 -0
  470. package/sub-skills/local-seek/scripts/seek_frecency.py +126 -0
  471. package/sub-skills/local-seek/scripts/seek_fts.py +430 -0
  472. package/sub-skills/local-seek/scripts/seek_rank.py +197 -0
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ query_understanding.py — 查询理解中间层(P0-001)
4
+
5
+ 第一性原理:
6
+ 检索前先「读懂」查询,把用户的隐含约束(否定、地域、意图、多意图)
7
+ 显式化为结构化信号,供路由 / 检索 / 过滤 / 并行度决策统一消费。
8
+
9
+ 职责(MECE 四个互不相干子任务):
10
+ 1. 否定解析:除了X / 不想X / 不要X / 排除X / 不是X / -X / NOT X / without X
11
+ → exclude_terms(供融合后过滤)
12
+ 2. 地域解析:附近|本地|同城|周边 触发词 + 城市词典
13
+ → geo(供 route.py 追加 local_openstreetmap)
14
+ 3. 意图分类:compare / definition / news / fact / social
15
+ → intents(供 route.py 动态并行度 P0-005)
16
+ 4. 多意图拆分:显式并列词(和/与/以及/、)且两段均 ≥2 有效 token
17
+ → multi_intent_splits(最多 2 子查询)
18
+
19
+ 纯本地、零依赖(仅 stdlib),典型延迟 <1ms。
20
+
21
+ 用法:
22
+ from query_understanding import understand
23
+ qu = understand("除了百度的搜索引擎")
24
+ qu.exclude_terms # ["百度"]
25
+ qu.clean_query # "的搜索引擎"(去掉否定片段)
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import copy
31
+ import functools
32
+ import re
33
+ from typing import Any
34
+ from cli_io import dumps
35
+
36
+
37
+ # ── 数据结构 ──────────────────────────────────────────────────────────────────
38
+
39
+ class QueryUnderstanding:
40
+ """查询理解结果(结构化信号容器)。
41
+
42
+ 用 __slots__ 类而不是 @dataclass:`from dataclasses import ...` 会把
43
+ inspect/dis/ast 链拉进 import(实测 3.9ms,占本模块导入成本近四成),而本
44
+ 模块在每次查询里被无条件导入(query_rewriter / route.extract_features /
45
+ execute_search 三个调用点)。字段与 to_dict() 契约保持不变——
46
+ `_understand_cached` 依赖 `QueryUnderstanding(**to_dict())` 重建。
47
+ """
48
+
49
+ __slots__ = ("original", "clean_query", "exclude_terms", "geo",
50
+ "intents", "multi_intent_splits", "confidence")
51
+
52
+ def __init__(self, original: str, clean_query: str,
53
+ exclude_terms: list[str] | None = None,
54
+ geo: dict[str, Any] | None = None,
55
+ intents: list[str] | None = None,
56
+ multi_intent_splits: list[str] | None = None,
57
+ confidence: float = 0.0):
58
+ self.original = original
59
+ self.clean_query = clean_query
60
+ self.exclude_terms = list(exclude_terms) if exclude_terms else []
61
+ self.geo = geo
62
+ self.intents = list(intents) if intents else []
63
+ self.multi_intent_splits = list(multi_intent_splits) if multi_intent_splits else []
64
+ self.confidence = confidence
65
+
66
+ def to_dict(self) -> dict[str, Any]:
67
+ """转为可 JSON 序列化的 dict(与旧 asdict(self) 同形、同样不共享内部容器)。"""
68
+ return {
69
+ "original": self.original,
70
+ "clean_query": self.clean_query,
71
+ "exclude_terms": list(self.exclude_terms),
72
+ "geo": copy.deepcopy(self.geo),
73
+ "intents": list(self.intents),
74
+ "multi_intent_splits": list(self.multi_intent_splits),
75
+ "confidence": self.confidence,
76
+ }
77
+
78
+ def __repr__(self) -> str: # 等价于 dataclass 的默认 repr,便于日志排查
79
+ return (f"QueryUnderstanding(original={self.original!r}, "
80
+ f"clean_query={self.clean_query!r}, "
81
+ f"exclude_terms={self.exclude_terms!r}, geo={self.geo!r}, "
82
+ f"intents={self.intents!r}, "
83
+ f"multi_intent_splits={self.multi_intent_splits!r}, "
84
+ f"confidence={self.confidence!r})")
85
+
86
+
87
+ # ── 否定解析 ──────────────────────────────────────────────────────────────────
88
+ # 每个模式捕获「被排除的实体」到 group(1)。实体非贪婪,在 的/,/空白/末尾 处收边,
89
+ # 避免把 "百度的搜索引擎" 整段吞进 exclude。
90
+
91
+ # 实体边界:的 / 逗号 / 空白 / 以外之外外 / 末尾
92
+ _ENT = r"([\u4e00-\u9fffA-Za-z0-9]{1,20}?)(?=的|[,,、\s]|以外|之外|外|$)"
93
+
94
+ # 否定模式的**单一来源**:一行 = 一条否定 = (提取正则, 剔除正则, 旗标, 触发必要条件)。
95
+ # 新增第 8 条否定只改这里一行,正则与触发条件不会再漂移(此前是两张 SRC 表 +
96
+ # 一份 _NEGATION_LITERALS 三处手工副本,加一条要散改三处)。
97
+ #
98
+ # 这 14 条正则**不在模块级编译**:它们含 [\u4e00-\u9fffA-Za-z0-9] 这类两万字符的
99
+ # 字符集,CPython 编译每条要在 _optimize_charset 上建一次位图,14 条合计实测
100
+ # 5.5 ms——而 import query_understanding 是**无条件**发生的(rewrite_query /
101
+ # route.extract_features / execute_search 都会拉它),纯缓存命中的那一档也要付。
102
+ # 绝大多数查询根本不含否定片段,为它们付这 5.5 ms 是纯固定税。
103
+ # 触发条件是**必要条件**(宁可多答 True 走慢路径,也不能漏答让否定实体污染
104
+ # 消歧信号与检索串);"-" 是哨兵,表示按位置判定(见 _has_negation_trigger)。
105
+ _NEGATION_SPECS: list[tuple[str, str, int, tuple[str, ...]]] = [
106
+ (r"除了" + _ENT,
107
+ r"除了[\u4e00-\u9fffA-Za-z0-9]{1,20}?(?=的|[,,、\s]|以外|之外|外|$)(?:以外|之外|外)?",
108
+ 0, ("除了",)),
109
+ (r"不想(?:要|用|看)?" + _ENT,
110
+ r"不想(?:要|用|看)?[\u4e00-\u9fffA-Za-z0-9]{1,20}?(?=的|[,,、\s]|$)",
111
+ 0, ("不想",)),
112
+ (r"不要" + _ENT,
113
+ r"不要[\u4e00-\u9fffA-Za-z0-9]{1,20}?(?=的|[,,、\s]|$)",
114
+ 0, ("不要",)),
115
+ (r"排除" + _ENT,
116
+ r"排除[\u4e00-\u9fffA-Za-z0-9]{1,20}?(?=的|[,,、\s]|$)",
117
+ 0, ("排除",)),
118
+ # 2026-10-16 方案一抢救:从死代码 query_signals_v2 回收的唯一安全缺口。
119
+ # 同表评估后**否决**的两条(FP 实测,勿再补):
120
+ # 「非X」——非阻塞/非空/非对称是复合术语不是否定,"非阻塞 socket" 若
121
+ # 排除「阻塞」会射杀最相关结果(术语陷阱,词表 unless 防不住);
122
+ # 「没有X」——"没有 API key 能用吗" 会把查询的主语 API 当排除项,
123
+ # 「没有」在查询里绝大多数是状态描述而非过滤意图。
124
+ # (?<!\u662f):「X是不是Y」里的「不是」属于「是否」疑问句式,不是否定
125
+ # 过滤("他是不是中国人"若排除「中国人」= 把问题主语射杀;2026-10-16
126
+ # 对抗审查实测该 FP 后补)。Python lookbehind 定宽可用。
127
+ (r"(?<!\u662f)不是" + _ENT,
128
+ r"(?<!\u662f)不是[\u4e00-\u9fffA-Za-z0-9]{1,20}?(?=的|[,,、\s]|$)",
129
+ 0, ("不是",)),
130
+ (r"(?<![A-Za-z0-9])-([A-Za-z0-9\u4e00-\u9fff]{1,20})",
131
+ r"(?<![A-Za-z0-9])-[A-Za-z0-9\u4e00-\u9fff]{1,20}",
132
+ 0, ("-",)),
133
+ (r"\bNOT\s+([A-Za-z0-9\u4e00-\u9fff]{1,20})",
134
+ r"\bNOT\s+[A-Za-z0-9\u4e00-\u9fff]{1,20}",
135
+ re.I, ("not",)),
136
+ (r"\bwithout\s+([A-Za-z0-9\u4e00-\u9fff]{1,20})",
137
+ r"\bwithout\s+[A-Za-z0-9\u4e00-\u9fff]{1,20}",
138
+ re.I, ("without",)),
139
+ ]
140
+
141
+
142
+ @functools.lru_cache(maxsize=1)
143
+ def _negation_patterns() -> tuple[list[re.Pattern], list[re.Pattern]]:
144
+ """首次真正需要否定解析时才编译这些正则(进程内只编一次)。
145
+
146
+ 触发条件(第四列)在模块级是纯数据,不触发编译,所以「不含否定片段的
147
+ 查询」这一档可以完全不付编译成本。
148
+ """
149
+ return (
150
+ [re.compile(extract, flags) for extract, _span, flags, _trig in _NEGATION_SPECS],
151
+ [re.compile(span, flags) for _extract, span, flags, _trig in _NEGATION_SPECS],
152
+ )
153
+
154
+
155
+ _RE_COLLAPSE_WS = re.compile(r"\s+")
156
+ _RE_LEAD_PARTICLES = re.compile(r"^[的了,,、\s]+")
157
+
158
+
159
+ def _has_negation_trigger(query: str) -> bool:
160
+ """否定解析的廉价前置条件:**必要条件**,不是判据。
161
+
162
+ 只回答「有没有可能命中」,答 True 就走完整解析。宁可多答 True(多编译一次
163
+ 正则),也不能漏答——漏答会让否定实体重新污染消歧信号与检索串。
164
+
165
+ 触发条件与正则同表(_NEGATION_SPECS 第四列),所以两者不会漂移;覆盖关系:
166
+ - 除了 / 不想 / 不要 / 排除:正则要求字面量本身,直接子串判定;
167
+ - NOT / without:正则带 re.I,故按小写子串判定;
168
+ - `-`(哨兵):正则要求 (?<![A-Za-z0-9]),即连字符前一位不是 ASCII 字母数字。
169
+ 逐个位置判而不是「含 - 就走慢路径」——GPT-4o / 2026-09-19 / SWE-bench
170
+ 这类查询的连字符前是字母数字,本来就不构成否定,不该因此丢掉快路径。
171
+ """
172
+ lowered = query.lower()
173
+ for _extract, _span, _flags, triggers in _NEGATION_SPECS:
174
+ for trigger in triggers:
175
+ if trigger != "-":
176
+ if trigger in lowered:
177
+ return True
178
+ continue
179
+ idx = query.find("-")
180
+ while idx != -1:
181
+ if idx == 0 or not (query[idx - 1].isascii()
182
+ and query[idx - 1].isalnum()):
183
+ return True
184
+ idx = query.find("-", idx + 1)
185
+ return False
186
+
187
+
188
+ def _normalize_clean(text: str) -> str:
189
+ """无否定片段时的 clean_query——与走完整 sub 链后完全同路。
190
+
191
+ 两条 sub 在零命中时是恒等操作,所以「跳过解析」与「解析但没命中」必须给出
192
+ 同一个 clean_query,否则跳过就成了行为变更(clean_query 会喂给消歧)。
193
+ """
194
+ return _RE_LEAD_PARTICLES.sub("", _RE_COLLAPSE_WS.sub(" ", text).strip()).strip()
195
+
196
+
197
+ def parse_negation(query: str) -> tuple[list[str], str]:
198
+ """解析否定约束。
199
+
200
+ Returns:
201
+ (exclude_terms, clean_query):被排除词列表 + 去掉否定片段后的查询。
202
+ """
203
+ if not _has_negation_trigger(query):
204
+ return [], _normalize_clean(query)
205
+
206
+ patterns, spans = _negation_patterns()
207
+ exclude: list[str] = []
208
+ for pat in patterns:
209
+ for m in pat.finditer(query):
210
+ term = m.group(1).strip()
211
+ if term and term not in exclude:
212
+ exclude.append(term)
213
+
214
+ clean = query
215
+ for pat in spans:
216
+ clean = pat.sub(" ", clean)
217
+ return exclude, _normalize_clean(clean)
218
+
219
+
220
+ # ── 地域解析 ──────────────────────────────────────────────────────────────────
221
+
222
+ # 本地生活 + 地理/地点实体(LoHo Geography & Places 保持一致)
223
+ _GEO_TRIGGERS = re.compile(
224
+ r"(附近|本地|同城|周边|"
225
+ r"在哪里|在哪儿|在哪|位于|坐落|坐标|经纬度|海拔|发源地|地标|名胜|景点|"
226
+ r"流经|途经|贯穿|横跨|流域|水系|汇入|注入|源头|入海|省份|省区|"
227
+ r"山脉|河流|湖泊|岛屿|沙漠|高原|峡谷|海峡|首都|省会|"
228
+ r"where\s+is|located\s+in|capital\s+of|latitude|longitude|coordinates?|"
229
+ r"flows?\s+through|passes\s+through|drainage|basin|"
230
+ r"openstreetmap|nominatim|geonames)",
231
+ re.I,
232
+ )
233
+
234
+ # 省级市 + 地级市(前 100,覆盖高频城市)
235
+ _CITY_DICT: tuple[str, ...] = (
236
+ # 直辖市 + 省会 + 副省级
237
+ "北京", "上海", "天津", "重庆", "广州", "深圳", "成都", "杭州", "武汉",
238
+ "西安", "南京", "郑州", "长沙", "沈阳", "青岛", "宁波", "东莞", "无锡",
239
+ "昆明", "大连", "厦门", "苏州", "合肥", "佛山", "福州", "哈尔滨", "济南",
240
+ "温州", "长春", "石家庄", "常州", "泉州", "南宁", "贵阳", "南昌", "南通",
241
+ "金华", "徐州", "太原", "嘉兴", "烟台", "惠州", "保定", "台州", "中山",
242
+ "绍兴", "乌鲁木齐", "潍坊", "兰州", "珠海", "扬州", "邯郸", "海口", "洛阳",
243
+ "临沂", "唐山", "汕头", "湖州", "盐城", "泰州", "镇江", "赣州", "廊坊",
244
+ "呼和浩特", "银川", "西宁", "拉萨", "三亚", "威海", "泰安", "淄博", "德州",
245
+ "岳阳", "衡阳", "襄阳", "宜昌", "荆州", "株洲", "湘潭", "常德", "桂林",
246
+ "柳州", "北海", "秦皇岛", "包头", "鞍山", "吉林", "大庆", "connecticut",
247
+ "绵阳", "南充", "宜宾", "遵义", "大理", "丽江", "咸阳", "宝鸡", "榆林",
248
+ "十堰", "九江", "上饶", "抚州", "漳州", "莆田", "龙岩", "宁德",
249
+ )
250
+ _CITY_SET = frozenset(c for c in _CITY_DICT if any("\u4e00" <= ch <= "\u9fff" for ch in c))
251
+
252
+
253
+ def parse_geo(query: str) -> dict[str, Any] | None:
254
+ """解析地域意图。
255
+
256
+ Returns:
257
+ {"has_geo": True, "trigger": str|None, "city": str|None} 或 None(无地域信号)。
258
+ """
259
+ trigger_m = _GEO_TRIGGERS.search(query)
260
+ city = None
261
+ for c in _CITY_SET:
262
+ if c in query:
263
+ city = c
264
+ break
265
+ if not trigger_m and not city:
266
+ return None
267
+ return {
268
+ "has_geo": True,
269
+ "trigger": trigger_m.group(1) if trigger_m else None,
270
+ "city": city,
271
+ }
272
+
273
+
274
+ # ── 意图分类 ──────────────────────────────────────────────────────────────────
275
+
276
+ _INTENT_PATTERNS: dict[str, re.Pattern] = {
277
+ "compare": re.compile(
278
+ r"\b(vs|versus)\b|(对比|比较|区别|相比|哪个好|哪个更|谁更|优缺点|pk)", re.I),
279
+ "definition": re.compile(
280
+ r"\b(what is|what are|define|definition)\b|(是什么|什么是|定义|含义|概念|指的是)", re.I),
281
+ "news": re.compile(
282
+ r"\b(news|latest|breaking)\b|(最新|新闻|快讯|突发|今天|近期|最近|进展|动态)", re.I),
283
+ "fact": re.compile(
284
+ r"\b(how many|how much|when did|where is|who is)\b|"
285
+ r"(多少|几个|几号|什么时候|哪一年|哪里|谁是|是谁)", re.I),
286
+ "social": re.compile(
287
+ r"(小红书|抖音|推特|twitter|reddit|b站|bilibili|微博|舆情|舆论|"
288
+ r"网友|口碑|种草|拔草|评价|讨论|热议)", re.I),
289
+ }
290
+
291
+
292
+ def classify_intents(query: str) -> list[str]:
293
+ """多标签意图分类,按固定优先级返回命中的意图列表。"""
294
+ intents: list[str] = []
295
+ # compare / social / news 优先于 fact / definition(更具体)
296
+ for name in ("compare", "social", "news", "definition", "fact"):
297
+ if _INTENT_PATTERNS[name].search(query):
298
+ intents.append(name)
299
+ return intents
300
+
301
+
302
+ # ── 多意图拆分 ────────────────────────────────────────────────────────────────
303
+
304
+ _CONJUNCTIONS = re.compile(r"(以及|和|与|、)")
305
+ _TOKEN_RE = re.compile(r"[\u4e00-\u9fff]|[a-zA-Z0-9]+")
306
+
307
+
308
+ def _effective_tokens(text: str) -> int:
309
+ """统计有效 token 数(中文单字 + 英文单词)。"""
310
+ return len(_TOKEN_RE.findall(text))
311
+
312
+
313
+ def split_multi_intent(query: str) -> list[str]:
314
+ """基于显式并列词拆分多意图查询(最多 2 子查询)。
315
+
316
+ 条件:存在并列词 且 拆分后两段均 ≥2 有效 token。
317
+ """
318
+ parts = _CONJUNCTIONS.split(query)
319
+ if len(parts) < 3:
320
+ return []
321
+ # split 会保留分隔符:[left, conj, right, conj, right2, ...]
322
+ segments = [p.strip() for i, p in enumerate(parts) if i % 2 == 0 and p.strip()]
323
+ valid = [s for s in segments if _effective_tokens(s) >= 2]
324
+ if len(valid) >= 2:
325
+ return valid[:2]
326
+ return []
327
+
328
+
329
+ # ── 主入口 ────────────────────────────────────────────────────────────────────
330
+
331
+ def understand(query: str) -> QueryUnderstanding:
332
+ """对查询做完整语义理解,返回结构化信号。
333
+
334
+ Args:
335
+ query: 原始查询词。
336
+
337
+ Returns:
338
+ QueryUnderstanding:含否定、地域、意图、多意图拆分及总置信度。
339
+ """
340
+ if not isinstance(query, str):
341
+ raise TypeError(f"query 必须为 str,实际 {type(query).__name__}")
342
+
343
+ original = query
344
+ exclude_terms, clean_query = parse_negation(query)
345
+ if not clean_query:
346
+ clean_query = original # 全被否定片段吃掉时回退原查询,避免空检索
347
+
348
+ geo = parse_geo(query)
349
+ intents = classify_intents(query)
350
+ multi_splits = split_multi_intent(clean_query)
351
+
352
+ # 置信度:命中的信号越多、越明确,置信度越高(上限 0.95)
353
+ conf = 0.0
354
+ if exclude_terms:
355
+ conf += 0.3
356
+ if geo:
357
+ conf += 0.25
358
+ if intents:
359
+ conf += 0.2 + 0.05 * min(len(intents), 2)
360
+ if multi_splits:
361
+ conf += 0.2
362
+ confidence = round(min(conf, 0.95), 2)
363
+
364
+ return QueryUnderstanding(
365
+ original=original,
366
+ clean_query=clean_query,
367
+ exclude_terms=exclude_terms,
368
+ geo=geo,
369
+ intents=intents,
370
+ multi_intent_splits=multi_splits,
371
+ confidence=confidence,
372
+ )
373
+
374
+
375
+ # ── 进程内 memoize ────────────────────────────────────────────────────────────
376
+ # 同一次搜索中 query_rewriter / route.extract_features / execute_search 会各调
377
+ # 一次 understand(),同一查询重复计算纯属浪费。query 即 key,用 lru_cache 做
378
+ # LRU 淘汰(上限 256 条,热查询复用),比满则清空更平滑。缓存 to_dict() 后再
379
+ # 重建 dataclass,避免不可哈希对象的 lru_cache 限制;纯本地正则,不设 TTL。
380
+
381
+ @functools.lru_cache(maxsize=256)
382
+ def _understand_cached_dict(query: str) -> dict[str, Any]:
383
+ """understand(query).to_dict() 的 lru_cache 包装(key 为原始查询词)。"""
384
+ return understand(query).to_dict()
385
+
386
+
387
+ def _understand_cached(query: str) -> QueryUnderstanding:
388
+ """understand 的进程内缓存包装:同一查询只解析一次。"""
389
+ return QueryUnderstanding(**_understand_cached_dict(query))
390
+
391
+
392
+ # ── CLI 测试 ──────────────────────────────────────────────────────────────────
393
+
394
+ if __name__ == "__main__":
395
+ import sys
396
+
397
+ tests = sys.argv[1:] if len(sys.argv) > 1 else [
398
+ "除了百度的搜索引擎",
399
+ "附近医院",
400
+ "北京附近的川菜馆",
401
+ "Python 和 Rust 哪个好",
402
+ "什么是 Transformer",
403
+ "英伟达最新财报进展",
404
+ "小米 SU7 车主口碑 -广告",
405
+ "React vs Vue without jQuery",
406
+ "上海周边亲子游 以及 露营地推荐",
407
+ ]
408
+ for q in tests:
409
+ qu = understand(q)
410
+ print(dumps(qu.to_dict()))
411
+ print("-" * 60)