@tikomni/skills 0.1.2 → 0.1.4

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 (480) hide show
  1. package/.skill-package-allowlist.txt +1 -3
  2. package/README.md +41 -49
  3. package/README.zh-CN.md +43 -51
  4. package/bin/tikomni-skills.js +2 -2
  5. package/env.example +37 -56
  6. package/package.json +7 -3
  7. package/skills/social-media-crawl/SKILL.md +53 -0
  8. package/skills/social-media-crawl/agents/openai.yaml +5 -0
  9. package/skills/social-media-crawl/references/contracts/output-envelope.md +22 -0
  10. package/skills/social-media-crawl/references/contracts/work-fact-card-fields.md +48 -0
  11. package/skills/social-media-crawl/references/guides/generic-mcp-objects.md +30 -0
  12. package/skills/social-media-crawl/references/mcp-usage-contract.md +30 -0
  13. package/skills/social-media-crawl/references/pipelines/douyin-creator-home.md +7 -0
  14. package/skills/social-media-crawl/references/pipelines/douyin-single-work.md +7 -0
  15. package/skills/social-media-crawl/references/pipelines/xiaohongshu-creator-home.md +7 -0
  16. package/skills/social-media-crawl/references/pipelines/xiaohongshu-single-work.md +7 -0
  17. package/skills/social-media-crawl/references/schemas/creator-profile.schema.json +33 -0
  18. package/skills/social-media-crawl/references/schemas/output-envelope.schema.json +41 -0
  19. package/skills/social-media-crawl/references/schemas/work-collection.schema.json +29 -0
  20. package/skills/social-media-crawl/references/schemas/work-fact-card.schema.json +67 -0
  21. package/skills/social-media-crawl/references/service-guides/u2-u3-mandatory-fallback.md +21 -0
  22. package/skills/social-media-crawl/scripts/__init__.py +2 -0
  23. package/skills/social-media-crawl/scripts/core/__init__.py +2 -0
  24. package/skills/{creator-analysis/scripts/pipeline/asr → social-media-crawl/scripts/core}/asr_pipeline.py +252 -9
  25. package/skills/social-media-crawl/scripts/core/completeness.py +83 -0
  26. package/skills/{single-work-analysis → social-media-crawl}/scripts/core/config_loader.py +108 -167
  27. package/skills/social-media-crawl/scripts/core/mcp_dispatch.py +145 -0
  28. package/skills/social-media-crawl/scripts/core/object_detection.py +63 -0
  29. package/skills/{creator-analysis/scripts/pipeline/asr → social-media-crawl/scripts/core}/poll_u2_task.py +6 -2
  30. package/skills/{single-work-analysis → social-media-crawl}/scripts/core/progress_report.py +32 -0
  31. package/skills/social-media-crawl/scripts/core/storage_router.py +160 -0
  32. package/skills/{creator-analysis → social-media-crawl}/scripts/core/tikomni_common.py +13 -3
  33. package/skills/social-media-crawl/scripts/core/u3_fallback.py +328 -0
  34. package/skills/social-media-crawl/scripts/pipelines/__init__.py +2 -0
  35. package/skills/social-media-crawl/scripts/pipelines/douyin_creator_home_helpers.py +35 -0
  36. package/skills/social-media-crawl/scripts/pipelines/douyin_platform_adapter.py +7 -0
  37. package/skills/{creator-analysis/scripts/author_home/asr → social-media-crawl/scripts/pipelines}/home_asr.py +1 -1
  38. package/skills/{creator-analysis/scripts/author_home/adapters → social-media-crawl/scripts/pipelines}/platform_adapters.py +8 -2
  39. package/skills/social-media-crawl/scripts/pipelines/run_douyin_creator_home.py +237 -0
  40. package/skills/{single-work-analysis/scripts/platform/douyin/run_douyin_single_video.py → social-media-crawl/scripts/pipelines/run_douyin_single_work.py} +282 -174
  41. package/skills/social-media-crawl/scripts/pipelines/run_xiaohongshu_creator_home.py +237 -0
  42. package/skills/{single-work-analysis/scripts/platform/xiaohongshu/run_xiaohongshu_extract.py → social-media-crawl/scripts/pipelines/run_xiaohongshu_single_work.py} +290 -141
  43. package/skills/{creator-analysis/scripts/author_home → social-media-crawl/scripts/pipelines}/schema.py +1 -1
  44. package/skills/social-media-crawl/scripts/pipelines/xiaohongshu_creator_home_helpers.py +35 -0
  45. package/skills/social-media-crawl/scripts/pipelines/xiaohongshu_platform_adapter.py +7 -0
  46. package/skills/social-media-crawl/scripts/writers/__init__.py +1 -0
  47. package/skills/social-media-crawl/scripts/writers/write_work_fact_card.py +391 -0
  48. package/skills/creator-analysis/SKILL.md +0 -95
  49. package/skills/creator-analysis/agents/openai.yaml +0 -4
  50. package/skills/creator-analysis/env.example +0 -36
  51. package/skills/creator-analysis/references/api-capability-index.md +0 -92
  52. package/skills/creator-analysis/references/api-contracts/asr-api.md +0 -130
  53. package/skills/creator-analysis/references/api-contracts/bilibili-app-api.md +0 -776
  54. package/skills/creator-analysis/references/api-contracts/bilibili-web-api.md +0 -2017
  55. package/skills/creator-analysis/references/api-contracts/demo-api.md +0 -717
  56. package/skills/creator-analysis/references/api-contracts/douyin-app-v3-api.md +0 -3594
  57. package/skills/creator-analysis/references/api-contracts/douyin-billboard-api.md +0 -2274
  58. package/skills/creator-analysis/references/api-contracts/douyin-creator-api.md +0 -1575
  59. package/skills/creator-analysis/references/api-contracts/douyin-creator-v2-api.md +0 -3254
  60. package/skills/creator-analysis/references/api-contracts/douyin-search-api.md +0 -4118
  61. package/skills/creator-analysis/references/api-contracts/douyin-web-api.md +0 -5544
  62. package/skills/creator-analysis/references/api-contracts/douyin-xingtu-api.md +0 -1916
  63. package/skills/creator-analysis/references/api-contracts/douyin-xingtu-v2-api.md +0 -1540
  64. package/skills/creator-analysis/references/api-contracts/health-check.md +0 -69
  65. package/skills/creator-analysis/references/api-contracts/hybrid-parsing.md +0 -78
  66. package/skills/creator-analysis/references/api-contracts/instagram-v1-api.md +0 -2256
  67. package/skills/creator-analysis/references/api-contracts/instagram-v2-api.md +0 -2011
  68. package/skills/creator-analysis/references/api-contracts/instagram-v3-api.md +0 -2630
  69. package/skills/creator-analysis/references/api-contracts/ios-shortcut.md +0 -44
  70. package/skills/creator-analysis/references/api-contracts/kuaishou-app-api.md +0 -1518
  71. package/skills/creator-analysis/references/api-contracts/kuaishou-web-api.md +0 -1242
  72. package/skills/creator-analysis/references/api-contracts/lemon8-app-api.md +0 -1088
  73. package/skills/creator-analysis/references/api-contracts/linkedin-web-api.md +0 -1949
  74. package/skills/creator-analysis/references/api-contracts/media-ingest-api.md +0 -126
  75. package/skills/creator-analysis/references/api-contracts/pipixia-app-api.md +0 -1142
  76. package/skills/creator-analysis/references/api-contracts/reddit-app-api.md +0 -2025
  77. package/skills/creator-analysis/references/api-contracts/sora2-api.md +0 -2266
  78. package/skills/creator-analysis/references/api-contracts/temp-mail-api.md +0 -208
  79. package/skills/creator-analysis/references/api-contracts/threads-web-api.md +0 -897
  80. package/skills/creator-analysis/references/api-contracts/tikhub-downloader-api.md +0 -134
  81. package/skills/creator-analysis/references/api-contracts/tikhub-user-api.md +0 -494
  82. package/skills/creator-analysis/references/api-contracts/tiktok-ads-api.md +0 -5947
  83. package/skills/creator-analysis/references/api-contracts/tiktok-analytics-api.md +0 -968
  84. package/skills/creator-analysis/references/api-contracts/tiktok-app-v3-api.md +0 -5735
  85. package/skills/creator-analysis/references/api-contracts/tiktok-creator-api.md +0 -1951
  86. package/skills/creator-analysis/references/api-contracts/tiktok-interaction-api.md +0 -742
  87. package/skills/creator-analysis/references/api-contracts/tiktok-shop-web-api.md +0 -1890
  88. package/skills/creator-analysis/references/api-contracts/tiktok-web-api.md +0 -4448
  89. package/skills/creator-analysis/references/api-contracts/toutiao-app-api.md +0 -342
  90. package/skills/creator-analysis/references/api-contracts/toutiao-web-api.md +0 -143
  91. package/skills/creator-analysis/references/api-contracts/twitter-web-api.md +0 -989
  92. package/skills/creator-analysis/references/api-contracts/wechat-channels-api.md +0 -809
  93. package/skills/creator-analysis/references/api-contracts/wechat-media-platform-web-api.md +0 -677
  94. package/skills/creator-analysis/references/api-contracts/weibo-app-api.md +0 -1547
  95. package/skills/creator-analysis/references/api-contracts/weibo-web-api.md +0 -798
  96. package/skills/creator-analysis/references/api-contracts/weibo-web-v2-api.md +0 -2459
  97. package/skills/creator-analysis/references/api-contracts/xiaohongshu-app-api.md +0 -1291
  98. package/skills/creator-analysis/references/api-contracts/xiaohongshu-app-v2-api.md +0 -1683
  99. package/skills/creator-analysis/references/api-contracts/xiaohongshu-web-api.md +0 -1324
  100. package/skills/creator-analysis/references/api-contracts/xiaohongshu-web-v2-api.md +0 -1209
  101. package/skills/creator-analysis/references/api-contracts/xigua-app-v2-api.md +0 -489
  102. package/skills/creator-analysis/references/api-contracts/youtube-web-api.md +0 -2636
  103. package/skills/creator-analysis/references/api-contracts/youtube-web-v2-api.md +0 -2660
  104. package/skills/creator-analysis/references/api-contracts/zhihu-web-api.md +0 -2315
  105. package/skills/creator-analysis/references/api-tags/asr-api.md +0 -100
  106. package/skills/creator-analysis/references/api-tags/bilibili-app-api.md +0 -482
  107. package/skills/creator-analysis/references/api-tags/bilibili-web-api.md +0 -1267
  108. package/skills/creator-analysis/references/api-tags/demo-api.md +0 -365
  109. package/skills/creator-analysis/references/api-tags/douyin-app-v3-api.md +0 -2012
  110. package/skills/creator-analysis/references/api-tags/douyin-billboard-api.md +0 -1428
  111. package/skills/creator-analysis/references/api-tags/douyin-creator-api.md +0 -694
  112. package/skills/creator-analysis/references/api-tags/douyin-creator-v2-api.md +0 -694
  113. package/skills/creator-analysis/references/api-tags/douyin-search-api.md +0 -1059
  114. package/skills/creator-analysis/references/api-tags/douyin-web-api.md +0 -3314
  115. package/skills/creator-analysis/references/api-tags/douyin-xingtu-api.md +0 -935
  116. package/skills/creator-analysis/references/api-tags/douyin-xingtu-v2-api.md +0 -925
  117. package/skills/creator-analysis/references/api-tags/health-check.md +0 -40
  118. package/skills/creator-analysis/references/api-tags/hybrid-parsing.md +0 -57
  119. package/skills/creator-analysis/references/api-tags/instagram-v1-api.md +0 -1224
  120. package/skills/creator-analysis/references/api-tags/instagram-v2-api.md +0 -1147
  121. package/skills/creator-analysis/references/api-tags/instagram-v3-api.md +0 -1123
  122. package/skills/creator-analysis/references/api-tags/ios-shortcut.md +0 -45
  123. package/skills/creator-analysis/references/api-tags/kuaishou-app-api.md +0 -846
  124. package/skills/creator-analysis/references/api-tags/kuaishou-web-api.md +0 -551
  125. package/skills/creator-analysis/references/api-tags/lemon8-app-api.md +0 -687
  126. package/skills/creator-analysis/references/api-tags/linkedin-web-api.md +0 -1105
  127. package/skills/creator-analysis/references/api-tags/media-ingest-api.md +0 -112
  128. package/skills/creator-analysis/references/api-tags/pipixia-app-api.md +0 -721
  129. package/skills/creator-analysis/references/api-tags/reddit-app-api.md +0 -1057
  130. package/skills/creator-analysis/references/api-tags/sora2-api.md +0 -737
  131. package/skills/creator-analysis/references/api-tags/temp-mail-api.md +0 -136
  132. package/skills/creator-analysis/references/api-tags/threads-web-api.md +0 -472
  133. package/skills/creator-analysis/references/api-tags/tikhub-downloader-api.md +0 -65
  134. package/skills/creator-analysis/references/api-tags/tikhub-user-api.md +0 -253
  135. package/skills/creator-analysis/references/api-tags/tiktok-ads-api.md +0 -1393
  136. package/skills/creator-analysis/references/api-tags/tiktok-analytics-api.md +0 -179
  137. package/skills/creator-analysis/references/api-tags/tiktok-app-v3-api.md +0 -3264
  138. package/skills/creator-analysis/references/api-tags/tiktok-creator-api.md +0 -709
  139. package/skills/creator-analysis/references/api-tags/tiktok-interaction-api.md +0 -366
  140. package/skills/creator-analysis/references/api-tags/tiktok-shop-web-api.md +0 -663
  141. package/skills/creator-analysis/references/api-tags/tiktok-web-api.md +0 -2516
  142. package/skills/creator-analysis/references/api-tags/toutiao-app-api.md +0 -220
  143. package/skills/creator-analysis/references/api-tags/toutiao-web-api.md +0 -96
  144. package/skills/creator-analysis/references/api-tags/twitter-web-api.md +0 -562
  145. package/skills/creator-analysis/references/api-tags/wechat-channels-api.md +0 -405
  146. package/skills/creator-analysis/references/api-tags/wechat-media-platform-web-api.md +0 -431
  147. package/skills/creator-analysis/references/api-tags/weibo-app-api.md +0 -851
  148. package/skills/creator-analysis/references/api-tags/weibo-web-api.md +0 -470
  149. package/skills/creator-analysis/references/api-tags/weibo-web-v2-api.md +0 -1405
  150. package/skills/creator-analysis/references/api-tags/xiaohongshu-app-api.md +0 -534
  151. package/skills/creator-analysis/references/api-tags/xiaohongshu-app-v2-api.md +0 -934
  152. package/skills/creator-analysis/references/api-tags/xiaohongshu-web-api.md +0 -757
  153. package/skills/creator-analysis/references/api-tags/xiaohongshu-web-v2-api.md +0 -762
  154. package/skills/creator-analysis/references/api-tags/xigua-app-v2-api.md +0 -308
  155. package/skills/creator-analysis/references/api-tags/youtube-web-api.md +0 -934
  156. package/skills/creator-analysis/references/api-tags/youtube-web-v2-api.md +0 -717
  157. package/skills/creator-analysis/references/api-tags/zhihu-web-api.md +0 -1384
  158. package/skills/creator-analysis/references/asr-orchestration.md +0 -33
  159. package/skills/creator-analysis/references/config-templates/defaults.yaml +0 -60
  160. package/skills/creator-analysis/references/contracts/creator-card-fields.md +0 -25
  161. package/skills/creator-analysis/references/contracts/work-card-fields.md +0 -68
  162. package/skills/creator-analysis/references/platform-guides/douyin.md +0 -54
  163. package/skills/creator-analysis/references/platform-guides/generic.md +0 -50
  164. package/skills/creator-analysis/references/platform-guides/xiaohongshu.md +0 -69
  165. package/skills/creator-analysis/references/prompt-contracts/asr-clean.md +0 -28
  166. package/skills/creator-analysis/references/prompt-contracts/author-analysis-v2.md +0 -46
  167. package/skills/creator-analysis/references/prompt-contracts/author-analysis.md +0 -49
  168. package/skills/creator-analysis/references/prompt-contracts/cta.md +0 -24
  169. package/skills/creator-analysis/references/prompt-contracts/hook.md +0 -25
  170. package/skills/creator-analysis/references/prompt-contracts/insight.md +0 -47
  171. package/skills/creator-analysis/references/prompt-contracts/sampled-work-batch-explanations.md +0 -30
  172. package/skills/creator-analysis/references/prompt-contracts/structure.md +0 -25
  173. package/skills/creator-analysis/references/prompt-contracts/style.md +0 -27
  174. package/skills/creator-analysis/references/prompt-contracts/summary.md +0 -29
  175. package/skills/creator-analysis/references/prompt-contracts/topic.md +0 -29
  176. package/skills/creator-analysis/references/schemas/author-analysis-input-v1.schema.json +0 -325
  177. package/skills/creator-analysis/references/schemas/author-analysis-v2.schema.json +0 -287
  178. package/skills/creator-analysis/references/schemas/sampled-work-batch-explanations.schema.json +0 -41
  179. package/skills/creator-analysis/references/service-guides/asr-u2-u3-fallback.md +0 -75
  180. package/skills/creator-analysis/references/workflow.md +0 -23
  181. package/skills/creator-analysis/scripts/__init__.py +0 -0
  182. package/skills/creator-analysis/scripts/author_home/__init__.py +0 -0
  183. package/skills/creator-analysis/scripts/author_home/adapters/__init__.py +0 -0
  184. package/skills/creator-analysis/scripts/author_home/analyzers/__init__.py +0 -0
  185. package/skills/creator-analysis/scripts/author_home/analyzers/author_analysis_v2_support.py +0 -1165
  186. package/skills/creator-analysis/scripts/author_home/analyzers/prompt_first_analyzers.py +0 -447
  187. package/skills/creator-analysis/scripts/author_home/analyzers/sampled_work_batch_explainer.py +0 -331
  188. package/skills/creator-analysis/scripts/author_home/asr/__init__.py +0 -5
  189. package/skills/creator-analysis/scripts/author_home/builders/__init__.py +0 -0
  190. package/skills/creator-analysis/scripts/author_home/builders/home_builders.py +0 -213
  191. package/skills/creator-analysis/scripts/author_home/collectors/__init__.py +0 -0
  192. package/skills/creator-analysis/scripts/author_home/orchestrator/__init__.py +0 -0
  193. package/skills/creator-analysis/scripts/author_home/orchestrator/run_author_analysis.py +0 -834
  194. package/skills/creator-analysis/scripts/author_home/orchestrator/work_analysis_artifacts.py +0 -609
  195. package/skills/creator-analysis/scripts/core/__init__.py +0 -0
  196. package/skills/creator-analysis/scripts/core/analysis_pipeline.py +0 -133
  197. package/skills/creator-analysis/scripts/core/config_loader.py +0 -418
  198. package/skills/creator-analysis/scripts/core/progress_report.py +0 -111
  199. package/skills/creator-analysis/scripts/core/storage_router.py +0 -256
  200. package/skills/creator-analysis/scripts/pipeline/__init__.py +0 -0
  201. package/skills/creator-analysis/scripts/pipeline/asr/__init__.py +0 -0
  202. package/skills/creator-analysis/scripts/platform/__init__.py +0 -0
  203. package/skills/creator-analysis/scripts/platform/douyin/__init__.py +0 -0
  204. package/skills/creator-analysis/scripts/platform/douyin/run_douyin_single_video.py +0 -1208
  205. package/skills/creator-analysis/scripts/platform/xiaohongshu/__init__.py +0 -0
  206. package/skills/creator-analysis/scripts/platform/xiaohongshu/run_xiaohongshu_extract.py +0 -2128
  207. package/skills/creator-analysis/scripts/writers/__init__.py +0 -0
  208. package/skills/creator-analysis/scripts/writers/write_author_homepage_samples.py +0 -107
  209. package/skills/creator-analysis/scripts/writers/write_benchmark_card.py +0 -1579
  210. package/skills/meta-capability/SKILL.md +0 -69
  211. package/skills/meta-capability/agents/openai.yaml +0 -4
  212. package/skills/meta-capability/env.example +0 -42
  213. package/skills/meta-capability/references/api-capability-index.md +0 -92
  214. package/skills/meta-capability/references/api-contracts/asr-api.md +0 -130
  215. package/skills/meta-capability/references/api-contracts/bilibili-app-api.md +0 -776
  216. package/skills/meta-capability/references/api-contracts/bilibili-web-api.md +0 -2017
  217. package/skills/meta-capability/references/api-contracts/demo-api.md +0 -717
  218. package/skills/meta-capability/references/api-contracts/douyin-app-v3-api.md +0 -3594
  219. package/skills/meta-capability/references/api-contracts/douyin-billboard-api.md +0 -2274
  220. package/skills/meta-capability/references/api-contracts/douyin-creator-api.md +0 -1575
  221. package/skills/meta-capability/references/api-contracts/douyin-creator-v2-api.md +0 -3254
  222. package/skills/meta-capability/references/api-contracts/douyin-search-api.md +0 -4118
  223. package/skills/meta-capability/references/api-contracts/douyin-web-api.md +0 -5544
  224. package/skills/meta-capability/references/api-contracts/douyin-xingtu-api.md +0 -1916
  225. package/skills/meta-capability/references/api-contracts/douyin-xingtu-v2-api.md +0 -1540
  226. package/skills/meta-capability/references/api-contracts/health-check.md +0 -69
  227. package/skills/meta-capability/references/api-contracts/hybrid-parsing.md +0 -78
  228. package/skills/meta-capability/references/api-contracts/instagram-v1-api.md +0 -2256
  229. package/skills/meta-capability/references/api-contracts/instagram-v2-api.md +0 -2011
  230. package/skills/meta-capability/references/api-contracts/instagram-v3-api.md +0 -2630
  231. package/skills/meta-capability/references/api-contracts/ios-shortcut.md +0 -44
  232. package/skills/meta-capability/references/api-contracts/kuaishou-app-api.md +0 -1518
  233. package/skills/meta-capability/references/api-contracts/kuaishou-web-api.md +0 -1242
  234. package/skills/meta-capability/references/api-contracts/lemon8-app-api.md +0 -1088
  235. package/skills/meta-capability/references/api-contracts/linkedin-web-api.md +0 -1949
  236. package/skills/meta-capability/references/api-contracts/media-ingest-api.md +0 -126
  237. package/skills/meta-capability/references/api-contracts/pipixia-app-api.md +0 -1142
  238. package/skills/meta-capability/references/api-contracts/reddit-app-api.md +0 -2025
  239. package/skills/meta-capability/references/api-contracts/sora2-api.md +0 -2266
  240. package/skills/meta-capability/references/api-contracts/temp-mail-api.md +0 -208
  241. package/skills/meta-capability/references/api-contracts/threads-web-api.md +0 -897
  242. package/skills/meta-capability/references/api-contracts/tikhub-downloader-api.md +0 -134
  243. package/skills/meta-capability/references/api-contracts/tikhub-user-api.md +0 -494
  244. package/skills/meta-capability/references/api-contracts/tiktok-ads-api.md +0 -5947
  245. package/skills/meta-capability/references/api-contracts/tiktok-analytics-api.md +0 -968
  246. package/skills/meta-capability/references/api-contracts/tiktok-app-v3-api.md +0 -5735
  247. package/skills/meta-capability/references/api-contracts/tiktok-creator-api.md +0 -1951
  248. package/skills/meta-capability/references/api-contracts/tiktok-interaction-api.md +0 -742
  249. package/skills/meta-capability/references/api-contracts/tiktok-shop-web-api.md +0 -1890
  250. package/skills/meta-capability/references/api-contracts/tiktok-web-api.md +0 -4448
  251. package/skills/meta-capability/references/api-contracts/toutiao-app-api.md +0 -342
  252. package/skills/meta-capability/references/api-contracts/toutiao-web-api.md +0 -143
  253. package/skills/meta-capability/references/api-contracts/twitter-web-api.md +0 -989
  254. package/skills/meta-capability/references/api-contracts/wechat-channels-api.md +0 -809
  255. package/skills/meta-capability/references/api-contracts/wechat-media-platform-web-api.md +0 -677
  256. package/skills/meta-capability/references/api-contracts/weibo-app-api.md +0 -1547
  257. package/skills/meta-capability/references/api-contracts/weibo-web-api.md +0 -798
  258. package/skills/meta-capability/references/api-contracts/weibo-web-v2-api.md +0 -2459
  259. package/skills/meta-capability/references/api-contracts/xiaohongshu-app-api.md +0 -1291
  260. package/skills/meta-capability/references/api-contracts/xiaohongshu-app-v2-api.md +0 -1683
  261. package/skills/meta-capability/references/api-contracts/xiaohongshu-web-api.md +0 -1324
  262. package/skills/meta-capability/references/api-contracts/xiaohongshu-web-v2-api.md +0 -1209
  263. package/skills/meta-capability/references/api-contracts/xigua-app-v2-api.md +0 -489
  264. package/skills/meta-capability/references/api-contracts/youtube-web-api.md +0 -2636
  265. package/skills/meta-capability/references/api-contracts/youtube-web-v2-api.md +0 -2660
  266. package/skills/meta-capability/references/api-contracts/zhihu-web-api.md +0 -2315
  267. package/skills/meta-capability/references/api-tags/asr-api.md +0 -100
  268. package/skills/meta-capability/references/api-tags/bilibili-app-api.md +0 -482
  269. package/skills/meta-capability/references/api-tags/bilibili-web-api.md +0 -1267
  270. package/skills/meta-capability/references/api-tags/demo-api.md +0 -365
  271. package/skills/meta-capability/references/api-tags/douyin-app-v3-api.md +0 -2012
  272. package/skills/meta-capability/references/api-tags/douyin-billboard-api.md +0 -1428
  273. package/skills/meta-capability/references/api-tags/douyin-creator-api.md +0 -694
  274. package/skills/meta-capability/references/api-tags/douyin-creator-v2-api.md +0 -694
  275. package/skills/meta-capability/references/api-tags/douyin-search-api.md +0 -1059
  276. package/skills/meta-capability/references/api-tags/douyin-web-api.md +0 -3314
  277. package/skills/meta-capability/references/api-tags/douyin-xingtu-api.md +0 -935
  278. package/skills/meta-capability/references/api-tags/douyin-xingtu-v2-api.md +0 -925
  279. package/skills/meta-capability/references/api-tags/health-check.md +0 -40
  280. package/skills/meta-capability/references/api-tags/hybrid-parsing.md +0 -57
  281. package/skills/meta-capability/references/api-tags/instagram-v1-api.md +0 -1224
  282. package/skills/meta-capability/references/api-tags/instagram-v2-api.md +0 -1147
  283. package/skills/meta-capability/references/api-tags/instagram-v3-api.md +0 -1123
  284. package/skills/meta-capability/references/api-tags/ios-shortcut.md +0 -45
  285. package/skills/meta-capability/references/api-tags/kuaishou-app-api.md +0 -846
  286. package/skills/meta-capability/references/api-tags/kuaishou-web-api.md +0 -551
  287. package/skills/meta-capability/references/api-tags/lemon8-app-api.md +0 -687
  288. package/skills/meta-capability/references/api-tags/linkedin-web-api.md +0 -1105
  289. package/skills/meta-capability/references/api-tags/media-ingest-api.md +0 -112
  290. package/skills/meta-capability/references/api-tags/pipixia-app-api.md +0 -721
  291. package/skills/meta-capability/references/api-tags/reddit-app-api.md +0 -1057
  292. package/skills/meta-capability/references/api-tags/sora2-api.md +0 -737
  293. package/skills/meta-capability/references/api-tags/temp-mail-api.md +0 -136
  294. package/skills/meta-capability/references/api-tags/threads-web-api.md +0 -472
  295. package/skills/meta-capability/references/api-tags/tikhub-downloader-api.md +0 -65
  296. package/skills/meta-capability/references/api-tags/tikhub-user-api.md +0 -253
  297. package/skills/meta-capability/references/api-tags/tiktok-ads-api.md +0 -1393
  298. package/skills/meta-capability/references/api-tags/tiktok-analytics-api.md +0 -179
  299. package/skills/meta-capability/references/api-tags/tiktok-app-v3-api.md +0 -3264
  300. package/skills/meta-capability/references/api-tags/tiktok-creator-api.md +0 -709
  301. package/skills/meta-capability/references/api-tags/tiktok-interaction-api.md +0 -366
  302. package/skills/meta-capability/references/api-tags/tiktok-shop-web-api.md +0 -663
  303. package/skills/meta-capability/references/api-tags/tiktok-web-api.md +0 -2516
  304. package/skills/meta-capability/references/api-tags/toutiao-app-api.md +0 -220
  305. package/skills/meta-capability/references/api-tags/toutiao-web-api.md +0 -96
  306. package/skills/meta-capability/references/api-tags/twitter-web-api.md +0 -562
  307. package/skills/meta-capability/references/api-tags/wechat-channels-api.md +0 -405
  308. package/skills/meta-capability/references/api-tags/wechat-media-platform-web-api.md +0 -431
  309. package/skills/meta-capability/references/api-tags/weibo-app-api.md +0 -851
  310. package/skills/meta-capability/references/api-tags/weibo-web-api.md +0 -470
  311. package/skills/meta-capability/references/api-tags/weibo-web-v2-api.md +0 -1405
  312. package/skills/meta-capability/references/api-tags/xiaohongshu-app-api.md +0 -534
  313. package/skills/meta-capability/references/api-tags/xiaohongshu-app-v2-api.md +0 -934
  314. package/skills/meta-capability/references/api-tags/xiaohongshu-web-api.md +0 -757
  315. package/skills/meta-capability/references/api-tags/xiaohongshu-web-v2-api.md +0 -762
  316. package/skills/meta-capability/references/api-tags/xigua-app-v2-api.md +0 -308
  317. package/skills/meta-capability/references/api-tags/youtube-web-api.md +0 -934
  318. package/skills/meta-capability/references/api-tags/youtube-web-v2-api.md +0 -717
  319. package/skills/meta-capability/references/api-tags/zhihu-web-api.md +0 -1384
  320. package/skills/meta-capability/references/config-templates/defaults.yaml +0 -18
  321. package/skills/meta-capability/references/dispatch.md +0 -27
  322. package/skills/meta-capability/references/execution-guidelines.md +0 -25
  323. package/skills/meta-capability/references/implemented-route-map.md +0 -177
  324. package/skills/meta-capability/references/service-guides/asr-u2-u3-fallback.md +0 -75
  325. package/skills/meta-capability/scripts/__init__.py +0 -1
  326. package/skills/meta-capability/scripts/call_route.py +0 -141
  327. package/skills/meta-capability/scripts/core/__init__.py +0 -1
  328. package/skills/meta-capability/scripts/core/bootstrap_env.py +0 -32
  329. package/skills/meta-capability/scripts/core/config_loader.py +0 -204
  330. package/skills/meta-capability/scripts/core/tikomni_common.py +0 -443
  331. package/skills/meta-capability/scripts/test_auth.py +0 -98
  332. package/skills/single-work-analysis/SKILL.md +0 -62
  333. package/skills/single-work-analysis/agents/openai.yaml +0 -4
  334. package/skills/single-work-analysis/env.example +0 -36
  335. package/skills/single-work-analysis/references/api-capability-index.md +0 -92
  336. package/skills/single-work-analysis/references/api-contracts/asr-api.md +0 -130
  337. package/skills/single-work-analysis/references/api-contracts/bilibili-app-api.md +0 -776
  338. package/skills/single-work-analysis/references/api-contracts/bilibili-web-api.md +0 -2017
  339. package/skills/single-work-analysis/references/api-contracts/demo-api.md +0 -717
  340. package/skills/single-work-analysis/references/api-contracts/douyin-app-v3-api.md +0 -3594
  341. package/skills/single-work-analysis/references/api-contracts/douyin-billboard-api.md +0 -2274
  342. package/skills/single-work-analysis/references/api-contracts/douyin-creator-api.md +0 -1575
  343. package/skills/single-work-analysis/references/api-contracts/douyin-creator-v2-api.md +0 -3254
  344. package/skills/single-work-analysis/references/api-contracts/douyin-search-api.md +0 -4118
  345. package/skills/single-work-analysis/references/api-contracts/douyin-web-api.md +0 -5544
  346. package/skills/single-work-analysis/references/api-contracts/douyin-xingtu-api.md +0 -1916
  347. package/skills/single-work-analysis/references/api-contracts/douyin-xingtu-v2-api.md +0 -1540
  348. package/skills/single-work-analysis/references/api-contracts/health-check.md +0 -69
  349. package/skills/single-work-analysis/references/api-contracts/hybrid-parsing.md +0 -78
  350. package/skills/single-work-analysis/references/api-contracts/instagram-v1-api.md +0 -2256
  351. package/skills/single-work-analysis/references/api-contracts/instagram-v2-api.md +0 -2011
  352. package/skills/single-work-analysis/references/api-contracts/instagram-v3-api.md +0 -2630
  353. package/skills/single-work-analysis/references/api-contracts/ios-shortcut.md +0 -44
  354. package/skills/single-work-analysis/references/api-contracts/kuaishou-app-api.md +0 -1518
  355. package/skills/single-work-analysis/references/api-contracts/kuaishou-web-api.md +0 -1242
  356. package/skills/single-work-analysis/references/api-contracts/lemon8-app-api.md +0 -1088
  357. package/skills/single-work-analysis/references/api-contracts/linkedin-web-api.md +0 -1949
  358. package/skills/single-work-analysis/references/api-contracts/media-ingest-api.md +0 -126
  359. package/skills/single-work-analysis/references/api-contracts/pipixia-app-api.md +0 -1142
  360. package/skills/single-work-analysis/references/api-contracts/reddit-app-api.md +0 -2025
  361. package/skills/single-work-analysis/references/api-contracts/sora2-api.md +0 -2266
  362. package/skills/single-work-analysis/references/api-contracts/temp-mail-api.md +0 -208
  363. package/skills/single-work-analysis/references/api-contracts/threads-web-api.md +0 -897
  364. package/skills/single-work-analysis/references/api-contracts/tikhub-downloader-api.md +0 -134
  365. package/skills/single-work-analysis/references/api-contracts/tikhub-user-api.md +0 -494
  366. package/skills/single-work-analysis/references/api-contracts/tiktok-ads-api.md +0 -5947
  367. package/skills/single-work-analysis/references/api-contracts/tiktok-analytics-api.md +0 -968
  368. package/skills/single-work-analysis/references/api-contracts/tiktok-app-v3-api.md +0 -5735
  369. package/skills/single-work-analysis/references/api-contracts/tiktok-creator-api.md +0 -1951
  370. package/skills/single-work-analysis/references/api-contracts/tiktok-interaction-api.md +0 -742
  371. package/skills/single-work-analysis/references/api-contracts/tiktok-shop-web-api.md +0 -1890
  372. package/skills/single-work-analysis/references/api-contracts/tiktok-web-api.md +0 -4448
  373. package/skills/single-work-analysis/references/api-contracts/toutiao-app-api.md +0 -342
  374. package/skills/single-work-analysis/references/api-contracts/toutiao-web-api.md +0 -143
  375. package/skills/single-work-analysis/references/api-contracts/twitter-web-api.md +0 -989
  376. package/skills/single-work-analysis/references/api-contracts/wechat-channels-api.md +0 -809
  377. package/skills/single-work-analysis/references/api-contracts/wechat-media-platform-web-api.md +0 -677
  378. package/skills/single-work-analysis/references/api-contracts/weibo-app-api.md +0 -1547
  379. package/skills/single-work-analysis/references/api-contracts/weibo-web-api.md +0 -798
  380. package/skills/single-work-analysis/references/api-contracts/weibo-web-v2-api.md +0 -2459
  381. package/skills/single-work-analysis/references/api-contracts/xiaohongshu-app-api.md +0 -1291
  382. package/skills/single-work-analysis/references/api-contracts/xiaohongshu-app-v2-api.md +0 -1683
  383. package/skills/single-work-analysis/references/api-contracts/xiaohongshu-web-api.md +0 -1324
  384. package/skills/single-work-analysis/references/api-contracts/xiaohongshu-web-v2-api.md +0 -1209
  385. package/skills/single-work-analysis/references/api-contracts/xigua-app-v2-api.md +0 -489
  386. package/skills/single-work-analysis/references/api-contracts/youtube-web-api.md +0 -2636
  387. package/skills/single-work-analysis/references/api-contracts/youtube-web-v2-api.md +0 -2660
  388. package/skills/single-work-analysis/references/api-contracts/zhihu-web-api.md +0 -2315
  389. package/skills/single-work-analysis/references/api-tags/asr-api.md +0 -100
  390. package/skills/single-work-analysis/references/api-tags/bilibili-app-api.md +0 -482
  391. package/skills/single-work-analysis/references/api-tags/bilibili-web-api.md +0 -1267
  392. package/skills/single-work-analysis/references/api-tags/demo-api.md +0 -365
  393. package/skills/single-work-analysis/references/api-tags/douyin-app-v3-api.md +0 -2012
  394. package/skills/single-work-analysis/references/api-tags/douyin-billboard-api.md +0 -1428
  395. package/skills/single-work-analysis/references/api-tags/douyin-creator-api.md +0 -694
  396. package/skills/single-work-analysis/references/api-tags/douyin-creator-v2-api.md +0 -694
  397. package/skills/single-work-analysis/references/api-tags/douyin-search-api.md +0 -1059
  398. package/skills/single-work-analysis/references/api-tags/douyin-web-api.md +0 -3314
  399. package/skills/single-work-analysis/references/api-tags/douyin-xingtu-api.md +0 -935
  400. package/skills/single-work-analysis/references/api-tags/douyin-xingtu-v2-api.md +0 -925
  401. package/skills/single-work-analysis/references/api-tags/health-check.md +0 -40
  402. package/skills/single-work-analysis/references/api-tags/hybrid-parsing.md +0 -57
  403. package/skills/single-work-analysis/references/api-tags/instagram-v1-api.md +0 -1224
  404. package/skills/single-work-analysis/references/api-tags/instagram-v2-api.md +0 -1147
  405. package/skills/single-work-analysis/references/api-tags/instagram-v3-api.md +0 -1123
  406. package/skills/single-work-analysis/references/api-tags/ios-shortcut.md +0 -45
  407. package/skills/single-work-analysis/references/api-tags/kuaishou-app-api.md +0 -846
  408. package/skills/single-work-analysis/references/api-tags/kuaishou-web-api.md +0 -551
  409. package/skills/single-work-analysis/references/api-tags/lemon8-app-api.md +0 -687
  410. package/skills/single-work-analysis/references/api-tags/linkedin-web-api.md +0 -1105
  411. package/skills/single-work-analysis/references/api-tags/media-ingest-api.md +0 -112
  412. package/skills/single-work-analysis/references/api-tags/pipixia-app-api.md +0 -721
  413. package/skills/single-work-analysis/references/api-tags/reddit-app-api.md +0 -1057
  414. package/skills/single-work-analysis/references/api-tags/sora2-api.md +0 -737
  415. package/skills/single-work-analysis/references/api-tags/temp-mail-api.md +0 -136
  416. package/skills/single-work-analysis/references/api-tags/threads-web-api.md +0 -472
  417. package/skills/single-work-analysis/references/api-tags/tikhub-downloader-api.md +0 -65
  418. package/skills/single-work-analysis/references/api-tags/tikhub-user-api.md +0 -253
  419. package/skills/single-work-analysis/references/api-tags/tiktok-ads-api.md +0 -1393
  420. package/skills/single-work-analysis/references/api-tags/tiktok-analytics-api.md +0 -179
  421. package/skills/single-work-analysis/references/api-tags/tiktok-app-v3-api.md +0 -3264
  422. package/skills/single-work-analysis/references/api-tags/tiktok-creator-api.md +0 -709
  423. package/skills/single-work-analysis/references/api-tags/tiktok-interaction-api.md +0 -366
  424. package/skills/single-work-analysis/references/api-tags/tiktok-shop-web-api.md +0 -663
  425. package/skills/single-work-analysis/references/api-tags/tiktok-web-api.md +0 -2516
  426. package/skills/single-work-analysis/references/api-tags/toutiao-app-api.md +0 -220
  427. package/skills/single-work-analysis/references/api-tags/toutiao-web-api.md +0 -96
  428. package/skills/single-work-analysis/references/api-tags/twitter-web-api.md +0 -562
  429. package/skills/single-work-analysis/references/api-tags/wechat-channels-api.md +0 -405
  430. package/skills/single-work-analysis/references/api-tags/wechat-media-platform-web-api.md +0 -431
  431. package/skills/single-work-analysis/references/api-tags/weibo-app-api.md +0 -851
  432. package/skills/single-work-analysis/references/api-tags/weibo-web-api.md +0 -470
  433. package/skills/single-work-analysis/references/api-tags/weibo-web-v2-api.md +0 -1405
  434. package/skills/single-work-analysis/references/api-tags/xiaohongshu-app-api.md +0 -534
  435. package/skills/single-work-analysis/references/api-tags/xiaohongshu-app-v2-api.md +0 -934
  436. package/skills/single-work-analysis/references/api-tags/xiaohongshu-web-api.md +0 -757
  437. package/skills/single-work-analysis/references/api-tags/xiaohongshu-web-v2-api.md +0 -762
  438. package/skills/single-work-analysis/references/api-tags/xigua-app-v2-api.md +0 -308
  439. package/skills/single-work-analysis/references/api-tags/youtube-web-api.md +0 -934
  440. package/skills/single-work-analysis/references/api-tags/youtube-web-v2-api.md +0 -717
  441. package/skills/single-work-analysis/references/api-tags/zhihu-web-api.md +0 -1384
  442. package/skills/single-work-analysis/references/asr-and-fallback.md +0 -20
  443. package/skills/single-work-analysis/references/config-templates/defaults.yaml +0 -58
  444. package/skills/single-work-analysis/references/contracts/work-card-fields.md +0 -41
  445. package/skills/single-work-analysis/references/platform-guides/douyin.md +0 -47
  446. package/skills/single-work-analysis/references/platform-guides/generic.md +0 -43
  447. package/skills/single-work-analysis/references/platform-guides/xiaohongshu.md +0 -54
  448. package/skills/single-work-analysis/references/prompt-contracts/asr-clean.md +0 -28
  449. package/skills/single-work-analysis/references/prompt-contracts/cta.md +0 -24
  450. package/skills/single-work-analysis/references/prompt-contracts/hook.md +0 -25
  451. package/skills/single-work-analysis/references/prompt-contracts/insight.md +0 -47
  452. package/skills/single-work-analysis/references/prompt-contracts/structure.md +0 -25
  453. package/skills/single-work-analysis/references/prompt-contracts/style.md +0 -27
  454. package/skills/single-work-analysis/references/prompt-contracts/summary.md +0 -29
  455. package/skills/single-work-analysis/references/prompt-contracts/topic.md +0 -29
  456. package/skills/single-work-analysis/references/schemas/work-card.schema.json +0 -39
  457. package/skills/single-work-analysis/references/service-guides/asr-u2-u3-fallback.md +0 -75
  458. package/skills/single-work-analysis/scripts/__init__.py +0 -0
  459. package/skills/single-work-analysis/scripts/core/__init__.py +0 -0
  460. package/skills/single-work-analysis/scripts/core/analysis_pipeline.py +0 -133
  461. package/skills/single-work-analysis/scripts/core/bootstrap_env.py +0 -35
  462. package/skills/single-work-analysis/scripts/core/extract_pipeline.py +0 -173
  463. package/skills/single-work-analysis/scripts/core/storage_router.py +0 -253
  464. package/skills/single-work-analysis/scripts/core/tikomni_common.py +0 -588
  465. package/skills/single-work-analysis/scripts/pipeline/__init__.py +0 -0
  466. package/skills/single-work-analysis/scripts/pipeline/asr/__init__.py +0 -0
  467. package/skills/single-work-analysis/scripts/pipeline/asr/asr_pipeline.py +0 -1189
  468. package/skills/single-work-analysis/scripts/pipeline/asr/poll_u2_task.py +0 -95
  469. package/skills/single-work-analysis/scripts/platform/__init__.py +0 -0
  470. package/skills/single-work-analysis/scripts/platform/douyin/__init__.py +0 -0
  471. package/skills/single-work-analysis/scripts/platform/douyin/douyin_video_type_matrix.py +0 -224
  472. package/skills/single-work-analysis/scripts/platform/douyin/select_low_quality_video_url.py +0 -200
  473. package/skills/single-work-analysis/scripts/platform/xiaohongshu/__init__.py +0 -0
  474. package/skills/single-work-analysis/scripts/writers/__init__.py +0 -0
  475. package/skills/single-work-analysis/scripts/writers/write_benchmark_card.py +0 -1402
  476. /package/skills/{creator-analysis → social-media-crawl}/scripts/core/bootstrap_env.py +0 -0
  477. /package/skills/{creator-analysis → social-media-crawl}/scripts/core/extract_pipeline.py +0 -0
  478. /package/skills/{creator-analysis/scripts/platform/douyin → social-media-crawl/scripts/pipelines}/douyin_video_type_matrix.py +0 -0
  479. /package/skills/{creator-analysis/scripts/author_home/collectors → social-media-crawl/scripts/pipelines}/homepage_collectors.py +0 -0
  480. /package/skills/{creator-analysis/scripts/platform/douyin → social-media-crawl/scripts/pipelines}/select_low_quality_video_url.py +0 -0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """Lightweight config loader for Tikomni scripts (Phase 1 skeleton)."""
2
+ """Config loader for social-media-crawl."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
@@ -11,7 +11,7 @@ from scripts.core.tikomni_common import bootstrap_runtime_env
11
11
 
12
12
  try:
13
13
  import yaml
14
- except Exception: # pragma: no cover - defensive fallback
14
+ except Exception: # pragma: no cover
15
15
  yaml = None
16
16
 
17
17
  SKILL_ROOT = Path(__file__).resolve().parents[2]
@@ -23,40 +23,35 @@ BUILTIN_DEFAULT_CONFIG: Dict[str, Any] = {
23
23
  "profile": "default",
24
24
  "runtime": {
25
25
  "base_url": "https://api.tikomni.com",
26
+ "mcp_url": "https://mcp.tikomni.com/mcp",
26
27
  "auth_env_key": "TIKOMNI_API_KEY",
27
28
  "timeout_ms": 60000,
29
+ "u2_pending_timeout_sec": 60,
28
30
  },
29
31
  "storage_routes": {
30
32
  "default": {
31
33
  "root_dir": "",
34
+ "card_root": "",
32
35
  "runs_dir": "_runs",
33
36
  "results_dir": "results",
34
37
  "errors_dir": "_errors",
35
38
  },
36
39
  "content_kind_card_type": {
37
40
  "single_video": "work",
41
+ "note": "work",
38
42
  "work": "work",
39
- "author_home": "author_sample_work",
40
- "author_sample_work": "author_sample_work",
41
- "author_analysis": "author",
43
+ "author_home": "work",
44
+ "work_collection": "work",
42
45
  },
43
46
  "card_type_routes": {
44
47
  "work": {
45
48
  "prefix": "CBV",
46
- "parts": ["内容系统", "对标研究", "作品卡"],
47
- },
48
- "author": {
49
- "prefix": "CBA",
50
- "parts": ["内容系统", "对标研究", "作者卡"],
51
- },
52
- "author_sample_work": {
53
- "prefix": "CBV",
54
- "parts": ["内容系统", "对标研究", "作者样本卡", "{platform}-{author_slug}"],
55
- },
49
+ "parts": ["内容系统", "作品库", "{platform}-{author_slug}"],
50
+ }
56
51
  },
57
52
  },
58
53
  "naming_rules": {
59
- "card_filename_pattern": "{prefix}-{author_slug}-{title_slug}{ext}",
54
+ "card_filename_pattern": "{identifier}{ext}",
60
55
  "json_filename_pattern": "{timestamp}-{platform}-{identifier}{ext}",
61
56
  },
62
57
  "asr_strategy": {
@@ -68,10 +63,7 @@ BUILTIN_DEFAULT_CONFIG: Dict[str, Any] = {
68
63
  },
69
64
  "u2_timeout_retry": {
70
65
  "enabled": True,
71
- "max_retries": 3,
72
- },
73
- "author_home": {
74
- "batch_submit_size": 50,
66
+ "max_retries": 0,
75
67
  },
76
68
  },
77
69
  }
@@ -80,54 +72,29 @@ LOCALE_ROUTE_PRESETS: Dict[str, Dict[str, Dict[str, Any]]] = {
80
72
  "zh": {
81
73
  "work": {
82
74
  "prefix": "CBV",
83
- "parts": ["内容系统", "对标研究", "作品卡"],
84
- },
85
- "author": {
86
- "prefix": "CBA",
87
- "parts": ["内容系统", "对标研究", "作者卡"],
88
- },
89
- "author_sample_work": {
90
- "prefix": "CBV",
91
- "parts": ["内容系统", "对标研究", "作者样本卡", "{platform}-{author_slug}"],
92
- },
75
+ "parts": ["内容系统", "作品库", "{platform}-{author_slug}"],
76
+ }
93
77
  },
94
78
  "en": {
95
79
  "work": {
96
80
  "prefix": "CBV",
97
- "parts": ["content-system", "benchmark-research", "work-cards"],
98
- },
99
- "author": {
100
- "prefix": "CBA",
101
- "parts": ["content-system", "benchmark-research", "author-cards"],
102
- },
103
- "author_sample_work": {
104
- "prefix": "CBV",
105
- "parts": [
106
- "content-system",
107
- "benchmark-research",
108
- "author-sample-cards",
109
- "{platform}-{author_slug}",
110
- ],
111
- },
81
+ "parts": ["content-system", "work-library", "{platform}-{author_slug}"],
82
+ }
112
83
  },
113
84
  }
114
85
 
115
- CARD_ROUTE_ENV_KEYS: Dict[str, str] = {
116
- "work": "TIKOMNI_CARD_ROUTE_WORK",
117
- "author": "TIKOMNI_CARD_ROUTE_AUTHOR",
118
- "author_sample_work": "TIKOMNI_CARD_ROUTE_AUTHOR_SAMPLE_WORK",
86
+ CARD_ROUTE_ENV_KEYS: Dict[str, List[str]] = {
87
+ "work": ["TIKOMNI_CARD_ROUTE_WORK", "TIKOMNI_CARD_ROUTE_AUTHOR_SAMPLE_WORK"],
119
88
  }
120
89
 
121
- CARD_PREFIX_ENV_KEYS: Dict[str, str] = {
122
- "work": "TIKOMNI_CARD_PREFIX_WORK",
123
- "author": "TIKOMNI_CARD_PREFIX_AUTHOR",
124
- "author_sample_work": "TIKOMNI_CARD_PREFIX_AUTHOR_SAMPLE_WORK",
90
+ CARD_PREFIX_ENV_KEYS: Dict[str, List[str]] = {
91
+ "work": ["TIKOMNI_CARD_PREFIX_WORK", "TIKOMNI_CARD_PREFIX_AUTHOR_SAMPLE_WORK"],
125
92
  }
126
93
 
127
94
 
128
95
  def _deep_clone(value: Any) -> Any:
129
96
  if isinstance(value, dict):
130
- return {k: _deep_clone(v) for k, v in value.items()}
97
+ return {key: _deep_clone(item) for key, item in value.items()}
131
98
  if isinstance(value, list):
132
99
  return [_deep_clone(item) for item in value]
133
100
  return value
@@ -143,6 +110,10 @@ def _deep_merge(defaults: Dict[str, Any], override: Dict[str, Any]) -> Dict[str,
143
110
  return merged
144
111
 
145
112
 
113
+ def _builtin_defaults() -> Dict[str, Any]:
114
+ return _deep_clone(BUILTIN_DEFAULT_CONFIG)
115
+
116
+
146
117
  def _resolve_repo_anchored_path(path_value: str) -> str:
147
118
  candidate = Path(path_value).expanduser()
148
119
  if not candidate.is_absolute():
@@ -150,15 +121,17 @@ def _resolve_repo_anchored_path(path_value: str) -> str:
150
121
  return str(candidate.resolve())
151
122
 
152
123
 
153
- def resolve_config_path(cli_config_path: Optional[str] = None, env_values: Optional[Dict[str, str]] = None) -> str:
154
- """Resolve config file path with priority:
155
- 1) --config
156
- 2) TIKOMNI_CONFIG_FILE
157
- 3) references/config-templates/defaults.yaml
124
+ def _load_yaml(path: str) -> Dict[str, Any]:
125
+ if yaml is None:
126
+ raise RuntimeError("PyYAML unavailable")
127
+ with open(path, "r", encoding="utf-8") as handle:
128
+ payload = yaml.safe_load(handle) or {}
129
+ if not isinstance(payload, dict):
130
+ raise ValueError(f"config_root_must_be_mapping:{path}")
131
+ return payload
158
132
 
159
- Relative paths are always anchored at repository root (not current CWD).
160
- """
161
133
 
134
+ def resolve_config_path(cli_config_path: Optional[str] = None, env_values: Optional[Dict[str, str]] = None) -> str:
162
135
  if cli_config_path and str(cli_config_path).strip():
163
136
  return _resolve_repo_anchored_path(str(cli_config_path).strip())
164
137
 
@@ -170,31 +143,20 @@ def resolve_config_path(cli_config_path: Optional[str] = None, env_values: Optio
170
143
 
171
144
  if raw_env_path:
172
145
  return _resolve_repo_anchored_path(raw_env_path)
173
-
174
146
  return str(DEFAULT_CONFIG_PATH)
175
147
 
176
148
 
177
- def _load_yaml(path: str) -> Dict[str, Any]:
178
- if yaml is None:
179
- raise RuntimeError("PyYAML unavailable")
180
-
181
- with open(path, "r", encoding="utf-8") as handle:
182
- payload = yaml.safe_load(handle) or {}
183
- if not isinstance(payload, dict):
184
- raise ValueError(f"config_root_must_be_mapping:{path}")
185
- return payload
186
-
187
-
188
- def _builtin_defaults() -> Dict[str, Any]:
189
- return _deep_clone(BUILTIN_DEFAULT_CONFIG)
190
-
191
-
192
149
  def _read_env(name: str, env_values: Optional[Dict[str, str]] = None) -> str:
193
150
  if isinstance(env_values, dict) and name in env_values:
194
151
  return str(env_values.get(name, "") or "").strip()
195
152
  return os.getenv(name, "").strip()
196
153
 
197
154
 
155
+ def _env_text(name: str, env_values: Optional[Dict[str, str]] = None) -> Optional[str]:
156
+ value = _read_env(name, env_values=env_values)
157
+ return value or None
158
+
159
+
198
160
  def _env_int(name: str, env_values: Optional[Dict[str, str]] = None) -> Optional[int]:
199
161
  raw = _read_env(name, env_values=env_values)
200
162
  if not raw:
@@ -203,12 +165,14 @@ def _env_int(name: str, env_values: Optional[Dict[str, str]] = None) -> Optional
203
165
  value = int(raw)
204
166
  except Exception:
205
167
  return None
206
- return value if value > 0 else None
168
+ return value
207
169
 
208
170
 
209
- def _env_text(name: str, env_values: Optional[Dict[str, str]] = None) -> Optional[str]:
210
- value = _read_env(name, env_values=env_values)
211
- return value or None
171
+ def _require_absolute_path(path_value: str, env_key: str) -> str:
172
+ candidate = Path(path_value).expanduser()
173
+ if not candidate.is_absolute():
174
+ raise ValueError(f"{env_key} must be an absolute path")
175
+ return str(candidate.resolve())
212
176
 
213
177
 
214
178
  def _require_absolute_env(name: str, env_values: Optional[Dict[str, str]] = None) -> str:
@@ -220,8 +184,8 @@ def _require_absolute_env(name: str, env_values: Optional[Dict[str, str]] = None
220
184
 
221
185
  def _route_from_env(value: str) -> Optional[List[str]]:
222
186
  parts = [item.strip() for item in value.split("|")]
223
- normalized = [item for item in parts if item]
224
- return normalized if normalized else None
187
+ cleaned = [item for item in parts if item]
188
+ return cleaned if cleaned else None
225
189
 
226
190
 
227
191
  def _normalize_path_locale(raw_value: Optional[str]) -> str:
@@ -231,44 +195,30 @@ def _normalize_path_locale(raw_value: Optional[str]) -> str:
231
195
  return "zh"
232
196
 
233
197
 
234
- def _require_absolute_path(path_value: str, env_key: str) -> str:
235
- candidate = Path(path_value).expanduser()
236
- if not candidate.is_absolute():
237
- raise ValueError(f"{env_key} must be an absolute path")
238
- return str(candidate.resolve())
239
-
240
-
241
198
  def resolve_storage_paths(config: Dict[str, Any]) -> Dict[str, str]:
242
- """Resolve storage directories from an explicit absolute root (never CWD)."""
243
-
244
199
  default_route = config_get(config, "storage_routes.default", {})
245
200
  default_route = default_route if isinstance(default_route, dict) else {}
246
201
 
247
- root_dir = Path(
248
- _require_absolute_path(str(default_route.get("root_dir") or ""), "TIKOMNI_OUTPUT_ROOT")
249
- )
202
+ root_dir = Path(_require_absolute_path(str(default_route.get("root_dir") or ""), "TIKOMNI_OUTPUT_ROOT"))
203
+ card_root = Path(_require_absolute_path(str(default_route.get("card_root") or ""), "TIKOMNI_CARD_ROOT"))
250
204
 
251
205
  resolved: Dict[str, str] = {
252
206
  "root_dir": str(root_dir),
207
+ "card_root": str(card_root),
253
208
  }
254
- for key in ("runs_dir", "results_dir", "errors_dir"):
255
- raw_value = str(default_route.get(key) or "").strip()
256
- if not raw_value:
257
- raw_value = {
258
- "runs_dir": "_runs",
259
- "results_dir": "results",
260
- "errors_dir": "_errors",
261
- }[key]
262
209
 
210
+ for key in ("runs_dir", "results_dir", "errors_dir"):
211
+ raw_value = str(default_route.get(key) or "").strip() or {
212
+ "runs_dir": "_runs",
213
+ "results_dir": "results",
214
+ "errors_dir": "_errors",
215
+ }[key]
263
216
  part = Path(raw_value).expanduser()
264
- if part.is_absolute():
265
- resolved[key] = str(part.resolve())
266
- else:
267
- resolved[key] = str((root_dir / part).resolve())
217
+ resolved[key] = str(part.resolve()) if part.is_absolute() else str((root_dir / part).resolve())
268
218
 
269
- resolved["runs_root"] = resolved.get("runs_dir", str((root_dir / "_runs").resolve()))
270
- resolved["results_root"] = resolved.get("results_dir", str((root_dir / "results").resolve()))
271
- resolved["errors_root"] = resolved.get("errors_dir", str((root_dir / "_errors").resolve()))
219
+ resolved["runs_root"] = resolved["runs_dir"]
220
+ resolved["results_root"] = resolved["results_dir"]
221
+ resolved["errors_root"] = resolved["errors_dir"]
272
222
  return resolved
273
223
 
274
224
 
@@ -278,10 +228,8 @@ def apply_env_overrides(config: Dict[str, Any], env_values: Optional[Dict[str, s
278
228
 
279
229
  storage_routes = config.setdefault("storage_routes", {}) if isinstance(config.get("storage_routes"), dict) else {}
280
230
  config["storage_routes"] = storage_routes
281
-
282
231
  default_route = storage_routes.setdefault("default", {}) if isinstance(storage_routes.get("default"), dict) else {}
283
232
  storage_routes["default"] = default_route
284
-
285
233
  card_type_routes = (
286
234
  storage_routes.setdefault("card_type_routes", {}) if isinstance(storage_routes.get("card_type_routes"), dict) else {}
287
235
  )
@@ -289,12 +237,31 @@ def apply_env_overrides(config: Dict[str, Any], env_values: Optional[Dict[str, s
289
237
 
290
238
  naming_rules = config.setdefault("naming_rules", {}) if isinstance(config.get("naming_rules"), dict) else {}
291
239
  config["naming_rules"] = naming_rules
240
+ asr_strategy = config.setdefault("asr_strategy", {}) if isinstance(config.get("asr_strategy"), dict) else {}
241
+ config["asr_strategy"] = asr_strategy
242
+
243
+ auth_env_key = _env_text("TIKOMNI_AUTH_ENV_KEY", env_values=env_values)
244
+ if auth_env_key is not None:
245
+ runtime["auth_env_key"] = auth_env_key
246
+
247
+ for env_key, config_key in {
248
+ "TIKOMNI_BASE_URL": "base_url",
249
+ "TIKOMNI_MCP_URL": "mcp_url",
250
+ }.items():
251
+ value = _env_text(env_key, env_values=env_values)
252
+ if value is not None:
253
+ runtime[config_key] = value.rstrip("/")
292
254
 
293
255
  timeout_ms = _env_int("TIKOMNI_TIMEOUT_MS", env_values=env_values)
294
256
  if timeout_ms is not None:
295
257
  runtime["timeout_ms"] = timeout_ms
296
258
 
259
+ pending_timeout_sec = _env_int("TIKOMNI_U2_PENDING_TIMEOUT_SEC", env_values=env_values)
260
+ if pending_timeout_sec is not None and pending_timeout_sec > 0:
261
+ runtime["u2_pending_timeout_sec"] = pending_timeout_sec
262
+
297
263
  default_route["root_dir"] = _require_absolute_env("TIKOMNI_OUTPUT_ROOT", env_values=env_values)
264
+ default_route["card_root"] = _require_absolute_env("TIKOMNI_CARD_ROOT", env_values=env_values)
298
265
 
299
266
  for env_key, config_key in {
300
267
  "TIKOMNI_OUTPUT_RUNS_DIR": "runs_dir",
@@ -307,72 +274,49 @@ def apply_env_overrides(config: Dict[str, Any], env_values: Optional[Dict[str, s
307
274
 
308
275
  card_filename_pattern = _env_text("TIKOMNI_FILENAME_PATTERN_CARD", env_values=env_values)
309
276
  json_filename_pattern = _env_text("TIKOMNI_FILENAME_PATTERN_JSON", env_values=env_values)
310
- legacy_filename_pattern = _env_text("TIKOMNI_FILENAME_PATTERN", env_values=env_values)
311
277
  if card_filename_pattern is not None:
312
278
  naming_rules["card_filename_pattern"] = card_filename_pattern
313
- elif legacy_filename_pattern is not None:
314
- naming_rules["card_filename_pattern"] = legacy_filename_pattern
315
279
  if json_filename_pattern is not None:
316
280
  naming_rules["json_filename_pattern"] = json_filename_pattern
317
281
 
282
+ poll_interval_sec = _env_int("TIKOMNI_POLL_INTERVAL_SEC", env_values=env_values)
283
+ if poll_interval_sec is not None and poll_interval_sec > 0:
284
+ asr_strategy["poll_interval_sec"] = float(poll_interval_sec)
285
+
318
286
  path_locale = _normalize_path_locale(_read_env("TIKOMNI_PATH_LOCALE", env_values=env_values) or "zh")
319
287
  locale_routes = LOCALE_ROUTE_PRESETS.get(path_locale, LOCALE_ROUTE_PRESETS["zh"])
320
-
321
288
  for route_key, route_value in locale_routes.items():
322
- existing = card_type_routes.get(route_key)
323
- existing_prefix = ""
324
- existing_parts: List[str] = []
325
- if isinstance(existing, dict):
326
- if isinstance(existing.get("prefix"), str):
327
- existing_prefix = existing.get("prefix", "").strip()
328
- if isinstance(existing.get("parts"), list) and existing.get("parts"):
329
- existing_parts = [str(item) for item in existing.get("parts", []) if str(item).strip()]
330
-
331
289
  card_type_routes[route_key] = {
332
- "prefix": existing_prefix or str(route_value.get("prefix") or ""),
333
- "parts": existing_parts or _deep_clone(route_value.get("parts", [])),
290
+ "prefix": str(route_value.get("prefix") or "CBV"),
291
+ "parts": list(route_value.get("parts") or []),
334
292
  }
335
293
 
336
- for route_key, env_name in CARD_ROUTE_ENV_KEYS.items():
337
- raw_value = _env_text(env_name, env_values=env_values)
338
- if raw_value is None:
339
- continue
340
-
341
- env_parts = _route_from_env(raw_value)
342
- if not env_parts:
343
- continue
344
-
345
- current = card_type_routes.get(route_key)
346
- prefix = ""
347
- if isinstance(current, dict) and isinstance(current.get("prefix"), str):
348
- prefix = current.get("prefix") or ""
349
- if not prefix:
350
- prefix = LOCALE_ROUTE_PRESETS["zh"].get(route_key, {}).get("prefix", "")
351
-
352
- card_type_routes[route_key] = {
353
- "prefix": prefix,
354
- "parts": env_parts,
355
- }
356
-
357
- for route_key, env_name in CARD_PREFIX_ENV_KEYS.items():
358
- prefix_value = _env_text(env_name, env_values=env_values)
359
- if prefix_value is None:
360
- continue
361
- current = card_type_routes.get(route_key)
362
- current_parts: List[str] = []
363
- if isinstance(current, dict) and isinstance(current.get("parts"), list):
364
- current_parts = [str(item) for item in current.get("parts", []) if str(item).strip()]
365
- if not current_parts:
366
- current_parts = list(LOCALE_ROUTE_PRESETS["zh"].get(route_key, {}).get("parts", []))
367
- card_type_routes[route_key] = {
368
- "prefix": prefix_value,
369
- "parts": current_parts,
370
- }
294
+ for route_key, env_names in CARD_ROUTE_ENV_KEYS.items():
295
+ for env_name in env_names:
296
+ raw_value = _env_text(env_name, env_values=env_values)
297
+ if raw_value is None:
298
+ continue
299
+ env_parts = _route_from_env(raw_value)
300
+ if not env_parts:
301
+ continue
302
+ current = card_type_routes.get(route_key) if isinstance(card_type_routes.get(route_key), dict) else {}
303
+ prefix = str(current.get("prefix") or LOCALE_ROUTE_PRESETS["zh"][route_key]["prefix"])
304
+ card_type_routes[route_key] = {"prefix": prefix, "parts": env_parts}
305
+ break
306
+
307
+ for route_key, env_names in CARD_PREFIX_ENV_KEYS.items():
308
+ for env_name in env_names:
309
+ prefix_value = _env_text(env_name, env_values=env_values)
310
+ if prefix_value is None:
311
+ continue
312
+ current = card_type_routes.get(route_key) if isinstance(card_type_routes.get(route_key), dict) else {}
313
+ parts = current.get("parts") if isinstance(current.get("parts"), list) else list(LOCALE_ROUTE_PRESETS["zh"][route_key]["parts"])
314
+ card_type_routes[route_key] = {"prefix": prefix_value, "parts": parts}
315
+ break
371
316
 
372
317
  resolved_storage = resolve_storage_paths(config)
373
318
  for key, value in resolved_storage.items():
374
319
  default_route[key] = value
375
-
376
320
  return config
377
321
 
378
322
 
@@ -381,10 +325,7 @@ def load_tikomni_config(
381
325
  env_file: Optional[str] = None,
382
326
  allow_process_env: bool = False,
383
327
  ) -> Tuple[Dict[str, Any], str]:
384
- bootstrap = bootstrap_runtime_env(
385
- primary_env_file=env_file,
386
- allow_process_env=allow_process_env,
387
- )
328
+ bootstrap = bootstrap_runtime_env(primary_env_file=env_file, allow_process_env=allow_process_env)
388
329
  env_values = bootstrap.get("effective_env", {}) if isinstance(bootstrap, dict) else {}
389
330
 
390
331
  explicit_config_requested = bool(
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python3
2
+ """Minimal MCP HTTP client for social-media-crawl."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import urllib.request
8
+ from dataclasses import dataclass
9
+ from typing import Any, Dict, Optional
10
+
11
+
12
+ def _parse_response_body(body: bytes) -> Any:
13
+ text = body.decode("utf-8", errors="replace").strip()
14
+ if not text:
15
+ return {}
16
+ if text.startswith("data:"):
17
+ payloads = []
18
+ for line in text.splitlines():
19
+ if not line.startswith("data:"):
20
+ continue
21
+ payload = line.split("data:", 1)[1].strip()
22
+ if payload:
23
+ payloads.append(payload)
24
+ if payloads:
25
+ return json.loads(payloads[-1])
26
+ return json.loads(text)
27
+
28
+
29
+ @dataclass
30
+ class McpResponse:
31
+ ok: bool
32
+ status_code: int
33
+ data: Any
34
+ session_id: Optional[str]
35
+ error_reason: Optional[str] = None
36
+
37
+
38
+ class McpHttpClient:
39
+ def __init__(self, *, url: str, api_key: str, timeout_ms: int = 60000) -> None:
40
+ self.url = url.rstrip("/")
41
+ self.api_key = api_key
42
+ self.timeout_ms = timeout_ms
43
+ self.session_id: Optional[str] = None
44
+ self._next_id = 1
45
+
46
+ def _headers(self) -> Dict[str, str]:
47
+ headers = {
48
+ "Authorization": f"Bearer {self.api_key}",
49
+ "Content-Type": "application/json",
50
+ "Accept": "application/json, text/event-stream",
51
+ }
52
+ if self.session_id:
53
+ headers["mcp-session-id"] = self.session_id
54
+ return headers
55
+
56
+ def _request(self, payload: Dict[str, Any]) -> McpResponse:
57
+ req = urllib.request.Request(
58
+ self.url,
59
+ data=json.dumps(payload).encode("utf-8"),
60
+ headers=self._headers(),
61
+ method="POST",
62
+ )
63
+ try:
64
+ with urllib.request.urlopen(req, timeout=max(self.timeout_ms / 1000.0, 1.0)) as response:
65
+ body = response.read()
66
+ data = _parse_response_body(body)
67
+ session_id = response.headers.get("mcp-session-id") or response.headers.get("Mcp-Session-Id")
68
+ if session_id:
69
+ self.session_id = session_id
70
+ return McpResponse(ok=True, status_code=response.getcode(), data=data, session_id=self.session_id)
71
+ except urllib.error.HTTPError as error:
72
+ body = error.read()
73
+ try:
74
+ data = _parse_response_body(body)
75
+ except Exception:
76
+ data = {"raw": body.decode("utf-8", errors="replace")}
77
+ return McpResponse(
78
+ ok=False,
79
+ status_code=error.code,
80
+ data=data,
81
+ session_id=self.session_id,
82
+ error_reason=f"http_error:{error.code}",
83
+ )
84
+ except Exception as error:
85
+ return McpResponse(
86
+ ok=False,
87
+ status_code=0,
88
+ data={},
89
+ session_id=self.session_id,
90
+ error_reason=f"request_failed:{type(error).__name__}:{error}",
91
+ )
92
+
93
+ def _rpc(self, method: str, params: Optional[Dict[str, Any]] = None, notification: bool = False) -> McpResponse:
94
+ payload: Dict[str, Any] = {"jsonrpc": "2.0", "method": method}
95
+ if not notification:
96
+ payload["id"] = self._next_id
97
+ self._next_id += 1
98
+ if params is not None:
99
+ payload["params"] = params
100
+ return self._request(payload)
101
+
102
+ def initialize(self) -> McpResponse:
103
+ response = self._rpc(
104
+ "initialize",
105
+ {
106
+ "protocolVersion": "2025-03-26",
107
+ "capabilities": {},
108
+ "clientInfo": {"name": "social-media-crawl", "version": "0.1.0"},
109
+ },
110
+ )
111
+ if response.ok:
112
+ self._rpc("notifications/initialized", notification=True)
113
+ return response
114
+
115
+ def tools_list(self) -> McpResponse:
116
+ if not self.session_id:
117
+ init = self.initialize()
118
+ if not init.ok:
119
+ return init
120
+ return self._rpc("tools/list")
121
+
122
+ def tool_call(self, name: str, arguments: Optional[Dict[str, Any]] = None) -> McpResponse:
123
+ if not self.session_id:
124
+ init = self.initialize()
125
+ if not init.ok:
126
+ return init
127
+ return self._rpc("tools/call", {"name": name, "arguments": arguments or {}})
128
+
129
+ def catalog_search(self, query: str) -> McpResponse:
130
+ return self.tool_call("catalog.search", {"query": query})
131
+
132
+ def endpoint_describe(self, endpoint: str) -> McpResponse:
133
+ return self.tool_call("endpoint.describe", {"endpoint": endpoint})
134
+
135
+ def api_call(self, endpoint: str, params: Optional[Dict[str, Any]] = None, body: Optional[Dict[str, Any]] = None, method: str = "GET") -> McpResponse:
136
+ return self.tool_call(
137
+ "api.call",
138
+ {"endpoint": endpoint, "params": params or {}, "body": body or {}, "method": method},
139
+ )
140
+
141
+ def u2_submit(self, file_url: str) -> McpResponse:
142
+ return self.tool_call("u2.submit", {"file_url": file_url})
143
+
144
+ def u2_query(self, task_id: str) -> McpResponse:
145
+ return self.tool_call("u2.query", {"task_id": task_id})
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """Platform and object detection helpers."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import urllib.request
7
+ from dataclasses import dataclass, asdict
8
+ from typing import Dict
9
+ from urllib.parse import urlparse
10
+
11
+
12
+ @dataclass
13
+ class DetectionResult:
14
+ input_value: str
15
+ resolved_url: str
16
+ platform: str
17
+ object_type: str
18
+
19
+ def to_dict(self) -> Dict[str, str]:
20
+ return asdict(self)
21
+
22
+
23
+ def resolve_final_url(input_value: str, timeout_ms: int = 10000) -> str:
24
+ candidate = str(input_value or "").strip()
25
+ if not candidate.startswith(("http://", "https://")):
26
+ return candidate
27
+ try:
28
+ request = urllib.request.Request(candidate, method="GET")
29
+ with urllib.request.urlopen(request, timeout=max(timeout_ms / 1000.0, 1.0)) as response:
30
+ return response.geturl() or candidate
31
+ except Exception:
32
+ return candidate
33
+
34
+
35
+ def detect_target(input_value: str, timeout_ms: int = 10000) -> DetectionResult:
36
+ raw = str(input_value or "").strip()
37
+ resolved = resolve_final_url(raw, timeout_ms=timeout_ms)
38
+ candidate = resolved or raw
39
+ lower = candidate.lower()
40
+ host = urlparse(lower).netloc
41
+
42
+ platform = "unknown"
43
+ object_type = "unknown"
44
+
45
+ if any(token in host for token in ["douyin.com", "iesdouyin.com"]):
46
+ platform = "douyin"
47
+ if "/video/" in lower:
48
+ object_type = "work"
49
+ elif "/user/" in lower or "sec_uid=" in lower or "sec_user_id=" in lower:
50
+ object_type = "creator"
51
+ elif any(token in host for token in ["xiaohongshu.com", "xhslink.com"]):
52
+ platform = "xiaohongshu"
53
+ if any(token in lower for token in ["/discovery/item/", "/explore/"]):
54
+ object_type = "work"
55
+ elif any(token in lower for token in ["/user/profile/", "/user/", "/profile/"]):
56
+ object_type = "creator"
57
+
58
+ return DetectionResult(
59
+ input_value=raw,
60
+ resolved_url=resolved or raw,
61
+ platform=platform,
62
+ object_type=object_type,
63
+ )