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.
- {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/METADATA +38 -32
- MeUtils-2025.1.16.17.15.52.dist-info/RECORD +864 -0
- {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/WHEEL +1 -1
- {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/entry_points.txt +1 -0
- apps/spider.py +24 -8
- examples/_openaisdk/4v.py +110 -0
- examples/_openaisdk/__init__.py +11 -0
- examples/_openaisdk/baichuan.py +38 -0
- examples/_openaisdk/bpo.py +138 -0
- examples/_openaisdk/chat_latex.py +95 -0
- examples/_openaisdk/chattts.py +85 -0
- examples/_openaisdk/copilot.py +48 -0
- examples/_openaisdk/dalle3.py +48 -0
- examples/_openaisdk/deeplx.py +31 -0
- examples/_openaisdk/demo.py +77 -0
- examples/_openaisdk/embeddings.py +34 -0
- examples/_openaisdk/gpt4all.py +69 -0
- examples/_openaisdk/gpt_fc.py +23 -0
- examples/_openaisdk/gr_vl.py +46 -0
- examples/_openaisdk/json_mode.py +12 -0
- examples/_openaisdk/kimi.py +91 -0
- examples/_openaisdk/kimi_qa.py +57 -0
- examples/_openaisdk/minimax.py +75 -0
- examples/_openaisdk/open_router.py +48 -0
- examples/_openaisdk/openai_aiplus.py +54 -0
- examples/_openaisdk/openai_audio.py +20 -0
- examples/_openaisdk/openai_baichuan.py +59 -0
- examples/_openaisdk/openai_cache.py +37 -0
- examples/_openaisdk/openai_chatfire.py +228 -0
- examples/_openaisdk/openai_chatfire_all.py +166 -0
- examples/_openaisdk/openai_deepinfra.py +55 -0
- examples/_openaisdk/openai_deepseek.py +29 -0
- examples/_openaisdk/openai_doubao.py +43 -0
- examples/_openaisdk/openai_embeddings.py +36 -0
- examples/_openaisdk/openai_files.py +57 -0
- examples/_openaisdk/openai_gitee.py +33 -0
- examples/_openaisdk/openai_god.py +45 -0
- examples/_openaisdk/openai_groq.py +240 -0
- examples/_openaisdk/openai_images.py +203 -0
- examples/_openaisdk/openai_json.py +78 -0
- examples/_openaisdk/openai_lingyi.py +59 -0
- examples/_openaisdk/openai_modelscope.py +54 -0
- examples/_openaisdk/openai_moon.py +55 -0
- examples/_openaisdk/openai_oi.py +61 -0
- examples/_openaisdk/openai_ppu.py +47 -0
- examples/_openaisdk/openai_qwen.py +58 -0
- examples/_openaisdk/openai_search.py +42 -0
- examples/_openaisdk/openai_sensenova.py +81 -0
- examples/_openaisdk/openai_siliconflow.py +52 -0
- examples/_openaisdk/openai_step.py +45 -0
- examples/_openaisdk/openai_test.py +66 -0
- examples/_openaisdk/openai_together.py +57 -0
- examples/_openaisdk/openai_tune.py +38 -0
- examples/_openaisdk/openai_zhipu.py +59 -0
- examples/_openaisdk/ppu.py +28 -0
- examples/_openaisdk/rag.py +54 -0
- examples/_openaisdk/rag_.py +26 -0
- examples/_openaisdk/test.py +52 -0
- examples/_openaisdk/x.py +32 -0
- examples/_openaisdk/xx.py +29 -0
- examples/_openaisdk/zhipu_files.py +47 -0
- examples/_openaisdk/zhipu_/346/231/272/350/203/275/344/275/223.py +45 -0
- examples/_openaisdk//345/205/234/345/272/225/346/265/213/350/257/225.py +50 -0
- examples/_openaisdk//345/244/232/346/250/241/346/200/201/346/265/213/350/257/225.py +76 -0
- examples/_openaisdk//345/244/232/346/250/241/346/200/201/346/265/213/350/257/225_.py +56 -0
- examples/_openaisdk//346/226/207/344/273/266/351/227/256/347/255/224.py +36 -0
- examples/_openaisdk//346/226/207/346/241/243/350/247/243/346/236/220.py +34 -0
- examples/_openaisdk//346/250/241/345/236/213/346/265/213/350/257/225.py +53 -0
- examples/_openaisdk//351/230/277/351/207/214.py +80 -0
- {meutils/serving/jina/__demo → examples/ann}/__init__.py +1 -1
- examples/ann/main.py +31 -0
- examples/apis/kl.py +28 -0
- examples/apis/x.py +17 -0
- examples/apis/xx.py +17 -0
- examples/arq_demo/demo.py +3 -0
- examples/backgroundtasks.py +25 -0
- examples/bserver.py +513 -21
- examples/cache_demo/HermesCache_demo.py +81 -0
- examples/cache_demo/acacge.py +26 -0
- examples/cache_demo/x.py +31 -0
- {meutils/docarray_utils → examples/caches}/__init__.py +1 -1
- examples/caches/llmcache.py +18 -0
- examples/celery_demo/product_task.py +2 -0
- examples/demo.py +17 -1
- examples/fastapi_caching.py +59 -0
- {meutils/dependencies → examples/gr}/__init__.py +1 -1
- examples/gr/d.py +22 -0
- examples/gr/demo.py +30 -0
- examples/ip2/345/234/260/345/214/272.py +16 -0
- examples/jinja2_demo/j2_demo.py +20 -1
- examples/json/346/240/207/345/207/206/345/214/226.py +54 -0
- examples/md.py +29 -0
- {meutils/serving/jina → examples/nesc}/__init__.py +1 -1
- examples/nesc/main.py +76 -0
- examples/orm/mysql_orm.py +113 -0
- examples/orm/sql_creater.py +57 -0
- examples/orm/sqlm.py +134 -0
- examples/rq_demo/fns.py +18 -0
- examples/rq_demo/redis/351/230/237/345/210/227.py +14 -7
- examples/rq_demo/redis/351/230/237/345/210/227_add_chatfire.py +30 -0
- examples/size_map.py +43 -0
- examples/test.py +59 -0
- examples/webs/__init__.py +11 -0
- examples/webs/main.py +34 -0
- examples/x.py +13 -0
- examples//345/216/273/346/260/264/345/215/260.py +20 -0
- examples//346/226/207/346/241/243/346/231/272/350/203/275/__init__.py +11 -0
- meutils/_utils.py +15 -6
- meutils/ai_audio/asr/__init__.py +3 -2
- meutils/ai_audio/asr/cf_asr.py +53 -0
- meutils/ai_audio/asr/de.py +11 -0
- meutils/ai_audio/asr/fast_asr.py +15 -7
- meutils/ai_audio/asr/openai_asr.py +83 -6
- meutils/ai_audio/fast_asr.py +8 -4
- meutils/ai_audio/tts/EdgeTTS.py +33 -7
- meutils/ai_audio/tts/openai_tts.py +24 -20
- meutils/ai_audio/tts/tts_ui.py +1 -0
- meutils/ai_audio/utils.py +9 -0
- meutils/ai_cv/__init__.py +0 -1
- meutils/ai_cv/ocr.py +3 -2
- meutils/ai_cv/utils.py +154 -0
- meutils/ai_video/avmerge.py +6 -0
- meutils/ai_video/video.py +11 -2
- meutils/{api → apis}/__init__.py +1 -1
- meutils/apis/ali_apis.py +60 -0
- meutils/apis/audio/__init__.py +10 -0
- meutils/apis/audio/deepinfra.py +59 -0
- meutils/apis/audio/fish.py +248 -0
- meutils/apis/baidu/__init__.py +9 -0
- meutils/apis/baidu/bdaitpzs.py +229 -0
- meutils/apis/baidu/test.py +78 -0
- meutils/apis/chatglm/__init__.py +11 -0
- meutils/apis/chatglm/glm_video.py +273 -0
- meutils/apis/chatglm/glm_video_api.py +116 -0
- meutils/apis/chatglm/images.py +63 -0
- meutils/apis/chatglm/temp.py +259 -0
- meutils/apis/chatglm/x.py +31 -0
- meutils/{api → apis}/common.py +10 -6
- meutils/apis/fal/__init__.py +11 -0
- meutils/apis/fal/files.py +53 -0
- meutils/apis/fal/images.py +57 -0
- meutils/apis/fal/images_.py +72 -0
- meutils/apis/fal/videos.py +77 -0
- meutils/apis/firecrawl.py +45 -0
- meutils/apis/gitee/__init__.py +11 -0
- meutils/apis/gitee/images/__init__.py +9 -0
- meutils/apis/gitee/images/kolors.py +99 -0
- meutils/apis/hailuoai/__init__.py +11 -0
- meutils/apis/hailuoai/demo.py +34 -0
- meutils/apis/hailuoai/hasha_new.py +248 -0
- meutils/apis/hailuoai/music.py +11 -0
- meutils/apis/hailuoai/upload.py +116 -0
- meutils/apis/hailuoai/videos.py +460 -0
- meutils/apis/hailuoai/yy.py +242 -0
- meutils/apis/hf/__init__.py +11 -0
- meutils/apis/hf/got_ocr.py +64 -0
- meutils/apis/hf/gradio.py +34 -0
- meutils/apis/hf/hivisionidphotos.py +80 -0
- meutils/apis/hf/kolors.py +68 -0
- meutils/apis/hf/kolors_virtual_try_on.py +107 -0
- meutils/apis/hf/r.py +53 -0
- meutils/apis/hf/x.py +26 -0
- meutils/apis/hf//350/257/201/344/273/266/347/205/247.py +41 -0
- meutils/apis/hunyuan/__init__.py +11 -0
- meutils/apis/hunyuan/image_tools.py +84 -0
- meutils/apis/images/__init__.py +11 -0
- meutils/apis/images/deepinfra.py +92 -0
- meutils/apis/images/demo.py +150 -0
- meutils/apis/images/eidt.py +36 -0
- meutils/apis/images/flux/__init__.py +11 -0
- meutils/apis/images/flux/fluxpro.py +108 -0
- meutils/apis/images/flux/mystic.py +116 -0
- meutils/apis/images/ideogram/__init__.py +10 -0
- meutils/apis/images/ideogram/ideogram_images.py +193 -0
- meutils/apis/images/prodia/__init__.py +12 -0
- meutils/apis/images/prodia/faceswap.py +76 -0
- meutils/apis/images/recraft.py +152 -0
- meutils/apis/images/virtual_try_on/__init__.py +11 -0
- meutils/apis/images/virtual_try_on/images.py +65 -0
- meutils/apis/jiema/24mail.py +96 -0
- meutils/apis/jiema/__init__.py +11 -0
- meutils/apis/jiema/yezi.py +97 -0
- meutils/apis/jimeng/__init__.py +11 -0
- meutils/apis/jimeng/common.py +328 -0
- meutils/apis/jimeng/doubao.py +68 -0
- meutils/apis/jimeng/doubao_utils.py +175 -0
- meutils/apis/jimeng/files.py +263 -0
- meutils/apis/jimeng/images.py +140 -0
- meutils/apis/jimeng/lip_sync.py +11 -0
- meutils/apis/jina.py +55 -0
- meutils/apis/kling/__init__.py +11 -0
- meutils/apis/kling/api.py +60 -0
- meutils/apis/kling/images.py +174 -0
- meutils/apis/kling/kolors_virtual_try_on.py +111 -0
- meutils/apis/kling/kolors_virtual_try_on_web.py +126 -0
- meutils/apis/kling/videos.py +67 -0
- meutils/apis/kling//351/211/264/346/235/203.py +34 -0
- meutils/apis/kuaidi.py +32 -0
- meutils/apis/kuaishou/__init__.py +10 -0
- meutils/apis/kuaishou/klingai.py +523 -0
- meutils/apis/kuaishou/klingai_video.py +197 -0
- meutils/apis/kuaishou/kolors.py +189 -0
- meutils/apis/llm_qa.py +55 -0
- meutils/apis/luma/__init__.py +11 -0
- meutils/apis/luma/luma.py +123 -0
- meutils/apis/minicpm/__init__.py +9 -0
- meutils/apis/minicpm/luca.py +137 -0
- meutils/apis/monica/__init__.py +11 -0
- meutils/apis/monica/llm.py +11 -0
- meutils/apis/napkin/__init__.py +11 -0
- meutils/apis/napkin/icons.py +42 -0
- meutils/apis/niutrans.py +73 -0
- meutils/apis/oneapi/__init__.py +11 -0
- meutils/apis/oneapi/channel.py +68 -0
- meutils/apis/oneapi/common.py +135 -0
- meutils/apis/oneapi/log.py +47 -0
- meutils/apis/oneapi/token.py +48 -0
- meutils/apis/oneapi/token_.py +112 -0
- meutils/apis/oneapi/user.py +100 -0
- meutils/apis/oneapi/utils.py +47 -0
- meutils/apis/pixverse/__init__.py +11 -0
- meutils/apis/pixverse/pixverse.py +150 -0
- meutils/apis/proxy/__init__.py +11 -0
- meutils/apis/proxy/ips.py +178 -0
- meutils/apis/remini/__init__.py +11 -0
- meutils/apis/remini/remini.py +89 -0
- meutils/apis/replicateai/__init__.py +11 -0
- meutils/apis/replicateai/images.py +79 -0
- meutils/apis/replicateai/raw.py +53 -0
- meutils/apis/runwayml/__init__.py +10 -0
- meutils/apis/runwayml/gen.py +143 -0
- meutils/apis/search/__init__.py +11 -0
- meutils/apis/search/baichuan.py +11 -0
- meutils/apis/search/metaso.py +218 -0
- meutils/apis/search/metaso_.py +77 -0
- meutils/apis/search/n.py +99 -0
- meutils/apis/search/searxng.py +42 -0
- meutils/apis/search_music.py +39 -0
- meutils/apis/siliconflow/__init__.py +9 -0
- meutils/apis/siliconflow/audio.py +63 -0
- meutils/apis/siliconflow/image_to_image.py +116 -0
- meutils/apis/siliconflow/images.py +154 -0
- meutils/apis/siliconflow/rerankers.py +40 -0
- meutils/apis/siliconflow/text_to_image.py +132 -0
- meutils/apis/siliconflow/utils.py +66 -0
- meutils/apis/siliconflow/videos.py +102 -0
- meutils/apis/sunoai/__init__.py +10 -0
- meutils/apis/sunoai/haimian.py +135 -0
- meutils/apis/sunoai/suno.py +373 -0
- meutils/apis/textcard/__init__.py +11 -0
- meutils/apis/textcard/demo.py +25 -0
- meutils/apis/textcard/hanyuxinjie.py +81 -0
- meutils/apis/textin.py +159 -0
- meutils/apis/to_image/__init__.py +11 -0
- meutils/apis/to_image/html2image.py +29 -0
- meutils/apis/to_image/md.py +29 -0
- meutils/apis/to_image/url2image.py +41 -0
- meutils/apis/together/__init__.py +11 -0
- meutils/apis/together/images.py +80 -0
- meutils/apis/translator/__init__.py +9 -0
- meutils/apis/translator/deeplx.py +55 -0
- meutils/apis/tripo3d/__init__.py +11 -0
- meutils/apis/tripo3d/images.py +106 -0
- meutils/apis/ts.py +60 -0
- meutils/apis/uptime_kuma/__init__.py +11 -0
- meutils/apis/uptime_kuma/common.py +56 -0
- meutils/apis/uptime_kuma//345/233/275/344/272/247/345/210/206/347/273/204.py +68 -0
- meutils/apis/utils.py +47 -0
- meutils/apis/videos/__init__.py +11 -0
- meutils/apis/videos/sora.py +16 -0
- meutils/apis/vidu/__init__.py +9 -0
- meutils/apis/vidu/vidu_video.py +254 -0
- meutils/apis/vidu/x.py +14 -0
- meutils/apis/voice_clone/__init__.py +10 -0
- meutils/apis/voice_clone/fish.py +236 -0
- meutils/apis/voice_clone/fish_api.py +16 -0
- meutils/apis/web_search.py +31 -0
- meutils/apis/yezi.py +97 -0
- meutils/async_task/__init__.py +13 -0
- meutils/async_task/celery_config.py +106 -0
- meutils/async_task/common.py +37 -0
- meutils/async_task/demo_create_tasks.py +73 -0
- meutils/async_task/tasks/__init__.py +11 -0
- meutils/async_task/tasks/_all.py +20 -0
- meutils/async_task/tasks/hailuo.py +24 -0
- meutils/async_task/tasks/kling.py +30 -0
- meutils/async_task/tasks/replicateai.py +24 -0
- meutils/async_task/tasks/test.py +124 -0
- meutils/async_task/tasks/vidu.py +28 -0
- meutils/async_task/utils.py +191 -0
- meutils/async_task//351/200/232/347/224/250/350/256/276/350/256/241.py +119 -0
- meutils/async_utils/asyncer_.py +37 -0
- meutils/async_utils/background.py +68 -0
- meutils/async_utils/common.py +136 -16
- meutils/async_utils/test.py +47 -0
- meutils/cache_utils.py +29 -23
- meutils/caches/__init__.py +9 -0
- meutils/caches/acache.py +45 -0
- meutils/caches/redis_cache.py +63 -0
- meutils/clis/check_api.py +66 -0
- meutils/clis/cli.py +1 -1
- meutils/common.py +56 -17
- meutils/config_utils/__init__.py +11 -0
- meutils/config_utils/lark_utils/__init__.py +11 -0
- meutils/config_utils/lark_utils/common.py +385 -0
- meutils/config_utils/lark_utils/demo.py +13 -0
- meutils/config_utils/lark_utils/x.py +50 -0
- meutils/config_utils/manager.py +108 -0
- meutils/crawlers/__init__.py +11 -0
- meutils/data/VERSION +1 -1
- meutils/data/cowboy-hat-face.webp +0 -0
- meutils/data/oneapi/FOOTER.md +7 -0
- meutils/data/oneapi/NOTICE.md +138 -0
- meutils/data/oneapi/__init__.py +15 -0
- meutils/db/orm.py +179 -0
- meutils/db/redis_db.py +87 -0
- meutils/decorators/cache.py +1 -1
- meutils/decorators/common.py +84 -5
- meutils/decorators/contextmanagers.py +17 -6
- meutils/decorators/fastapi_decorator.py +77 -3
- meutils/decorators/polling.py +46 -0
- meutils/decorators/retry.py +150 -26
- meutils/fastapi_utils/__init__.py +11 -0
- meutils/fastapi_utils/exceptions/http_error.py +72 -0
- meutils/fastapi_utils/exceptions/validation_error.py +44 -0
- meutils/hash_utils.py +9 -4
- meutils/hooks/__init__.py +11 -0
- meutils/hooks/hook_test.py +174 -0
- meutils/hooks/wechat.py +162 -0
- meutils/hooks/wechat_channel.py +303 -0
- meutils/init/evn.py +1 -1
- meutils/io/files_utils.py +232 -0
- meutils/io/image.py +148 -10
- meutils/io/x.py +75 -0
- meutils/llm/__init__.py +10 -0
- meutils/llm/check_api.py +109 -0
- meutils/llm/check_utils.py +106 -0
- meutils/llm/clients.py +38 -0
- meutils/llm/completions/__init__.py +11 -0
- meutils/llm/completions/agents/__init__.py +11 -0
- meutils/llm/completions/agents/file.py +125 -0
- meutils/llm/completions/cp.py +112 -0
- meutils/llm/completions/delilegal.py +135 -0
- meutils/llm/completions/dify.py +81 -0
- meutils/llm/completions/kimi.py +47 -0
- meutils/llm/completions/modelscope.py +11 -0
- meutils/{fileparser/filetype.py → llm/completions/oi.py} +5 -3
- meutils/llm/completions/rag/__init__.py +11 -0
- meutils/llm/completions/rag/fire.py +157 -0
- meutils/llm/completions/rag/qwen.py +11 -0
- meutils/llm/completions/rag/rag.py +41 -0
- meutils/llm/completions/rag.py +38 -0
- meutils/llm/completions/tryblend.py +201 -0
- meutils/llm/completions/tune.py +284 -0
- meutils/llm/completions/x.py +26 -0
- meutils/llm/completions/xx.py +61 -0
- meutils/llm/completions/yuanbao.py +176 -0
- meutils/llm/demo.py +114 -0
- meutils/llm/functions/__init__.py +11 -0
- meutils/llm/mappers.py +15 -0
- meutils/llm/openai_utils/__init__.py +11 -0
- meutils/llm/openai_utils/common.py +284 -0
- meutils/llm/openai_utils/tool_outputs.py +45 -0
- meutils/llm/output_parsers/__init__.py +80 -0
- meutils/llm/prompts/__init__.py +244 -0
- meutils/llm/prompts/demo.py +155 -0
- meutils/llm/prompts/html2image_test.py +19 -0
- meutils/llm/utils.py +133 -0
- meutils/llm/x.py +75 -0
- meutils/notice/feishu.py +40 -9
- meutils/notice/wechat.py +23 -21
- meutils/np_utils.py +10 -1
- meutils/office_automation/pdf.py +6 -1
- meutils/oss/__init__.py +20 -0
- meutils/oss/minio_oss.py +184 -0
- meutils/oss/minio_utils.py +48 -0
- meutils/other/__demo.py +6 -4
- meutils/pandas_utils/__init__.py +1 -0
- meutils/pandas_utils/common.py +31 -0
- meutils/pandas_utils/pd_utils.py +10 -6
- meutils/parsers/__init__.py +10 -0
- meutils/parsers/file_parsers.py +110 -0
- meutils/parsers/fileparser/demo.py +41 -0
- meutils/parsers/fileparser/filetype.py +41 -0
- meutils/pay.py +37 -0
- meutils/pipe.py +37 -4
- meutils/playwright_utils/common.py +20 -12
- meutils/plots/common.py +35 -34
- meutils/queues/demo.py +56 -0
- meutils/queues/smooth_queue.py +120 -0
- meutils/queues/uniform_queue.py +3 -1
- meutils/request_utils/__init__.py +26 -2
- meutils/request_utils/ark.py +47 -0
- meutils/request_utils/crawler.py +34 -5
- meutils/request_utils/jwt_utils/__init__.py +11 -0
- meutils/request_utils/jwt_utils/common.py +42 -0
- meutils/request_utils/volc.py +160 -0
- meutils/schemas/__init__.py +0 -1
- meutils/schemas/baidu_types.py +70 -0
- meutils/schemas/batch_types.py +450 -0
- meutils/schemas/celery_types.py +64 -0
- meutils/schemas/chatfire_types.py +15 -0
- meutils/schemas/chatglm_types.py +197 -0
- meutils/schemas/db/__init__.py +11 -0
- meutils/schemas/db/oneapi_types.py +117 -0
- meutils/schemas/dify_types.py +40 -0
- meutils/schemas/embedding.py +31 -0
- meutils/schemas/fal_types.py +13 -0
- meutils/schemas/fish_types.py +11 -0
- meutils/schemas/hailuo_types.py +208 -0
- meutils/schemas/haimian_types.py +51 -0
- meutils/schemas/idphoto_types.py +43 -0
- meutils/schemas/image_types.py +476 -0
- meutils/schemas/jimeng_types.py +28 -0
- meutils/schemas/jina_types.py +67 -0
- meutils/schemas/kimi_types.py +86 -0
- meutils/schemas/kling_types.py +235 -0
- meutils/schemas/kuaishou_types.py +328 -0
- meutils/schemas/luma_types.py +59 -0
- meutils/schemas/message_types.py +165 -0
- meutils/schemas/message_types_.py +219 -0
- meutils/schemas/metaso_types.py +64 -0
- meutils/schemas/napkin_types.py +85 -0
- meutils/schemas/ocr_types.py +37 -0
- meutils/schemas/oneapi/__init__.py +11 -0
- meutils/schemas/oneapi/_types.py +49 -0
- meutils/schemas/oneapi/common.py +883 -0
- meutils/schemas/oneapi/icons.py +30 -0
- meutils/schemas/oneapi/model_group_info.py +48 -0
- meutils/schemas/oneapi/model_info.py +34 -0
- meutils/schemas/oneapi/models.py +26 -0
- meutils/schemas/oneapi/x.py +26 -0
- meutils/schemas/oneapi//351/207/215/345/256/232/345/220/221.py +132 -0
- meutils/schemas/openai_api_protocol.py +411 -0
- meutils/schemas/openai_types.py +366 -0
- meutils/schemas/pixverse_types.py +88 -0
- meutils/schemas/playwright_types.py +57 -0
- meutils/schemas/prodia_types.py +19 -0
- meutils/schemas/replicate_types.py +112 -0
- meutils/schemas/request_types.py +20 -0
- meutils/schemas/runwayml_types.py +190 -0
- meutils/schemas/siliconflow_types.py +80 -0
- meutils/schemas/step_types.py +19 -0
- meutils/schemas/suno_types.py +319 -0
- meutils/schemas/task_types.py +192 -0
- meutils/schemas/translator_types.py +29 -0
- meutils/schemas/tripo3d_types.py +57 -0
- meutils/schemas/tryblend_types.py +51 -0
- meutils/schemas/video_types.py +62 -0
- meutils/schemas/vidu_types.py +350 -0
- meutils/schemas/wechat_types.py +316 -0
- meutils/schemas/yuanbao_types.py +260 -0
- meutils/serving/celery/__init__.py +8 -0
- meutils/serving/celery/config.py +115 -0
- meutils/serving/celery/router.py +4 -6
- meutils/serving/celery/tasks.py +6 -4
- meutils/serving/celery//351/200/232/347/224/250/350/256/276/350/256/241.py +119 -0
- meutils/serving/fastapi/common.py +27 -31
- meutils/serving/fastapi/dependencies/__init__.py +0 -1
- meutils/serving/fastapi/dependencies/auth.py +55 -2
- meutils/serving/fastapi/exceptions/http_error.py +67 -2
- meutils/serving/fastapi/exceptions/validation_error.py +18 -2
- meutils/serving/fastapi/lifespans.py +73 -0
- meutils/serving/fastapi/routers/scheduler.py +12 -0
- meutils/serving/fastapi/routers/screenshot.py +47 -0
- meutils/serving/fastapi/routers/spider.py +8 -3
- meutils/serving/fastapi/routers/task.py +48 -0
- meutils/serving/fastapi/utils.py +48 -1
- meutils/serving/streamlit/common.py +1 -1
- meutils/smooth_utils.py +3 -0
- meutils/str_utils/__init__.py +22 -3
- meutils/str_utils/json_utils.py +7 -0
- meutils/str_utils/regular_expression.py +102 -10
- meutils/templates/xx.html +21 -0
- meutils/templates/xxx.html +117 -0
- meutils/todo.py +12 -0
- meutils/tools/token_monitor.py +33 -0
- MeUtils-2024.3.4.13.4.45.dist-info/RECORD +0 -540
- meutils/ai_audio/asr/subtitle.srt +0 -40
- meutils/ai_audio/demo.ipynb +0 -1215
- meutils/ai_audio/example.srt +0 -348
- meutils/ai_audio/new.srt +0 -179
- meutils/ai_audio/subtitles.srt +0 -696
- meutils/ai_audio/tts/new.srt +0 -179
- meutils/ai_audio//350/247/206/351/242/221/345/220/210/345/271/266.sh +0 -32
- meutils/ai_cv/1.jpg +0 -0
- meutils/ai_cv/197.jpg +0 -0
- meutils/ai_cv/2.jpg +0 -0
- meutils/ai_cv/img.png +0 -0
- meutils/ai_cv/invoice.jpg +0 -0
- meutils/ai_cv/tbl.png +0 -0
- meutils/ai_cv/test.png +0 -0
- meutils/ann/README.md +0 -33
- meutils/ann/README_gensim.md +0 -47
- meutils/ann/examples/client.py +0 -59
- meutils/ann/examples/demo.py +0 -24
- meutils/api/deeplx.py +0 -29
- meutils/api/qr.png +0 -0
- meutils/clis/README.md +0 -29
- meutils/clis/__test.sh +0 -17
- meutils/clis/deepseek.txt +0 -8
- meutils/clis/deepseek_13003330042.json +0 -1
- meutils/clis/deepseek_13003872192.json +0 -1
- meutils/clis/deepseek_13852263862.json +0 -1
- meutils/clis/deepseek_13913898681.json +0 -1
- meutils/clis/deepseek_13962978617.json +0 -1
- meutils/clis/deepseek_15251801790.json +0 -1
- meutils/clis/deepseek_15720826383.json +0 -1
- meutils/clis/deepseek_18395563611.json +0 -1
- meutils/clis/deepseek_313303303@qq.com.json +0 -1
- meutils/clis/kimi_state.json +0 -1
- meutils/cmds/README.md +0 -55
- meutils/coding/__init__.py +0 -11
- meutils/coding/find132.py +0 -40
- meutils/db/README.md +0 -51
- meutils/decorators/README.md +0 -17
- meutils/docarray_utils/demo_es.py +0 -34
- meutils/docarray_utils/demo_hnsw.py +0 -55
- meutils/docarray_utils/in_memory.py +0 -38
- meutils/docarray_utils//346/224/271/351/200/240/344/270/213hnsw.py +0 -43
- meutils/io/file.py +0 -20
- meutils/io/img.png +0 -0
- meutils/io/x.yml +0 -1
- meutils/notice/img.png +0 -0
- meutils/notice/todo.md +0 -10
- 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
- meutils/playwright_utils/__test.sh +0 -2
- meutils/playwright_utils/kimi1_cookies.json +0 -1
- meutils/playwright_utils/kimi2_cookies.json +0 -1
- meutils/playwright_utils/kimi_cookies.json +0 -93
- meutils/serving/README.md +0 -1
- meutils/serving/celery/_run.sh +0 -10
- meutils/serving/gui/run.sh +0 -9
- meutils/serving/jina/__demo/client.py +0 -42
- meutils/serving/jina/__demo/flow.svg +0 -1
- meutils/serving/jina/__demo/s.py +0 -34
- meutils/serving/jina/__demo/s2.py +0 -37
- meutils/serving/jina/__demo/server.py +0 -83
- meutils/serving/jina/__demo/test.py +0 -40
- meutils/serving/jina/executors/SentenceEncoder.py +0 -62
- meutils/serving/jina/executors/SentenceEncoder_.py +0 -63
- meutils/serving/jina/executors/__init__.py +0 -46
- meutils/serving/jina/executors/base.py +0 -40
- meutils/serving/jina/nlp_serving/__init__.py +0 -11
- meutils/serving/jina/nlp_serving/word_segmentation.py +0 -40
- meutils/serving/streamlit/conf.yaml +0 -5
- meutils/serving/streamlit/ocr.png +0 -0
- meutils/serving/streamlit/run.sh +0 -17
- meutils/serving/webui/.streamlit/_config.toml +0 -186
- meutils/serving/webui/.streamlit/config.toml +0 -26
- meutils/serving/webui/pages/_1_/345/210/206/350/257/215.py +0 -56
- 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
- meutils/serving/webui/pages/_3_/346/226/207/346/234/254/345/214/271/351/205/215.py +0 -64
- meutils/serving/webui/run.sh +0 -9
- meutils/spark/__init__.py +0 -26
- meutils/tools/monitor.yml +0 -29
- {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/LICENSE +0 -0
- {MeUtils-2024.3.4.13.4.45.dist-info → MeUtils-2025.1.16.17.15.52.dist-info}/top_level.txt +0 -0
- {meutils → examples}/comp_utils/__init__.py +0 -0
- {meutils → examples}/comp_utils/reverse_metric.py +0 -0
- /meutils/{fileparser/README.md → fastapi_utils/exceptions/__init__.py} +0 -0
- /meutils/{fileparser → parsers/fileparser}/PDF/346/212/275/345/217/226.py" +0 -0
- /meutils/{fileparser → parsers/fileparser}/__init__.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/common.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/__init__.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/__main__.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/filetype.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/helpers.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/match.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/__init__.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/application.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/archive.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/audio.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/base.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/document.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/font.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/image.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/isobmff.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/types/video.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/filetype/utils.py +0 -0
- /meutils/{fileparser → parsers/fileparser}/pdf.py +0 -0
- /meutils/{fileparser → parsers/fileparser}//350/241/250/346/240/274/346/212/275/345/217/226.py" +0 -0
meutils/decorators/common.py
CHANGED
@@ -21,7 +21,7 @@ import wrapt
|
|
21
21
|
from loguru import logger
|
22
22
|
from tqdm.auto import tqdm
|
23
23
|
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
|
24
|
-
from contextlib import contextmanager
|
24
|
+
from contextlib import contextmanager, asynccontextmanager
|
25
25
|
from typing import *
|
26
26
|
# ME
|
27
27
|
from meutils.decorators.decorator import decorator
|
@@ -77,7 +77,7 @@ def return2log(func, sink=sys.stderr, logkwargs=None, *args, **kwargs):
|
|
77
77
|
|
78
78
|
|
79
79
|
@contextmanager
|
80
|
-
def timer(task="Task"):
|
80
|
+
def timer(task="Task", notice_fn: Optional[Callable] = None):
|
81
81
|
"""https://www.kaggle.com/lopuhin/mercari-golf-0-3875-cv-in-75-loc-1900-s
|
82
82
|
# 其他装饰器可学习这种写法
|
83
83
|
with timer() as t:
|
@@ -88,13 +88,50 @@ def timer(task="Task"):
|
|
88
88
|
print('sleeping')
|
89
89
|
time.sleep(6)
|
90
90
|
return 6
|
91
|
+
|
92
|
+
|
93
|
+
from meutils.notice import feishu
|
94
|
+
feishu.send_message
|
91
95
|
"""
|
92
96
|
|
93
97
|
logger.info(f"{task} started")
|
94
98
|
s = time.perf_counter()
|
95
99
|
yield
|
96
100
|
e = time.perf_counter()
|
97
|
-
|
101
|
+
msg = f"{task} done in {e - s:.3f} s"
|
102
|
+
logger.info(msg) # feishu
|
103
|
+
|
104
|
+
# notice
|
105
|
+
if notice_fn: notice_fn(msg)
|
106
|
+
|
107
|
+
|
108
|
+
@asynccontextmanager
|
109
|
+
async def async_timer(task="Task", notice_fn: Optional[Callable] = None):
|
110
|
+
"""
|
111
|
+
Async context manager for timing tasks.
|
112
|
+
|
113
|
+
Usage:
|
114
|
+
```python
|
115
|
+
async with async_timer() as t:
|
116
|
+
await asyncio.sleep(3)
|
117
|
+
|
118
|
+
@async_timer()
|
119
|
+
async def f():
|
120
|
+
print('sleeping')
|
121
|
+
await asyncio.sleep(6)
|
122
|
+
return 6
|
123
|
+
```
|
124
|
+
"""
|
125
|
+
logger.info(f"{task} started")
|
126
|
+
s = time.perf_counter()
|
127
|
+
yield
|
128
|
+
e = time.perf_counter()
|
129
|
+
msg = f"{task} done in {e - s:.3f} s"
|
130
|
+
logger.info(msg) # feishu
|
131
|
+
|
132
|
+
# notice
|
133
|
+
if notice_fn:
|
134
|
+
await notice_fn(msg)
|
98
135
|
|
99
136
|
|
100
137
|
@contextmanager
|
@@ -170,6 +207,7 @@ def background_task(func, max_workers=1, *args, **kwargs):
|
|
170
207
|
# pool.shutdown(wait=False) # 不等待
|
171
208
|
# pool.shutdown(wait=True) # 等待
|
172
209
|
|
210
|
+
# with ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix='🐶') as pool: # 失去异步效果
|
173
211
|
pool = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix='🐶')
|
174
212
|
future = pool.submit(func, *args, **kwargs) # pool.map(fun4, ips)
|
175
213
|
future.add_done_callback(
|
@@ -177,6 +215,8 @@ def background_task(func, max_workers=1, *args, **kwargs):
|
|
177
215
|
)
|
178
216
|
# future.add_done_callback()
|
179
217
|
|
218
|
+
# pool.shutdown(wait=False) # 不等待
|
219
|
+
|
180
220
|
return future.running() # future.done()
|
181
221
|
|
182
222
|
|
@@ -187,7 +227,7 @@ background = background_task
|
|
187
227
|
def background_task_plus(func, *args, **kwargs):
|
188
228
|
pool = ThreadPoolExecutor(max_workers=1, thread_name_prefix='🐶')
|
189
229
|
future = pool.submit(func, *args, **kwargs) # pool.map(fun4, ips)
|
190
|
-
future.add_done_callback(lambda x: logger.error(future.exception()) if future.exception() else None)
|
230
|
+
future.add_done_callback(lambda x: logger.error(f"{future.exception()}") if future.exception() else None)
|
191
231
|
# 详细错误 traceback.format_exc()
|
192
232
|
return future.running() # future.done()
|
193
233
|
|
@@ -283,6 +323,43 @@ def requires_dependencies(
|
|
283
323
|
return decorator
|
284
324
|
|
285
325
|
|
326
|
+
def ratelimit(
|
327
|
+
name: str = "ratelimit",
|
328
|
+
weight: int = 1,
|
329
|
+
rates: Optional[List[Any]] = None,
|
330
|
+
):
|
331
|
+
""" https://github.com/vutran1710/PyrateLimiter
|
332
|
+
:param name:
|
333
|
+
:param weight:
|
334
|
+
:param rates:
|
335
|
+
:return:
|
336
|
+
"""
|
337
|
+
from pyrate_limiter import Duration, Rate, Limiter, BucketFullException
|
338
|
+
|
339
|
+
rates = rates or [
|
340
|
+
Rate(1, Duration.SECOND),
|
341
|
+
Rate(2, Duration.SECOND * 15),
|
342
|
+
Rate(2 ** 2, Duration.MINUTE),
|
343
|
+
Rate(2 ** 4, Duration.HOUR),
|
344
|
+
Rate(2 ** 8, Duration.DAY)
|
345
|
+
]
|
346
|
+
limiter = Limiter(rates)
|
347
|
+
|
348
|
+
def name2weight(*args, **kwargs): # 动态限频 limiter.try_acquire(self, name: str, weight: int = 1)
|
349
|
+
return name, weight
|
350
|
+
|
351
|
+
limiter_decorator = limiter.as_decorator()(name2weight)
|
352
|
+
|
353
|
+
@wrapt.decorator
|
354
|
+
def wrapper(wrapped, instance, args, kwargs):
|
355
|
+
try:
|
356
|
+
return limiter_decorator(wrapped)(*args, **kwargs)
|
357
|
+
except BucketFullException as e:
|
358
|
+
return e.meta_info
|
359
|
+
|
360
|
+
return wrapper
|
361
|
+
|
362
|
+
|
286
363
|
def ratelimiter(limit_value: str = '3/1', callback=None):
|
287
364
|
from ratelimiter import RateLimiter
|
288
365
|
|
@@ -321,6 +398,8 @@ def limit(limit_value: str = '1/second', key_func: Callable[..., str] = None, er
|
|
321
398
|
return inner
|
322
399
|
|
323
400
|
|
401
|
+
|
402
|
+
|
324
403
|
if __name__ == '__main__':
|
325
404
|
import time
|
326
405
|
|
@@ -398,7 +477,7 @@ if __name__ == '__main__':
|
|
398
477
|
# pass
|
399
478
|
|
400
479
|
def f():
|
401
|
-
return
|
480
|
+
return 1 / 0
|
402
481
|
# return 1
|
403
482
|
|
404
483
|
|
@@ -10,9 +10,7 @@
|
|
10
10
|
|
11
11
|
from meutils.pipe import *
|
12
12
|
|
13
|
-
from contextlib import contextmanager
|
14
|
-
|
15
|
-
from urllib3 import HTTPResponse
|
13
|
+
from contextlib import contextmanager, asynccontextmanager
|
16
14
|
|
17
15
|
|
18
16
|
@contextmanager
|
@@ -37,18 +35,31 @@ def timer(task="Task"):
|
|
37
35
|
|
38
36
|
|
39
37
|
@contextmanager
|
40
|
-
def
|
38
|
+
def try_catcher(task="Task", fallback: Callable = None, is_trace: bool = False):
|
41
39
|
try:
|
42
40
|
yield
|
43
41
|
except Exception as e:
|
44
42
|
error = traceback.format_exc() if is_trace else e
|
45
43
|
logger.error(f"{task}: {error}")
|
44
|
+
if fallback:
|
45
|
+
yield fallback()
|
46
46
|
|
47
47
|
|
48
|
-
@
|
49
|
-
def
|
48
|
+
@asynccontextmanager
|
49
|
+
async def atry_catcher(task="Task", fallback: Callable = None, is_trace: bool = False):
|
50
50
|
try:
|
51
51
|
yield
|
52
52
|
except Exception as e:
|
53
53
|
error = traceback.format_exc() if is_trace else e
|
54
54
|
logger.error(f"{task}: {error}")
|
55
|
+
if fallback:
|
56
|
+
yield await fallback()
|
57
|
+
|
58
|
+
|
59
|
+
if __name__ == '__main__':
|
60
|
+
async def f():
|
61
|
+
return 1/0
|
62
|
+
|
63
|
+
|
64
|
+
with try_catcher("test"):
|
65
|
+
arun(f())
|
@@ -34,17 +34,91 @@ def catch_exceptions(func=None, *, exception_type=Exception, status_code=404):
|
|
34
34
|
return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
|
35
35
|
|
36
36
|
|
37
|
+
def catch_exceptions_(func):
|
38
|
+
@wraps(func)
|
39
|
+
async def wrapper(*args, **kwargs):
|
40
|
+
try:
|
41
|
+
return await func(*args, **kwargs)
|
42
|
+
except CustomException as e:
|
43
|
+
return JSONResponse(
|
44
|
+
status_code=418,
|
45
|
+
content={"message": f"An error occurred: {str(e)}"},
|
46
|
+
)
|
47
|
+
except Exception as e:
|
48
|
+
return JSONResponse(
|
49
|
+
status_code=500,
|
50
|
+
content={"message": "An unexpected error occurred."}
|
51
|
+
)
|
52
|
+
|
53
|
+
return wrapper
|
54
|
+
|
55
|
+
|
56
|
+
# 然后在你的路由中使用装饰器:
|
57
|
+
# @app.get("/items/{item_id}")
|
58
|
+
# @catch_exceptions
|
59
|
+
# async def read_item(item_id: int):
|
60
|
+
# # 你的业务逻辑
|
61
|
+
# pass
|
62
|
+
|
63
|
+
|
37
64
|
if __name__ == '__main__':
|
38
65
|
from meutils.serving.fastapi import App
|
66
|
+
from fastapi import Depends
|
39
67
|
|
40
68
|
app = App()
|
41
69
|
|
42
70
|
|
71
|
+
async def catch_exceptions(exception_type=Exception, status_code=404):
|
72
|
+
try:
|
73
|
+
yield
|
74
|
+
except exception_type as e:
|
75
|
+
raise HTTPException(status_code=status_code, detail=f"Error: {e}")
|
76
|
+
|
77
|
+
|
78
|
+
from fastapi import FastAPI, HTTPException, Depends, Request
|
79
|
+
from starlette.responses import JSONResponse
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
async def catch_exceptions(request: Request, call_next):
|
84
|
+
try:
|
85
|
+
response = await call_next(request)
|
86
|
+
return response
|
87
|
+
except IOError as e:
|
88
|
+
return JSONResponse(status_code=500, content={"detail": f"IOError: {e}"})
|
89
|
+
|
90
|
+
|
91
|
+
@app.middleware("http")
|
92
|
+
async def catch_exceptions_middleware(request: Request, call_next):
|
93
|
+
return await catch_exceptions(request, call_next)
|
94
|
+
|
95
|
+
|
43
96
|
@app.get("/test")
|
44
|
-
|
45
|
-
|
46
|
-
logger.debug(file_id)
|
97
|
+
def test_endpoint(file_id: str):
|
98
|
+
# Your endpoint logic here
|
47
99
|
raise Exception("test")
|
100
|
+
# return {"file_id": file_id}
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
# @app.get("/test_plus")
|
105
|
+
# def test_endpoint(file_id: str, _=Depends(catch_exceptions(exception_type=IOError, status_code=500))):
|
106
|
+
# # Your endpoint logic here
|
107
|
+
# return {"file_id": file_id}
|
108
|
+
|
109
|
+
|
110
|
+
# @app.get("/test")
|
111
|
+
# @catch_exceptions(exception_type=IOError, status_code=500)
|
112
|
+
# def f(file_id: str):
|
113
|
+
# logger.debug(file_id)
|
114
|
+
# # raise Exception("test")
|
115
|
+
#
|
116
|
+
#
|
117
|
+
# @app.get("/{file_id}")
|
118
|
+
# @catch_exceptions(status_code=1)
|
119
|
+
# def f(file_id: str):
|
120
|
+
# logger.debug(file_id)
|
121
|
+
# raise Exception("test")
|
48
122
|
|
49
123
|
|
50
124
|
app.run(port=9000)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Project : AI. @by PyCharm
|
4
|
+
# @File : polling
|
5
|
+
# @Time : 2024/12/26 14:08
|
6
|
+
# @Author : betterme
|
7
|
+
# @WeChat : meutils
|
8
|
+
# @Software : PyCharm
|
9
|
+
# @Description :
|
10
|
+
import time
|
11
|
+
|
12
|
+
from meutils.pipe import *
|
13
|
+
|
14
|
+
|
15
|
+
def poll(n: int = 30, sleep_fn: Optional[Callable] = None):
|
16
|
+
if sleep_fn is None:
|
17
|
+
sleep_fn = lambda i: max(n / (i + 1), 1) # 预估大概 2~3 *n
|
18
|
+
|
19
|
+
def decorator(fn):
|
20
|
+
is_coroutine = inspect.iscoroutinefunction(fn)
|
21
|
+
|
22
|
+
@wraps(fn)
|
23
|
+
async def wrapper(*args, **kwargs):
|
24
|
+
for i in range(n):
|
25
|
+
await asyncio.sleep(sleep_fn(i))
|
26
|
+
# 根据函数类型选择调用方式
|
27
|
+
result = await fn(*args, **kwargs) if is_coroutine else fn(*args, **kwargs)
|
28
|
+
if result: # 跳出
|
29
|
+
return result
|
30
|
+
return None
|
31
|
+
|
32
|
+
return wrapper
|
33
|
+
|
34
|
+
return decorator
|
35
|
+
|
36
|
+
|
37
|
+
if __name__ == '__main__':
|
38
|
+
@poll(n=5)
|
39
|
+
async def check_something():
|
40
|
+
# 你的检查逻辑
|
41
|
+
|
42
|
+
logger.debug(time.ctime())
|
43
|
+
return {"status": "ok"}
|
44
|
+
|
45
|
+
|
46
|
+
arun(check_something())
|
meutils/decorators/retry.py
CHANGED
@@ -9,29 +9,89 @@
|
|
9
9
|
# @Description :
|
10
10
|
|
11
11
|
from meutils.pipe import *
|
12
|
-
from tenacity import retry,
|
13
|
-
from tenacity import
|
12
|
+
from tenacity import retry, stop_after_attempt, before_sleep_log
|
13
|
+
from tenacity import wait_fixed, wait_exponential, wait_incrementing, wait_exponential_jitter # Wait strategy
|
14
|
+
from tenacity import retry_if_result, RetryCallState # 重试策略
|
15
|
+
from tenacity import retry_if_exception, retry_if_exception_type, retry_if_not_exception_type
|
14
16
|
|
17
|
+
# 不兼容异步
|
18
|
+
from meutils.notice.feishu import send_message
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
|
21
|
+
class IgnoredRetryException(Exception):
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
def default_retry_error_callback(retry_state: RetryCallState, title: Optional[str] = None):
|
26
|
+
"""return the result of the last call attempt"""
|
27
|
+
# logger.debug(f"最后一次重试仍然失败调用的函数: {retry_state.outcome}")
|
28
|
+
logger.debug(f"最后一次重试仍然失败调用的函数: {retry_state}")
|
29
|
+
|
30
|
+
send_message(f"""{retry_state}""", title)
|
31
|
+
|
32
|
+
# logger.debug(retry_state.outcome.result())
|
33
|
+
|
34
|
+
exc = retry_state.outcome.exception() # 最后抛出错误
|
35
|
+
if exc:
|
36
|
+
raise exc # 最后返回结果
|
37
|
+
|
38
|
+
|
39
|
+
def not_in_status_codes(exception):
|
40
|
+
"""451不触发重试"""
|
41
|
+
# logger.debug(exception)
|
42
|
+
|
43
|
+
if isinstance(exception, httpx.HTTPStatusError):
|
44
|
+
# logger.debug(f"status_code: {exception.response.status_code}")
|
45
|
+
|
46
|
+
status_code = exception.response.status_code
|
47
|
+
return status_code not in {451}
|
48
|
+
return True
|
49
|
+
|
50
|
+
|
51
|
+
def retrying(
|
52
|
+
max_retries=2,
|
53
|
+
exp_base=2,
|
54
|
+
min: int = 0,
|
55
|
+
max: int = 100000,
|
56
|
+
retry_error_callback: Optional[Callable[[RetryCallState], Any]] = None,
|
57
|
+
predicate: Callable[[Any], bool] = lambda r: False,
|
58
|
+
title: Optional[str] = None,
|
59
|
+
ignored_exception_types: Optional[typing.Union[
|
60
|
+
typing.Type[BaseException],
|
61
|
+
typing.Tuple[typing.Type[BaseException], ...],
|
62
|
+
]] = None, # 该错误类型不重试
|
63
|
+
):
|
21
64
|
import logging
|
22
65
|
|
23
66
|
logger = logging.getLogger()
|
24
67
|
|
68
|
+
retry_error_callback = retry_error_callback or partial(default_retry_error_callback, title=title)
|
69
|
+
|
70
|
+
# 抛错或者返回结果判断为True重试 就重试
|
71
|
+
retry_reasons = (
|
72
|
+
(
|
73
|
+
retry_if_exception_type()
|
74
|
+
& retry_if_exception(not_in_status_codes)
|
75
|
+
)
|
76
|
+
| retry_if_result(predicate)
|
77
|
+
)
|
78
|
+
if ignored_exception_types:
|
79
|
+
retry_reasons = retry_reasons & retry_if_not_exception_type(ignored_exception_types)
|
80
|
+
|
25
81
|
_retry_decorator = retry(
|
26
82
|
reraise=True,
|
27
83
|
stop=stop_after_attempt(max_retries),
|
28
|
-
wait=wait_exponential(multiplier=1, min=
|
29
|
-
retry=
|
30
|
-
before_sleep=before_sleep_log(logger, 30),
|
84
|
+
wait=wait_exponential(multiplier=1.0, exp_base=exp_base, min=min, max=max), # max=max_seconds
|
85
|
+
retry=retry_reasons,
|
86
|
+
# before_sleep=before_sleep_log(logger, 30),
|
31
87
|
retry_error_callback=retry_error_callback,
|
32
88
|
)
|
33
89
|
|
34
|
-
|
90
|
+
@wrapt.decorator
|
91
|
+
def wrapper(wrapped, instance, args, kwargs):
|
92
|
+
return _retry_decorator(wrapped)(*args, **kwargs)
|
93
|
+
|
94
|
+
return wrapper
|
35
95
|
|
36
96
|
|
37
97
|
def create_retry_decorator() -> Callable[[Any], Any]: # todo: Retrying
|
@@ -84,25 +144,89 @@ def wait_retry(n=3):
|
|
84
144
|
|
85
145
|
|
86
146
|
if __name__ == '__main__':
|
87
|
-
s = time.time() # 1616145296
|
88
|
-
print(s)
|
89
|
-
e1 = s + 10
|
90
|
-
e2 = e1 + 10
|
147
|
+
# s = time.time() # 1616145296
|
148
|
+
# print(s)
|
149
|
+
# e1 = s + 10
|
150
|
+
# e2 = e1 + 10
|
151
|
+
#
|
152
|
+
#
|
153
|
+
# @wait_retry(5)
|
154
|
+
# def f(e):
|
155
|
+
# return time.time() > e # 变的
|
156
|
+
#
|
157
|
+
#
|
158
|
+
# def run(e):
|
159
|
+
# f(e)
|
160
|
+
# print(f"task {e}")
|
161
|
+
#
|
162
|
+
#
|
163
|
+
# # for e in [e2, e1]:
|
164
|
+
# # print(run(e))
|
165
|
+
# #
|
166
|
+
# # print("耗时", time.time() - s)
|
167
|
+
#
|
168
|
+
# [e1, e2, 1000000000000] | xProcessPoolExecutor(run, 2)
|
169
|
+
|
170
|
+
# class retry_state:
|
171
|
+
# attempt_number = 0
|
172
|
+
#
|
173
|
+
#
|
174
|
+
# for i in range(1, 10):
|
175
|
+
# retry_state.attempt_number = i
|
176
|
+
# # print(wait_incrementing(100, -10)(retry_state))
|
177
|
+
# print(wait_exponential(1, exp_base=2)(retry_state))
|
178
|
+
|
179
|
+
# @retrying(3)
|
180
|
+
# async def f():
|
181
|
+
# logger.debug("retry")
|
182
|
+
# pass
|
183
|
+
# # 1 / 0
|
184
|
+
# raise Exception('xx')
|
185
|
+
|
186
|
+
# try:
|
187
|
+
# f()
|
188
|
+
#
|
189
|
+
# except Exception as e:
|
190
|
+
# print(e)
|
191
|
+
# print(type(e))
|
91
192
|
|
193
|
+
# @retrying(3)
|
194
|
+
# def f():
|
195
|
+
# # async def f():
|
196
|
+
# logger.debug("retry")
|
197
|
+
# for i in range(10):
|
198
|
+
# yield ""
|
199
|
+
# if i == 8:
|
200
|
+
# raise Exception('xx')
|
92
201
|
|
93
|
-
|
94
|
-
def f(e):
|
95
|
-
return time.time() > e # 变的
|
202
|
+
# arun(f())
|
96
203
|
|
204
|
+
# f()
|
97
205
|
|
98
|
-
|
99
|
-
|
100
|
-
|
206
|
+
# 示例使用
|
207
|
+
class CustomError1(Exception):
|
208
|
+
pass
|
101
209
|
|
102
210
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
211
|
+
class CustomError2(Exception):
|
212
|
+
pass
|
213
|
+
|
214
|
+
|
215
|
+
@retrying(
|
216
|
+
max_retries=3,
|
217
|
+
ignored_exception_types=(CustomError1, IgnoredRetryException)
|
218
|
+
)
|
219
|
+
def my_function():
|
220
|
+
logger.debug(1)
|
221
|
+
# 模拟抛出异常
|
222
|
+
raise IgnoredRetryException("This is a custom error")
|
223
|
+
|
224
|
+
|
225
|
+
def main():
|
226
|
+
try:
|
227
|
+
my_function()
|
228
|
+
except Exception as e:
|
229
|
+
print(f"Operation failed after all retries: {e}")
|
230
|
+
|
107
231
|
|
108
|
-
|
232
|
+
main()
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import json
|
2
|
+
import traceback
|
3
|
+
|
4
|
+
from fastapi import status
|
5
|
+
from starlette.requests import Request
|
6
|
+
from starlette.responses import JSONResponse
|
7
|
+
|
8
|
+
from fastapi.exceptions import RequestValidationError, HTTPException
|
9
|
+
|
10
|
+
from meutils.notice.feishu import send_message
|
11
|
+
|
12
|
+
UNAUTHORIZED_HTTPException = HTTPException(
|
13
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
14
|
+
detail={
|
15
|
+
"error": {
|
16
|
+
"message": "",
|
17
|
+
"type": "invalid_request_error",
|
18
|
+
"param": None,
|
19
|
+
"code": "invalid_api_key",
|
20
|
+
}
|
21
|
+
})
|
22
|
+
|
23
|
+
|
24
|
+
async def http_error_handler(_: Request, exc: HTTPException) -> JSONResponse:
|
25
|
+
# print(exc)
|
26
|
+
content = {
|
27
|
+
"error":
|
28
|
+
{
|
29
|
+
"message": f"{exc.detail}",
|
30
|
+
"type": "http-error",
|
31
|
+
}
|
32
|
+
}
|
33
|
+
return JSONResponse(
|
34
|
+
content=content,
|
35
|
+
status_code=exc.status_code
|
36
|
+
)
|
37
|
+
|
38
|
+
|
39
|
+
async def general_exception_handler(request: Request, exc: Exception):
|
40
|
+
return JSONResponse(
|
41
|
+
content={"message": str(exc)},
|
42
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
43
|
+
)
|
44
|
+
|
45
|
+
|
46
|
+
async def chatfire_api_exception_handler(request: Request, exc: Exception):
|
47
|
+
content = {
|
48
|
+
"error":
|
49
|
+
{
|
50
|
+
"message": f"{exc}",
|
51
|
+
"type": "cf-api-error",
|
52
|
+
},
|
53
|
+
|
54
|
+
# "code": status.HTTP_500_INTERNAL_SERVER_ERROR
|
55
|
+
}
|
56
|
+
content_detail = f"{traceback.format_exc()}"
|
57
|
+
|
58
|
+
send_message(
|
59
|
+
content_detail,
|
60
|
+
title="cf-api-error",
|
61
|
+
url="https://open.feishu.cn/open-apis/bot/v2/hook/79fc258f-46a9-419e-b131-1d79b3d0bcff"
|
62
|
+
)
|
63
|
+
|
64
|
+
# send_message
|
65
|
+
return JSONResponse(
|
66
|
+
content=content,
|
67
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
68
|
+
)
|
69
|
+
|
70
|
+
|
71
|
+
if __name__ == '__main__':
|
72
|
+
from meutils.notice.feishu import send_message
|
@@ -0,0 +1,44 @@
|
|
1
|
+
from typing import Union
|
2
|
+
|
3
|
+
from fastapi import status
|
4
|
+
from fastapi.exceptions import RequestValidationError
|
5
|
+
from fastapi.openapi.constants import REF_PREFIX
|
6
|
+
from fastapi.openapi.utils import validation_error_response_definition
|
7
|
+
from pydantic import ValidationError
|
8
|
+
from starlette.requests import Request
|
9
|
+
from starlette.responses import JSONResponse
|
10
|
+
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
11
|
+
|
12
|
+
|
13
|
+
async def http422_error_handler(
|
14
|
+
_: Request,
|
15
|
+
exc: Union[RequestValidationError, ValidationError],
|
16
|
+
) -> JSONResponse:
|
17
|
+
return JSONResponse(
|
18
|
+
{"errors": exc.errors()},
|
19
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
validation_error_response_definition["properties"] = {
|
24
|
+
"errors": {
|
25
|
+
"title": "Errors",
|
26
|
+
"type": "array",
|
27
|
+
"items": {"$ref": "{0}ValidationError".format(REF_PREFIX)},
|
28
|
+
},
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
async def validation_exception_handler(_: Request, exc: RequestValidationError) -> JSONResponse:
|
33
|
+
# print(exc)
|
34
|
+
content = {
|
35
|
+
"error":
|
36
|
+
{
|
37
|
+
"message": f"{exc}",
|
38
|
+
"type": "RequestValidationError",
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return JSONResponse(
|
42
|
+
content=content,
|
43
|
+
status_code=status.HTTP_400_BAD_REQUEST
|
44
|
+
)
|