MeUtils 2024.3.4.13.4.45__py3-none-any.whl → 2025.1.16.17.15.52__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 (582) hide show
  1. {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/METADATA +38 -32
  2. MeUtils-2025.1.16.17.15.52.dist-info/RECORD +864 -0
  3. {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/WHEEL +1 -1
  4. {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/entry_points.txt +1 -0
  5. apps/spider.py +24 -8
  6. examples/_openaisdk/4v.py +110 -0
  7. examples/_openaisdk/__init__.py +11 -0
  8. examples/_openaisdk/baichuan.py +38 -0
  9. examples/_openaisdk/bpo.py +138 -0
  10. examples/_openaisdk/chat_latex.py +95 -0
  11. examples/_openaisdk/chattts.py +85 -0
  12. examples/_openaisdk/copilot.py +48 -0
  13. examples/_openaisdk/dalle3.py +48 -0
  14. examples/_openaisdk/deeplx.py +31 -0
  15. examples/_openaisdk/demo.py +77 -0
  16. examples/_openaisdk/embeddings.py +34 -0
  17. examples/_openaisdk/gpt4all.py +69 -0
  18. examples/_openaisdk/gpt_fc.py +23 -0
  19. examples/_openaisdk/gr_vl.py +46 -0
  20. examples/_openaisdk/json_mode.py +12 -0
  21. examples/_openaisdk/kimi.py +91 -0
  22. examples/_openaisdk/kimi_qa.py +57 -0
  23. examples/_openaisdk/minimax.py +75 -0
  24. examples/_openaisdk/open_router.py +48 -0
  25. examples/_openaisdk/openai_aiplus.py +54 -0
  26. examples/_openaisdk/openai_audio.py +20 -0
  27. examples/_openaisdk/openai_baichuan.py +59 -0
  28. examples/_openaisdk/openai_cache.py +37 -0
  29. examples/_openaisdk/openai_chatfire.py +228 -0
  30. examples/_openaisdk/openai_chatfire_all.py +166 -0
  31. examples/_openaisdk/openai_deepinfra.py +55 -0
  32. examples/_openaisdk/openai_deepseek.py +29 -0
  33. examples/_openaisdk/openai_doubao.py +43 -0
  34. examples/_openaisdk/openai_embeddings.py +36 -0
  35. examples/_openaisdk/openai_files.py +57 -0
  36. examples/_openaisdk/openai_gitee.py +33 -0
  37. examples/_openaisdk/openai_god.py +45 -0
  38. examples/_openaisdk/openai_groq.py +240 -0
  39. examples/_openaisdk/openai_images.py +203 -0
  40. examples/_openaisdk/openai_json.py +78 -0
  41. examples/_openaisdk/openai_lingyi.py +59 -0
  42. examples/_openaisdk/openai_modelscope.py +54 -0
  43. examples/_openaisdk/openai_moon.py +55 -0
  44. examples/_openaisdk/openai_oi.py +61 -0
  45. examples/_openaisdk/openai_ppu.py +47 -0
  46. examples/_openaisdk/openai_qwen.py +58 -0
  47. examples/_openaisdk/openai_search.py +42 -0
  48. examples/_openaisdk/openai_sensenova.py +81 -0
  49. examples/_openaisdk/openai_siliconflow.py +52 -0
  50. examples/_openaisdk/openai_step.py +45 -0
  51. examples/_openaisdk/openai_test.py +66 -0
  52. examples/_openaisdk/openai_together.py +57 -0
  53. examples/_openaisdk/openai_tune.py +38 -0
  54. examples/_openaisdk/openai_zhipu.py +59 -0
  55. examples/_openaisdk/ppu.py +28 -0
  56. examples/_openaisdk/rag.py +54 -0
  57. examples/_openaisdk/rag_.py +26 -0
  58. examples/_openaisdk/test.py +52 -0
  59. examples/_openaisdk/x.py +32 -0
  60. examples/_openaisdk/xx.py +29 -0
  61. examples/_openaisdk/zhipu_files.py +47 -0
  62. examples/_openaisdk/zhipu_/346/231/272/350/203/275/344/275/223.py +45 -0
  63. examples/_openaisdk//345/205/234/345/272/225/346/265/213/350/257/225.py +50 -0
  64. examples/_openaisdk//345/244/232/346/250/241/346/200/201/346/265/213/350/257/225.py +76 -0
  65. examples/_openaisdk//345/244/232/346/250/241/346/200/201/346/265/213/350/257/225_.py +56 -0
  66. examples/_openaisdk//346/226/207/344/273/266/351/227/256/347/255/224.py +36 -0
  67. examples/_openaisdk//346/226/207/346/241/243/350/247/243/346/236/220.py +34 -0
  68. examples/_openaisdk//346/250/241/345/236/213/346/265/213/350/257/225.py +53 -0
  69. examples/_openaisdk//351/230/277/351/207/214.py +80 -0
  70. {meutils/serving/jina/__demo → examples/ann}/__init__.py +1 -1
  71. examples/ann/main.py +31 -0
  72. examples/apis/kl.py +28 -0
  73. examples/apis/x.py +17 -0
  74. examples/apis/xx.py +17 -0
  75. examples/arq_demo/demo.py +3 -0
  76. examples/backgroundtasks.py +25 -0
  77. examples/bserver.py +513 -21
  78. examples/cache_demo/HermesCache_demo.py +81 -0
  79. examples/cache_demo/acacge.py +26 -0
  80. examples/cache_demo/x.py +31 -0
  81. {meutils/docarray_utils → examples/caches}/__init__.py +1 -1
  82. examples/caches/llmcache.py +18 -0
  83. examples/celery_demo/product_task.py +2 -0
  84. examples/demo.py +17 -1
  85. examples/fastapi_caching.py +59 -0
  86. {meutils/dependencies → examples/gr}/__init__.py +1 -1
  87. examples/gr/d.py +22 -0
  88. examples/gr/demo.py +30 -0
  89. examples/ip2/345/234/260/345/214/272.py +16 -0
  90. examples/jinja2_demo/j2_demo.py +20 -1
  91. examples/json/346/240/207/345/207/206/345/214/226.py +54 -0
  92. examples/md.py +29 -0
  93. {meutils/serving/jina → examples/nesc}/__init__.py +1 -1
  94. examples/nesc/main.py +76 -0
  95. examples/orm/mysql_orm.py +113 -0
  96. examples/orm/sql_creater.py +57 -0
  97. examples/orm/sqlm.py +134 -0
  98. examples/rq_demo/fns.py +18 -0
  99. examples/rq_demo/redis/351/230/237/345/210/227.py +14 -7
  100. examples/rq_demo/redis/351/230/237/345/210/227_add_chatfire.py +30 -0
  101. examples/size_map.py +43 -0
  102. examples/test.py +59 -0
  103. examples/webs/__init__.py +11 -0
  104. examples/webs/main.py +34 -0
  105. examples/x.py +13 -0
  106. examples//345/216/273/346/260/264/345/215/260.py +20 -0
  107. examples//346/226/207/346/241/243/346/231/272/350/203/275/__init__.py +11 -0
  108. meutils/_utils.py +15 -6
  109. meutils/ai_audio/asr/__init__.py +3 -2
  110. meutils/ai_audio/asr/cf_asr.py +53 -0
  111. meutils/ai_audio/asr/de.py +11 -0
  112. meutils/ai_audio/asr/fast_asr.py +15 -7
  113. meutils/ai_audio/asr/openai_asr.py +83 -6
  114. meutils/ai_audio/fast_asr.py +8 -4
  115. meutils/ai_audio/tts/EdgeTTS.py +33 -7
  116. meutils/ai_audio/tts/openai_tts.py +24 -20
  117. meutils/ai_audio/tts/tts_ui.py +1 -0
  118. meutils/ai_audio/utils.py +9 -0
  119. meutils/ai_cv/__init__.py +0 -1
  120. meutils/ai_cv/ocr.py +3 -2
  121. meutils/ai_cv/utils.py +154 -0
  122. meutils/ai_video/avmerge.py +6 -0
  123. meutils/ai_video/video.py +11 -2
  124. meutils/{api → apis}/__init__.py +1 -1
  125. meutils/apis/ali_apis.py +60 -0
  126. meutils/apis/audio/__init__.py +10 -0
  127. meutils/apis/audio/deepinfra.py +59 -0
  128. meutils/apis/audio/fish.py +248 -0
  129. meutils/apis/baidu/__init__.py +9 -0
  130. meutils/apis/baidu/bdaitpzs.py +229 -0
  131. meutils/apis/baidu/test.py +78 -0
  132. meutils/apis/chatglm/__init__.py +11 -0
  133. meutils/apis/chatglm/glm_video.py +273 -0
  134. meutils/apis/chatglm/glm_video_api.py +116 -0
  135. meutils/apis/chatglm/images.py +63 -0
  136. meutils/apis/chatglm/temp.py +259 -0
  137. meutils/apis/chatglm/x.py +31 -0
  138. meutils/{api → apis}/common.py +10 -6
  139. meutils/apis/fal/__init__.py +11 -0
  140. meutils/apis/fal/files.py +53 -0
  141. meutils/apis/fal/images.py +57 -0
  142. meutils/apis/fal/images_.py +72 -0
  143. meutils/apis/fal/videos.py +77 -0
  144. meutils/apis/firecrawl.py +45 -0
  145. meutils/apis/gitee/__init__.py +11 -0
  146. meutils/apis/gitee/images/__init__.py +9 -0
  147. meutils/apis/gitee/images/kolors.py +99 -0
  148. meutils/apis/hailuoai/__init__.py +11 -0
  149. meutils/apis/hailuoai/demo.py +34 -0
  150. meutils/apis/hailuoai/hasha_new.py +248 -0
  151. meutils/apis/hailuoai/music.py +11 -0
  152. meutils/apis/hailuoai/upload.py +116 -0
  153. meutils/apis/hailuoai/videos.py +460 -0
  154. meutils/apis/hailuoai/yy.py +242 -0
  155. meutils/apis/hf/__init__.py +11 -0
  156. meutils/apis/hf/got_ocr.py +64 -0
  157. meutils/apis/hf/gradio.py +34 -0
  158. meutils/apis/hf/hivisionidphotos.py +80 -0
  159. meutils/apis/hf/kolors.py +68 -0
  160. meutils/apis/hf/kolors_virtual_try_on.py +107 -0
  161. meutils/apis/hf/r.py +53 -0
  162. meutils/apis/hf/x.py +26 -0
  163. meutils/apis/hf//350/257/201/344/273/266/347/205/247.py +41 -0
  164. meutils/apis/hunyuan/__init__.py +11 -0
  165. meutils/apis/hunyuan/image_tools.py +84 -0
  166. meutils/apis/images/__init__.py +11 -0
  167. meutils/apis/images/deepinfra.py +92 -0
  168. meutils/apis/images/demo.py +150 -0
  169. meutils/apis/images/eidt.py +36 -0
  170. meutils/apis/images/flux/__init__.py +11 -0
  171. meutils/apis/images/flux/fluxpro.py +108 -0
  172. meutils/apis/images/flux/mystic.py +116 -0
  173. meutils/apis/images/ideogram/__init__.py +10 -0
  174. meutils/apis/images/ideogram/ideogram_images.py +193 -0
  175. meutils/apis/images/prodia/__init__.py +12 -0
  176. meutils/apis/images/prodia/faceswap.py +76 -0
  177. meutils/apis/images/recraft.py +152 -0
  178. meutils/apis/images/virtual_try_on/__init__.py +11 -0
  179. meutils/apis/images/virtual_try_on/images.py +65 -0
  180. meutils/apis/jiema/24mail.py +96 -0
  181. meutils/apis/jiema/__init__.py +11 -0
  182. meutils/apis/jiema/yezi.py +97 -0
  183. meutils/apis/jimeng/__init__.py +11 -0
  184. meutils/apis/jimeng/common.py +328 -0
  185. meutils/apis/jimeng/doubao.py +68 -0
  186. meutils/apis/jimeng/doubao_utils.py +175 -0
  187. meutils/apis/jimeng/files.py +263 -0
  188. meutils/apis/jimeng/images.py +140 -0
  189. meutils/apis/jimeng/lip_sync.py +11 -0
  190. meutils/apis/jina.py +55 -0
  191. meutils/apis/kling/__init__.py +11 -0
  192. meutils/apis/kling/api.py +60 -0
  193. meutils/apis/kling/images.py +174 -0
  194. meutils/apis/kling/kolors_virtual_try_on.py +111 -0
  195. meutils/apis/kling/kolors_virtual_try_on_web.py +126 -0
  196. meutils/apis/kling/videos.py +67 -0
  197. meutils/apis/kling//351/211/264/346/235/203.py +34 -0
  198. meutils/apis/kuaidi.py +32 -0
  199. meutils/apis/kuaishou/__init__.py +10 -0
  200. meutils/apis/kuaishou/klingai.py +523 -0
  201. meutils/apis/kuaishou/klingai_video.py +197 -0
  202. meutils/apis/kuaishou/kolors.py +189 -0
  203. meutils/apis/llm_qa.py +55 -0
  204. meutils/apis/luma/__init__.py +11 -0
  205. meutils/apis/luma/luma.py +123 -0
  206. meutils/apis/minicpm/__init__.py +9 -0
  207. meutils/apis/minicpm/luca.py +137 -0
  208. meutils/apis/monica/__init__.py +11 -0
  209. meutils/apis/monica/llm.py +11 -0
  210. meutils/apis/napkin/__init__.py +11 -0
  211. meutils/apis/napkin/icons.py +42 -0
  212. meutils/apis/niutrans.py +73 -0
  213. meutils/apis/oneapi/__init__.py +11 -0
  214. meutils/apis/oneapi/channel.py +68 -0
  215. meutils/apis/oneapi/common.py +135 -0
  216. meutils/apis/oneapi/log.py +47 -0
  217. meutils/apis/oneapi/token.py +48 -0
  218. meutils/apis/oneapi/token_.py +112 -0
  219. meutils/apis/oneapi/user.py +100 -0
  220. meutils/apis/oneapi/utils.py +47 -0
  221. meutils/apis/pixverse/__init__.py +11 -0
  222. meutils/apis/pixverse/pixverse.py +150 -0
  223. meutils/apis/proxy/__init__.py +11 -0
  224. meutils/apis/proxy/ips.py +178 -0
  225. meutils/apis/remini/__init__.py +11 -0
  226. meutils/apis/remini/remini.py +89 -0
  227. meutils/apis/replicateai/__init__.py +11 -0
  228. meutils/apis/replicateai/images.py +79 -0
  229. meutils/apis/replicateai/raw.py +53 -0
  230. meutils/apis/runwayml/__init__.py +10 -0
  231. meutils/apis/runwayml/gen.py +143 -0
  232. meutils/apis/search/__init__.py +11 -0
  233. meutils/apis/search/baichuan.py +11 -0
  234. meutils/apis/search/metaso.py +218 -0
  235. meutils/apis/search/metaso_.py +77 -0
  236. meutils/apis/search/n.py +99 -0
  237. meutils/apis/search/searxng.py +42 -0
  238. meutils/apis/search_music.py +39 -0
  239. meutils/apis/siliconflow/__init__.py +9 -0
  240. meutils/apis/siliconflow/audio.py +63 -0
  241. meutils/apis/siliconflow/image_to_image.py +116 -0
  242. meutils/apis/siliconflow/images.py +154 -0
  243. meutils/apis/siliconflow/rerankers.py +40 -0
  244. meutils/apis/siliconflow/text_to_image.py +132 -0
  245. meutils/apis/siliconflow/utils.py +66 -0
  246. meutils/apis/siliconflow/videos.py +102 -0
  247. meutils/apis/sunoai/__init__.py +10 -0
  248. meutils/apis/sunoai/haimian.py +135 -0
  249. meutils/apis/sunoai/suno.py +373 -0
  250. meutils/apis/textcard/__init__.py +11 -0
  251. meutils/apis/textcard/demo.py +25 -0
  252. meutils/apis/textcard/hanyuxinjie.py +81 -0
  253. meutils/apis/textin.py +159 -0
  254. meutils/apis/to_image/__init__.py +11 -0
  255. meutils/apis/to_image/html2image.py +29 -0
  256. meutils/apis/to_image/md.py +29 -0
  257. meutils/apis/to_image/url2image.py +41 -0
  258. meutils/apis/together/__init__.py +11 -0
  259. meutils/apis/together/images.py +80 -0
  260. meutils/apis/translator/__init__.py +9 -0
  261. meutils/apis/translator/deeplx.py +55 -0
  262. meutils/apis/tripo3d/__init__.py +11 -0
  263. meutils/apis/tripo3d/images.py +106 -0
  264. meutils/apis/ts.py +60 -0
  265. meutils/apis/uptime_kuma/__init__.py +11 -0
  266. meutils/apis/uptime_kuma/common.py +56 -0
  267. meutils/apis/uptime_kuma//345/233/275/344/272/247/345/210/206/347/273/204.py +68 -0
  268. meutils/apis/utils.py +47 -0
  269. meutils/apis/videos/__init__.py +11 -0
  270. meutils/apis/videos/sora.py +16 -0
  271. meutils/apis/vidu/__init__.py +9 -0
  272. meutils/apis/vidu/vidu_video.py +254 -0
  273. meutils/apis/vidu/x.py +14 -0
  274. meutils/apis/voice_clone/__init__.py +10 -0
  275. meutils/apis/voice_clone/fish.py +236 -0
  276. meutils/apis/voice_clone/fish_api.py +16 -0
  277. meutils/apis/web_search.py +31 -0
  278. meutils/apis/yezi.py +97 -0
  279. meutils/async_task/__init__.py +13 -0
  280. meutils/async_task/celery_config.py +106 -0
  281. meutils/async_task/common.py +37 -0
  282. meutils/async_task/demo_create_tasks.py +73 -0
  283. meutils/async_task/tasks/__init__.py +11 -0
  284. meutils/async_task/tasks/_all.py +20 -0
  285. meutils/async_task/tasks/hailuo.py +24 -0
  286. meutils/async_task/tasks/kling.py +30 -0
  287. meutils/async_task/tasks/replicateai.py +24 -0
  288. meutils/async_task/tasks/test.py +124 -0
  289. meutils/async_task/tasks/vidu.py +28 -0
  290. meutils/async_task/utils.py +191 -0
  291. meutils/async_task//351/200/232/347/224/250/350/256/276/350/256/241.py +119 -0
  292. meutils/async_utils/asyncer_.py +37 -0
  293. meutils/async_utils/background.py +68 -0
  294. meutils/async_utils/common.py +136 -16
  295. meutils/async_utils/test.py +47 -0
  296. meutils/cache_utils.py +29 -23
  297. meutils/caches/__init__.py +9 -0
  298. meutils/caches/acache.py +45 -0
  299. meutils/caches/redis_cache.py +63 -0
  300. meutils/clis/check_api.py +66 -0
  301. meutils/clis/cli.py +1 -1
  302. meutils/common.py +56 -17
  303. meutils/config_utils/__init__.py +11 -0
  304. meutils/config_utils/lark_utils/__init__.py +11 -0
  305. meutils/config_utils/lark_utils/common.py +385 -0
  306. meutils/config_utils/lark_utils/demo.py +13 -0
  307. meutils/config_utils/lark_utils/x.py +50 -0
  308. meutils/config_utils/manager.py +108 -0
  309. meutils/crawlers/__init__.py +11 -0
  310. meutils/data/VERSION +1 -1
  311. meutils/data/cowboy-hat-face.webp +0 -0
  312. meutils/data/oneapi/FOOTER.md +7 -0
  313. meutils/data/oneapi/NOTICE.md +138 -0
  314. meutils/data/oneapi/__init__.py +15 -0
  315. meutils/db/orm.py +179 -0
  316. meutils/db/redis_db.py +87 -0
  317. meutils/decorators/cache.py +1 -1
  318. meutils/decorators/common.py +84 -5
  319. meutils/decorators/contextmanagers.py +17 -6
  320. meutils/decorators/fastapi_decorator.py +77 -3
  321. meutils/decorators/polling.py +46 -0
  322. meutils/decorators/retry.py +150 -26
  323. meutils/fastapi_utils/__init__.py +11 -0
  324. meutils/fastapi_utils/exceptions/http_error.py +72 -0
  325. meutils/fastapi_utils/exceptions/validation_error.py +44 -0
  326. meutils/hash_utils.py +9 -4
  327. meutils/hooks/__init__.py +11 -0
  328. meutils/hooks/hook_test.py +174 -0
  329. meutils/hooks/wechat.py +162 -0
  330. meutils/hooks/wechat_channel.py +303 -0
  331. meutils/init/evn.py +1 -1
  332. meutils/io/files_utils.py +232 -0
  333. meutils/io/image.py +148 -10
  334. meutils/io/x.py +75 -0
  335. meutils/llm/__init__.py +10 -0
  336. meutils/llm/check_api.py +109 -0
  337. meutils/llm/check_utils.py +106 -0
  338. meutils/llm/clients.py +38 -0
  339. meutils/llm/completions/__init__.py +11 -0
  340. meutils/llm/completions/agents/__init__.py +11 -0
  341. meutils/llm/completions/agents/file.py +125 -0
  342. meutils/llm/completions/cp.py +112 -0
  343. meutils/llm/completions/delilegal.py +135 -0
  344. meutils/llm/completions/dify.py +81 -0
  345. meutils/llm/completions/kimi.py +47 -0
  346. meutils/llm/completions/modelscope.py +11 -0
  347. meutils/{fileparser/filetype.py → llm/completions/oi.py} +5 -3
  348. meutils/llm/completions/rag/__init__.py +11 -0
  349. meutils/llm/completions/rag/fire.py +157 -0
  350. meutils/llm/completions/rag/qwen.py +11 -0
  351. meutils/llm/completions/rag/rag.py +41 -0
  352. meutils/llm/completions/rag.py +38 -0
  353. meutils/llm/completions/tryblend.py +201 -0
  354. meutils/llm/completions/tune.py +284 -0
  355. meutils/llm/completions/x.py +26 -0
  356. meutils/llm/completions/xx.py +61 -0
  357. meutils/llm/completions/yuanbao.py +176 -0
  358. meutils/llm/demo.py +114 -0
  359. meutils/llm/functions/__init__.py +11 -0
  360. meutils/llm/mappers.py +15 -0
  361. meutils/llm/openai_utils/__init__.py +11 -0
  362. meutils/llm/openai_utils/common.py +284 -0
  363. meutils/llm/openai_utils/tool_outputs.py +45 -0
  364. meutils/llm/output_parsers/__init__.py +80 -0
  365. meutils/llm/prompts/__init__.py +244 -0
  366. meutils/llm/prompts/demo.py +155 -0
  367. meutils/llm/prompts/html2image_test.py +19 -0
  368. meutils/llm/utils.py +133 -0
  369. meutils/llm/x.py +75 -0
  370. meutils/notice/feishu.py +40 -9
  371. meutils/notice/wechat.py +23 -21
  372. meutils/np_utils.py +10 -1
  373. meutils/office_automation/pdf.py +6 -1
  374. meutils/oss/__init__.py +20 -0
  375. meutils/oss/minio_oss.py +184 -0
  376. meutils/oss/minio_utils.py +48 -0
  377. meutils/other/__demo.py +6 -4
  378. meutils/pandas_utils/__init__.py +1 -0
  379. meutils/pandas_utils/common.py +31 -0
  380. meutils/pandas_utils/pd_utils.py +10 -6
  381. meutils/parsers/__init__.py +10 -0
  382. meutils/parsers/file_parsers.py +110 -0
  383. meutils/parsers/fileparser/demo.py +41 -0
  384. meutils/parsers/fileparser/filetype.py +41 -0
  385. meutils/pay.py +37 -0
  386. meutils/pipe.py +37 -4
  387. meutils/playwright_utils/common.py +20 -12
  388. meutils/plots/common.py +35 -34
  389. meutils/queues/demo.py +56 -0
  390. meutils/queues/smooth_queue.py +120 -0
  391. meutils/queues/uniform_queue.py +3 -1
  392. meutils/request_utils/__init__.py +26 -2
  393. meutils/request_utils/ark.py +47 -0
  394. meutils/request_utils/crawler.py +34 -5
  395. meutils/request_utils/jwt_utils/__init__.py +11 -0
  396. meutils/request_utils/jwt_utils/common.py +42 -0
  397. meutils/request_utils/volc.py +160 -0
  398. meutils/schemas/__init__.py +0 -1
  399. meutils/schemas/baidu_types.py +70 -0
  400. meutils/schemas/batch_types.py +450 -0
  401. meutils/schemas/celery_types.py +64 -0
  402. meutils/schemas/chatfire_types.py +15 -0
  403. meutils/schemas/chatglm_types.py +197 -0
  404. meutils/schemas/db/__init__.py +11 -0
  405. meutils/schemas/db/oneapi_types.py +117 -0
  406. meutils/schemas/dify_types.py +40 -0
  407. meutils/schemas/embedding.py +31 -0
  408. meutils/schemas/fal_types.py +13 -0
  409. meutils/schemas/fish_types.py +11 -0
  410. meutils/schemas/hailuo_types.py +208 -0
  411. meutils/schemas/haimian_types.py +51 -0
  412. meutils/schemas/idphoto_types.py +43 -0
  413. meutils/schemas/image_types.py +476 -0
  414. meutils/schemas/jimeng_types.py +28 -0
  415. meutils/schemas/jina_types.py +67 -0
  416. meutils/schemas/kimi_types.py +86 -0
  417. meutils/schemas/kling_types.py +235 -0
  418. meutils/schemas/kuaishou_types.py +328 -0
  419. meutils/schemas/luma_types.py +59 -0
  420. meutils/schemas/message_types.py +165 -0
  421. meutils/schemas/message_types_.py +219 -0
  422. meutils/schemas/metaso_types.py +64 -0
  423. meutils/schemas/napkin_types.py +85 -0
  424. meutils/schemas/ocr_types.py +37 -0
  425. meutils/schemas/oneapi/__init__.py +11 -0
  426. meutils/schemas/oneapi/_types.py +49 -0
  427. meutils/schemas/oneapi/common.py +883 -0
  428. meutils/schemas/oneapi/icons.py +30 -0
  429. meutils/schemas/oneapi/model_group_info.py +48 -0
  430. meutils/schemas/oneapi/model_info.py +34 -0
  431. meutils/schemas/oneapi/models.py +26 -0
  432. meutils/schemas/oneapi/x.py +26 -0
  433. meutils/schemas/oneapi//351/207/215/345/256/232/345/220/221.py +132 -0
  434. meutils/schemas/openai_api_protocol.py +411 -0
  435. meutils/schemas/openai_types.py +366 -0
  436. meutils/schemas/pixverse_types.py +88 -0
  437. meutils/schemas/playwright_types.py +57 -0
  438. meutils/schemas/prodia_types.py +19 -0
  439. meutils/schemas/replicate_types.py +112 -0
  440. meutils/schemas/request_types.py +20 -0
  441. meutils/schemas/runwayml_types.py +190 -0
  442. meutils/schemas/siliconflow_types.py +80 -0
  443. meutils/schemas/step_types.py +19 -0
  444. meutils/schemas/suno_types.py +319 -0
  445. meutils/schemas/task_types.py +192 -0
  446. meutils/schemas/translator_types.py +29 -0
  447. meutils/schemas/tripo3d_types.py +57 -0
  448. meutils/schemas/tryblend_types.py +51 -0
  449. meutils/schemas/video_types.py +62 -0
  450. meutils/schemas/vidu_types.py +350 -0
  451. meutils/schemas/wechat_types.py +316 -0
  452. meutils/schemas/yuanbao_types.py +260 -0
  453. meutils/serving/celery/__init__.py +8 -0
  454. meutils/serving/celery/config.py +115 -0
  455. meutils/serving/celery/router.py +4 -6
  456. meutils/serving/celery/tasks.py +6 -4
  457. meutils/serving/celery//351/200/232/347/224/250/350/256/276/350/256/241.py +119 -0
  458. meutils/serving/fastapi/common.py +27 -31
  459. meutils/serving/fastapi/dependencies/__init__.py +0 -1
  460. meutils/serving/fastapi/dependencies/auth.py +55 -2
  461. meutils/serving/fastapi/exceptions/http_error.py +67 -2
  462. meutils/serving/fastapi/exceptions/validation_error.py +18 -2
  463. meutils/serving/fastapi/lifespans.py +73 -0
  464. meutils/serving/fastapi/routers/scheduler.py +12 -0
  465. meutils/serving/fastapi/routers/screenshot.py +47 -0
  466. meutils/serving/fastapi/routers/spider.py +8 -3
  467. meutils/serving/fastapi/routers/task.py +48 -0
  468. meutils/serving/fastapi/utils.py +48 -1
  469. meutils/serving/streamlit/common.py +1 -1
  470. meutils/smooth_utils.py +3 -0
  471. meutils/str_utils/__init__.py +22 -3
  472. meutils/str_utils/json_utils.py +7 -0
  473. meutils/str_utils/regular_expression.py +102 -10
  474. meutils/templates/xx.html +21 -0
  475. meutils/templates/xxx.html +117 -0
  476. meutils/todo.py +12 -0
  477. meutils/tools/token_monitor.py +33 -0
  478. MeUtils-2024.3.4.13.4.45.dist-info/RECORD +0 -540
  479. meutils/ai_audio/asr/subtitle.srt +0 -40
  480. meutils/ai_audio/demo.ipynb +0 -1215
  481. meutils/ai_audio/example.srt +0 -348
  482. meutils/ai_audio/new.srt +0 -179
  483. meutils/ai_audio/subtitles.srt +0 -696
  484. meutils/ai_audio/tts/new.srt +0 -179
  485. meutils/ai_audio//350/247/206/351/242/221/345/220/210/345/271/266.sh +0 -32
  486. meutils/ai_cv/1.jpg +0 -0
  487. meutils/ai_cv/197.jpg +0 -0
  488. meutils/ai_cv/2.jpg +0 -0
  489. meutils/ai_cv/img.png +0 -0
  490. meutils/ai_cv/invoice.jpg +0 -0
  491. meutils/ai_cv/tbl.png +0 -0
  492. meutils/ai_cv/test.png +0 -0
  493. meutils/ann/README.md +0 -33
  494. meutils/ann/README_gensim.md +0 -47
  495. meutils/ann/examples/client.py +0 -59
  496. meutils/ann/examples/demo.py +0 -24
  497. meutils/api/deeplx.py +0 -29
  498. meutils/api/qr.png +0 -0
  499. meutils/clis/README.md +0 -29
  500. meutils/clis/__test.sh +0 -17
  501. meutils/clis/deepseek.txt +0 -8
  502. meutils/clis/deepseek_13003330042.json +0 -1
  503. meutils/clis/deepseek_13003872192.json +0 -1
  504. meutils/clis/deepseek_13852263862.json +0 -1
  505. meutils/clis/deepseek_13913898681.json +0 -1
  506. meutils/clis/deepseek_13962978617.json +0 -1
  507. meutils/clis/deepseek_15251801790.json +0 -1
  508. meutils/clis/deepseek_15720826383.json +0 -1
  509. meutils/clis/deepseek_18395563611.json +0 -1
  510. meutils/clis/deepseek_313303303@qq.com.json +0 -1
  511. meutils/clis/kimi_state.json +0 -1
  512. meutils/cmds/README.md +0 -55
  513. meutils/coding/__init__.py +0 -11
  514. meutils/coding/find132.py +0 -40
  515. meutils/db/README.md +0 -51
  516. meutils/decorators/README.md +0 -17
  517. meutils/docarray_utils/demo_es.py +0 -34
  518. meutils/docarray_utils/demo_hnsw.py +0 -55
  519. meutils/docarray_utils/in_memory.py +0 -38
  520. meutils/docarray_utils//346/224/271/351/200/240/344/270/213hnsw.py +0 -43
  521. meutils/io/file.py +0 -20
  522. meutils/io/img.png +0 -0
  523. meutils/io/x.yml +0 -1
  524. meutils/notice/img.png +0 -0
  525. meutils/notice/todo.md +0 -10
  526. meutils/office_automation//346/212/225/350/265/204/347/256/241/347/220/206/347/263/273/347/273/237O3.2_/344/272/244/346/230/223/347/273/204.pdm +0 -22469
  527. meutils/playwright_utils/__test.sh +0 -2
  528. meutils/playwright_utils/kimi1_cookies.json +0 -1
  529. meutils/playwright_utils/kimi2_cookies.json +0 -1
  530. meutils/playwright_utils/kimi_cookies.json +0 -93
  531. meutils/serving/README.md +0 -1
  532. meutils/serving/celery/_run.sh +0 -10
  533. meutils/serving/gui/run.sh +0 -9
  534. meutils/serving/jina/__demo/client.py +0 -42
  535. meutils/serving/jina/__demo/flow.svg +0 -1
  536. meutils/serving/jina/__demo/s.py +0 -34
  537. meutils/serving/jina/__demo/s2.py +0 -37
  538. meutils/serving/jina/__demo/server.py +0 -83
  539. meutils/serving/jina/__demo/test.py +0 -40
  540. meutils/serving/jina/executors/SentenceEncoder.py +0 -62
  541. meutils/serving/jina/executors/SentenceEncoder_.py +0 -63
  542. meutils/serving/jina/executors/__init__.py +0 -46
  543. meutils/serving/jina/executors/base.py +0 -40
  544. meutils/serving/jina/nlp_serving/__init__.py +0 -11
  545. meutils/serving/jina/nlp_serving/word_segmentation.py +0 -40
  546. meutils/serving/streamlit/conf.yaml +0 -5
  547. meutils/serving/streamlit/ocr.png +0 -0
  548. meutils/serving/streamlit/run.sh +0 -17
  549. meutils/serving/webui/.streamlit/_config.toml +0 -186
  550. meutils/serving/webui/.streamlit/config.toml +0 -26
  551. meutils/serving/webui/pages/_1_/345/210/206/350/257/215.py +0 -56
  552. meutils/serving/webui/pages/_2_/350/257/215/346/200/247/346/240/207/346/263/250/344/270/216/345/256/236/344/275/223/350/257/206/345/210/253.py +0 -54
  553. meutils/serving/webui/pages/_3_/346/226/207/346/234/254/345/214/271/351/205/215.py +0 -64
  554. meutils/serving/webui/run.sh +0 -9
  555. meutils/spark/__init__.py +0 -26
  556. meutils/tools/monitor.yml +0 -29
  557. {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/LICENSE +0 -0
  558. {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/top_level.txt +0 -0
  559. {meutils → examples}/comp_utils/__init__.py +0 -0
  560. {meutils → examples}/comp_utils/reverse_metric.py +0 -0
  561. /meutils/{fileparser/README.md → fastapi_utils/exceptions/__init__.py} +0 -0
  562. /meutils/{fileparser → parsers/fileparser}/PDF/346/212/275/345/217/226.py" +0 -0
  563. /meutils/{fileparser → parsers/fileparser}/__init__.py +0 -0
  564. /meutils/{fileparser → parsers/fileparser}/common.py +0 -0
  565. /meutils/{fileparser → parsers/fileparser}/filetype/__init__.py +0 -0
  566. /meutils/{fileparser → parsers/fileparser}/filetype/__main__.py +0 -0
  567. /meutils/{fileparser → parsers/fileparser}/filetype/filetype.py +0 -0
  568. /meutils/{fileparser → parsers/fileparser}/filetype/helpers.py +0 -0
  569. /meutils/{fileparser → parsers/fileparser}/filetype/match.py +0 -0
  570. /meutils/{fileparser → parsers/fileparser}/filetype/types/__init__.py +0 -0
  571. /meutils/{fileparser → parsers/fileparser}/filetype/types/application.py +0 -0
  572. /meutils/{fileparser → parsers/fileparser}/filetype/types/archive.py +0 -0
  573. /meutils/{fileparser → parsers/fileparser}/filetype/types/audio.py +0 -0
  574. /meutils/{fileparser → parsers/fileparser}/filetype/types/base.py +0 -0
  575. /meutils/{fileparser → parsers/fileparser}/filetype/types/document.py +0 -0
  576. /meutils/{fileparser → parsers/fileparser}/filetype/types/font.py +0 -0
  577. /meutils/{fileparser → parsers/fileparser}/filetype/types/image.py +0 -0
  578. /meutils/{fileparser → parsers/fileparser}/filetype/types/isobmff.py +0 -0
  579. /meutils/{fileparser → parsers/fileparser}/filetype/types/video.py +0 -0
  580. /meutils/{fileparser → parsers/fileparser}/filetype/utils.py +0 -0
  581. /meutils/{fileparser → parsers/fileparser}/pdf.py +0 -0
  582. /meutils/{fileparser → parsers/fileparser}//350/241/250/346/240/274/346/212/275/345/217/226.py" +0 -0
meutils/hash_utils.py CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  import hashlib as _hashlib
12
12
  from functools import lru_cache
13
- from sklearn.utils.murmurhash import murmurhash3_32 as _murmurhash3_32
13
+ from typing import Union
14
14
 
15
15
  # ME
16
16
  from meutils.decorators import singleton
@@ -26,9 +26,10 @@ def hash(key: String = "key", value: String = "value", bins: Int = 10000): Int =
26
26
  """
27
27
 
28
28
 
29
- def md5(string: str, encoding=True):
30
- s = string.encode('utf8') if encoding else string
31
- return _hashlib.md5(s).hexdigest()
29
+ def md5(data: Union[str, bytes]):
30
+ if isinstance(data, str):
31
+ data = data.encode('utf8')
32
+ return _hashlib.md5(data).hexdigest()
32
33
 
33
34
 
34
35
  def murmurhash(key="key", value="value", bins=None, str2md5=True):
@@ -37,6 +38,8 @@ def murmurhash(key="key", value="value", bins=None, str2md5=True):
37
38
  if str2md5:
38
39
  string = md5(string)
39
40
 
41
+ from sklearn.utils.murmurhash import murmurhash3_32 as _murmurhash3_32
42
+
40
43
  _ = _murmurhash3_32(string, positive=True) # 与java一致
41
44
  return _ % bins if bins else _
42
45
 
@@ -68,6 +71,8 @@ class ABTest(object):
68
71
  def is_hit(self, value="userid"):
69
72
  s = f"{value}:{self._expid}"
70
73
 
74
+ from sklearn.utils.murmurhash import murmurhash3_32 as _murmurhash3_32
75
+
71
76
  _ = _murmurhash3_32(s, positive=True) % self._bins # 与java一致
72
77
  return _ in self._ranger
73
78
 
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : __init__.py
5
+ # @Time : 2024/8/8 18:45
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : MeUtils.
4
+ # @File : demo
5
+ # @Time : 2021/9/4 下午3:26
6
+ # @Author : yuanjie
7
+ # @WeChat : 313303303
8
+ # @Software : PyCharm
9
+ # @Description : 根据系统信息与聊天记录评价一个人
10
+ import re
11
+
12
+ from meutils.pipe import *
13
+
14
+ import xchat.itchat as itchat
15
+ from xchat.itchat.content import INCOME_MSG, TEXT, PICTURE, NOTE
16
+ from xchat.schemas.wechat.message import MessageType, QuoteMessage
17
+ from xchat.itchat.storage.messagequeue import Message
18
+ # from xchat.schemas.msg import Message as _Message, User
19
+
20
+ from xchat.schemas.wechat.message import Message as _Message
21
+
22
+
23
+ @decorator
24
+ def msg_filter(func, chatroom_regexp: Optional[str] = None, *msgs):
25
+ """
26
+ 过滤群聊、私聊
27
+ """
28
+ msg = _Message(**obj_to_dict(msgs[0]))
29
+
30
+ if (
31
+ msg.CreateTime > time.time() - 5
32
+ and (re.search(chatroom_regexp, msg.chatroom_name) if chatroom_regexp else True)
33
+
34
+ ):
35
+ return func(msg)
36
+
37
+
38
+ @itchat.msg_register([MessageType.TEXT, MessageType.ATTACHMENT], isGroupChat=True) # 注册处理文本信息
39
+ @msg_filter
40
+ def reply(msg: Message):
41
+ logger.debug(msg)
42
+ _msg = msg
43
+ msg = obj_to_dict(msg)
44
+ # logger.debug(f"{msg}")
45
+ # logger.debug(f"{User(**msg['User'])}")
46
+ # logger.debug(f"UserUserUserUserUserUserUserUserUserUser")
47
+ # user = msg.pop('User')
48
+
49
+ msg = _Message(**msg) # filter
50
+ logger.debug(f"{msg}")
51
+
52
+ group_name = msg.chatroom_name # msg.User.NickName
53
+ # msg.ToUserName 加密的群名
54
+ logger.debug(f"群名: {group_name}")
55
+
56
+ # msg.ToUserName, msg.ActualNickName群里机器人的name
57
+ # msg.FromUserName 群id【除非机器人本身发信息,就是他自己的id】
58
+
59
+ if (
60
+ not hasattr(msg, 'CreateTime')
61
+ or msg.CreateTime > time.time() - 10
62
+ and "机器人调试" in group_name
63
+ ): # todo: 增加过滤函数
64
+ logger.debug(f"[{type(msg)} => {msg.Type}]")
65
+
66
+ ###############################################################
67
+
68
+ from meutils.hooks.wechat import create_reply
69
+
70
+ hook = create_reply(_msg, itchat_send=itchat.send)
71
+ if hook: return
72
+
73
+ ###############################################################
74
+ logger.debug("测试发送")
75
+
76
+ # itchat.send('@img@doc_watermark.jpg', toUserName=msg.chatroom_id) # ToUserName
77
+ # itchat.send('@img@doc_watermark.webp', toUserName=msg.chatroom_id)
78
+ # itchat.send_image('doc_watermark.jpg', toUserName=msg.chatroom_id)
79
+ # logger.debug('1')
80
+ # itchat.send_image('doc_watermark.webp', toUserName=msg.chatroom_id)
81
+ # logger.debug('2')
82
+
83
+
84
+
85
+
86
+ # 使用上下文管理器自动处理文件的关闭和删除
87
+ with tempfile.NamedTemporaryFile(mode='wb+', suffix='.txt') as temp: # suffix
88
+ temp.write(b"This is a temporary file.")
89
+ temp.seek(0)
90
+
91
+ itchat.send(f'@fil@{temp.name}', toUserName=msg.chatroom_id) # ToUserName
92
+
93
+ # itchat.send_image(open('doc_watermark.jpg', 'rb'), toUserName=msg.chatroom_id)
94
+
95
+ # itchat.send('@img@1.webp', toUserName=msg.chatroom_id) # ToUserName
96
+ # itchat.send('@img@1.webp', toUserName=msg.chatroom_id) # ToUserName
97
+ # itchat.send('@msg@1.webp', toUserName=msg.chatroom_id) # ToUserName
98
+ #
99
+ # itchat.send('@vid@vidu.mp4', toUserName=msg.chatroom_id) # ToUserName
100
+
101
+ # itchat.send(f"FromUserName: {msg.FromUserName}", toUserName=msg.chatroom_id) # msg.FromUserName
102
+ # itchat.send('@fil@test.ipynb', toUserName=msg.chatroom_id) # ToUserName
103
+ # itchat.send('@fil@test.ipynb', toUserName=msg.ToUserName) # ToUserName
104
+ # itchat.send('@fil@test.ipynb', toUserName=msg.chatroom_id) # ToUserName
105
+
106
+ # itchat.send_image
107
+
108
+ # itchat.send('@vid@vidu.mp4', toUserName=msg.chatroom_id) # ToUserName
109
+
110
+ # itchat.send('@img@1.webp', toUserName=msg.chatroom_id) # ToUserName
111
+ # itchat.send('@img@1.png', toUserName=msg.chatroom_id) # ToUserName
112
+ # itchat.send('@img@doc_watermark.jpg', toUserName=msg.chatroom_id) # ToUserName
113
+
114
+ # itchat.send('@fil@vidu.mp4', toUserName=msg.chatroom_id) # ToUserName
115
+ # itchat.send('@fil@doc_watermark.jpg', toUserName=msg.chatroom_id) # ToUserName
116
+
117
+ # itchat.send('@vid@x.mp3', toUserName=msg.chatroom_id) # ToUserName
118
+ # itchat.send('@img@x.mp3', toUserName=msg.chatroom_id) # ToUserName
119
+
120
+ # itchat.send(
121
+ # f'@fil@{"/Users/betterme/PycharmProjects/AI/aizoo/.idea/misc.xml"}',
122
+ # toUserName=msg.chatroom_id) # ToUserName
123
+
124
+
125
+ # ['@fil@', '@img@', '@msg@', '@vid@']
126
+
127
+ # @itchat.msg_register(MessageType.SHARING) # 注册处理文本信息
128
+ # def reply(msg):
129
+ # print(str(msg))
130
+ # print(requests.get(msg.Url).content)
131
+ #
132
+ #
133
+ # @itchat.msg_register([MessageType.TEXT, MessageType.ATTACHMENT], isGroupChat=True)
134
+ # def handler_group_msg(msg):
135
+ # if not hasattr(msg, 'CreateTime') or msg.CreateTime > time.time() - 10: # todo: 增加过滤函数
136
+ # # ActualNickName
137
+ # WECHAT_DATA = os.getenv('WECHAT_DATA', 'wechat_data').rstrip('/')
138
+ # p = Path(f'{WECHAT_DATA}/{msg.User.NickName}') # 用户【非机器人】todo: 常用信息封装
139
+ # if msg.ToUserName == msg.User.UserName: p /= '机器返回'
140
+ # p.mkdir(parents=True, exist_ok=True)
141
+ # if msg["FileName"]:
142
+ # msg.download(p / msg["FileName"]) # ['Picture', 'Recording', 'Attachment', 'Video']
143
+ # # background_tasks
144
+ #
145
+ # if msg.User.NickName == 'Wechat测试' and msg.IsAt: # 被@回答问题
146
+ # logger.debug(f"[{type(msg)} => {msg.type}]")
147
+ # logger.debug(msg.keys())
148
+ #
149
+ # print(str(msg))
150
+ # # 'Text': '「Bettermeeeeeee:[文件]东北证券AI架构.pptx」\n- - - - - - - - - - - - - - -\n@Bettermeeeeeee\u2005qqqq'
151
+ # logger.debug(msg.User)
152
+ #
153
+ # msg.User.send_msg(f'@{msg.ActualNickName}\u2005「机器人回答1」')
154
+ # # msg.User.send_msg(f'@{msg.ActualNickName} 「机器人回答2」')
155
+ # # msg.User.send_msg(f'@{msg.ActualNickName}「机器人回答3」')
156
+
157
+
158
+ # 'ActualNickName', 'IsAt', 'ActualUserName'
159
+ # 'ActualNickName', 'IsAt', 'ActualUserName',
160
+
161
+ # import wxpy
162
+
163
+ # mp_username = itchat.search_mps(name='Python之禅')[0]['UserName']
164
+
165
+ if __name__ == '__main__':
166
+ itchat.auto_login(hotReload=os.getenv('WECHAT_RELOAD')) # hotReload=True表示短时间关闭程序后可重连
167
+ # print(itchat.search_mps('Python之禅'))
168
+ # mp_username = itchat.search_mps(name='Python之禅')[0]['UserName']
169
+
170
+ # 'FromUserName': '@839adce9c446b9aa6284371d2a03ea74', 'ToUserName': '@65b692db46f1365b376891a856853124544b18b95e52e9e18985a466fd1e34d0'
171
+ # print(itchat.search_friends(userName="@aa8e769e75daa860fd7bebf0a7c3af32bc4b731f920ef02a3830328ce936c492"))
172
+ # itchat.run()
173
+
174
+ itchat.run()
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : wechat
5
+ # @Time : 2024/8/8 18:45
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : 摸鱼早报 https://api.52vmy.cn/api/wl/moyu
10
+
11
+ from meutils.pipe import *
12
+ from meutils.schemas.wechat_types import Message, HookResponse, HookResponses
13
+ from pyrate_limiter import Duration, Rate, Limiter, BucketFullException, RedisBucket
14
+
15
+ rates = [
16
+ Rate(1, Duration.MINUTE),
17
+ Rate(2, Duration.MINUTE * 15),
18
+
19
+ Rate(2 ** 2, Duration.HOUR),
20
+ Rate(2 ** 3, Duration.HOUR * 6),
21
+ Rate(2 ** 4, Duration.HOUR * 24)
22
+ ]
23
+ limiter = Limiter(rates)
24
+
25
+
26
+ # handler_group_msg
27
+ # pip install wget pyrate_limiter meutils -U --user && cd /app/channel/wechat && rm -rf wechat_channel.py* && python -m wget https://oss.ffire.cc/files/wechat_channel.py
28
+ # docker commit <container-name> chatfire/wechat:latest
29
+ # docker commit chatfire-wechat chatfire/wechat:latest
30
+ # docker push chatfire/wechat:latest
31
+
32
+ @background_task
33
+ def wechat_send(msg: Message, response: HookResponse, itchat_send: Callable):
34
+ url = response.content
35
+ if response.type == 'image':
36
+ with tempfile.NamedTemporaryFile(mode='wb+', suffix='.txt') as file, \
37
+ httpx.Client(follow_redirects=True, timeout=100) as client:
38
+ response = client.get(url)
39
+ file.write(response.content)
40
+ file.seek(0)
41
+
42
+ itchat_send(f'@fil@{file.name}', toUserName=msg.chatroom_id) # ToUserName
43
+
44
+ elif response.type == 'video':
45
+ filename = wget.download(response.content)
46
+ itchat_send(f"@vid@{filename}", toUserName=msg.chatroom_id)
47
+
48
+ elif response.type == 'text':
49
+ itchat_send(f"@{msg.ActualNickName}\n{response.content}", toUserName=msg.chatroom_id)
50
+
51
+ elif response.type in {'audio', 'file'}:
52
+ filename = wget.download(response.content)
53
+ itchat_send(f"@fil@{filename}", toUserName=msg.chatroom_id)
54
+
55
+ # debug
56
+ else:
57
+ itchat_send(f"@{msg.ActualNickName}\n未知消息类型\n{response.content}", toUserName=msg.chatroom_id)
58
+
59
+
60
+ @background_task
61
+ def post(msg: Message, itchat_send: Callable):
62
+ try:
63
+ url = os.getenv("WECHAT_HOOK_URL")
64
+ api_key = os.getenv("WECHAT_HOOK_API_KEY")
65
+
66
+ headers = {"Authorization": f"Bearer {api_key}"}
67
+ data = httpx.post(
68
+ url,
69
+ headers=headers,
70
+ json=msg.model_dump(),
71
+ timeout=200
72
+ ).json()
73
+
74
+ response: HookResponse
75
+ for response in HookResponses(responses=data).responses:
76
+ logger.debug(response)
77
+ wechat_send(msg, response, itchat_send)
78
+ except Exception as e:
79
+ wechat_send(msg, HookResponse(content=str(e)), itchat_send)
80
+
81
+
82
+ def create_reply(msg, itchat_send: Callable = None): # 持续更新后端逻辑 解耦
83
+ msg = obj_to_dict(msg)
84
+ msg = Message(**msg)
85
+
86
+ logger.debug(msg.Content)
87
+
88
+ if ( # 拦截逻辑
89
+ msg.IsAt
90
+ and os.getenv("WECHAT_HOOK_URL") and os.getenv("WECHAT_HOOK_API_KEY")
91
+ and msg.Content.split(maxsplit=1)[-1].startswith('/')
92
+ ):
93
+
94
+ try:
95
+ if msg.ActualNickName.lower() not in {'betterme'}:
96
+ limiter.try_acquire(msg.ActualNickName) # 按昵称限制并发
97
+
98
+ post(msg, itchat_send)
99
+ return True
100
+
101
+ except BucketFullException as err:
102
+ logger.error(err)
103
+
104
+ itchat_send(f"@{msg.ActualNickName}\n{err.meta_info}", toUserName=msg.chatroom_id)
105
+ return True
106
+
107
+ # yield "开始拼命执行任务"
108
+
109
+ # {"type": "text", "content": 'xx'}
110
+ # {"type": "error", "content": 'https://oss.ffire.cc/files/vidu.mp4'}
111
+
112
+ # {"type": "image", "content": 'https://oss.ffire.cc/files/xx.png'}
113
+
114
+ # {"type": "audio", "content": 'https://oss.ffire.cc/files/xx.mp3'}
115
+ # {"type": "file", "content": 'https://oss.ffire.cc/files/xx.mp3'}
116
+
117
+ # {"type": "video", "content": 'https://oss.ffire.cc/files/vidu.mp4'}
118
+
119
+
120
+ def chat_group_hook(msg, debug: bool = False, send_fn: Callable = None): # todo hk一个第三方服务
121
+ # pip install meutils
122
+ # os.system("pip install meutils -U --user") 第一次的时候 加缓存 定期更新 并且重载
123
+ logger.debug(msg)
124
+ msg = obj_to_dict(msg)
125
+ msg = Message(**msg) # filter
126
+
127
+ group_name = msg.chatroom_name # msg.User.NickName
128
+ # msg.ToUserName 加密的群名
129
+
130
+ if debug:
131
+ logger.debug(f"群名: {group_name}")
132
+ # logger.debug(msg.model_dump_json(indent=4))
133
+ logger.debug(f"[{type(msg)} => {msg.Type}]")
134
+
135
+ # msg.ToUserName, msg.ActualNickName群里机器人的name
136
+ # msg.FromUserName 群id【除非机器人本身发信息,就是他自己的id】
137
+
138
+ # 时间内容
139
+ prompt = msg.Content.split(maxsplit=1)[-1]
140
+ if any(flag.lower() in group_name for flag in ['TEST']) or prompt.startswith('视频'):
141
+ # itchat.send(f"FromUserName: {msg.FromUserName}", toUserName=msg.chatroom_id) # msg.FromUserName
142
+ # itchat.send('@fil@test.ipynb', toUserName=msg.chatroom_id) # ToUserName
143
+ # itchat.send('@fil@test.ipynb', toUserName=msg.ToUserName) # ToUserName
144
+ # itchat.send('@fil@test.ipynb', toUserName=msg.chatroom_id) # ToUserName
145
+
146
+ # send_fn('@vid@vidu.mp4', toUserName=msg.chatroom_id) # ToUserName itchat.send
147
+ # send_fn('@img@vidu.mp4', toUserName=msg.chatroom_id) # ToUserName
148
+
149
+ filename = wget.download('https://oss.ffire.cc/files/vidu.mp4')
150
+ send_fn(f'@vid@{filename}', toUserName=msg.chatroom_id) # ToUserName itchat.send
151
+
152
+ # todo: 异步发送
153
+
154
+ return None
155
+
156
+ # try:
157
+ # cmsg = WechatMessage(msg, True)
158
+ # except NotImplementedError as e:
159
+ # logger.debug("[WX]group message {} skipped: {}".format(msg["MsgId"], e))
160
+ # return None
161
+ # WechatChannel().handle_group(cmsg)
162
+ # return None
@@ -0,0 +1,303 @@
1
+ # encoding:utf-8
2
+
3
+ """
4
+ wechat channel
5
+ """
6
+
7
+ import io
8
+ import json
9
+ import os
10
+ import threading
11
+ import time
12
+ import requests
13
+
14
+ from bridge.context import *
15
+ from bridge.reply import *
16
+ from channel.chat_channel import ChatChannel
17
+ from channel import chat_channel
18
+ from channel.wechat.wechat_message import *
19
+ from common.expired_dict import ExpiredDict
20
+ from common.log import logger
21
+ from common.singleton import singleton
22
+ from common.time_check import time_checker
23
+ from common.utils import convert_webp_to_png
24
+ from config import conf, get_appdata_dir
25
+ from lib import itchat
26
+ from lib.itchat.content import *
27
+
28
+
29
+ @itchat.msg_register([TEXT, VOICE, PICTURE, NOTE, ATTACHMENT, SHARING])
30
+ def handler_single_msg(msg):
31
+ try:
32
+ cmsg = WechatMessage(msg, False)
33
+ except NotImplementedError as e:
34
+ logger.debug("[WX]single message {} skipped: {}".format(msg["MsgId"], e))
35
+ return None
36
+ WechatChannel().handle_single(cmsg)
37
+ return None
38
+
39
+
40
+ @itchat.msg_register([TEXT, VOICE, PICTURE, NOTE, ATTACHMENT, SHARING], isGroupChat=True)
41
+ def handler_group_msg(msg):
42
+ ###############################################################
43
+
44
+ from meutils.hooks.wechat import create_reply
45
+
46
+ hook = create_reply(msg, itchat_send=itchat.send)
47
+ if hook: return
48
+
49
+ ###############################################################
50
+ try:
51
+ cmsg = WechatMessage(msg, True)
52
+ except NotImplementedError as e:
53
+ logger.debug("[WX]group message {} skipped: {}".format(msg["MsgId"], e))
54
+ return None
55
+ WechatChannel().handle_group(cmsg)
56
+ return None
57
+
58
+
59
+ def _check(func):
60
+ def wrapper(self, cmsg: ChatMessage):
61
+ msgId = cmsg.msg_id
62
+ if msgId in self.receivedMsgs:
63
+ logger.info("Wechat message {} already received, ignore".format(msgId))
64
+ return
65
+ self.receivedMsgs[msgId] = True
66
+ create_time = cmsg.create_time # 消息时间戳
67
+ if conf().get("hot_reload") == True and int(create_time) < int(time.time()) - 60: # 跳过1分钟前的历史消息
68
+ logger.debug("[WX]history message {} skipped".format(msgId))
69
+ return
70
+ if cmsg.my_msg and not cmsg.is_group:
71
+ logger.debug("[WX]my message {} skipped".format(msgId))
72
+ return
73
+ return func(self, cmsg)
74
+
75
+ return wrapper
76
+
77
+
78
+ # 可用的二维码生成接口
79
+ # https://api.qrserver.com/v1/create-qr-code/?size=400×400&data=https://www.abc.com
80
+ # https://api.isoyu.com/qr/?m=1&e=L&p=20&url=https://www.abc.com
81
+ def qrCallback(uuid, status, qrcode):
82
+ # logger.debug("qrCallback: {} {}".format(uuid,status))
83
+ if status == "0":
84
+ try:
85
+ from PIL import Image
86
+
87
+ img = Image.open(io.BytesIO(qrcode))
88
+ _thread = threading.Thread(target=img.show, args=("QRCode",))
89
+ _thread.setDaemon(True)
90
+ _thread.start()
91
+ except Exception as e:
92
+ pass
93
+
94
+ import qrcode
95
+
96
+ url = f"https://login.weixin.qq.com/l/{uuid}"
97
+
98
+ qr_api1 = "https://api.isoyu.com/qr/?m=1&e=L&p=20&url={}".format(url)
99
+ qr_api2 = "https://api.qrserver.com/v1/create-qr-code/?size=400×400&data={}".format(url)
100
+ qr_api3 = "https://api.pwmqr.com/qrcode/create/?url={}".format(url)
101
+ qr_api4 = "https://my.tv.sohu.com/user/a/wvideo/getQRCode.do?text={}".format(url)
102
+ print("You can also scan QRCode in any website below:")
103
+ print(qr_api3)
104
+ print(qr_api4)
105
+ print(qr_api2)
106
+ print(qr_api1)
107
+
108
+ _send_qr_code([qr_api3, qr_api4, qr_api2, qr_api1])
109
+
110
+ qr = qrcode.QRCode(border=1)
111
+ qr.add_data(url)
112
+ qr.make(fit=True)
113
+ qr.print_ascii(invert=True)
114
+
115
+
116
+ @singleton
117
+ class WechatChannel(ChatChannel):
118
+ NOT_SUPPORT_REPLYTYPE = []
119
+
120
+ def __init__(self):
121
+ super().__init__()
122
+ self.receivedMsgs = ExpiredDict(conf().get("expires_in_seconds", 3600))
123
+ self.auto_login_times = 0
124
+
125
+ def startup(self):
126
+ try:
127
+ itchat.instance.receivingRetryCount = 600 # 修改断线超时时间
128
+ # login by scan QRCode
129
+ hotReload = conf().get("hot_reload", False)
130
+ status_path = os.path.join(get_appdata_dir(), "itchat.pkl")
131
+ itchat.auto_login(
132
+ enableCmdQR=2,
133
+ hotReload=hotReload,
134
+ statusStorageDir=status_path,
135
+ qrCallback=qrCallback,
136
+ exitCallback=self.exitCallback,
137
+ loginCallback=self.loginCallback
138
+ )
139
+ self.user_id = itchat.instance.storageClass.userName
140
+ self.name = itchat.instance.storageClass.nickName
141
+ logger.info("Wechat login success, user_id: {}, nickname: {}".format(self.user_id, self.name))
142
+ # start message listener
143
+ itchat.run()
144
+ except Exception as e:
145
+ logger.exception(e)
146
+
147
+ def exitCallback(self):
148
+ try:
149
+ from common.linkai_client import chat_client
150
+ if chat_client.client_id and conf().get("use_linkai"):
151
+ _send_logout()
152
+ time.sleep(2)
153
+ self.auto_login_times += 1
154
+ if self.auto_login_times < 100:
155
+ chat_channel.handler_pool._shutdown = False
156
+ self.startup()
157
+ except Exception as e:
158
+ pass
159
+
160
+ def loginCallback(self):
161
+ logger.debug("Login success")
162
+ _send_login_success()
163
+
164
+ # handle_* 系列函数处理收到的消息后构造Context,然后传入produce函数中处理Context和发送回复
165
+ # Context包含了消息的所有信息,包括以下属性
166
+ # type 消息类型, 包括TEXT、VOICE、IMAGE_CREATE
167
+ # content 消息内容,如果是TEXT类型,content就是文本内容,如果是VOICE类型,content就是语音文件名,如果是IMAGE_CREATE类型,content就是图片生成命令
168
+ # kwargs 附加参数字典,包含以下的key:
169
+ # session_id: 会话id
170
+ # isgroup: 是否是群聊
171
+ # receiver: 需要回复的对象
172
+ # msg: ChatMessage消息对象
173
+ # origin_ctype: 原始消息类型,语音转文字后,私聊时如果匹配前缀失败,会根据初始消息是否是语音来放宽触发规则
174
+ # desire_rtype: 希望回复类型,默认是文本回复,设置为ReplyType.VOICE是语音回复
175
+ @time_checker
176
+ @_check
177
+ def handle_single(self, cmsg: ChatMessage):
178
+ # filter system message
179
+ if cmsg.other_user_id in ["weixin"]:
180
+ return
181
+ if cmsg.ctype == ContextType.VOICE:
182
+ if conf().get("speech_recognition") != True:
183
+ return
184
+ logger.debug("[WX]receive voice msg: {}".format(cmsg.content))
185
+ elif cmsg.ctype == ContextType.IMAGE:
186
+ logger.debug("[WX]receive image msg: {}".format(cmsg.content))
187
+ elif cmsg.ctype == ContextType.PATPAT:
188
+ logger.debug("[WX]receive patpat msg: {}".format(cmsg.content))
189
+ elif cmsg.ctype == ContextType.TEXT:
190
+ logger.debug("[WX]receive text msg: {}, cmsg={}".format(json.dumps(cmsg._rawmsg, ensure_ascii=False), cmsg))
191
+ else:
192
+ logger.debug("[WX]receive msg: {}, cmsg={}".format(cmsg.content, cmsg))
193
+ context = self._compose_context(cmsg.ctype, cmsg.content, isgroup=False, msg=cmsg)
194
+ if context:
195
+ self.produce(context)
196
+
197
+ @time_checker
198
+ @_check
199
+ def handle_group(self, cmsg: ChatMessage):
200
+ if cmsg.ctype == ContextType.VOICE:
201
+ if conf().get("group_speech_recognition") != True:
202
+ return
203
+ logger.debug("[WX]receive voice for group msg: {}".format(cmsg.content))
204
+ elif cmsg.ctype == ContextType.IMAGE:
205
+ logger.debug("[WX]receive image for group msg: {}".format(cmsg.content))
206
+ elif cmsg.ctype in [ContextType.JOIN_GROUP, ContextType.PATPAT, ContextType.ACCEPT_FRIEND,
207
+ ContextType.EXIT_GROUP]:
208
+ logger.debug("[WX]receive note msg: {}".format(cmsg.content))
209
+ elif cmsg.ctype == ContextType.TEXT:
210
+ # logger.debug("[WX]receive group msg: {}, cmsg={}".format(json.dumps(cmsg._rawmsg, ensure_ascii=False), cmsg))
211
+ pass
212
+ elif cmsg.ctype == ContextType.FILE:
213
+ logger.debug(f"[WX]receive attachment msg, file_name={cmsg.content}")
214
+ else:
215
+ logger.debug("[WX]receive group msg: {}".format(cmsg.content))
216
+ context = self._compose_context(cmsg.ctype, cmsg.content, isgroup=True, msg=cmsg)
217
+ if context:
218
+ self.produce(context)
219
+
220
+ # 统一的发送函数,每个Channel自行实现,根据reply的type字段发送不同类型的消息
221
+ def send(self, reply: Reply, context: Context):
222
+ receiver = context["receiver"]
223
+ if reply.type == ReplyType.TEXT:
224
+ itchat.send(reply.content, toUserName=receiver)
225
+ logger.info("[WX] sendMsg={}, receiver={}".format(reply, receiver))
226
+ elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:
227
+ itchat.send(reply.content, toUserName=receiver)
228
+ logger.info("[WX] sendMsg={}, receiver={}".format(reply, receiver))
229
+ elif reply.type == ReplyType.VOICE:
230
+ itchat.send_file(reply.content, toUserName=receiver)
231
+ logger.info("[WX] sendFile={}, receiver={}".format(reply.content, receiver))
232
+ elif reply.type == ReplyType.IMAGE_URL: # 从网络下载图片
233
+ img_url = reply.content
234
+ logger.debug(f"[WX] start download image, img_url={img_url}")
235
+ pic_res = requests.get(img_url, stream=True)
236
+ image_storage = io.BytesIO()
237
+ size = 0
238
+ for block in pic_res.iter_content(1024):
239
+ size += len(block)
240
+ image_storage.write(block)
241
+ logger.info(f"[WX] download image success, size={size}, img_url={img_url}")
242
+ image_storage.seek(0)
243
+ if ".webp" in img_url:
244
+ try:
245
+ image_storage = convert_webp_to_png(image_storage)
246
+ except Exception as e:
247
+ logger.error(f"Failed to convert image: {e}")
248
+ return
249
+ itchat.send_image(image_storage, toUserName=receiver)
250
+ logger.info("[WX] sendImage url={}, receiver={}".format(img_url, receiver))
251
+ elif reply.type == ReplyType.IMAGE: # 从文件读取图片
252
+ image_storage = reply.content
253
+ image_storage.seek(0)
254
+ itchat.send_image(image_storage, toUserName=receiver)
255
+ logger.info("[WX] sendImage, receiver={}".format(receiver))
256
+ elif reply.type == ReplyType.FILE: # 新增文件回复类型
257
+ file_storage = reply.content
258
+ itchat.send_file(file_storage, toUserName=receiver)
259
+ logger.info("[WX] sendFile, receiver={}".format(receiver))
260
+ elif reply.type == ReplyType.VIDEO: # 新增视频回复类型
261
+ video_storage = reply.content
262
+ itchat.send_video(video_storage, toUserName=receiver)
263
+ logger.info("[WX] sendFile, receiver={}".format(receiver))
264
+ elif reply.type == ReplyType.VIDEO_URL: # 新增视频URL回复类型
265
+ video_url = reply.content
266
+ logger.debug(f"[WX] start download video, video_url={video_url}")
267
+ video_res = requests.get(video_url, stream=True)
268
+ video_storage = io.BytesIO()
269
+ size = 0
270
+ for block in video_res.iter_content(1024):
271
+ size += len(block)
272
+ video_storage.write(block)
273
+ logger.info(f"[WX] download video success, size={size}, video_url={video_url}")
274
+ video_storage.seek(0)
275
+ itchat.send_video(video_storage, toUserName=receiver)
276
+ logger.info("[WX] sendVideo url={}, receiver={}".format(video_url, receiver))
277
+
278
+
279
+ def _send_login_success():
280
+ try:
281
+ from common.linkai_client import chat_client
282
+ if chat_client.client_id:
283
+ chat_client.send_login_success()
284
+ except Exception as e:
285
+ pass
286
+
287
+
288
+ def _send_logout():
289
+ try:
290
+ from common.linkai_client import chat_client
291
+ if chat_client.client_id:
292
+ chat_client.send_logout()
293
+ except Exception as e:
294
+ pass
295
+
296
+
297
+ def _send_qr_code(qrcode_list: list):
298
+ try:
299
+ from common.linkai_client import chat_client
300
+ if chat_client.client_id:
301
+ chat_client.send_qrcode(qrcode_list)
302
+ except Exception as e:
303
+ pass