redfox-python-sdk 0.2.2__py3-none-any.whl → 0.3.0__py3-none-any.whl
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.
- redfox/client.py +158 -3
- redfox/endpoints/ai_search.py +73 -1
- redfox/endpoints/autohome.py +77 -0
- redfox/endpoints/bilibili.py +35 -0
- redfox/endpoints/dongchedi.py +74 -0
- redfox/endpoints/douyin.py +207 -0
- redfox/endpoints/hotspot.py +81 -0
- redfox/endpoints/instagram.py +83 -0
- redfox/endpoints/kuaishou.py +126 -0
- redfox/endpoints/tiktok.py +55 -0
- redfox/endpoints/tools.py +157 -0
- redfox/endpoints/toutiao.py +48 -0
- redfox/endpoints/twitter.py +84 -0
- redfox/endpoints/wechat.py +178 -0
- redfox/endpoints/wechat_channels.py +123 -0
- redfox/endpoints/xiaohongshu.py +195 -6
- redfox/endpoints/yiche.py +83 -0
- redfox/endpoints/youtube.py +101 -0
- redfox_python_sdk-0.3.0.dist-info/METADATA +672 -0
- redfox_python_sdk-0.3.0.dist-info/RECORD +28 -0
- {redfox_python_sdk-0.2.2.dist-info → redfox_python_sdk-0.3.0.dist-info}/WHEEL +1 -1
- redfox_python_sdk-0.2.2.dist-info/METADATA +0 -371
- redfox_python_sdk-0.2.2.dist-info/RECORD +0 -18
- {redfox_python_sdk-0.2.2.dist-info → redfox_python_sdk-0.3.0.dist-info}/top_level.txt +0 -0
redfox/client.py
CHANGED
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
import time
|
|
5
5
|
import random
|
|
6
6
|
import logging
|
|
7
|
-
from typing import Optional, Dict, Any
|
|
7
|
+
from typing import Optional, Dict, Any, Union, IO, Tuple
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
10
|
|
|
@@ -17,10 +17,20 @@ from .endpoints.wechat import WechatAPI
|
|
|
17
17
|
from .endpoints.bilibili import BilibiliAPI
|
|
18
18
|
from .endpoints.toutiao import ToutiaoAPI
|
|
19
19
|
from .endpoints.tiktok import TikTokAPI
|
|
20
|
+
from .endpoints.kuaishou import KuaishouAPI
|
|
21
|
+
from .endpoints.wechat_channels import WechatChannelsAPI
|
|
22
|
+
from .endpoints.youtube import YouTubeAPI
|
|
23
|
+
from .endpoints.twitter import TwitterAPI
|
|
24
|
+
from .endpoints.instagram import InstagramAPI
|
|
25
|
+
from .endpoints.dongchedi import DongchediAPI
|
|
26
|
+
from .endpoints.yiche import YicheAPI
|
|
27
|
+
from .endpoints.autohome import AutohomeAPI
|
|
28
|
+
from .endpoints.hotspot import HotspotAPI
|
|
20
29
|
from .endpoints.gpt_image import GPTImageAPI
|
|
21
30
|
from .endpoints.doubao_image import DoubaoImageAPI
|
|
22
31
|
from .endpoints.doubao_video import DoubaoVideoAPI
|
|
23
32
|
from .endpoints.ai_search import AISearchAPI
|
|
33
|
+
from .endpoints.tools import ToolsAPI
|
|
24
34
|
|
|
25
35
|
logger = logging.getLogger("redfox")
|
|
26
36
|
|
|
@@ -104,6 +114,27 @@ class _RequestMixin:
|
|
|
104
114
|
return RedFoxAPIError("网络连接失败,请检查网络")
|
|
105
115
|
return RedFoxAPIError(f"请求异常: {str(exc)}")
|
|
106
116
|
|
|
117
|
+
@staticmethod
|
|
118
|
+
def _read_file(file, field_name: str = "file") -> Tuple[str, bytes]:
|
|
119
|
+
"""读取上传文件内容,返回 (文件名, 字节内容)
|
|
120
|
+
|
|
121
|
+
支持:文件路径、(filename, bytes) 元组、文件对象、bytes
|
|
122
|
+
"""
|
|
123
|
+
if isinstance(file, tuple):
|
|
124
|
+
return file[0], file[1]
|
|
125
|
+
if isinstance(file, (str, os.PathLike)):
|
|
126
|
+
path = os.fspath(file)
|
|
127
|
+
with open(path, "rb") as f:
|
|
128
|
+
return os.path.basename(path), f.read()
|
|
129
|
+
if isinstance(file, bytes):
|
|
130
|
+
return "upload.bin", file
|
|
131
|
+
if hasattr(file, "read"):
|
|
132
|
+
content = file.read()
|
|
133
|
+
name = getattr(file, "name", None)
|
|
134
|
+
name = os.path.basename(name) if name else "upload.bin"
|
|
135
|
+
return name, content
|
|
136
|
+
raise TypeError(f"不支持的文件类型: {type(file)}")
|
|
137
|
+
|
|
107
138
|
|
|
108
139
|
class RedFoxClient(_RequestMixin):
|
|
109
140
|
"""
|
|
@@ -168,7 +199,6 @@ class RedFoxClient(_RequestMixin):
|
|
|
168
199
|
self._client = httpx.Client(
|
|
169
200
|
timeout=httpx.Timeout(timeout),
|
|
170
201
|
headers={
|
|
171
|
-
"Content-Type": "application/json",
|
|
172
202
|
"REDFOX_API_KEY": self.api_key,
|
|
173
203
|
},
|
|
174
204
|
)
|
|
@@ -180,10 +210,20 @@ class RedFoxClient(_RequestMixin):
|
|
|
180
210
|
self.bilibili = BilibiliAPI(self)
|
|
181
211
|
self.toutiao = ToutiaoAPI(self)
|
|
182
212
|
self.tiktok = TikTokAPI(self)
|
|
213
|
+
self.kuaishou = KuaishouAPI(self)
|
|
214
|
+
self.wechat_channels = WechatChannelsAPI(self)
|
|
215
|
+
self.youtube = YouTubeAPI(self)
|
|
216
|
+
self.twitter = TwitterAPI(self)
|
|
217
|
+
self.instagram = InstagramAPI(self)
|
|
218
|
+
self.dongchedi = DongchediAPI(self)
|
|
219
|
+
self.yiche = YicheAPI(self)
|
|
220
|
+
self.autohome = AutohomeAPI(self)
|
|
221
|
+
self.hotspot = HotspotAPI(self)
|
|
183
222
|
self.gpt_image = GPTImageAPI(self)
|
|
184
223
|
self.doubao_image = DoubaoImageAPI(self)
|
|
185
224
|
self.doubao_video = DoubaoVideoAPI(self)
|
|
186
225
|
self.ai_search = AISearchAPI(self)
|
|
226
|
+
self.tools = ToolsAPI(self)
|
|
187
227
|
|
|
188
228
|
def request(
|
|
189
229
|
self,
|
|
@@ -253,6 +293,59 @@ class RedFoxClient(_RequestMixin):
|
|
|
253
293
|
"""发送 GET 请求"""
|
|
254
294
|
return self.request("GET", path, params=params)
|
|
255
295
|
|
|
296
|
+
def upload(
|
|
297
|
+
self,
|
|
298
|
+
path: str,
|
|
299
|
+
file,
|
|
300
|
+
data: Optional[Dict[str, Any]] = None,
|
|
301
|
+
field_name: str = "file",
|
|
302
|
+
) -> dict:
|
|
303
|
+
"""
|
|
304
|
+
上传文件(multipart/form-data,含自动重试)
|
|
305
|
+
|
|
306
|
+
:param path: API 路径
|
|
307
|
+
:param file: 文件,支持文件路径 / (filename, bytes) 元组 / 文件对象 / bytes
|
|
308
|
+
:param data: 附加表单字段
|
|
309
|
+
:param field_name: 文件表单字段名,默认 "file"
|
|
310
|
+
:return: API 响应 data 字段内容
|
|
311
|
+
"""
|
|
312
|
+
url = f"{self.base_url}{path}"
|
|
313
|
+
filename, content = self._read_file(file, field_name)
|
|
314
|
+
if data:
|
|
315
|
+
data = {k: v for k, v in data.items() if v is not None}
|
|
316
|
+
last_exception = None
|
|
317
|
+
|
|
318
|
+
for attempt in range(self.max_retries + 1):
|
|
319
|
+
try:
|
|
320
|
+
response = self._client.post(
|
|
321
|
+
url,
|
|
322
|
+
files={field_name: (filename, content)},
|
|
323
|
+
data=data,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
if response.status_code in RETRYABLE_STATUSES and attempt < self.max_retries:
|
|
327
|
+
delay = _compute_delay(attempt, self.backoff_factor)
|
|
328
|
+
logger.debug(
|
|
329
|
+
"上传收到 %d,第 %d/%d 次重试,等待 %.1fs",
|
|
330
|
+
response.status_code, attempt + 1, self.max_retries, delay,
|
|
331
|
+
)
|
|
332
|
+
time.sleep(delay)
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
return self._handle_response(response)
|
|
336
|
+
|
|
337
|
+
except RETRYABLE_EXCEPTIONS as exc:
|
|
338
|
+
last_exception = exc
|
|
339
|
+
if attempt < self.max_retries:
|
|
340
|
+
time.sleep(_compute_delay(attempt, self.backoff_factor))
|
|
341
|
+
else:
|
|
342
|
+
raise self._map_exception(exc)
|
|
343
|
+
|
|
344
|
+
except (RedFoxAPIError, RedFoxAuthError, RedFoxRateLimitError):
|
|
345
|
+
raise
|
|
346
|
+
|
|
347
|
+
raise self._map_exception(last_exception) if last_exception else RedFoxAPIError("上传失败")
|
|
348
|
+
|
|
256
349
|
def close(self):
|
|
257
350
|
"""关闭 HTTP 连接"""
|
|
258
351
|
self._client.close()
|
|
@@ -320,7 +413,6 @@ class AsyncRedFoxClient(_RequestMixin):
|
|
|
320
413
|
self._client = httpx.AsyncClient(
|
|
321
414
|
timeout=httpx.Timeout(timeout),
|
|
322
415
|
headers={
|
|
323
|
-
"Content-Type": "application/json",
|
|
324
416
|
"REDFOX_API_KEY": self.api_key,
|
|
325
417
|
},
|
|
326
418
|
)
|
|
@@ -332,10 +424,20 @@ class AsyncRedFoxClient(_RequestMixin):
|
|
|
332
424
|
self.bilibili = BilibiliAPI(self)
|
|
333
425
|
self.toutiao = ToutiaoAPI(self)
|
|
334
426
|
self.tiktok = TikTokAPI(self)
|
|
427
|
+
self.kuaishou = KuaishouAPI(self)
|
|
428
|
+
self.wechat_channels = WechatChannelsAPI(self)
|
|
429
|
+
self.youtube = YouTubeAPI(self)
|
|
430
|
+
self.twitter = TwitterAPI(self)
|
|
431
|
+
self.instagram = InstagramAPI(self)
|
|
432
|
+
self.dongchedi = DongchediAPI(self)
|
|
433
|
+
self.yiche = YicheAPI(self)
|
|
434
|
+
self.autohome = AutohomeAPI(self)
|
|
435
|
+
self.hotspot = HotspotAPI(self)
|
|
335
436
|
self.gpt_image = GPTImageAPI(self)
|
|
336
437
|
self.doubao_image = DoubaoImageAPI(self)
|
|
337
438
|
self.doubao_video = DoubaoVideoAPI(self)
|
|
338
439
|
self.ai_search = AISearchAPI(self)
|
|
440
|
+
self.tools = ToolsAPI(self)
|
|
339
441
|
|
|
340
442
|
async def request(
|
|
341
443
|
self,
|
|
@@ -401,6 +503,59 @@ class AsyncRedFoxClient(_RequestMixin):
|
|
|
401
503
|
"""异步发送 GET 请求"""
|
|
402
504
|
return await self.request("GET", path, params=params)
|
|
403
505
|
|
|
506
|
+
async def upload(
|
|
507
|
+
self,
|
|
508
|
+
path: str,
|
|
509
|
+
file,
|
|
510
|
+
data: Optional[Dict[str, Any]] = None,
|
|
511
|
+
field_name: str = "file",
|
|
512
|
+
) -> dict:
|
|
513
|
+
"""
|
|
514
|
+
异步上传文件(multipart/form-data,含自动重试)
|
|
515
|
+
|
|
516
|
+
:param path: API 路径
|
|
517
|
+
:param file: 文件,支持文件路径 / (filename, bytes) 元组 / 文件对象 / bytes
|
|
518
|
+
:param data: 附加表单字段
|
|
519
|
+
:param field_name: 文件表单字段名,默认 "file"
|
|
520
|
+
:return: API 响应 data 字段内容
|
|
521
|
+
"""
|
|
522
|
+
url = f"{self.base_url}{path}"
|
|
523
|
+
filename, content = self._read_file(file, field_name)
|
|
524
|
+
if data:
|
|
525
|
+
data = {k: v for k, v in data.items() if v is not None}
|
|
526
|
+
last_exception = None
|
|
527
|
+
|
|
528
|
+
for attempt in range(self.max_retries + 1):
|
|
529
|
+
try:
|
|
530
|
+
response = await self._client.post(
|
|
531
|
+
url,
|
|
532
|
+
files={field_name: (filename, content)},
|
|
533
|
+
data=data,
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
if response.status_code in RETRYABLE_STATUSES and attempt < self.max_retries:
|
|
537
|
+
delay = _compute_delay(attempt, self.backoff_factor)
|
|
538
|
+
logger.debug(
|
|
539
|
+
"上传收到 %d,第 %d/%d 次重试,等待 %.1fs",
|
|
540
|
+
response.status_code, attempt + 1, self.max_retries, delay,
|
|
541
|
+
)
|
|
542
|
+
await self._async_sleep(delay)
|
|
543
|
+
continue
|
|
544
|
+
|
|
545
|
+
return self._handle_response(response)
|
|
546
|
+
|
|
547
|
+
except RETRYABLE_EXCEPTIONS as exc:
|
|
548
|
+
last_exception = exc
|
|
549
|
+
if attempt < self.max_retries:
|
|
550
|
+
await self._async_sleep(_compute_delay(attempt, self.backoff_factor))
|
|
551
|
+
else:
|
|
552
|
+
raise self._map_exception(exc)
|
|
553
|
+
|
|
554
|
+
except (RedFoxAPIError, RedFoxAuthError, RedFoxRateLimitError):
|
|
555
|
+
raise
|
|
556
|
+
|
|
557
|
+
raise self._map_exception(last_exception) if last_exception else RedFoxAPIError("上传失败")
|
|
558
|
+
|
|
404
559
|
async def _async_sleep(self, seconds: float):
|
|
405
560
|
"""异步延时"""
|
|
406
561
|
import asyncio
|
redfox/endpoints/ai_search.py
CHANGED
|
@@ -7,7 +7,7 @@ class AISearchAPI:
|
|
|
7
7
|
"""
|
|
8
8
|
AI 搜索工具 API 集合
|
|
9
9
|
|
|
10
|
-
支持 Kimi、豆包、Deepseek
|
|
10
|
+
支持 Kimi、豆包、Deepseek、元宝、千问、百度六种 AI 搜索引擎。
|
|
11
11
|
每种引擎均为异步模式:先 submit 提交任务,再 result 查询结果。
|
|
12
12
|
"""
|
|
13
13
|
|
|
@@ -85,3 +85,75 @@ class AISearchAPI:
|
|
|
85
85
|
return self._client.post(
|
|
86
86
|
"/story/api/deepSearch/dsResult", data={"taskId": task_id}
|
|
87
87
|
)
|
|
88
|
+
|
|
89
|
+
# ─── 元宝 ───────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
def yuanbao_submit(self, inquiry_text: str) -> dict:
|
|
92
|
+
"""
|
|
93
|
+
元宝纯文字搜索 - 提交任务
|
|
94
|
+
|
|
95
|
+
:param inquiry_text: 搜索文本(必填)
|
|
96
|
+
:return: 包含 taskId 的字典
|
|
97
|
+
"""
|
|
98
|
+
return self._client.post(
|
|
99
|
+
"/story/api/deepSearch/ybSubmit", data={"inquiryText": inquiry_text}
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def yuanbao_result(self, task_id: str) -> dict:
|
|
103
|
+
"""
|
|
104
|
+
元宝纯文字搜索 - 查询任务结果
|
|
105
|
+
|
|
106
|
+
:param task_id: 任务 ID(由 yuanbao_submit 返回)
|
|
107
|
+
:return: 任务结果字典
|
|
108
|
+
"""
|
|
109
|
+
return self._client.post(
|
|
110
|
+
"/story/api/deepSearch/ybResult", data={"taskId": task_id}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# ─── 千问 ───────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
def qianwen_submit(self, inquiry_text: str) -> dict:
|
|
116
|
+
"""
|
|
117
|
+
千问纯文字搜索 - 提交任务
|
|
118
|
+
|
|
119
|
+
:param inquiry_text: 搜索文本(必填)
|
|
120
|
+
:return: 包含 taskId 的字典
|
|
121
|
+
"""
|
|
122
|
+
return self._client.post(
|
|
123
|
+
"/story/api/deepSearch/qwSubmit", data={"inquiryText": inquiry_text}
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def qianwen_result(self, task_id: str) -> dict:
|
|
127
|
+
"""
|
|
128
|
+
千问纯文字搜索 - 查询任务结果
|
|
129
|
+
|
|
130
|
+
:param task_id: 任务 ID(由 qianwen_submit 返回)
|
|
131
|
+
:return: 任务结果字典
|
|
132
|
+
"""
|
|
133
|
+
return self._client.post(
|
|
134
|
+
"/story/api/deepSearch/qwResult", data={"taskId": task_id}
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# ─── 百度 ───────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
def baidu_submit(self, inquiry_text: str) -> dict:
|
|
140
|
+
"""
|
|
141
|
+
百度纯文字搜索 - 提交任务
|
|
142
|
+
|
|
143
|
+
:param inquiry_text: 搜索文本(必填)
|
|
144
|
+
:return: 包含 taskId 的字典
|
|
145
|
+
"""
|
|
146
|
+
return self._client.post(
|
|
147
|
+
"/story/api/deepSearch/bdSubmit", data={"inquiryText": inquiry_text}
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def baidu_result(self, task_id: str) -> dict:
|
|
151
|
+
"""
|
|
152
|
+
百度纯文字搜索 - 查询任务结果
|
|
153
|
+
|
|
154
|
+
:param task_id: 任务 ID(由 baidu_submit 返回)
|
|
155
|
+
:return: 任务结果字典
|
|
156
|
+
"""
|
|
157
|
+
return self._client.post(
|
|
158
|
+
"/story/api/deepSearch/bdResult", data={"taskId": task_id}
|
|
159
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""汽车之家平台 API 端点"""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Dict, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AutohomeAPI:
|
|
7
|
+
"""
|
|
8
|
+
汽车之家平台 API 集合
|
|
9
|
+
|
|
10
|
+
包含汽车之家作品搜索、文章/视频详情、账号作品列表等接口。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, client):
|
|
14
|
+
self._client = client
|
|
15
|
+
|
|
16
|
+
def search_works(
|
|
17
|
+
self,
|
|
18
|
+
keyword: str,
|
|
19
|
+
offset: str = "0",
|
|
20
|
+
page: str = "1",
|
|
21
|
+
source_type: str = "video",
|
|
22
|
+
) -> dict:
|
|
23
|
+
"""
|
|
24
|
+
汽车之家关键词搜索作品
|
|
25
|
+
|
|
26
|
+
:param keyword: 搜索关键词(必填)
|
|
27
|
+
:param offset: 翻页偏移量,从 0 开始,翻页 +10
|
|
28
|
+
:param page: 页码,从 1 开始,翻页 +1
|
|
29
|
+
:param source_type: 内容类型:club / article / video
|
|
30
|
+
:return: 搜索结果字典
|
|
31
|
+
"""
|
|
32
|
+
data: Dict[str, Any] = {
|
|
33
|
+
"keyword": keyword,
|
|
34
|
+
"offset": str(offset),
|
|
35
|
+
"page": str(page),
|
|
36
|
+
"sourceType": source_type,
|
|
37
|
+
}
|
|
38
|
+
return self._client.post("/story/api/autohome/searchWork", data=data)
|
|
39
|
+
|
|
40
|
+
def get_article(self, work_id: str, page: int = 0) -> dict:
|
|
41
|
+
"""
|
|
42
|
+
汽车之家文章详情(车家号)
|
|
43
|
+
|
|
44
|
+
:param work_id: 作品 ID(必填)
|
|
45
|
+
:param page: 页码,默认 0
|
|
46
|
+
:return: 文章详情字典
|
|
47
|
+
"""
|
|
48
|
+
return self._client.post(
|
|
49
|
+
"/story/api/autohome/articleDetail",
|
|
50
|
+
data={"workId": work_id, "page": page},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def get_video(self, video_id: str, video_type: int) -> dict:
|
|
54
|
+
"""
|
|
55
|
+
汽车之家视频详情(原创账号+车家号)
|
|
56
|
+
|
|
57
|
+
:param video_id: 视频 ID(必填)
|
|
58
|
+
:param video_type: 视频类型:0=原创账号,4=车家号(必填)
|
|
59
|
+
:return: 视频详情字典
|
|
60
|
+
"""
|
|
61
|
+
return self._client.post(
|
|
62
|
+
"/story/api/autohome/videoDetail",
|
|
63
|
+
data={"videoId": video_id, "videoType": video_type},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def get_user_works(self, author_id: str, page: int = 0) -> dict:
|
|
67
|
+
"""
|
|
68
|
+
汽车之家作品列表(原创账号)
|
|
69
|
+
|
|
70
|
+
:param author_id: 作者 ID(必填)
|
|
71
|
+
:param page: 页码,默认 0
|
|
72
|
+
:return: 作品列表字典
|
|
73
|
+
"""
|
|
74
|
+
return self._client.post(
|
|
75
|
+
"/story/api/autohome/workList",
|
|
76
|
+
data={"authorId": author_id, "page": page},
|
|
77
|
+
)
|
redfox/endpoints/bilibili.py
CHANGED
|
@@ -121,3 +121,38 @@ class BilibiliAPI:
|
|
|
121
121
|
if order is not None:
|
|
122
122
|
data["order"] = order
|
|
123
123
|
return self._client.post("/story/api/bili/data/accountWorkList", data=data)
|
|
124
|
+
|
|
125
|
+
# ─── 音频 / 提文案 ─────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
def get_audio(self, url: str) -> dict:
|
|
128
|
+
"""
|
|
129
|
+
获取哔哩哔哩音频地址
|
|
130
|
+
|
|
131
|
+
:param url: 作品链接(必填)
|
|
132
|
+
:return: 音频地址字典
|
|
133
|
+
"""
|
|
134
|
+
return self._client.post(
|
|
135
|
+
"/story/api/parseWork/audioExtract/bilibili", data={"url": url}
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def transcript_submit(self, url: str) -> dict:
|
|
139
|
+
"""
|
|
140
|
+
哔哩哔哩链接提文案 - 提交任务
|
|
141
|
+
|
|
142
|
+
:param url: 作品地址(必填)
|
|
143
|
+
:return: 包含 taskId 的字典
|
|
144
|
+
"""
|
|
145
|
+
return self._client.post(
|
|
146
|
+
"/story/api/parseWork/bilibiliSubtitle/submit", data={"url": url}
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def transcript_result(self, task_id: str) -> dict:
|
|
150
|
+
"""
|
|
151
|
+
哔哩哔哩链接提文案 - 查询结果
|
|
152
|
+
|
|
153
|
+
:param task_id: 任务 ID(由 transcript_submit 返回)
|
|
154
|
+
:return: 文案提取结果字典
|
|
155
|
+
"""
|
|
156
|
+
return self._client.post(
|
|
157
|
+
"/story/api/parseWork/bilibiliSubtitle/result", data={"taskId": task_id}
|
|
158
|
+
)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""懂车帝平台 API 端点"""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Dict, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DongchediAPI:
|
|
7
|
+
"""
|
|
8
|
+
懂车帝平台 API 集合
|
|
9
|
+
|
|
10
|
+
包含懂车帝作品搜索、作品详情、用户作品列表、用户搜索等接口。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, client):
|
|
14
|
+
self._client = client
|
|
15
|
+
|
|
16
|
+
def search_works(
|
|
17
|
+
self,
|
|
18
|
+
keyword: str,
|
|
19
|
+
offset: str = "0",
|
|
20
|
+
source_type: str = "1",
|
|
21
|
+
) -> dict:
|
|
22
|
+
"""
|
|
23
|
+
懂车帝关键词搜索作品
|
|
24
|
+
|
|
25
|
+
:param keyword: 搜索关键词(必填)
|
|
26
|
+
:param offset: 翻页偏移量,从 0 开始,翻页 +20
|
|
27
|
+
:param source_type: 内容类型:1=综合,2=视频
|
|
28
|
+
:return: 搜索结果字典
|
|
29
|
+
"""
|
|
30
|
+
data: Dict[str, Any] = {
|
|
31
|
+
"keyword": keyword,
|
|
32
|
+
"offset": str(offset),
|
|
33
|
+
"sourceType": str(source_type),
|
|
34
|
+
}
|
|
35
|
+
return self._client.post("/story/api/dongchedi/searchWork", data=data)
|
|
36
|
+
|
|
37
|
+
def get_work(self, work_id: str, work_type: str) -> dict:
|
|
38
|
+
"""
|
|
39
|
+
懂车帝作品详情
|
|
40
|
+
|
|
41
|
+
:param work_id: 懂车帝作品 ID(必填)
|
|
42
|
+
:param work_type: 作品类型:video=视频,article=图文(必填)
|
|
43
|
+
:return: 作品详情字典
|
|
44
|
+
"""
|
|
45
|
+
return self._client.post(
|
|
46
|
+
"/story/api/dongchedi/workDetail",
|
|
47
|
+
data={"workId": work_id, "workType": work_type},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def get_user_works(self, user_id: str, cursor: int = 0) -> dict:
|
|
51
|
+
"""
|
|
52
|
+
懂车帝用户作品列表
|
|
53
|
+
|
|
54
|
+
:param user_id: 用户 ID(必填)
|
|
55
|
+
:param cursor: 游标,首次传 0,翻页传上一页返回的 cursor 值
|
|
56
|
+
:return: 作品列表字典
|
|
57
|
+
"""
|
|
58
|
+
return self._client.post(
|
|
59
|
+
"/story/api/dongchedi/workList",
|
|
60
|
+
data={"userId": user_id, "cursor": cursor},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def search_users(self, keyword: str, offset: int = 0) -> dict:
|
|
64
|
+
"""
|
|
65
|
+
懂车帝用户搜索
|
|
66
|
+
|
|
67
|
+
:param keyword: 搜索关键词(必填)
|
|
68
|
+
:param offset: 偏移量,从 0 开始
|
|
69
|
+
:return: 搜索结果字典
|
|
70
|
+
"""
|
|
71
|
+
return self._client.post(
|
|
72
|
+
"/story/api/dongchedi/searchUser",
|
|
73
|
+
data={"keyword": keyword, "offset": offset},
|
|
74
|
+
)
|