uapi-sdk-python 0.1.5__tar.gz → 0.1.13__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uapi-sdk-python
3
- Version: 0.1.5
3
+ Version: 0.1.13
4
4
  Summary: Idiomatic UAPI SDK for Python
5
5
  Author-email: UAPI <dev@uapis.cn>
6
6
  Requires-Python: >=3.9
@@ -14,7 +14,7 @@ Requires-Dist: isort; extra == "dev"
14
14
 
15
15
  # uapi-sdk-python
16
16
 
17
- ![Banner](https://raw.githubusercontent.com/uapis/uapi-sdk-python/main/banner.png)
17
+ ![Banner](https://raw.githubusercontent.com/AxT-Team/uapi-sdk-python/main/banner.png)
18
18
 
19
19
  [![Python](https://img.shields.io/badge/Python-3.9+-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/)
20
20
  [![Docs](https://img.shields.io/badge/Docs-uapis.cn-2EAE5D?style=flat-square)](https://uapis.cn/)
@@ -1,6 +1,6 @@
1
1
  # uapi-sdk-python
2
2
 
3
- ![Banner](https://raw.githubusercontent.com/uapis/uapi-sdk-python/main/banner.png)
3
+ ![Banner](https://raw.githubusercontent.com/AxT-Team/uapi-sdk-python/main/banner.png)
4
4
 
5
5
  [![Python](https://img.shields.io/badge/Python-3.9+-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/)
6
6
  [![Docs](https://img.shields.io/badge/Docs-uapis.cn-2EAE5D?style=flat-square)](https://uapis.cn/)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "uapi-sdk-python"
7
- version = "0.1.5"
7
+ version = "0.1.13"
8
8
  description = "Idiomatic UAPI SDK for Python"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -27,5 +27,3 @@ strict = true
27
27
 
28
28
  [tool.isort]
29
29
  profile = "black"
30
-
31
-
@@ -15,7 +15,8 @@ class _Config:
15
15
  class _HTTP:
16
16
  def __init__(self, cfg: _Config):
17
17
  self._cfg = cfg
18
- self._client = httpx.Client(timeout=cfg.timeout)
18
+ self._client = httpx.Client(timeout=cfg.timeout, trust_env=False)
19
+ self.last_response_meta: Optional[ResponseMeta] = None
19
20
 
20
21
  def request(self, method: str, path: str, *, params: Dict[str, Any] | None = None, json: Any | None = None, headers: Dict[str, str] | None = None):
21
22
  url = self._cfg.base_url.rstrip("/") + path
@@ -24,7 +25,10 @@ class _HTTP:
24
25
  headers["Authorization"] = f"Bearer {self._cfg.token}"
25
26
  r = self._client.request(method, url, params=params, json=json, headers=headers)
26
27
  if r.status_code >= 400:
27
- raise map_error(r)
28
+ err = map_error(r)
29
+ self.last_response_meta = err.meta
30
+ raise err
31
+ self.last_response_meta = extract_meta(r.headers)
28
32
  # try json else bytes
29
33
  try:
30
34
  return r.json()
@@ -90,6 +94,10 @@ class UapiClient:
90
94
  self.zhi_neng_sou_suo = _zhi_neng_sou_suo
91
95
  setattr(self, "智能搜索", _zhi_neng_sou_suo)
92
96
 
97
+ @property
98
+ def last_response_meta(self) -> Optional[ResponseMeta]:
99
+ return self._http.last_response_meta
100
+
93
101
 
94
102
  class _ClipzyZaiXianJianTieBanApi:
95
103
  def __init__(self, http: _HTTP):
@@ -428,12 +436,7 @@ class _ImageApi:
428
436
  这个接口会获取 Bing 搜索引擎当天全球同步的每日壁纸,并直接以图片形式返回。你可以用它来做应用的启动页、网站背景,或者任何需要每日更新精美图片的地方。
429
437
 
430
438
  ## 使用须知
431
-
432
- > [!NOTE]
433
- > **响应格式是图片**
434
- > 请注意,此接口成功时直接返回图片二进制数据(通常为 `image/jpeg`),而非 JSON 格式。请确保客户端能够正确处理。
435
-
436
- 我们内置了备用方案:如果从必应官方获取图片失败,系统会尝试返回一张预存的高质量风景图,以保证服务的稳定性。
439
+ 此接口成功时直接返回图片二进制数据,通常是 `image/jpeg`,不是 JSON 格式。接入时请按图片响应来处理。
437
440
  """
438
441
  params = {}
439
442
  body = {}
@@ -443,7 +446,7 @@ class _ImageApi:
443
446
  return self._http.request("GET", path, params=params, json=body if body else None)
444
447
 
445
448
  def get_image_motou(self, **kwargs):
446
- r"""摸头 GIF
449
+ r"""生成摸摸头GIF (QQ号)
447
450
  想在线rua一下好友的头像吗?这个趣味接口可以满足你。
448
451
 
449
452
  ## 功能概述
@@ -471,16 +474,7 @@ class _ImageApi:
471
474
  无论是网址、文本还是联系方式,通通可以变成一个二维码!这是一个非常灵活的二维码生成工具。
472
475
 
473
476
  ## 功能概述
474
- 你提供一段文本内容,我们为你生成对应的二维码图片。你可以自定义尺寸,并选择不同的返回格式以适应不同场景。
475
-
476
- ## 使用须知
477
-
478
- > [!IMPORTANT]
479
- > **关键参数 `format`**
480
- > 此参数决定了成功响应的内容类型和结构,请务必根据你的需求选择并正确处理响应:
481
- > - **`image`** (默认): 直接返回 `image/png` 格式的图片二进制数据,适合在 `<img>` 标签中直接使用。
482
- > - **`json`**: 返回一个包含 Base64 Data URI 的 JSON 对象,适合需要在前端直接嵌入CSS或HTML的场景。
483
- > - **`json_url`**: 返回一个包含图片临时URL的JSON对象,适合需要图片链接的场景。
477
+ 你提供一段文本内容,我们为你生成对应的二维码图片。你可以自定义尺寸、前景色、背景色,还支持透明背景,并选择不同的返回格式以适应不同场景。
484
478
  """
485
479
  params = {}
486
480
  body = {}
@@ -494,6 +488,15 @@ class _ImageApi:
494
488
  if "query" == "query" and "format" in kwargs:
495
489
  params["format"] = kwargs["format"]
496
490
 
491
+ if "query" == "query" and "transparent" in kwargs:
492
+ params["transparent"] = kwargs["transparent"]
493
+
494
+ if "query" == "query" and "fgcolor" in kwargs:
495
+ params["fgcolor"] = kwargs["fgcolor"]
496
+
497
+ if "query" == "query" and "bgcolor" in kwargs:
498
+ params["bgcolor"] = kwargs["bgcolor"]
499
+
497
500
  path = "/api/v1/image/qrcode"
498
501
 
499
502
  return self._http.request("GET", path, params=params, json=body if body else None)
@@ -589,7 +592,7 @@ class _ImageApi:
589
592
  return self._http.request("POST", path, params=params, json=body if body else None)
590
593
 
591
594
  def post_image_motou(self, **kwargs):
592
- r"""摸头 GIF (上传)
595
+ r"""生成摸摸头GIF
593
596
  除了使用QQ头像,你还可以通过上传自己的图片或提供图片URL来制作独一无二的摸摸头GIF。
594
597
 
595
598
  ## 功能概述
@@ -619,13 +622,47 @@ class _ImageApi:
619
622
 
620
623
  return self._http.request("POST", path, params=params, json=body if body else None)
621
624
 
625
+ def post_image_nsfw(self, **kwargs):
626
+ r"""图片敏感检测
627
+ 这是一个图片内容审核接口,自动识别图片中的违规内容并返回处理建议。
628
+
629
+ ## 功能概述
630
+ 上传图片文件或提供图片URL,接口会自动分析图片内容,返回是否违规、风险等级和处理建议。适合对接到用户上传流程中,实现自动化内容审核。
631
+
632
+ ## 返回字段说明
633
+ - **is_nsfw**: 是否判定为违规内容,`true` 表示违规,`false` 表示正常
634
+ - **nsfw_score**: 违规内容置信度,0-1 之间,越高表示越可能违规
635
+ - **normal_score**: 正常内容置信度,0-1 之间,与 nsfw_score 互补
636
+ - **suggestion**: 处理建议
637
+ - `pass`: 内容正常,可以直接放行
638
+ - `review`: 存在风险,建议转人工复核
639
+ - `block`: 高风险内容,建议直接拦截
640
+ - **risk_level**: 风险等级
641
+ - `low`: 低风险
642
+ - `medium`: 中风险
643
+ - `high`: 高风险
644
+ - **label**: 内容标签,`nsfw` 或 `normal`
645
+ - **confidence**: 模型对当前判断的整体置信度
646
+ - **inference_time_ms**: 模型推理耗时,单位毫秒
647
+ """
648
+ params = {}
649
+ body = {}
650
+
651
+
652
+ if "file" in kwargs:
653
+ body["file"] = kwargs["file"]
654
+
655
+ if "url" in kwargs:
656
+ body["url"] = kwargs["url"]
657
+
658
+ path = "/api/v1/image/nsfw"
659
+
660
+ return self._http.request("POST", path, params=params, json=body if body else None)
661
+
622
662
  def post_image_speechless(self, **kwargs):
623
663
  r"""生成你们怎么不说话了表情包
624
664
  你们怎么不说话了?是不是都在偷偷玩Uapi,求求你们不要玩Uapi了
625
665
 
626
- ## 效果展示
627
- ![示例](https://uapis.cn/static/uploads/33580466897f1e5815296f235b582815.png)
628
-
629
666
  ## 使用须知
630
667
  - **响应格式**:接口成功时直接返回 `image/png` 格式的二进制数据。
631
668
  - **文字内容**:至少需要提供 `top_text`(上方文字)或 `bottom_text`(下方文字)之一。
@@ -715,6 +752,91 @@ class _MiscApi:
715
752
 
716
753
  return self._http.request("GET", path, params=params, json=body if body else None)
717
754
 
755
+ def get_misc_district(self, **kwargs):
756
+ r"""Adcode 国内外行政区域查询
757
+ 一个接口,覆盖全球 243 个国家、中国省/市/区/街道四级行政区划,支持关键词搜索、行政编码查询、坐标反查三种查询模式(必须至少传入一种查询参数)。
758
+
759
+ ## 功能概述
760
+ 根据用户输入的搜索条件快速查找行政区域信息。例如:中国 > 山东省 > 济南市 > 历下区 > 舜华路街道。
761
+
762
+ 无需注册、无需密钥,直接调用即可获取结构化的行政区域数据。支持三种查询方式:
763
+ - 传 `adcode`,按行政编码精确查询,同时返回下级区划列表
764
+ - 传 `lat` + `lng`,坐标反查附近地点
765
+ - 传 `keywords`,按关键词搜索,支持中英文
766
+
767
+ ## 中国与国际数据差异
768
+ 中国数据包含 `adcode`、`citycode` 等字段,支持省/市/区/街道四级逐级查询;国际城市数据不含这些字段,但额外提供 `population`(人口)和 `timezone`(时区)。
769
+
770
+ > [!NOTE]
771
+ > 部分城市(如东莞、文昌)没有区县层级,市级下方直接显示街道。街道级别的 `adcode` 返回的是所属区县的 `adcode`。
772
+ """
773
+ params = {}
774
+ body = {}
775
+
776
+ if "query" == "query" and "keywords" in kwargs:
777
+ params["keywords"] = kwargs["keywords"]
778
+
779
+ if "query" == "query" and "adcode" in kwargs:
780
+ params["adcode"] = kwargs["adcode"]
781
+
782
+ if "query" == "query" and "lat" in kwargs:
783
+ params["lat"] = kwargs["lat"]
784
+
785
+ if "query" == "query" and "lng" in kwargs:
786
+ params["lng"] = kwargs["lng"]
787
+
788
+ if "query" == "query" and "level" in kwargs:
789
+ params["level"] = kwargs["level"]
790
+
791
+ if "query" == "query" and "country" in kwargs:
792
+ params["country"] = kwargs["country"]
793
+
794
+ if "query" == "query" and "limit" in kwargs:
795
+ params["limit"] = kwargs["limit"]
796
+
797
+ path = "/api/v1/misc/district"
798
+
799
+ return self._http.request("GET", path, params=params, json=body if body else None)
800
+
801
+ def get_misc_holiday_calendar(self, **kwargs):
802
+ r"""查询节假日与万年历
803
+ 查询指定日期、月份或年份的万年历与节假日信息。
804
+
805
+ ## 功能概述
806
+ 这个接口支持三种查询方式:按天(`date`)、按月(`month`)和按年(`year`)。调用时三者选一个传入即可。
807
+
808
+ 如果你只关心某一类事件,可以通过 `holiday_type` 进行筛选,例如只看法定休假/调休、公历节日、农历节日或节气。
809
+
810
+ 在 `date` 模式下,传 `include_nearby=true` 可以额外返回该日期前后最近的节日;返回数量由 `nearby_limit` 控制,默认 7,最大 30。
811
+ """
812
+ params = {}
813
+ body = {}
814
+
815
+ if "query" == "query" and "date" in kwargs:
816
+ params["date"] = kwargs["date"]
817
+
818
+ if "query" == "query" and "month" in kwargs:
819
+ params["month"] = kwargs["month"]
820
+
821
+ if "query" == "query" and "year" in kwargs:
822
+ params["year"] = kwargs["year"]
823
+
824
+ if "query" == "query" and "timezone" in kwargs:
825
+ params["timezone"] = kwargs["timezone"]
826
+
827
+ if "query" == "query" and "holiday_type" in kwargs:
828
+ params["holiday_type"] = kwargs["holiday_type"]
829
+
830
+ if "query" == "query" and "include_nearby" in kwargs:
831
+ params["include_nearby"] = kwargs["include_nearby"]
832
+
833
+ if "query" == "query" and "nearby_limit" in kwargs:
834
+ params["nearby_limit"] = kwargs["nearby_limit"]
835
+
836
+ path = "/api/v1/misc/holiday-calendar"
837
+
838
+ return self._http.request("GET", path, params=params, json=body if body else None)
839
+
718
840
  def get_misc_hotboard(self, **kwargs):
719
841
  r"""查询热榜
720
842
  想快速跟上网络热点?这个接口让你一网打尽各大主流平台的实时热榜/热搜!
@@ -722,17 +844,19 @@ class _MiscApi:
722
844
  ## 功能概述
723
845
  你只需要指定一个平台类型,就能获取到该平台当前的热榜数据列表。每个热榜条目都包含标题、热度值和原始链接。非常适合用于制作信息聚合类应用或看板。
724
846
 
725
- ## 可选值
726
- `type` 参数接受多种不同的值,每种值对应一个不同的热榜来源。以下是目前支持的所有值:
847
+ ## 三种使用模式
848
+
849
+ ### 默认模式
850
+ 只传 `type` 参数,返回该平台当前的实时热榜。
851
+
852
+ ### 时光机模式
853
+ 传 `type` + `time` 参数,返回最接近指定时间的热榜快照。如果不可用或无数据,会返回空。
727
854
 
728
- | 分类 | 支持的 type 值 |
729
- |------------|-----------------------------------------------------------------------------------------------------------------------------------|
730
- | 视频/社区 | bilibili(哔哩哔哩弹幕网), acfun(A站弹幕视频网站), weibo(新浪微博热搜), zhihu(知乎热榜), zhihu-daily(知乎日报热榜), douyin(抖音热榜), kuaishou(快手热榜), douban-movie(豆瓣电影榜单), douban-group(豆瓣小组话题), tieba(百度贴吧热帖), hupu(虎扑热帖), miyoushe(米游社话题榜), ngabbs(NGA游戏论坛热帖), v2ex(V2EX技术社区热帖), 52pojie(吾爱破解热帖), hostloc(全球主机交流论坛), coolapk(酷安热榜) |
731
- | 新闻/资讯 | baidu(百度热搜), thepaper(澎湃新闻热榜), toutiao(今日头条热榜), qq-news(腾讯新闻热榜), sina(新浪热搜), sina-news(新浪新闻热榜), netease-news(网易新闻热榜), huxiu(虎嗅网热榜), ifanr(爱范儿热榜) |
732
- | 技术/IT | sspai(少数派热榜), ithome(IT之家热榜), ithome-xijiayi(IT之家·喜加一栏目), juejin(掘金社区热榜), jianshu(简书热榜), guokr(果壳热榜), 36kr(36氪热榜), 51cto(51CTO热榜), csdn(CSDN博客热榜), nodeseek(NodeSeek 技术社区), hellogithub(HelloGitHub 项目推荐) |
733
- | 游戏 | lol(英雄联盟热帖), genshin(原神热榜), honkai(崩坏3热榜), starrail(星穹铁道热榜) |
734
- | 其他 | weread(微信读书热门书籍), weatheralarm(天气预警信息), earthquake(地震速报), history(历史上的今天) |
855
+ ### 搜索模式
856
+ 传 `type` + `keyword` + `time_start` + `time_end` 参数,在指定时间范围内搜索包含关键词的热榜条目。可选传 `limit` 限制返回数量。
735
857
 
858
+ ### 数据源列表
859
+ 传 `sources=true`,返回所有支持历史数据的平台列表。
736
860
  """
737
861
  params = {}
738
862
  body = {}
@@ -740,10 +864,53 @@ class _MiscApi:
740
864
  if "query" == "query" and "type" in kwargs:
741
865
  params["type"] = kwargs["type"]
742
866
 
867
+ if "query" == "query" and "time" in kwargs:
868
+ params["time"] = kwargs["time"]
869
+
870
+ if "query" == "query" and "keyword" in kwargs:
871
+ params["keyword"] = kwargs["keyword"]
872
+
873
+ if "query" == "query" and "time_start" in kwargs:
874
+ params["time_start"] = kwargs["time_start"]
875
+
876
+ if "query" == "query" and "time_end" in kwargs:
877
+ params["time_end"] = kwargs["time_end"]
878
+
879
+ if "query" == "query" and "limit" in kwargs:
880
+ params["limit"] = kwargs["limit"]
881
+
882
+ if "query" == "query" and "sources" in kwargs:
883
+ params["sources"] = kwargs["sources"]
884
+
743
885
  path = "/api/v1/misc/hotboard"
744
886
 
745
887
  return self._http.request("GET", path, params=params, json=body if body else None)
746
888
 
889
+ def get_misc_lunartime(self, **kwargs):
890
+ r"""查询农历时间
891
+ 需要在指定时区下查看某个时间点的农历信息?这个接口可以直接返回完整结果。
892
+
893
+ ## 功能概述
894
+ 支持传入 Unix 时间戳(秒或毫秒)和 IANA 时区名,返回公历时间、星期、农历年月日、干支、生肖、节气与节日信息。不传 `ts` 时默认使用当前时间,不传 `timezone` 时默认 `Asia/Shanghai`。
895
+
896
+ ## 时区说明
897
+ - 支持标准 IANA 时区,例如 `Asia/Shanghai`、`Asia/Tokyo`
898
+ - 也支持别名:`Shanghai`、`Beijing`
899
+ - 时区非法时返回 400 并提示 `invalid timezone: xxx`
900
+ """
901
+ params = {}
902
+ body = {}
903
+
904
+ if "query" == "query" and "ts" in kwargs:
905
+ params["ts"] = kwargs["ts"]
906
+
907
+ if "query" == "query" and "timezone" in kwargs:
908
+ params["timezone"] = kwargs["timezone"]
909
+
910
+ path = "/api/v1/misc/lunartime"
911
+
912
+ return self._http.request("GET", path, params=params, json=body if body else None)
913
+
747
914
  def get_misc_phoneinfo(self, **kwargs):
748
915
  r"""查询手机归属地
749
916
  想知道一个手机号码来自哪里?是移动、联通还是电信?这个接口可以告诉你答案。
@@ -823,7 +990,7 @@ graph TD
823
990
  > [!WARNING]
824
991
  > **接口已过时**:这个接口已被新的 `/convert/unixtime` 取代。新接口功能更强大,支持双向转换。我们建议你迁移到新接口。
825
992
 
826
- [👉 前往新版接口文档](/docs/api-reference/get-convert-unixtime)
993
+ [➡️ 前往新版接口文档](/docs/api-reference/get-convert-unixtime)
827
994
  """
828
995
  params = {}
829
996
  body = {}
@@ -839,9 +1006,6 @@ graph TD
839
1006
  r"""获取支持的快递公司列表
840
1007
  不确定系统支持哪些快递公司?这个接口返回完整的支持列表。
841
1008
 
842
- > [!VIP]
843
- > 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
844
-
845
1009
  ## 功能概述
846
1010
  获取系统当前支持的所有快递公司列表,包括每家公司的标准编码(code)和中文名称(name)。
847
1011
 
@@ -861,9 +1025,6 @@ graph TD
861
1025
  r"""识别快递公司
862
1026
  不确定手里的快递单号属于哪家快递公司?这个接口专门做识别,不查物流。
863
1027
 
864
- > [!VIP]
865
- > 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
866
-
867
1028
  ## 功能概述
868
1029
  输入快递单号,系统会根据单号规则快速识别出最可能的快递公司。如果存在多个可能的匹配结果,还会在 `alternatives` 字段中返回备选项,供你参考选择。
869
1030
 
@@ -886,15 +1047,15 @@ graph TD
886
1047
  r"""查询快递物流信息
887
1048
  买了东西想知道快递到哪儿了?这个接口帮你实时追踪物流状态。
888
1049
 
889
- > [!VIP]
890
- > 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
891
-
892
1050
  ## 功能概述
893
- 提供一个快递单号,系统会自动识别快递公司并返回完整的物流轨迹信息。支持中通、圆通、韵达、申通、极兔、顺丰、京东、EMS、德邦等60+国内外主流快递公司。
1051
+ 提供一个快递单号,系统会自动识别快递公司并返回完整的物流轨迹信息。这个接口目前可以查询中通、圆通、韵达、申通、极兔、京东、EMS、德邦等主流快递公司的物流信息。
894
1052
 
895
1053
  ## 使用须知
1054
+ 目前暂不支持顺丰快递单号的物流查询。
1055
+
896
1056
  - **自动识别**:不知道是哪家快递?系统会根据单号规则自动识别快递公司(推荐使用)
897
1057
  - **手动指定**:如果已知快递公司,可以传递 `carrier_code` 参数,查询速度会更快
1058
+ - **手机尾号验证**:部分快递公司需要验证收件人手机尾号才能查询详细物流,如果返回 `暂无物流信息`,建议尝试传入 `phone` 参数
898
1059
  - **查询时效**:物流信息实时查询,响应时间通常在1-2秒内
899
1060
  """
900
1061
  params = {}
@@ -906,23 +1067,38 @@ graph TD
906
1067
  if "query" == "query" and "carrier_code" in kwargs:
907
1068
  params["carrier_code"] = kwargs["carrier_code"]
908
1069
 
1070
+ if "query" == "query" and "phone" in kwargs:
1071
+ params["phone"] = kwargs["phone"]
1072
+
909
1073
  path = "/api/v1/misc/tracking/query"
910
1074
 
911
1075
  return self._http.request("GET", path, params=params, json=body if body else None)
912
1076
 
913
1077
  def get_misc_weather(self, **kwargs):
914
1078
  r"""查询天气
915
- 出门前,查一下天气总是个好习惯。这个接口为你提供精准、实时的天气数据。
1079
+ 出门前,查一下天气总是个好习惯。这个接口为你提供精准、实时的天气数据,支持国内和国际城市。
916
1080
 
917
1081
  ## 功能概述
918
- 你可以通过城市名称或6位数字的Adcode来查询指定地区的实时天气状况,包括天气现象、温度、湿度、风向和风力等。
1082
+ 这个接口支持三种查询方式:
1083
+ - 可以传 `adcode`,按行政区编码查询(优先级最高)
1084
+ - 可以传 `city`,按城市名称查询,支持中文(`北京`)和英文(`Tokyo`)
1085
+ - 两个都不传时,按客户端 IP 自动定位查询
919
1086
 
920
- ## 使用须知
921
- - **参数优先级**:当你同时提供了 `city` (城市名) 和 `adcode` (城市编码) 两个参数时,系统会 **优先使用 `adcode`** 进行查询,因为它更精确。
922
- - **查询范围**:为了保证查询的准确性,我们的服务仅支持标准的“省”、“市”、“区/县”级别的行政区划名称查询,不保证能查询到乡镇或具体地点。
1087
+ 支持 `lang` 参数,可选 `zh`(默认)和 `en`,城市名翻译覆盖 7000+ 城市。
923
1088
 
924
- ## 错误处理指南
925
- - **410 Gone**: 这个特殊的错误码意味着你查询的地区无效或不受我们支持。比如你输入了“火星”,或者某个我们无法识别的村庄名称。这个状态码告诉你,这个“资源”是永久性地不可用了。
1089
+ ## 可选功能模块
1090
+ - `extended=true`:扩展气象字段(体感温度、能见度、气压、紫外线、空气质量及污染物分项数据)
1091
+ - `forecast=true`:多天预报(最多7天,会额外返回每天的最高温度、最低温度,以及日出日落、风速等详细数据)
1092
+ - `hourly=true`:逐小时预报(24小时)
1093
+ - `minutely=true`:分钟级降水预报(仅国内城市,精确到2分钟)
1094
+ - `indices=true`:18项生活指数(穿衣、紫外线、洗车、运动、花粉等)
1095
+
1096
+ ## 天气字段说明
1097
+ `weather` 是天气现象文本,不是固定枚举。
1098
+
1099
+ 常见值包括:晴、多云、阴、小雨、中雨、大雨、雷阵雨、小雪、中雪、大雪、雨夹雪、雾、霾、沙尘。
1100
+
1101
+ 如果你的业务需要稳定的天气分类,建议使用 `weather_code` 进行映射。完整的天气图标代码请参考[天气图标代码表](#enum-list)。
926
1102
  """
927
1103
  params = {}
928
1104
  body = {}
@@ -936,11 +1112,20 @@ graph TD
936
1112
  if "query" == "query" and "extended" in kwargs:
937
1113
  params["extended"] = kwargs["extended"]
938
1114
 
1115
+ if "query" == "query" and "forecast" in kwargs:
1116
+ params["forecast"] = kwargs["forecast"]
1117
+
1118
+ if "query" == "query" and "hourly" in kwargs:
1119
+ params["hourly"] = kwargs["hourly"]
1120
+
1121
+ if "query" == "query" and "minutely" in kwargs:
1122
+ params["minutely"] = kwargs["minutely"]
1123
+
939
1124
  if "query" == "query" and "indices" in kwargs:
940
1125
  params["indices"] = kwargs["indices"]
941
1126
 
942
- if "query" == "query" and "forecast" in kwargs:
943
- params["forecast"] = kwargs["forecast"]
1127
+ if "query" == "query" and "lang" in kwargs:
1128
+ params["lang"] = kwargs["lang"]
944
1129
 
945
1130
  path = "/api/v1/misc/weather"
946
1131
 
@@ -1042,10 +1227,10 @@ class _NetworkApi:
1042
1227
 
1043
1228
  def get_network_ipinfo(self, **kwargs):
1044
1229
  r"""查询 IP
1045
- 想知道一个IP地址或域名来自地球的哪个角落?这个接口可以帮你定位它。你可以选择使用默认的GeoIP数据库,也可以指定 `source=commercial` 参数来查询更详细的商业级IP归属信息。
1230
+ 想知道一个IP地址或域名来自地球的哪个角落?这个接口可以帮你定位它。你可以使用默认数据源,也可以指定 `source=commercial` 参数来查询更详细的商业级IP归属信息。
1046
1231
 
1047
1232
  ## 功能概述
1048
- 提供一个公网IPv4、IPv6地址或域名,我们会利用GeoIP数据库查询并返回它的地理位置(国家、省份、城市)、经纬度、以及所属的运营商(ISP)和自治系统(ASN)信息。这在网络安全分析、访问来源统计等领域非常有用。
1233
+ 提供一个公网IPv4、IPv6地址或域名,我们会查询并返回它的地理位置(国家、省份、城市)、经纬度、以及所属的运营商(ISP)和自治系统(ASN)信息。这在网络安全分析、访问来源统计等领域非常有用。
1049
1234
 
1050
1235
  当使用 `source=commercial` 参数时,接口将调用高性能商业API,提供更精确的市、区、运营商、时区、海拔等信息。请注意,商业查询的响应时间可能会稍长。
1051
1236
  """
@@ -1064,7 +1249,7 @@ class _NetworkApi:
1064
1249
 
1065
1250
  def get_network_myip(self, **kwargs):
1066
1251
  r"""查询我的 IP
1067
- 想知道你自己的出口公网IP是多少吗?这个接口就是你的“网络身份证”。你可以选择使用默认的GeoIP数据库,也可以指定 `source=commercial` 参数来查询更详细的商业级IP归属信息。
1252
+ 想知道你自己的出口公网IP是多少吗?这个接口就是你的“网络身份证”。你可以使用默认数据源,也可以指定 `source=commercial` 参数来查询更详细的商业级IP归属信息。
1068
1253
 
1069
1254
  ## 功能概述
1070
1255
  调用此接口,它会返回你(即发起请求的客户端)的公网IP地址,并附带与 `/network/ipinfo` 接口相同的地理位置和网络归属信息。非常适合用于在网页上向用户展示他们自己的IP和地理位置。
@@ -1141,9 +1326,6 @@ class _NetworkApi:
1141
1326
 
1142
1327
  ## 功能概述
1143
1328
  提供一个URL,我们会向它发起一个请求,并返回其HTTP响应状态码。这是一种简单而有效的服务可用性监控方法。
1144
-
1145
- > [!TIP]
1146
- > **性能优化**:为了提高效率并减少对目标服务器的负载,我们实际发送的是 `HEAD` 请求,而不是 `GET` 请求。`HEAD` 请求只会获取响应头,而不会下载整个页面内容,因此速度更快。
1147
1329
  """
1148
1330
  params = {}
1149
1331
  body = {}
@@ -1266,30 +1448,28 @@ class _RandomApi:
1266
1448
  > 如果你需要更精确地控制图片类型,请使用 `/image/random/{category}/{type}` 接口。
1267
1449
 
1268
1450
  ### 支持的主类别与子类别
1269
- - **UapiPro服务器图片**
1451
+ - **acg**(二次元动漫)
1452
+ - pc
1453
+ - mb
1454
+ - **外部图床精选/混合动漫**
1455
+ - **landscape**: 风景图。
1456
+ - **anime**: 混合了UapiPro服务器的acg和外部图床的general_anime分类下的图片。
1457
+ - **pc_wallpaper**: 电脑壁纸。
1458
+ - **mobile_wallpaper**: 手机壁纸。
1459
+ - **general_anime**: 动漫图。
1460
+ - **ai_drawing**: AI绘画。
1461
+ - **其他分类**
1462
+ - **bq**(表情包/趣图)
1463
+ - eciyuan
1464
+ - ikun
1465
+ - xiongmao
1466
+ - waiguoren
1467
+ - maomao
1270
1468
  - **furry**(福瑞)
1271
1469
  - z4k
1272
1470
  - szs8k
1273
1471
  - s4k
1274
1472
  - 4k
1275
- - **bq**(表情包/趣图)
1276
- - youshou
1277
- - xiongmao
1278
- - waiguoren
1279
- - maomao
1280
- - ikun
1281
- - eciyuan
1282
- - **acg**(二次元动漫)
1283
- - pc
1284
- - mb
1285
- - **外部图床精选图片**
1286
- - **ai_drawing**: AI绘画。
1287
- - **general_anime**: 动漫图。
1288
- - **landscape**: 风景图。
1289
- - **mobile_wallpaper**: 手机壁纸。
1290
- - **pc_wallpaper**: 电脑壁纸。
1291
- - **混合动漫**
1292
- - **anime**: 混合了UapiPro服务器的acg和外部图床的general_anime分类下的图片。
1293
1473
 
1294
1474
  > [!NOTE]
1295
1475
  > 默认全局随机(未指定category参数)时,不会包含ikun和AI绘画(ai_drawing)类别的图片。
@@ -1479,7 +1659,11 @@ class _SocialApi:
1479
1659
  通过视频的 `oid`(通常就是视频的`aid`),你可以分页获取该视频的评论区内容。你可以指定排序方式和分页参数,来精确地获取你需要的数据。
1480
1660
 
1481
1661
  ## 参数说明
1482
- - **`sort` (排序方式)**: `0`=按时间排序, `1`=按点赞数排序, `2`=按回复数排序。默认为按时间排序。
1662
+ - **`sort` (排序方式)**
1663
+ - `0` 或 `time`:按时间排序
1664
+ - `1` 或 `like`:按点赞排序
1665
+ - `2` 或 `reply`:按回复数排序
1666
+ - `3` 或 `hot`(也支持 `hottest`、`最热`):按最热排序
1483
1667
 
1484
1668
  ## 响应体字段说明
1485
1669
  - **`hots` (热门评论)**: 仅在请求第一页时,可能会返回热门评论列表。其结构与 `replies` 中的对象一致。
@@ -1551,10 +1735,7 @@ class _SocialApi:
1551
1735
 
1552
1736
  def get_social_qq_groupinfo(self, **kwargs):
1553
1737
  r"""查询 QQ 群信息
1554
- 想在你的应用里展示QQ群信息?这个接口让你轻松获取群名称、群头像、群简介、成员数量等详细公开信息。它能帮你快速构建社群导航站、群聊推荐系统,或是为你的数据分析工具提供可靠的数据源。
1555
-
1556
- > [!VIP]
1557
- > 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
1738
+ 想在你的应用里展示QQ群信息?这个接口让你轻松获取群名称、群头像、群简介、成员数量等详细公开信息。
1558
1739
 
1559
1740
  ## 功能概述
1560
1741
  你只需要提供一个QQ群号(5-12位纯数字),接口就会返回该群的完整公开信息。我们会先验证群号的有效性,确保返回的数据准确可靠。接口响应速度快,数据结构清晰,非常适合集成到各类应用场景中。
@@ -1594,9 +1775,6 @@ class _SocialApi:
1594
1775
  r"""查询 QQ 信息
1595
1776
  这是一个功能丰富的QQ用户信息查询接口,能够获取QQ用户的详细公开信息。
1596
1777
 
1597
- > [!VIP]
1598
- > 我们在近日优化了此接口,速度应该会更加快了。
1599
-
1600
1778
  ## 功能概述
1601
1779
  通过QQ号查询用户的详细信息,包括基础资料、等级信息、VIP状态等。返回的信息丰富全面,适合用于用户画像分析、社交应用集成等场景。
1602
1780
 
@@ -2067,7 +2245,7 @@ class _TranslateApi:
2067
2245
 
2068
2246
  def get_ai_translate_languages(self, **kwargs):
2069
2247
  r"""AI翻译配置
2070
- 获取AI智能翻译服务支持的完整语言列表、翻译风格选项、上下文场景选项以及性能指标信息。这个接口对于需要在前端动态展示翻译配置选项的应用非常有用,它会返回当前AI翻译服务所支持的所有语言代码、原生名称、翻译风格说明、上下文场景描述,以及服务的性能特征和限制信息。通过此接口,开发者可以构建用户友好的翻译界面,让用户选择合适的翻译参数。
2248
+ 获取AI智能翻译服务支持的完整语言列表、翻译风格选项、上下文场景选项以及性能指标信息。
2071
2249
  """
2072
2250
  params = {}
2073
2251
  body = {}
@@ -2078,21 +2256,18 @@ class _TranslateApi:
2078
2256
 
2079
2257
  def post_ai_translate(self, **kwargs):
2080
2258
  r"""AI智能翻译
2081
- 这是一个商业级的AI智能翻译服务,采用最新的神经网络翻译技术和大语言模型,提供远超传统机器翻译的质量。它不仅能够智能处理单个文本翻译,还支持高效的批量文本翻译,并且具备上下文感知、风格适配、格式保留等高级功能。
2082
-
2083
- > [!VIP]
2084
- > 本API目前处于**限时免费**阶段,我们鼓励开发者深度集成和测试。未来,它将转为付费API,为用户提供更稳定、更智能的翻译服务。
2259
+ 这是一个商业级的AI智能翻译服务,采用最新的神经网络翻译技术和大语言模型,提供远超传统机器翻译的质量。
2085
2260
 
2086
2261
  ## 功能概述
2087
2262
 
2088
- - **智能双模式**: 支持单个文本翻译和批量文本翻译的统一接口设计,自动识别请求类型并提供相应的翻译服务。系统会根据输入自动判断是处理单条文本还是批量文本,无需使用不同的接口。
2263
+ - **单文本翻译**: 专注处理单条文本翻译,适合需要高质量译文的业务场景。
2089
2264
  - **多风格适配**: 提供随意口语化、专业商务、学术正式、文学艺术四种翻译风格,能够根据不同场景需求调整翻译的语言风格和表达方式。
2090
2265
  - **上下文感知**: 支持通用、商务、技术、医疗、法律、市场营销、娱乐、教育、新闻等九种专业领域的上下文翻译,确保术语准确性和表达地道性。
2091
- - **高质量保证**: 内置质量评估系统,对每次翻译结果进行流畅度、准确度、完整性评分,并提供置信度分数和替代翻译建议。
2092
- - **智能解释**: 提供关键词组翻译注释、文化背景说明和语法结构分析,帮助用户理解翻译逻辑和文化差异。
2093
- - **高效批量**: 批量翻译支持最多50条文本,总计10万字符,配备智能并发控制(1-10并发)和失败重试机制。
2094
- - **快速模式**: 提供快速模式选项,在保证95%+准确率的前提下,响应时间缩短至800ms内,适合实时翻译和聊天应用。
2095
2266
  - **格式保留**: 智能识别并保持原文的格式结构,包括换行、缩进、特殊符号等,确保翻译后的文本保持良好的可读性。
2267
+
2268
+ ## 支持的语言
2269
+
2270
+ 我们支持超过100种语言的互译,详见下方参数列表。
2096
2271
  """
2097
2272
  params = {}
2098
2273
  body = {}
@@ -2104,12 +2279,6 @@ class _TranslateApi:
2104
2279
  if "context" in kwargs:
2105
2280
  body["context"] = kwargs["context"]
2106
2281
 
2107
- if "fast_mode" in kwargs:
2108
- body["fast_mode"] = kwargs["fast_mode"]
2109
-
2110
- if "max_concurrency" in kwargs:
2111
- body["max_concurrency"] = kwargs["max_concurrency"]
2112
-
2113
2282
  if "preserve_format" in kwargs:
2114
2283
  body["preserve_format"] = kwargs["preserve_format"]
2115
2284
 
@@ -2122,9 +2291,6 @@ class _TranslateApi:
2122
2291
  if "text" in kwargs:
2123
2292
  body["text"] = kwargs["text"]
2124
2293
 
2125
- if "texts" in kwargs:
2126
- body["texts"] = kwargs["texts"]
2127
-
2128
2294
  path = "/api/v1/ai/translate"
2129
2295
 
2130
2296
  return self._http.request("POST", path, params=params, json=body if body else None)
@@ -2200,25 +2366,23 @@ class _WebparseApi:
2200
2366
 
2201
2367
  def get_web_tomarkdown_async_status(self, **kwargs):
2202
2368
  r"""转换任务状态
2203
- 提交了URL转Markdown任务后,想知道处理进度和结果?这个接口可以帮你实时追踪。
2369
+ 提交了网页转 Markdown 任务后,想知道处理进度和结果?用这个接口来查询。
2204
2370
 
2205
2371
  ## 功能概述
2372
+ 通过任务 ID 查询转换任务的当前状态、处理进度和最终结果。任务结果缓存 30 分钟,期间可重复查询。
2206
2373
 
2207
- 通过之前提交任务时获得的任务ID,你可以查询该任务的当前状态、处理进度以及最终结果。任务结果会在缓存中保存30分钟,期间可以重复查询,非常方便。
2208
-
2209
- 任务有五种状态:等待处理(pending)时进度为0%;处理中(processing)时进度在10-90%之间;已完成(completed)时进度为100%并返回Markdown内容;失败(failed)时会返回错误信息;超时(timeout)表示任务处理时间超过60秒已被取消。建议采用指数退避策略进行轮询,初始延迟1秒,每次延迟增加20%,最大延迟5秒。当状态为已完成、失败或超时时停止轮询。
2210
-
2211
- 系统会自动管理任务生命周期,单个任务最长处理时间为60秒,任务结果保存30分钟后自动清理,每5分钟清理一次过期任务。
2374
+ ## 任务状态
2212
2375
 
2213
- ## 任务状态说明
2376
+ | 状态 | 说明 |
2377
+ |------|------|
2378
+ | `pending` | 等待处理 |
2379
+ | `processing` | 处理中 |
2380
+ | `completed` | 已完成,可获取结果 |
2381
+ | `failed` | 失败 |
2382
+ | `timeout` | 超时(超过 60 秒) |
2214
2383
 
2215
- | 状态 | 说明 | 进度 | 轮询建议 |
2216
- |------|------|------|----------|
2217
- | `pending` | 等待处理 | 0% | 立即开始轮询 |
2218
- | `processing` | 处理中 | 10-90% | 每2-5秒轮询一次 |
2219
- | `completed` | 已完成 | 100% | 停止轮询,获取结果 |
2220
- | `failed` | 失败 | 100% | 停止轮询,查看错误信息 |
2221
- | `timeout` | 超时 | 100% | 停止轮询,任务已取消 |
2384
+ > [!NOTE]
2385
+ > 建议每 2-5 秒轮询一次,当状态为 `completed`、`failed` 或 `timeout` 时停止轮询。
2222
2386
  """
2223
2387
  params = {}
2224
2388
  body = {}
@@ -2235,10 +2399,10 @@ class _WebparseApi:
2235
2399
 
2236
2400
  def get_webparse_extractimages(self, **kwargs):
2237
2401
  r"""提取网页图片
2238
- 想一次性“打包”一个网页上的所有图片吗?这个接口可以帮你实现。
2402
+ 想批量获取一个网页上的所有图片链接?这个接口帮你搞定。
2239
2403
 
2240
2404
  ## 功能概述
2241
- 你提供一个网页的URL,我们会访问该页面,解析其HTML内容,并提取出所有 `<img>` 标签中的图片链接,然后将这些链接列表返回给你。非常适合用于制作图片采集器或素材下载工具。
2405
+ 提供一个网页 URL,返回该页面中所有图片的链接列表。适合用于图片采集、素材下载等场景。
2242
2406
  """
2243
2407
  params = {}
2244
2408
  body = {}
@@ -2251,11 +2415,11 @@ class _WebparseApi:
2251
2415
  return self._http.request("GET", path, params=params, json=body if body else None)
2252
2416
 
2253
2417
  def get_webparse_metadata(self, **kwargs):
2254
- r"""网页元数据
2255
- 当你在应用中需要展示一个链接的预览时(就像微信或Telegram里那样),这个接口能帮你轻松获取所需信息。
2418
+ r"""提取网页元数据
2419
+ 想在应用里做链接预览卡片?这个接口帮你一键获取网页的标题、描述、图标等信息。
2256
2420
 
2257
2421
  ## 功能概述
2258
- 你提供一个网页的URL,我们会抓取并解析它的 `<head>` 部分,提取出关键的元数据(Metadata),如页面标题(Title)、描述(Description)、关键词(Keywords)以及网站图标(Favicon)等。
2422
+ 提供一个网页 URL,返回该页面的元数据,包括标题、描述、关键词、Favicon、Open Graph 信息等。非常适合用于生成链接预览卡片或做 SEO 分析。
2259
2423
  """
2260
2424
  params = {}
2261
2425
  body = {}
@@ -2269,20 +2433,13 @@ class _WebparseApi:
2269
2433
 
2270
2434
  def post_web_tomarkdown_async(self, **kwargs):
2271
2435
  r"""网页转 Markdown
2272
- 想要将复杂的网页转换为结构清晰的Markdown?这个接口采用异步处理模式,特别适合处理大型网页、复杂网站或需要长时间处理的转换任务。
2436
+ 想把一个网页的内容转成干净的 Markdown 文本?这个异步接口可以帮你搞定,特别适合处理大型或复杂的网页。
2273
2437
 
2274
2438
  ## 功能概述
2275
2439
 
2276
- > [!VIP]
2277
- >本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
2278
-
2279
- UAPI Pro平台推出的异步网页转Markdown API能够将任意网页URL转换为结构清晰、格式优美的Markdown文本。提交任务后立即返回任务ID,不会阻塞客户端等待。您可以通过任务ID实时查询转换进度和处理状态,支持长达60秒的处理时间,轻松应对大型网站、需要JS渲染的单页应用等复杂页面。任务结果会缓存30分钟,期间可重复查询,过期任务自动清理无需手动管理。
2280
-
2281
- 此API采用先进算法,自动识别并抓取网页主体内容,精准剔除广告、导航栏、页眉页脚等无关元素。完美保留原文的格式,包括标题、列表、代码块、表格、引用、图片等,并输出为兼容性强的GitHub Flavored Markdown (GFM) 格式。同时会自动解析并提取文章标题、作者、发布日期、站点名称等关键元数据,并将其格式化为标准的YAML Front Matter,方便后续处理和CMS集成。
2440
+ 提交一个网页 URL,我们会自动抓取主体内容,剔除广告、导航栏等干扰元素,并转换为 Markdown 格式。同时会提取标题、作者、发布日期等元数据,生成 YAML Front Matter。
2282
2441
 
2283
- ## 使用流程
2284
-
2285
- 调用本接口提交URL转换任务后,会立即获得一个唯一的任务ID。随后使用任务ID调用查询接口,获取任务状态和进度。任务完成后,从查询接口的响应中获取Markdown内容。
2442
+ 任务提交后会立即返回任务 ID,你可以用它来查询处理进度和结果。单个任务最长处理 60 秒,结果缓存 30 分钟。
2286
2443
  """
2287
2444
  params = {}
2288
2445
  body = {}
@@ -2316,28 +2473,17 @@ class _MinGanCiShiBieApi:
2316
2473
 
2317
2474
  def post_sensitive_word_analyze(self, **kwargs):
2318
2475
  r"""分析敏感词
2319
- 分析单个或多个关键词的敏感程度,返回详细的风险评分和分析结果。
2320
-
2321
- > [!VIP]
2322
- > 本API基于先进的分析模型,提供三级缓存策略和并发处理能力。
2476
+ 分析单个或多个关键词的敏感程度,返回标准化风险标签与置信度结果。
2323
2477
 
2324
2478
  ## 功能概述
2325
2479
 
2326
2480
  - **模型驱动**: 使用先进的分析模型进行语义分析。
2327
2481
  - **高性能**: 采用三级缓存策略(持久化存储 → 统一缓存 → 模型分析),确保高频请求的响应速度。
2328
2482
  - **并发支持**: 支持批量并发处理,单次最多可分析100个关键词。
2329
- - **详细评分**: 提供色情、辱骂、暴力三个维度的详细风险评分。
2330
- - **变体识别**: 能够自动识别关键词的常见变体形式,如拼音、缩写等。
2331
-
2332
- ## 风险评分说明
2333
-
2334
- 返回的 `s` 字段包含三个维度的风险评分,范围均为0.0至1.0:
2335
-
2336
- - **s[0] - 色情风险**: 评估内容涉及色情信息的程度。
2337
- - **s[1] - 辱骂/仇恨言论风险**: 评估内容是否包含侮辱性或仇恨性言论。
2338
- - **s[2] - 暴力/威胁风险**: 评估内容是否涉及暴力或威胁信息。
2339
-
2340
- 风险等级可参考:0.0-0.3为低风险,0.3-0.7为中等风险,0.7-1.0为高风险。
2483
+ - **输入限制**: 单条关键词最多 1,000 字符,总字符数最多 20,000。
2484
+ - **标准标签**: 返回 `label` 字段,明确区分 `sensitive` 与 `normal`。
2485
+ - **分类清晰**: 返回 `category` 字段,用于标识具体风险类别。
2486
+ - **置信度输出**: 返回 `confidence` 字段,范围为0.0到1.0。
2341
2487
 
2342
2488
  ## 响应字段说明
2343
2489
 
@@ -2345,11 +2491,9 @@ class _MinGanCiShiBieApi:
2345
2491
  |------|------|------|
2346
2492
  | `results` | array | 分析结果对象的数组。 |
2347
2493
  | `results[].k` | string | 您在请求中提供的原始关键词。 |
2348
- | `results[].r` | string | 模型对该关键词的分析过程和判断理由的简要说明。 |
2349
- | `results[].s` | array[float] | 一个包含三个浮点数的数组,分别代表[色情, 辱骂, 暴力]三个维度的风险评分。分值范围从0.0到1.0,越高代表风险越大。 |
2350
- | `results[].v` | array[string] | 模型识别出的该关键词的常见变体形式,例如拼音、谐音、缩写等。 |
2351
- | `results[].t` | array[string] | 根据分析结果为关键词附加的分类标签,便于进行程序化处理和过滤。 |
2352
- | `results[].d` | string | 对整体分析结果的一句简短总结,适合直接展示给用户或记录在日志中。 |
2494
+ | `results[].label` | string | 核心判断字段:`sensitive`(敏感)、`normal`(正常)。 |
2495
+ | `results[].category` | string | 风险分类:`safe`(安全)、`threat`(威胁)、`porn`(色情)、`fraud`(欺诈)、`insult`(辱骂)。 |
2496
+ | `results[].confidence` | number | 当前分类的置信度,范围0.0到1.0。 |
2353
2497
  | `total` | integer | 本次请求成功分析的关键词总数。 |
2354
2498
 
2355
2499
  """
@@ -2433,9 +2577,6 @@ UAPI Pro Search 是一个智能搜索引擎,采用机器学习算法对搜索
2433
2577
  - **时间范围过滤**: 支持按天/周/月/年过滤结果
2434
2578
  - **站内搜索**: 支持 `site:` 操作符,在指定网站内搜索
2435
2579
  - **文件类型过滤**: 支持 `filetype:` 操作符,快速找到 PDF、Word 等特定格式文件
2436
-
2437
- > [!VIP]
2438
- > 本API目前处于**限时免费**阶段,我们鼓励开发者集成和测试。未来,它将转为付费API,为用户提供更稳定和强大的服务。
2439
2580
 
2440
2581
  """
2441
2582
  params = {}
@@ -0,0 +1,335 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass, field
3
+ from typing import Any, Dict, Mapping, Optional
4
+ import httpx
5
+
6
+ @dataclass
7
+ class RateLimitPolicyEntry:
8
+ name: str
9
+ quota: Optional[int] = None
10
+ unit: Optional[str] = None
11
+ window_seconds: Optional[int] = None
12
+
13
+ @dataclass
14
+ class RateLimitStateEntry:
15
+ name: str
16
+ remaining: Optional[int] = None
17
+ unit: Optional[str] = None
18
+ reset_after_seconds: Optional[int] = None
19
+
20
+ @dataclass
21
+ class ResponseMeta:
22
+ request_id: Optional[str] = None
23
+ retry_after_seconds: Optional[int] = None
24
+ debit_status: Optional[str] = None
25
+ credits_requested: Optional[int] = None
26
+ credits_charged: Optional[int] = None
27
+ credits_pricing: Optional[str] = None
28
+ active_quota_buckets: Optional[int] = None
29
+ stop_on_empty: Optional[bool] = None
30
+ rate_limit_policy_raw: Optional[str] = None
31
+ rate_limit_raw: Optional[str] = None
32
+ rate_limit_policies: Dict[str, RateLimitPolicyEntry] = field(default_factory=dict)
33
+ rate_limits: Dict[str, RateLimitStateEntry] = field(default_factory=dict)
34
+ balance_limit_cents: Optional[int] = None
35
+ balance_remaining_cents: Optional[int] = None
36
+ quota_limit_credits: Optional[int] = None
37
+ quota_remaining_credits: Optional[int] = None
38
+ visitor_quota_limit_credits: Optional[int] = None
39
+ visitor_quota_remaining_credits: Optional[int] = None
40
+ raw_headers: Dict[str, str] = field(default_factory=dict)
41
+
42
+ class UapiError(Exception):
43
+ code: str
44
+ status: int
45
+ message: str
46
+ details: Any
47
+ payload: Any
48
+ meta: Optional[ResponseMeta]
49
+
50
+ def __init__(
51
+ self,
52
+ code: str,
53
+ status: int,
54
+ message: str,
55
+ details: Any = None,
56
+ payload: Any = None,
57
+ meta: Optional[ResponseMeta] = None,
58
+ ):
59
+ super().__init__(f"[{status}] {code}: {message}")
60
+ self.code = code
61
+ self.status = status
62
+ self.message = message
63
+ self.details = details
64
+ self.payload = payload
65
+ self.meta = meta
66
+
67
+
68
+ class ApiErrorError(UapiError):
69
+ """上游/内部错误 (API_ERROR)"""
70
+ DEFAULT_STATUS = 502
71
+
72
+ class AvatarNotFoundError(UapiError):
73
+ """头像未找到 (AVATAR_NOT_FOUND)"""
74
+ DEFAULT_STATUS = 404
75
+
76
+ class ConversionFailedError(UapiError):
77
+ """转换失败 (CONVERSION_FAILED)"""
78
+ DEFAULT_STATUS = 400
79
+
80
+ class FileOpenErrorError(UapiError):
81
+ """文件打开错误 (FILE_OPEN_ERROR)"""
82
+ DEFAULT_STATUS = 500
83
+
84
+ class FileRequiredError(UapiError):
85
+ """文件必需 (FILE_REQUIRED)"""
86
+ DEFAULT_STATUS = 400
87
+
88
+ class InsufficientCreditsError(UapiError):
89
+ """账户积分不足 (INSUFFICIENT_CREDITS)"""
90
+ DEFAULT_STATUS = 402
91
+
92
+ class InternalServerErrorError(UapiError):
93
+ """服务器内部错误 (INTERNAL_SERVER_ERROR)"""
94
+ DEFAULT_STATUS = 500
95
+
96
+ class InvalidParameterError(UapiError):
97
+ """请求参数错误 (INVALID_PARAMETER)"""
98
+ DEFAULT_STATUS = 400
99
+
100
+ class InvalidParamsError(UapiError):
101
+ """无效参数 (INVALID_PARAMS)"""
102
+ DEFAULT_STATUS = 400
103
+
104
+ class NotFoundError(UapiError):
105
+ """资源不存在 (NOT_FOUND)"""
106
+ DEFAULT_STATUS = 404
107
+
108
+ class NoMatchError(UapiError):
109
+ """无匹配 (NO_MATCH)"""
110
+ DEFAULT_STATUS = 404
111
+
112
+ class NoTrackingDataError(UapiError):
113
+ """无物流数据 (NO_TRACKING_DATA)"""
114
+ DEFAULT_STATUS = 404
115
+
116
+ class PhoneInfoFailedError(UapiError):
117
+ """手机号信息查询失败 (PHONE_INFO_FAILED)"""
118
+ DEFAULT_STATUS = 500
119
+
120
+ class RecognitionFailedError(UapiError):
121
+ """识别失败 (RECOGNITION_FAILED)"""
122
+ DEFAULT_STATUS = 404
123
+
124
+ class RequestEntityTooLargeError(UapiError):
125
+ """错误 (REQUEST_ENTITY_TOO_LARGE)"""
126
+ DEFAULT_STATUS = 413
127
+
128
+ class ServiceBusyError(UapiError):
129
+ """请求过于频繁 (SERVICE_BUSY)"""
130
+ DEFAULT_STATUS = 429
131
+
132
+ class TimezoneNotFoundError(UapiError):
133
+ """时区未找到 (TIMEZONE_NOT_FOUND)"""
134
+ DEFAULT_STATUS = 404
135
+
136
+ class UnauthorizedError(UapiError):
137
+ """请求未授权 (UNAUTHORIZED)"""
138
+ DEFAULT_STATUS = 401
139
+
140
+ class UnsupportedCarrierError(UapiError):
141
+ """不支持的承运商 (UNSUPPORTED_CARRIER)"""
142
+ DEFAULT_STATUS = 404
143
+
144
+ class UnsupportedFormatError(UapiError):
145
+ """格式不支持 (UNSUPPORTED_FORMAT)"""
146
+ DEFAULT_STATUS = 400
147
+
148
+ class VisitorMonthlyQuotaExhaustedError(UapiError):
149
+ """访客月度免费额度已用尽 (VISITOR_MONTHLY_QUOTA_EXHAUSTED)"""
150
+ DEFAULT_STATUS = 429
151
+
152
+
153
+ def _default_code(status: int) -> str:
154
+ if status == 400:
155
+ return "INVALID_PARAMETER"
156
+ if status == 401:
157
+ return "UNAUTHORIZED"
158
+ if status == 402:
159
+ return "INSUFFICIENT_CREDITS"
160
+ if status == 404:
161
+ return "NOT_FOUND"
162
+ if status == 413:
163
+ return "REQUEST_ENTITY_TOO_LARGE"
164
+ if status == 429:
165
+ return "SERVICE_BUSY"
166
+ if status >= 500:
167
+ return "INTERNAL_SERVER_ERROR"
168
+ return "API_ERROR"
169
+
170
+ def _parse_int(value: Optional[str]) -> Optional[int]:
171
+ if value is None:
172
+ return None
173
+ try:
174
+ return int(value)
175
+ except (TypeError, ValueError):
176
+ return None
177
+
178
+ def _parse_bool(value: Optional[str]) -> Optional[bool]:
179
+ if value is None:
180
+ return None
181
+ lowered = value.strip().lower()
182
+ if lowered == "true":
183
+ return True
184
+ if lowered == "false":
185
+ return False
186
+ return None
187
+
188
+ def _unquote(value: str) -> str:
189
+ text = value.strip()
190
+ if len(text) >= 2 and text[0] == '"' and text[-1] == '"':
191
+ return text[1:-1]
192
+ return text
193
+
194
+ def _parse_structured_items(raw: Optional[str]) -> list[tuple[str, Dict[str, str]]]:
195
+ if not raw:
196
+ return []
197
+ items: list[tuple[str, Dict[str, str]]] = []
198
+ for chunk in [part.strip() for part in raw.split(",") if part.strip()]:
199
+ segments = [segment.strip() for segment in chunk.split(";") if segment.strip()]
200
+ if not segments:
201
+ continue
202
+ name = _unquote(segments[0])
203
+ params: Dict[str, str] = {}
204
+ for segment in segments[1:]:
205
+ if "=" not in segment:
206
+ continue
207
+ key, value = segment.split("=", 1)
208
+ params[key.strip()] = _unquote(value)
209
+ items.append((name, params))
210
+ return items
211
+
212
+ def extract_meta(headers: Mapping[str, str]) -> ResponseMeta:
213
+ raw_headers = {str(key).lower(): str(value) for key, value in headers.items()}
214
+ rate_limit_policies: Dict[str, RateLimitPolicyEntry] = {}
215
+ rate_limits: Dict[str, RateLimitStateEntry] = {}
216
+
217
+ for name, params in _parse_structured_items(raw_headers.get("ratelimit-policy")):
218
+ rate_limit_policies[name] = RateLimitPolicyEntry(
219
+ name=name,
220
+ quota=_parse_int(params.get("q")),
221
+ unit=params.get("uapi-unit"),
222
+ window_seconds=_parse_int(params.get("w")),
223
+ )
224
+
225
+ for name, params in _parse_structured_items(raw_headers.get("ratelimit")):
226
+ rate_limits[name] = RateLimitStateEntry(
227
+ name=name,
228
+ remaining=_parse_int(params.get("r")),
229
+ unit=params.get("uapi-unit"),
230
+ reset_after_seconds=_parse_int(params.get("t")),
231
+ )
232
+
233
+ return ResponseMeta(
234
+ request_id=raw_headers.get("x-request-id"),
235
+ retry_after_seconds=_parse_int(raw_headers.get("retry-after")),
236
+ debit_status=raw_headers.get("uapi-debit-status"),
237
+ credits_requested=_parse_int(raw_headers.get("uapi-credits-requested")),
238
+ credits_charged=_parse_int(raw_headers.get("uapi-credits-charged")),
239
+ credits_pricing=raw_headers.get("uapi-credits-pricing"),
240
+ active_quota_buckets=_parse_int(raw_headers.get("uapi-quota-active-buckets")),
241
+ stop_on_empty=_parse_bool(raw_headers.get("uapi-stop-on-empty")),
242
+ rate_limit_policy_raw=raw_headers.get("ratelimit-policy"),
243
+ rate_limit_raw=raw_headers.get("ratelimit"),
244
+ rate_limit_policies=rate_limit_policies,
245
+ rate_limits=rate_limits,
246
+ balance_limit_cents=rate_limit_policies.get("billing-balance").quota if "billing-balance" in rate_limit_policies else None,
247
+ balance_remaining_cents=rate_limits.get("billing-balance").remaining if "billing-balance" in rate_limits else None,
248
+ quota_limit_credits=rate_limit_policies.get("billing-quota").quota if "billing-quota" in rate_limit_policies else None,
249
+ quota_remaining_credits=rate_limits.get("billing-quota").remaining if "billing-quota" in rate_limits else None,
250
+ visitor_quota_limit_credits=rate_limit_policies.get("visitor-quota").quota if "visitor-quota" in rate_limit_policies else None,
251
+ visitor_quota_remaining_credits=rate_limits.get("visitor-quota").remaining if "visitor-quota" in rate_limits else None,
252
+ raw_headers=raw_headers,
253
+ )
254
+
255
+ def _pick_details(data: Any) -> Any:
256
+ if not isinstance(data, dict):
257
+ return None
258
+ if "details" in data:
259
+ return data["details"]
260
+ if "quota" in data:
261
+ return data["quota"]
262
+ if "docs" in data:
263
+ return data["docs"]
264
+ return None
265
+
266
+ def map_error(r: httpx.Response) -> UapiError:
267
+ code = None
268
+ msg = r.text
269
+ data: Any = None
270
+ try:
271
+ data = r.json()
272
+ code = data.get("code") or data.get("error") or data.get("errCode") or _default_code(r.status_code)
273
+ msg = data.get("message") or data.get("errMsg") or msg
274
+ except Exception:
275
+ code = _default_code(r.status_code)
276
+ status = r.status_code
277
+ meta = extract_meta(r.headers)
278
+ cls = _class_by_code(code, status)
279
+ return cls(code, status, msg, _pick_details(data), data, meta)
280
+
281
+ def _class_by_code(code: str, status: int):
282
+ c = (code or "").upper()
283
+ mapping = {
284
+
285
+ "API_ERROR": ApiErrorError,
286
+
287
+ "AVATAR_NOT_FOUND": AvatarNotFoundError,
288
+
289
+ "CONVERSION_FAILED": ConversionFailedError,
290
+
291
+ "FILE_OPEN_ERROR": FileOpenErrorError,
292
+
293
+ "FILE_REQUIRED": FileRequiredError,
294
+
295
+ "INSUFFICIENT_CREDITS": InsufficientCreditsError,
296
+
297
+ "INTERNAL_SERVER_ERROR": InternalServerErrorError,
298
+
299
+ "INVALID_PARAMETER": InvalidParameterError,
300
+
301
+ "INVALID_PARAMS": InvalidParamsError,
302
+
303
+ "NOT_FOUND": NotFoundError,
304
+
305
+ "NO_MATCH": NoMatchError,
306
+
307
+ "NO_TRACKING_DATA": NoTrackingDataError,
308
+
309
+ "PHONE_INFO_FAILED": PhoneInfoFailedError,
310
+
311
+ "RECOGNITION_FAILED": RecognitionFailedError,
312
+
313
+ "REQUEST_ENTITY_TOO_LARGE": RequestEntityTooLargeError,
314
+
315
+ "SERVICE_BUSY": ServiceBusyError,
316
+
317
+ "TIMEZONE_NOT_FOUND": TimezoneNotFoundError,
318
+
319
+ "UNAUTHORIZED": UnauthorizedError,
320
+
321
+ "UNSUPPORTED_CARRIER": UnsupportedCarrierError,
322
+
323
+ "UNSUPPORTED_FORMAT": UnsupportedFormatError,
324
+
325
+ "VISITOR_MONTHLY_QUOTA_EXHAUSTED": VisitorMonthlyQuotaExhaustedError,
326
+
327
+ }
328
+ return mapping.get(c) or ({
329
+ 400: InvalidParameterError,
330
+ 401: UnauthorizedError,
331
+ 402: InsufficientCreditsError,
332
+ 404: NotFoundError,
333
+ 429: ServiceBusyError,
334
+ 500: InternalServerErrorError,
335
+ }.get(status) or UapiError)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uapi-sdk-python
3
- Version: 0.1.5
3
+ Version: 0.1.13
4
4
  Summary: Idiomatic UAPI SDK for Python
5
5
  Author-email: UAPI <dev@uapis.cn>
6
6
  Requires-Python: >=3.9
@@ -14,7 +14,7 @@ Requires-Dist: isort; extra == "dev"
14
14
 
15
15
  # uapi-sdk-python
16
16
 
17
- ![Banner](https://raw.githubusercontent.com/uapis/uapi-sdk-python/main/banner.png)
17
+ ![Banner](https://raw.githubusercontent.com/AxT-Team/uapi-sdk-python/main/banner.png)
18
18
 
19
19
  [![Python](https://img.shields.io/badge/Python-3.9+-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/)
20
20
  [![Docs](https://img.shields.io/badge/Docs-uapis.cn-2EAE5D?style=flat-square)](https://uapis.cn/)
@@ -1,153 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Any, Dict, Optional
3
- import httpx
4
-
5
- class UapiError(Exception):
6
- code: str
7
- status: int
8
- message: str
9
- details: Optional[Dict[str, Any]]
10
-
11
- def __init__(self, code: str, status: int, message: str, details: Optional[Dict[str, Any]] = None):
12
- super().__init__(f"[{status}] {code}: {message}")
13
- self.code = code
14
- self.status = status
15
- self.message = message
16
- self.details = details
17
-
18
-
19
- class ApiErrorError(UapiError):
20
- """上游/内部错误 (API_ERROR)"""
21
- DEFAULT_STATUS = 502
22
-
23
- class AvatarNotFoundError(UapiError):
24
- """头像未找到 (AVATAR_NOT_FOUND)"""
25
- DEFAULT_STATUS = 404
26
-
27
- class ConversionFailedError(UapiError):
28
- """转换失败 (CONVERSION_FAILED)"""
29
- DEFAULT_STATUS = 400
30
-
31
- class FileOpenErrorError(UapiError):
32
- """文件打开错误 (FILE_OPEN_ERROR)"""
33
- DEFAULT_STATUS = 500
34
-
35
- class FileRequiredError(UapiError):
36
- """文件必需 (FILE_REQUIRED)"""
37
- DEFAULT_STATUS = 400
38
-
39
- class InternalServerErrorError(UapiError):
40
- """服务器内部错误 (INTERNAL_SERVER_ERROR)"""
41
- DEFAULT_STATUS = 500
42
-
43
- class InvalidParameterError(UapiError):
44
- """请求参数错误 (INVALID_PARAMETER)"""
45
- DEFAULT_STATUS = 400
46
-
47
- class InvalidParamsError(UapiError):
48
- """无效参数 (INVALID_PARAMS)"""
49
- DEFAULT_STATUS = 400
50
-
51
- class NotFoundError(UapiError):
52
- """资源不存在 (NOT_FOUND)"""
53
- DEFAULT_STATUS = 404
54
-
55
- class NoMatchError(UapiError):
56
- """无匹配 (NO_MATCH)"""
57
- DEFAULT_STATUS = 404
58
-
59
- class NoTrackingDataError(UapiError):
60
- """无物流数据 (NO_TRACKING_DATA)"""
61
- DEFAULT_STATUS = 404
62
-
63
- class PhoneInfoFailedError(UapiError):
64
- """手机号信息查询失败 (PHONE_INFO_FAILED)"""
65
- DEFAULT_STATUS = 500
66
-
67
- class RecognitionFailedError(UapiError):
68
- """识别失败 (RECOGNITION_FAILED)"""
69
- DEFAULT_STATUS = 404
70
-
71
- class RequestEntityTooLargeError(UapiError):
72
- """错误 (REQUEST_ENTITY_TOO_LARGE)"""
73
- DEFAULT_STATUS = 413
74
-
75
- class ServiceBusyError(UapiError):
76
- """请求过于频繁 (SERVICE_BUSY)"""
77
- DEFAULT_STATUS = 429
78
-
79
- class TimezoneNotFoundError(UapiError):
80
- """时区未找到 (TIMEZONE_NOT_FOUND)"""
81
- DEFAULT_STATUS = 404
82
-
83
- class UnauthorizedError(UapiError):
84
- """请求未授权 (UNAUTHORIZED)"""
85
- DEFAULT_STATUS = 401
86
-
87
- class UnsupportedCarrierError(UapiError):
88
- """不支持的承运商 (UNSUPPORTED_CARRIER)"""
89
- DEFAULT_STATUS = 404
90
-
91
- class UnsupportedFormatError(UapiError):
92
- """格式不支持 (UNSUPPORTED_FORMAT)"""
93
- DEFAULT_STATUS = 400
94
-
95
-
96
- def map_error(r: httpx.Response) -> UapiError:
97
- code = None
98
- msg = r.text
99
- try:
100
- data = r.json()
101
- code = data.get("code") or data.get("error") or data.get("errCode") or "API_ERROR"
102
- msg = data.get("message") or data.get("errMsg") or msg
103
- details = data.get("details")
104
- except Exception:
105
- details = None
106
- status = r.status_code
107
- cls = _class_by_code(code, status)
108
- return cls(code, status, msg, details)
109
-
110
- def _class_by_code(code: str, status: int):
111
- c = (code or "").upper()
112
- mapping = {
113
-
114
- "API_ERROR": ApiErrorError,
115
-
116
- "AVATAR_NOT_FOUND": AvatarNotFoundError,
117
-
118
- "CONVERSION_FAILED": ConversionFailedError,
119
-
120
- "FILE_OPEN_ERROR": FileOpenErrorError,
121
-
122
- "FILE_REQUIRED": FileRequiredError,
123
-
124
- "INTERNAL_SERVER_ERROR": InternalServerErrorError,
125
-
126
- "INVALID_PARAMETER": InvalidParameterError,
127
-
128
- "INVALID_PARAMS": InvalidParamsError,
129
-
130
- "NOT_FOUND": NotFoundError,
131
-
132
- "NO_MATCH": NoMatchError,
133
-
134
- "NO_TRACKING_DATA": NoTrackingDataError,
135
-
136
- "PHONE_INFO_FAILED": PhoneInfoFailedError,
137
-
138
- "RECOGNITION_FAILED": RecognitionFailedError,
139
-
140
- "REQUEST_ENTITY_TOO_LARGE": RequestEntityTooLargeError,
141
-
142
- "SERVICE_BUSY": ServiceBusyError,
143
-
144
- "TIMEZONE_NOT_FOUND": TimezoneNotFoundError,
145
-
146
- "UNAUTHORIZED": UnauthorizedError,
147
-
148
- "UNSUPPORTED_CARRIER": UnsupportedCarrierError,
149
-
150
- "UNSUPPORTED_FORMAT": UnsupportedFormatError,
151
-
152
- }
153
- return mapping.get(c) or ( {400: InvalidParameterError, 401: UnauthorizedError, 404: NotFoundError, 429: ServiceBusyError, 500: InternalServerErrorError}.get(status) or UapiError )