@tikomni/skills 1.0.5 → 1.0.6
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tikomni/skills",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "TikOmni skill installer CLI for structured social media crawling in Codex, Claude Code, and OpenClaw",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/mark-ly-wang/TikOmni-Skills#readme",
|
|
@@ -424,7 +424,6 @@ def _u1_fetch_one_video(
|
|
|
424
424
|
fallback_reason="" if app_response.get("ok") else (
|
|
425
425
|
"primary_timeout_retry_exhausted" if app_response.get("timeout_retry_exhausted") else "primary_non_timeout_failure"
|
|
426
426
|
),
|
|
427
|
-
extra={"response": app_response},
|
|
428
427
|
)
|
|
429
428
|
)
|
|
430
429
|
if app_response.get("ok"):
|
|
@@ -458,7 +457,6 @@ def _u1_fetch_one_video(
|
|
|
458
457
|
fallback_reason="" if web_response.get("ok") else (
|
|
459
458
|
"fallback_timeout_retry_exhausted" if web_response.get("timeout_retry_exhausted") else "fallback_non_timeout_failure"
|
|
460
459
|
),
|
|
461
|
-
extra={"response": web_response},
|
|
462
460
|
)
|
|
463
461
|
)
|
|
464
462
|
web_response["_attempts"] = attempts
|
|
@@ -891,23 +889,24 @@ def run_douyin_single_video(
|
|
|
891
889
|
all_routes_failed=not bool(one_video_response.get("ok")),
|
|
892
890
|
)
|
|
893
891
|
for index, attempt in enumerate(attempts, start=1):
|
|
894
|
-
|
|
892
|
+
if not isinstance(attempt, dict):
|
|
893
|
+
continue
|
|
894
|
+
response = attempt.get("response") if isinstance(attempt.get("response"), dict) else attempt
|
|
895
895
|
endpoint = attempt.get("endpoint") if isinstance(attempt, dict) else None
|
|
896
896
|
label = attempt.get("route_label") if isinstance(attempt, dict) else None
|
|
897
|
-
if
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
{
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
)
|
|
897
|
+
if attempt.get("skipped"):
|
|
898
|
+
trace.append(
|
|
899
|
+
{
|
|
900
|
+
"step": f"u1_fetch_one_video_attempt_{index}",
|
|
901
|
+
"route_label": label,
|
|
902
|
+
"endpoint": endpoint,
|
|
903
|
+
"accept_reason": attempt.get("accept_reason"),
|
|
904
|
+
"fallback_reason": attempt.get("fallback_reason"),
|
|
905
|
+
"param_readiness": attempt.get("param_readiness"),
|
|
906
|
+
"param_reason": attempt.get("param_reason"),
|
|
907
|
+
"skipped": True,
|
|
908
|
+
}
|
|
909
|
+
)
|
|
911
910
|
continue
|
|
912
911
|
_emit_http_progress(progress, stage="single_video.fetch", response=response, route_label=str(label or "route"))
|
|
913
912
|
step = "u1_fetch_one_video_effective" if index == len(attempts) else f"u1_fetch_one_video_attempt_{index}"
|
|
@@ -1125,7 +1125,6 @@ def _fetch_note_info(
|
|
|
1125
1125
|
extra={
|
|
1126
1126
|
"method": str(route["method"]).upper(),
|
|
1127
1127
|
"field_completeness": response.get("_field_completeness"),
|
|
1128
|
-
"response": response,
|
|
1129
1128
|
},
|
|
1130
1129
|
)
|
|
1131
1130
|
)
|
|
@@ -1843,23 +1842,24 @@ def run_xiaohongshu_extract(
|
|
|
1843
1842
|
all_routes_failed=not bool(note_response.get("ok")),
|
|
1844
1843
|
)
|
|
1845
1844
|
for index, attempt in enumerate(attempts, start=1):
|
|
1846
|
-
|
|
1845
|
+
if not isinstance(attempt, dict):
|
|
1846
|
+
continue
|
|
1847
|
+
response = attempt.get("response") if isinstance(attempt.get("response"), dict) else attempt
|
|
1847
1848
|
endpoint = attempt.get("endpoint") if isinstance(attempt, dict) else None
|
|
1848
1849
|
label = attempt.get("route_label") if isinstance(attempt, dict) else None
|
|
1849
|
-
if
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
{
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
)
|
|
1850
|
+
if attempt.get("skipped"):
|
|
1851
|
+
trace.append(
|
|
1852
|
+
{
|
|
1853
|
+
"step": f"u1_get_note_info_attempt_{index}",
|
|
1854
|
+
"route_label": label,
|
|
1855
|
+
"endpoint": endpoint,
|
|
1856
|
+
"accept_reason": attempt.get("accept_reason"),
|
|
1857
|
+
"fallback_reason": attempt.get("fallback_reason"),
|
|
1858
|
+
"param_readiness": attempt.get("param_readiness"),
|
|
1859
|
+
"param_reason": attempt.get("param_reason"),
|
|
1860
|
+
"skipped": True,
|
|
1861
|
+
}
|
|
1862
|
+
)
|
|
1863
1863
|
continue
|
|
1864
1864
|
step = "u1_get_note_info_effective" if index == len(attempts) else f"u1_get_note_info_attempt_{index}"
|
|
1865
1865
|
trace.append(
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import os
|
|
6
7
|
import sys
|
|
7
8
|
import unittest
|
|
@@ -14,10 +15,59 @@ if str(SKILL_ROOT) not in sys.path:
|
|
|
14
15
|
|
|
15
16
|
from scripts.core.asr_pipeline import run_u2_asr_batch_with_timeout_retry
|
|
16
17
|
from scripts.pipelines import homepage_collectors
|
|
18
|
+
from scripts.pipelines import run_douyin_single_work
|
|
17
19
|
from scripts.pipelines import run_xiaohongshu_single_work
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class FixedPipelineFallbackTest(unittest.TestCase):
|
|
23
|
+
def test_douyin_single_fetch_attempt_trace_is_json_serializable(self) -> None:
|
|
24
|
+
def fake_call_json_api(**_: object) -> dict:
|
|
25
|
+
return {
|
|
26
|
+
"ok": True,
|
|
27
|
+
"status_code": 200,
|
|
28
|
+
"request_id": "req-dy-single",
|
|
29
|
+
"error_reason": None,
|
|
30
|
+
"data": {"aweme_detail": {"aweme_id": "123"}},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
with patch.object(run_douyin_single_work, "call_json_api", side_effect=fake_call_json_api):
|
|
34
|
+
response = run_douyin_single_work._u1_fetch_one_video(
|
|
35
|
+
base_url="https://api.tikomni.com",
|
|
36
|
+
token="test-token",
|
|
37
|
+
share_url="https://v.douyin.com/test-single/",
|
|
38
|
+
app_timeout_ms=1000,
|
|
39
|
+
web_timeout_ms=1000,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
json.dumps(response, ensure_ascii=False)
|
|
43
|
+
self.assertNotIn("response", response["_attempts"][0])
|
|
44
|
+
|
|
45
|
+
def test_xhs_single_fetch_attempt_trace_is_json_serializable(self) -> None:
|
|
46
|
+
def fake_call_json_api(**_: object) -> dict:
|
|
47
|
+
return {
|
|
48
|
+
"ok": True,
|
|
49
|
+
"status_code": 200,
|
|
50
|
+
"request_id": "req-xhs-single",
|
|
51
|
+
"error_reason": None,
|
|
52
|
+
"data": {
|
|
53
|
+
"title": "test title",
|
|
54
|
+
"desc": "test content",
|
|
55
|
+
"video": {"master_url": "https://example.com/video.mp4"},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
with patch.object(run_xiaohongshu_single_work, "call_json_api", side_effect=fake_call_json_api):
|
|
60
|
+
response = run_xiaohongshu_single_work._fetch_note_info(
|
|
61
|
+
base_url="https://api.tikomni.com",
|
|
62
|
+
token="test-token",
|
|
63
|
+
timeout_ms=1000,
|
|
64
|
+
source_input={"share_text": "https://xhslink.com/test-single", "note_id": "note123"},
|
|
65
|
+
progress=None,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
json.dumps(response, ensure_ascii=False)
|
|
69
|
+
self.assertNotIn("response", response["_attempts"][0])
|
|
70
|
+
|
|
21
71
|
def test_xhs_single_route_plan_respects_version_priority_and_cookie_gate(self) -> None:
|
|
22
72
|
source_input = {
|
|
23
73
|
"share_text": (
|