MeUtils 2025.1.17.19.49.29__py3-none-any.whl → 2025.1.23.10.16.28__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 (31) hide show
  1. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/METADATA +27 -27
  2. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/RECORD +31 -30
  3. examples/_openaisdk/openai_chatfire.py +4 -2
  4. examples/_openaisdk/openai_deepseek.py +7 -6
  5. examples/_openaisdk/openai_doubao.py +16 -7
  6. examples/_openaisdk/openai_embeddings.py +1 -1
  7. meutils/apis/jimeng/lip_sync.py → examples/_openaisdk/openai_x.py +3 -2
  8. examples/bserver.py +60 -518
  9. meutils/apis/fal/videos.py +13 -7
  10. meutils/apis/hailuoai/videos.py +16 -6
  11. meutils/apis/images/edits.py +4 -4
  12. meutils/apis/images/recraft.py +5 -5
  13. meutils/apis/jimeng/common.py +4 -5
  14. meutils/apis/jimeng/doubao.py +2 -2
  15. meutils/apis/jimeng/files.py +63 -21
  16. meutils/apis/jimeng/images.py +29 -10
  17. meutils/apis/jimeng/videos.py +236 -0
  18. meutils/apis/oneapi/user.py +3 -1
  19. meutils/data/VERSION +1 -1
  20. meutils/io/files_utils.py +9 -3
  21. meutils/llm/completions/agents/file.py +7 -4
  22. meutils/schemas/hailuo_types.py +8 -2
  23. meutils/schemas/image_types.py +9 -4
  24. meutils/schemas/oneapi/common.py +136 -41
  25. meutils/schemas/task_types.py +2 -0
  26. meutils/schemas/video_types.py +11 -1
  27. meutils/str_utils/json_utils.py +29 -1
  28. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/LICENSE +0 -0
  29. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/WHEEL +0 -0
  30. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/entry_points.txt +0 -0
  31. {MeUtils-2025.1.17.19.49.29.dist-info → MeUtils-2025.1.23.10.16.28.dist-info}/top_level.txt +0 -0
meutils/io/files_utils.py CHANGED
@@ -58,23 +58,29 @@ async def to_bytes(
58
58
  """
59
59
  # assert file
60
60
 
61
- logger.debug(type(file))
62
-
63
- if isinstance(file, bytes): return file
61
+ if isinstance(file, bytes):
62
+ logger.debug(f"FileType: BYTES")
63
+ return file
64
64
 
65
65
  file_bytes = None
66
66
  if isinstance(file, UploadFile):
67
67
  file_bytes = await file.read()
68
68
 
69
69
  elif isinstance(file, str) and file.startswith('http'): # url
70
+ logger.debug(f"FileType: HTTP")
71
+
70
72
  async with AsyncClient(headers=headers or {}, timeout=60) as cilent:
71
73
  resp = await cilent.get(file)
72
74
  file_bytes = resp.content
73
75
 
74
76
  elif isinstance(file, str) and len(file) > 256: # base64
77
+ logger.debug(f"FileType: BASE64")
78
+
75
79
  file_bytes = base64_to_bytes(file)
76
80
 
77
81
  elif isinstance(file, str) and len(file) < 256 and Path(file).is_file(): # file
82
+ logger.debug(f"FileType: PATH")
83
+
78
84
  file_bytes = Path(file).read_bytes()
79
85
 
80
86
  return file_bytes
@@ -13,6 +13,7 @@ api形式
13
13
  - /agents/v1
14
14
  - /v1 前缀区分 agents-{model}【底层调用 /agents/v1】
15
15
 
16
+ todo: 记录上下文日志
16
17
  """
17
18
 
18
19
  from meutils.pipe import *
@@ -88,16 +89,18 @@ if __name__ == '__main__':
88
89
 
89
90
  {
90
91
  'role': 'user',
91
- 'content': {
92
- "type": "file_url",
93
- "file_url": {"url": "https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf", "detai": "auto"}
94
- },
92
+ # 'content': {
93
+ # "type": "file_url",
94
+ # "file_url": {"url": "https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf", "detai": "auto"}
95
+ # },
95
96
  # 'content': "https://oss.ffire.cc/files/%E6%8B%9B%E6%A0%87%E6%96%87%E4%BB%B6%E5%A4%87%E6%A1%88%E8%A1%A8%EF%BC%88%E7%AC%AC%E4%BA%8C%E6%AC%A1%EF%BC%89.pdf 这个文件讲了什么?",
96
97
  # 'content': "https://translate.google.com/?sl=zh-CN&tl=en&text=%E6%8F%90%E4%BE%9B%E6%96%B9&op=tr1anslate 这个文件讲了什么?",
97
98
 
98
99
  # "content": "总结下 https://oss.ffire.cc/files/百炼系列手机产品介绍.docx"
99
100
  # "content": "https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf\n\n总结下"
100
101
 
102
+ "content": "https://admin.ilovechatgpt.top/file/lunIMYAIzhinengzhushouduishenghuodocx_14905733.docx 总结"
103
+
101
104
  },
102
105
 
103
106
  # {'role': 'assistant', 'content': "好的"},
@@ -33,7 +33,7 @@ status_mapper = {
33
33
 
34
34
 
35
35
  class VideoRequest(BaseModel):
36
- """
36
+ """https://platform.minimaxi.com/document/video_generation?key=66d1439376e52fcee2853049
37
37
  23000 文生视频
38
38
  "T2V-01": "23000"
39
39
  "I2V-01": "23001"
@@ -61,6 +61,11 @@ class VideoRequest(BaseModel):
61
61
  传入图片需要满足以下条件:格式为JPG/JPEG/PNG;长宽比大于2:5、小于5:2;短边像素大于300px;体积不大于20MB。"""
62
62
  first_frame_image: Optional[str] = None
63
63
 
64
+ """本参数仅当model选择为S2V-01时可用。模型将依据此参数中上传的主体来生成视频。目前仅支持单主体参考(数组长度为 1)。"""
65
+ # subject_reference: list = [{"type": "character", "image": ""}]
66
+
67
+ callback_url: Optional[str] = None
68
+
64
69
  "n"
65
70
  n: int = 1
66
71
 
@@ -133,13 +138,14 @@ class VideoResponse(BaseModel):
133
138
  base_resp: BaseResponse # response.statusInfo
134
139
 
135
140
  """
141
+ SUBMITTED-已提交
136
142
  Preparing-准备中
137
143
  Queueing-队列中
138
144
  Processing-生成中
139
145
  Success-成功
140
146
  Failed-失败
141
147
  """
142
- status: str = "Queueing"
148
+ status: str = "SUBMITTED"
143
149
  file_id: Optional[str] = None # 通过file_id 可以获取视频地址download_url
144
150
 
145
151
  videos: Optional[List[Video]] = None # response.data.videos
@@ -62,10 +62,14 @@ class ImagesResponse(_ImagesResponse):
62
62
  # class Config:
63
63
  # extra = "allow"
64
64
 
65
+
65
66
  class ImageRequest(BaseModel): # openai
67
+ """
68
+ 图生图 两种方式: prompt + controls
69
+ """
66
70
  model: str = ""
67
71
 
68
- prompt: constr(min_length=1, max_length=2000) = ""
72
+ prompt: constr(min_length=1, max_length=3000) = ""
69
73
 
70
74
  n: Optional[int] = 1
71
75
 
@@ -78,11 +82,12 @@ class ImageRequest(BaseModel): # openai
78
82
  seed: Optional[int] = None
79
83
 
80
84
  # oneapi
81
- controls: dict = {} # 额外参数
82
-
83
85
  negative_prompt: Optional[str] = None
84
86
  guidance: Optional[int] = None
85
87
  steps: Optional[int] = None
88
+
89
+ controls: dict = {} # 额外参数
90
+
86
91
  safety_tolerance: Optional[int] = None
87
92
 
88
93
  aspect_ratio: Optional[str] = None
@@ -459,7 +464,7 @@ class ImageProcess(BaseModel):
459
464
  mask: Optional[str] = None
460
465
 
461
466
  style: Optional[str] = None
462
- aspect_ratio: Union[str, Literal["1:1", "4:3", "3:4"]] = "1:1" # 扩图
467
+ aspect_ratio: Union[str, Literal["1:1", "4:3", "3:4"]] = "1:1" # 扩图
463
468
 
464
469
  response_format: Literal["url", "b64_json"] = "url"
465
470
 
@@ -14,7 +14,8 @@ from meutils.data.oneapi import NOTICE, FOOTER
14
14
  BASE_URL = "https://api.chatfire.cn"
15
15
  # BASE_URL = "https://api-dev.chatfire.cn"
16
16
  FREE = 0.001
17
- MJ = 1.5
17
+ MJ_RELAX = 1
18
+ STEP = 2
18
19
 
19
20
  MODEL_PRICE = {
20
21
  "images": FREE,
@@ -22,9 +23,16 @@ MODEL_PRICE = {
22
23
  "kling_image": 0.025,
23
24
  "kling_virtual_try_on": 1,
24
25
 
25
- "kling_video": 1,
26
- "kling_extend": 1,
27
- "kling_lip_sync": 1,
26
+ "kling_video": 1.2,
27
+ "kling_extend": 1.2,
28
+ "kling_lip_sync": 1.2,
29
+
30
+ "minimax_video-01": 1.2,
31
+
32
+ "minimax_t2v-01": 1.2,
33
+ "minimax_i2v-01": 1.2,
34
+ "minimax_i2v-01-live": 1.2,
35
+ "minimax_s2v-01": 1.2,
28
36
 
29
37
  # chatfire
30
38
  "ppu-0001": 0.0001,
@@ -92,8 +100,6 @@ MODEL_PRICE = {
92
100
  "api-stt": 0.01,
93
101
  "api-tts": 0.01,
94
102
 
95
- "step-1x-medium": 0.1,
96
-
97
103
  "kolors": 0.02,
98
104
  "kling": 0.02,
99
105
 
@@ -127,7 +133,8 @@ MODEL_PRICE = {
127
133
  "stable-diffusion-3-5-large": 0.0001,
128
134
  "chat-stable-diffusion-3-5-large": 0.1,
129
135
 
130
- "chat-step-1x-medium": 0.1 / 4,
136
+ "step-1x-medium": 0.2,
137
+ "chat-step-1x-medium": 0.2,
131
138
 
132
139
  "chat-flux-schnell": 0.01,
133
140
  "chat-flux-dev": 0.03,
@@ -146,6 +153,12 @@ MODEL_PRICE = {
146
153
 
147
154
  # aitools
148
155
  "api-aitools": 0.007,
156
+ "api-images-edits-remove-watermark": 0.01, # mask
157
+ "api-images-edits-remove-textin": 0.02, # remove-watermark
158
+
159
+ "api-images-edits-clarity": 0.01,
160
+ "api-images-edits-expand": 0.01,
161
+ "api-images-edits-rmbg-2.0": 0.01,
149
162
 
150
163
  # 文档智能
151
164
  "api-textin": 0.02,
@@ -179,10 +192,11 @@ MODEL_PRICE = {
179
192
  "api-translator": 0.0001,
180
193
  "api-voice-clone": 0.01,
181
194
 
182
- "suno_music": 0.5,
195
+ "suno_music": 0.25,
183
196
  "suno_lyrics": 0.01,
184
-
185
- "api-reranker": 0.01,
197
+ "suno_uploads": 0.01,
198
+ "suno_upload": 0.01,
199
+ "suno_concat": 0.01,
186
200
 
187
201
  # all
188
202
  "o1-plus": 0.2,
@@ -232,22 +246,51 @@ MODEL_PRICE = {
232
246
  "ai-search-pro": 0.1,
233
247
  "ai-search-pro:scholar": 0.1,
234
248
 
235
- "mj_imagine": 0.1 * MJ,
236
- "mj_variation": 0.1 * MJ,
237
- "mj_high_variation": 0.1 * MJ,
238
- "mj_low_variation": 0.1 * MJ,
239
- "mj_pan": 0.1 * MJ,
240
- "mj_blend": 0.1 * MJ,
241
- "mj_inpaint": 0,
242
- "mj_reroll": 0.1 * MJ,
243
-
244
- "mj_upscale": 0.05 * MJ,
245
- "mj_custom_zoom": 0,
246
- "mj_describe": 0.05 * MJ,
247
- "mj_modal": 0.1 * MJ,
248
- "mj_shorten": 0.1 * MJ,
249
- "mj_zoom": 0.1 * MJ,
250
- "swap_face": 0.05 * MJ,
249
+ # MJ
250
+ "mj-chat": 0.3,
251
+
252
+ "mj_fast_blend": 0.08,
253
+ "mj_fast_custom_oom": 0,
254
+ "mj_fast_describe": 0.04,
255
+ "mj_fast_high_variation": 0.08,
256
+ "mj_fast_imagine": 0.08,
257
+ "mj_fast_inpaint": 0,
258
+ "mj_fast_low_variation": 0.08,
259
+ "mj_fast_modal": 0.08,
260
+ "mj_fast_pan": 0.08,
261
+ "mj_fast_pic_reader": 0,
262
+ "mj_fast_prompt_analyzer": 0,
263
+ "mj_fast_prompt_analyzer_extended": 0,
264
+ "mj_fast_reroll": 0.08,
265
+ "mj_fast_shorten": 0.08,
266
+ "mj_fast_upload": 0.01,
267
+ "mj_fast_upscale": 0.04,
268
+ "mj_fast_upscale_creative": 0.08,
269
+ "mj_fast_upscale_subtle": 0.08,
270
+ "mj_fast_variation": 0.08,
271
+ "mj_fast_zoom": 0.08,
272
+
273
+ "mj_relax_imagine": 0.08 * 0.5,
274
+
275
+ "mj_relax_blend": 0.08,
276
+ "mj_relax_custom_oom": 0,
277
+ "mj_relax_describe": 0.04 * MJ_RELAX,
278
+ "mj_relax_high_variation": 0.08 * MJ_RELAX,
279
+ "mj_relax_inpaint": 0,
280
+ "mj_relax_low_variation": 0.08 * MJ_RELAX,
281
+ "mj_relax_modal": 0.08 * MJ_RELAX,
282
+ "mj_relax_pan": 0.08 * MJ_RELAX,
283
+ "mj_relax_pic_reader": 0,
284
+ "mj_relax_prompt_analyzer": 0,
285
+ "mj_relax_prompt_analyzer_extended": 0,
286
+ "mj_relax_reroll": 0.08 * MJ_RELAX,
287
+ "mj_relax_shorten": 0.08 * MJ_RELAX,
288
+ "mj_relax_upload": 0.01 * MJ_RELAX,
289
+ "mj_relax_upscale": 0.04 * 1,
290
+ "mj_relax_upscale_creative": 0.08 * 1,
291
+ "mj_relax_upscale_subtle": 0.08 * 1,
292
+ "mj_relax_variation": 0.08 * 1,
293
+ "mj_relax_zoom": 0.08 * MJ_RELAX,
251
294
 
252
295
  }
253
296
 
@@ -359,10 +402,20 @@ MODEL_RATIO = {
359
402
  'spark-ultra': 50,
360
403
 
361
404
  # 阶跃星辰 https://platform.stepfun.com/docs/pricing/details
362
- "step-1-8k": 2.5,
363
- "step-1-32k": 7.5,
364
- "step-1v-8k": 2.5,
365
- "step-1v-32k": 7.5,
405
+ "step-1-flash": 0.5 * STEP,
406
+
407
+ "step-1-8k": 2.5 * STEP,
408
+ "step-1-32k": 7.5 * STEP,
409
+ "step-1-256k": 47.5 * STEP,
410
+
411
+ "step-2-16k": 19 * STEP,
412
+ "step-2-mini": 0.5 * STEP,
413
+ "step-2-16k-exp": 19 * STEP,
414
+
415
+ "step-1v-8k": 2.5 * STEP,
416
+ "step-1.5v-mini": 4 * STEP,
417
+ "step-1v-32k": 7.5 * STEP,
418
+ "step-1o-vision-32k": 7.5 * STEP,
366
419
 
367
420
  # 零一万物 https://platform.lingyiwanwu.com/docs#%E8%AE%A1%E8%B4%B9%E5%8D%95%E5%85%83
368
421
  "yi-spark": 0.05, # 特价
@@ -399,20 +452,29 @@ MODEL_RATIO = {
399
452
  "deepseek-ai/DeepSeek-V3": 0.5,
400
453
  "accounts/fireworks/models/deepseek-v3": 0.5,
401
454
 
402
- 'deepseek-r1': 0.5,
455
+ "deepseek-r1:1.5b": 0.1,
456
+ "deepseek-r1:7b": 0.2,
457
+ 'deepseek-r1': 2,
458
+ 'deepseek-reasoner': 2,
403
459
  'deepseek-think': 0.5,
404
460
  "deepseek-search": 0.5,
405
461
 
406
462
  # 豆包
407
463
  "doubao-lite-128k": 0.4,
408
464
  "doubao-lite-32k": 0.15,
465
+ "doubao-lite-32k-character": 0.15,
409
466
  "doubao-lite-4k": 0.15,
467
+ "doubao-1.5-lite-32k": 0.3,
410
468
 
469
+ "doubao-pro-4k": 0.4,
470
+ "doubao-pro-32k": 0.4,
471
+ "doubao-pro-32k-character": 0.4,
472
+ "doubao-pro-128k": 2.5,
411
473
  "doubao-pro-256k": 5,
474
+ "doubao-1.5-pro-32k": 0.8,
475
+ "doubao-1.5-pro-256k": 5,
412
476
 
413
- "doubao-pro-128k": 2.5,
414
- "doubao-pro-32k": 0.4,
415
- "doubao-pro-4k": 0.4,
477
+ "doubao-1.5-vision-pro-32k": 3,
416
478
  "doubao-vision-lite-32k": 0.75,
417
479
  "doubao-vision-pro-32k": 1.5,
418
480
 
@@ -483,6 +545,7 @@ MODEL_RATIO = {
483
545
  "gemini-1.0-pro-latest": 1,
484
546
  "gemini-1.0-pro-vision-001": 1,
485
547
  "gemini-1.0-pro-vision-latest": 1,
548
+ "gemini-exp-1206": 1,
486
549
 
487
550
  "gemini-1.5-flash-002": 0.3, # 重定向到openrouter
488
551
  "google/gemini-flash-1.5-8b": 0.3, # openrouter $0.0375 $0.15
@@ -584,11 +647,11 @@ MODEL_RATIO = {
584
647
 
585
648
  "internvl2-8b": 0.35 / 2,
586
649
  "internvl2-26b": 1 / 2,
587
- "internvl2-llama3-76b": 4.13 / 2,
650
+ "internvl2-llama3-76b": 2,
588
651
 
589
- "qwen2-vl-7b-instruct": 0.35 / 2,
590
- "qwen2-vl-72b-instruct": 4.13 / 2,
591
- "Qwen/Qwen2-VL-72B-Instruct": 4.13 / 2,
652
+ "qwen2-vl-7b-instruct": 0.5,
653
+ "qwen2-vl-72b-instruct": 2,
654
+ "Qwen/Qwen2-VL-72B-Instruct": 2,
592
655
 
593
656
  # 临时
594
657
  "ep-20240515073409-dlpqp": 5
@@ -656,6 +719,8 @@ COMPLETION_RATIO = {
656
719
  "gemini-1.5-pro-002": 4,
657
720
  "gemini-1.5-flash-002": 4,
658
721
 
722
+ "gemini-exp-1206": 5,
723
+
659
724
  "gemini-2.0-flash": 5,
660
725
  "gemini-2.0-flash-exp": 5,
661
726
  "gemini-2.0-flash-thinking-exp": 5,
@@ -674,15 +739,34 @@ COMPLETION_RATIO = {
674
739
  "qwen-max": 3,
675
740
  "qwen-vl-max-latest": 3,
676
741
  "qwen-vl-plus-latest": 3,
742
+ "qwen2-vl-7b-instruct": 5,
743
+ "qwen2-vl-72b-instruct": 5,
677
744
 
678
745
  "deepseek-ai/deepseek-vl2": 3,
746
+
747
+ # 豆包
748
+ "doubao-lite-128k": 3,
749
+ "doubao-lite-32k": 3,
750
+ "doubao-lite-32k-character": 3,
751
+ "doubao-lite-4k": 3,
752
+ "doubao-1.5-lite-32k": 3,
753
+
754
+ "doubao-pro-4k": 3,
755
+ "doubao-pro-32k": 3,
756
+ "doubao-pro-32k-character": 3,
757
+ "doubao-pro-128k": 3,
758
+ "doubao-pro-256k": 3,
759
+ "doubao-1.5-pro-32k": 3,
760
+ "doubao-1.5-pro-256k": 3,
761
+
762
+ "doubao-1.5-vision-pro-32k": 3,
679
763
  "doubao-vision-lite-32k": 3,
680
764
  "doubao-vision-pro-32k": 3,
681
765
 
682
766
  "deepseek-v3": 1,
683
- 'deepseek-r1': 1,
684
- 'deepseek-think': 1,
685
767
  "deepseek-search": 1,
768
+ 'deepseek-r1': 4,
769
+ 'deepseek-reasoner': 4,
686
770
  "deepseek/deepseek-chat": 1,
687
771
  "deepseek-ai/DeepSeek-V3": 1,
688
772
  "accounts/fireworks/models/deepseek-v3": 1,
@@ -691,6 +775,18 @@ COMPLETION_RATIO = {
691
775
  "glm-zero-preview": 5,
692
776
  "glm-4v-flash": 5,
693
777
 
778
+ "step-1-flash": 5,
779
+ "step-1-8k": 5,
780
+ "step-1-32k": 5,
781
+ "step-1-256k": 5,
782
+ "step-2-16k": 5,
783
+ "step-2-mini": 5,
784
+ "step-2-16k-exp": 5,
785
+ "step-1v-8k": 5,
786
+ "step-1v-32k": 5,
787
+ "step-1.5v-mini": 5,
788
+ "step-1o-vision-32k": 5,
789
+
694
790
  }
695
791
 
696
792
  REDIRECT_MODEL = {
@@ -871,7 +967,6 @@ GROUP_RATIO = {
871
967
 
872
968
  }
873
969
 
874
-
875
970
  # https://oss.ffire.cc/images/qw.jpeg?x-oss-process=image/format,jpg/resize,w_512
876
971
  if __name__ == '__main__':
877
972
  # print(','.join(REDIRECT_MODEL.keys()))
@@ -24,6 +24,7 @@ STATUSES = {
24
24
  "started": "QUEUED",
25
25
  "pending": "QUEUED",
26
26
  "PENDING": "QUEUED",
27
+ "Queueing": "QUEUED",
27
28
 
28
29
  "processing": "IN_PROGRESS",
29
30
  "in_progress": "IN_PROGRESS",
@@ -34,6 +35,7 @@ STATUSES = {
34
35
  "success": "SUCCESS",
35
36
  "succeeded": "SUCCESS",
36
37
 
38
+ "fail": "FAILURE",
37
39
  "failed": "FAILURE",
38
40
  "canceled": "FAILURE",
39
41
  "FAILURE": "FAILURE",
@@ -54,7 +54,17 @@ class VideoRequest(BaseModel):
54
54
 
55
55
 
56
56
  class FalVideoRequest(BaseModel):
57
- model: Union[str, Literal["latentsync", "sync-lipsync", ]] = 'latentsync'
57
+ model: Union[str, Literal["latentsync", "sync-lipsync",]] = 'latentsync'
58
+ video_url: Optional[str] = None
59
+ audio_url: Optional[str] = None
60
+ image_url: Optional[str] = None
61
+
62
+ sync_mode: Union[str, Literal["cut_off", "loop", "bounce"]] = "cut_off"
63
+
64
+
65
+ class LipsyncVideoRquest(BaseModel):
66
+ model: Union[str, Literal["latentsync", "sync-lipsync",]] = 'latentsync'
67
+
58
68
  video_url: Optional[str] = None
59
69
  audio_url: Optional[str] = None
60
70
  image_url: Optional[str] = None
@@ -7,6 +7,10 @@
7
7
  # @WeChat : 313303303
8
8
  # @Software : PyCharm
9
9
  # @Description : pd.io.json.json_normalize
10
+
11
+ # https://mangiucugna.github.io/json_repair/
12
+ # https://jsonpath.com/
13
+
10
14
  import jsonpath
11
15
 
12
16
  # json https://blog.csdn.net/freeking101/article/details/103048514
@@ -20,6 +24,7 @@ import jsonpath
20
24
  # https://blog.csdn.net/weixin_44799217/article/details/127590589
21
25
 
22
26
  from meutils.pipe import *
27
+ from json_repair import repair_json
23
28
 
24
29
 
25
30
  def json2class(dic, class_name='Test'):
@@ -46,5 +51,28 @@ def json_loads(s):
46
51
  return eval(s)
47
52
 
48
53
 
54
+ def json_path(obj, expr): # todo: 缓存
55
+ if isinstance(obj, dict):
56
+ pass
57
+ elif isinstance(obj, str):
58
+ obj = json_repair.loads(obj)
59
+ elif isinstance(obj, bytes):
60
+ obj = json_repair.loads(obj.decode())
61
+ elif isinstance(obj, BaseModel):
62
+ obj = obj.dict()
63
+
64
+ return jsonpath.jsonpath(obj, expr=expr)
65
+
66
+
49
67
  if __name__ == '__main__':
50
- print(jsonpath.jsonpath({"a": 1}, expr='$.a'))
68
+ print(json_path({"a": 1}, expr='$.a'))
69
+ print(json_path("""{"a": 1}""", expr='$.a'))
70
+
71
+ json_string = """{"a": 1}"""
72
+
73
+
74
+ class A(BaseModel):
75
+ a: int = 1
76
+
77
+
78
+ print(json_path(A(), '$.a'))