jwf-common-python 1.0.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.
Files changed (60) hide show
  1. jwf_common_python/__init__.py +14 -0
  2. jwf_common_python/db_utils/__init__.py +6 -0
  3. jwf_common_python/db_utils/clickhouse.py +124 -0
  4. jwf_common_python/db_utils/elasticsearch.py +196 -0
  5. jwf_common_python/db_utils/mysql.py +64 -0
  6. jwf_common_python/eudic/__init__.py +5 -0
  7. jwf_common_python/eudic/wordbook.py +211 -0
  8. jwf_common_python/file_storage/__init__.py +2 -0
  9. jwf_common_python/file_storage/file_interface.py +29 -0
  10. jwf_common_python/file_storage/local.py +50 -0
  11. jwf_common_python/file_storage/tencent_cos.py +65 -0
  12. jwf_common_python/geography/__init__.py +8 -0
  13. jwf_common_python/geography/district_amap.py +181 -0
  14. jwf_common_python/geography/search_amap.py +84 -0
  15. jwf_common_python/github/__init__.py +5 -0
  16. jwf_common_python/github/webhooks.py +87 -0
  17. jwf_common_python/language_utils/__init__.py +34 -0
  18. jwf_common_python/language_utils/core.py +203 -0
  19. jwf_common_python/language_utils/files.py +52 -0
  20. jwf_common_python/language_utils/web.py +117 -0
  21. jwf_common_python/llm/__init__.py +1 -0
  22. jwf_common_python/llm/aliyun_qwen.py +10 -0
  23. jwf_common_python/llm/azure_gpt.py +66 -0
  24. jwf_common_python/llm/baidu_ernie.py +112 -0
  25. jwf_common_python/message_queue/__init__.py +7 -0
  26. jwf_common_python/message_queue/interface.py +49 -0
  27. jwf_common_python/message_queue/kafka.py +145 -0
  28. jwf_common_python/message_queue/rabbitmq.py +113 -0
  29. jwf_common_python/oauth2/__init__.py +0 -0
  30. jwf_common_python/oauth2/google.py +158 -0
  31. jwf_common_python/parse_subtitle/__init__.py +6 -0
  32. jwf_common_python/parse_subtitle/aa.vtt +2364 -0
  33. jwf_common_python/parse_subtitle/parse_srt_file.py +60 -0
  34. jwf_common_python/pdf/__init__.py +0 -0
  35. jwf_common_python/pdf/aaa.py +38 -0
  36. jwf_common_python/pdf/local_parse.py +259 -0
  37. jwf_common_python/sms/__init__.py +1 -0
  38. jwf_common_python/sms/interface.py +7 -0
  39. jwf_common_python/sms/tencent_sms.py +117 -0
  40. jwf_common_python/translate/__init__.py +152 -0
  41. jwf_common_python/translate/_youdao.py +234 -0
  42. jwf_common_python/translate/microsoft.py +696 -0
  43. jwf_common_python/translate/tencent.py +194 -0
  44. jwf_common_python/tts/__init__.py +0 -0
  45. jwf_common_python/tts/microsoft.py +87 -0
  46. jwf_common_python/utils/__init__.py +0 -0
  47. jwf_common_python/utils/image_utils.py +18 -0
  48. jwf_common_python/utils/tencent_utils.py +51 -0
  49. jwf_common_python/utils/utils.py +46 -0
  50. jwf_common_python/video/__init__.py +5 -0
  51. jwf_common_python/video/merge.py +276 -0
  52. jwf_common_python/weather/__init__.py +0 -0
  53. jwf_common_python/weather/amap.py +127 -0
  54. jwf_common_python/weather/wanwei.py +58 -0
  55. jwf_common_python/youdao/__init__.py +13 -0
  56. jwf_common_python/youdao/wordbook.py +88 -0
  57. jwf_common_python-1.0.0.dist-info/METADATA +669 -0
  58. jwf_common_python-1.0.0.dist-info/RECORD +60 -0
  59. jwf_common_python-1.0.0.dist-info/WHEEL +4 -0
  60. jwf_common_python-1.0.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,127 @@
1
+ import datetime
2
+
3
+ import requests
4
+
5
+
6
+ class WeatherAmap:
7
+ def __init__(self, key: str):
8
+ """
9
+ city: 城市的 adcode,adcode
10
+ extensions: base 返回实时天气, all 返回预报天气
11
+ """
12
+ self.key = key
13
+ self.base_url = (
14
+ f"https://restapi.amap.com/v3/weather/weatherInfo?key={self.key}"
15
+ )
16
+
17
+ def _send_request(self, url: str) -> dict:
18
+ response = requests.get(url)
19
+ if response.status_code != 200:
20
+ raise Exception("请求高德地图API失败")
21
+ res = response.json()
22
+
23
+ # 1. 校验响应状态
24
+ status = res["status"]
25
+ assert status == "1", f"请求高德地图API失败,status: {status}"
26
+ info = res.get("info")
27
+ assert info == "OK", f"请求高德地图API失败,info: {info}"
28
+ infocode = res.get("infocode")
29
+ assert infocode == "10000", f"请求高德地图API失败,infocode: {infocode}"
30
+
31
+ return res
32
+
33
+ def get_current_weather(self, city_name: str, city_adcode: str):
34
+ """获取实时/当前天气
35
+ 实况天气每小时更新多次,预报天气每天更新3次,分别在8、11、18点左右更新。
36
+
37
+ 返回结构:
38
+ {
39
+ "province": "河南",
40
+ "city": "新安县",
41
+ "adcode": "410323",
42
+ "weather": "晴",
43
+ "temperature": "19",
44
+ "winddirection": "东南",
45
+ "windpower": "≤3",
46
+ "humidity": "36",
47
+ "reporttime": "2024-10-23 14:00:05",
48
+ "temperature_float": "19.0",
49
+ "humidity_float": "36.0"
50
+ }
51
+ """
52
+ url = f"{self.base_url}&city={city_name}&extensions=base"
53
+ res = self._send_request(url)
54
+ lives_data = res["lives"]
55
+
56
+ # check1 结构检查
57
+ assert len(lives_data) == 1
58
+ live_data = lives_data[0]
59
+
60
+ assert live_data["city"] == city_name
61
+ assert live_data["adcode"] == city_adcode
62
+
63
+ return live_data
64
+
65
+ def get_forecast_weather(
66
+ self, city_name: str, city_adcode: str, isTodayForecast: bool = True
67
+ ) -> list[dict]:
68
+ """获取预报/未来天气
69
+ city_name: 城市名
70
+ adcode: 城市的 adcode
71
+ isTodayForecast: 是否获取今天的天气预报
72
+ - True 表示只获取今天的预报天气。list长度为1,仅有今天的数据. [默认值]
73
+ - False 表示获取未来3天的预报天气。list长度为4
74
+
75
+ 返回的数据结构:
76
+ {
77
+ "date": "2024-10-23",
78
+ "week": "3",
79
+ "dayweather": "晴",
80
+ "nightweather": "晴",
81
+ "daytemp": "20",
82
+ "nighttemp": "9",
83
+ "daywind": "东",
84
+ "nightwind": "东",
85
+ "daypower": "1-3",
86
+ "nightpower": "1-3",
87
+ "daytemp_float": "20.0",
88
+ "nighttemp_float": "9.0"
89
+ }
90
+ """
91
+ url = f"{self.base_url}&city={city_name}&extensions=all"
92
+ res = self._send_request(url)
93
+ forecasts_data = res["forecasts"]
94
+
95
+ # check1 结构检查
96
+ assert len(forecasts_data) == 1
97
+ forecast_data = forecasts_data[0]
98
+
99
+ # check2 数据准确性检查
100
+ city_res = forecast_data["city"]
101
+ assert city_res == city_name, f"请求的城市名与返回的城市名不一致: {city_res} != {city_name}"
102
+ adcode_res = forecast_data["adcode"]
103
+ assert (
104
+ adcode_res == city_adcode
105
+ ), f"请求的城市adcode与返回的城市adcode不一致: {adcode_res} != {city_adcode}"
106
+
107
+ # 解析核心数据
108
+ forecast_core_res = forecast_data["casts"]
109
+
110
+ if isTodayForecast:
111
+ # 只获取今天的天气预报
112
+
113
+ # 1. 获取今天的日期字符串
114
+ today_datetime: datetime.datetime = datetime.datetime.now()
115
+ today_date: str = today_datetime.strftime("%Y-%m-%d")
116
+
117
+ # 2. 获取今天的预报天气数据
118
+ today_forecast_res = forecast_core_res[0]
119
+
120
+ # 断言,校验数据获取是否准确
121
+ today_forecast_date = today_forecast_res["date"]
122
+ _msg = f"获取到的预报数据的日期不是今天: 预测日期:'{today_forecast_date}' 实际日期:'{today_date}'"
123
+ assert today_date == today_forecast_date, _msg
124
+ return [today_forecast_res]
125
+
126
+ # 获取未来3天的预报天气
127
+ return forecast_core_res
@@ -0,0 +1,58 @@
1
+ # 【万维易源服务商】
2
+ import requests
3
+
4
+
5
+ class WeatherWanwei:
6
+ """万维易源历史天气数据查询
7
+ https://market.aliyun.com/apimarket/detail/cmapi010812
8
+ """
9
+
10
+ def __init__(self, key: str):
11
+ self.key = key
12
+ self.base_url = "https://ali-weather.showapi.com/weatherhistory"
13
+
14
+ def get_history_weather(
15
+ self, city_name: str, city_adcode: str, year_month: str
16
+ ) -> list[dict]:
17
+ """获取指定地区、月份的历史天气数据
18
+ :param area: 地区名称,如新安县
19
+ :param month: 年月,格式为YYYYMM, 201601
20
+
21
+ :return: 历史天气数据
22
+ {
23
+ "aqiLevel": "6",
24
+ "wind_direction": "西南风",
25
+ "aqi": "406",
26
+ "wind_power": "微风",
27
+ "area": "新安",
28
+ "time": "20160101",
29
+ "min_temperature": "1",
30
+ "max_temperature": "12",
31
+ "aqiInfo": "严重",
32
+ "weather": "晴"
33
+ }
34
+ """
35
+ url = f"{self.base_url}?area={city_name}&month={year_month}"
36
+ headers = {"Authorization": f"APPCODE {self.key}"}
37
+ params = {"area": city_name, "month": year_month}
38
+ response = requests.get(url, headers=headers, params=params)
39
+
40
+ # check 1
41
+ if response.status_code != 200:
42
+ raise Exception(f"请求历史天气数据失败,状态码:{response.status_code}")
43
+ res = response.json()
44
+
45
+ # check2
46
+ showapi_res_error = res["showapi_res_error"]
47
+ if showapi_res_error != "":
48
+ raise Exception(f"请求历史天气数据失败,错误码:{showapi_res_error}")
49
+
50
+ # check3
51
+ showapi_res_body = res["showapi_res_body"]
52
+ remark = showapi_res_body["remark"]
53
+ areaCode_res = showapi_res_body["areaCode"]
54
+ if remark != "查询成功!" or areaCode_res != city_adcode:
55
+ raise Exception(f"请求历史天气数据失败,错误信息:{remark} {areaCode_res}")
56
+
57
+ data = showapi_res_body["list"]
58
+ return data
@@ -0,0 +1,13 @@
1
+ """有道单词本导出和单词过滤工具。"""
2
+
3
+ from .wordbook import (
4
+ fetch_all_wordbook_data,
5
+ fetch_wordbook_data,
6
+ filter_new_words,
7
+ )
8
+
9
+ __all__ = [
10
+ "fetch_wordbook_data",
11
+ "fetch_all_wordbook_data",
12
+ "filter_new_words",
13
+ ]
@@ -0,0 +1,88 @@
1
+ """有道单词本工具;不读写文件,不打印,不在导入时发起请求。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from typing import Any
7
+
8
+ import requests
9
+
10
+ WORDBOOK_URL = "https://youdao.com/wordbook/webapi/words"
11
+
12
+
13
+ def fetch_wordbook_data(
14
+ cookie: str,
15
+ limit: int = 15,
16
+ offset: int = 0,
17
+ timeout: float = 30,
18
+ ) -> dict[str, Any]:
19
+ """获取一页单词本,返回完整 JSON,保留所有响应字段。
20
+
21
+ cookie 为浏览器请求头中的完整 Cookie 字符串。
22
+ HTTP 错误、超时、JSON 解析失败直接抛出 requests 对应异常;
23
+ 接口返回失败状态时抛出 ValueError。
24
+ """
25
+ if not cookie.strip():
26
+ raise ValueError("cookie 不能为空")
27
+ if limit <= 0:
28
+ raise ValueError("limit 必须大于 0")
29
+ if offset < 0:
30
+ raise ValueError("offset 不能小于 0")
31
+
32
+ response = requests.get(
33
+ WORDBOOK_URL,
34
+ params={"limit": limit, "offset": offset},
35
+ headers={"Cookie": cookie},
36
+ timeout=timeout,
37
+ )
38
+ response.raise_for_status()
39
+ data = response.json()
40
+ if not isinstance(data, dict) or data.get("msg") != "SUCCESS":
41
+ raise ValueError("获取有道单词本失败,请检查登录状态和 Cookie")
42
+ return data
43
+
44
+
45
+ def fetch_all_wordbook_data(
46
+ cookie: str, limit: int = 15, timeout: float = 30
47
+ ) -> list[dict[str, Any]]:
48
+ """按页导出整个单词本,返回每页完整 JSON 响应组成的列表。
49
+
50
+ 单词及释义等原始字段位于每页的 data.itemList 中,不提取或删减字段。
51
+ 中途请求失败时抛出异常,不将部分结果当作完整导出返回。
52
+ """
53
+ pages = []
54
+ offset = 0
55
+ while True:
56
+ page = fetch_wordbook_data(cookie, limit=limit, offset=offset, timeout=timeout)
57
+ data = page.get("data")
58
+ if not isinstance(data, dict) or not isinstance(data.get("itemList"), list):
59
+ raise ValueError("有道单词本响应缺少 data.itemList")
60
+ total = data.get("total")
61
+ if not isinstance(total, int) or total < 0:
62
+ raise ValueError("有道单词本响应中的 total 无效")
63
+
64
+ pages.append(page)
65
+ items = data["itemList"]
66
+ offset += len(items)
67
+ if not items and offset < total:
68
+ raise ValueError("有道单词本尚未导出完毕,但接口返回了空页")
69
+ if offset >= total:
70
+ return pages
71
+
72
+
73
+ def filter_new_words(
74
+ existing_words: Iterable[str], current_words: Iterable[str]
75
+ ) -> list[str]:
76
+ """返回当前词表中尚未存在的单词,按当前顺序去重。
77
+
78
+ 两个参数均为单词字符串的可迭代对象;多行文本请先调用 splitlines()。
79
+ 去除首尾空白、忽略空词,保留大小写差异,不修改传入的词表。
80
+ """
81
+ seen = {word.strip() for word in existing_words}
82
+ new_words = []
83
+ for word in current_words:
84
+ word = word.strip()
85
+ if word and word not in seen:
86
+ seen.add(word)
87
+ new_words.append(word)
88
+ return new_words