flexllm 0.3.3__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.
- flexllm/__init__.py +224 -0
- flexllm/__main__.py +1096 -0
- flexllm/async_api/__init__.py +9 -0
- flexllm/async_api/concurrent_call.py +100 -0
- flexllm/async_api/concurrent_executor.py +1036 -0
- flexllm/async_api/core.py +373 -0
- flexllm/async_api/interface.py +12 -0
- flexllm/async_api/progress.py +277 -0
- flexllm/base_client.py +988 -0
- flexllm/batch_tools/__init__.py +16 -0
- flexllm/batch_tools/folder_processor.py +317 -0
- flexllm/batch_tools/table_processor.py +363 -0
- flexllm/cache/__init__.py +10 -0
- flexllm/cache/response_cache.py +293 -0
- flexllm/chain_of_thought_client.py +1120 -0
- flexllm/claudeclient.py +402 -0
- flexllm/client_pool.py +698 -0
- flexllm/geminiclient.py +563 -0
- flexllm/llm_client.py +523 -0
- flexllm/llm_parser.py +60 -0
- flexllm/mllm_client.py +559 -0
- flexllm/msg_processors/__init__.py +174 -0
- flexllm/msg_processors/image_processor.py +729 -0
- flexllm/msg_processors/image_processor_helper.py +485 -0
- flexllm/msg_processors/messages_processor.py +341 -0
- flexllm/msg_processors/unified_processor.py +1404 -0
- flexllm/openaiclient.py +256 -0
- flexllm/pricing/__init__.py +104 -0
- flexllm/pricing/data.json +1201 -0
- flexllm/pricing/updater.py +223 -0
- flexllm/provider_router.py +213 -0
- flexllm/token_counter.py +270 -0
- flexllm/utils/__init__.py +1 -0
- flexllm/utils/core.py +41 -0
- flexllm-0.3.3.dist-info/METADATA +573 -0
- flexllm-0.3.3.dist-info/RECORD +39 -0
- flexllm-0.3.3.dist-info/WHEEL +4 -0
- flexllm-0.3.3.dist-info/entry_points.txt +3 -0
- flexllm-0.3.3.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
from typing import Optional, Union, Tuple, List, Dict, Any
|
|
4
|
+
|
|
5
|
+
import aiohttp
|
|
6
|
+
from PIL import Image
|
|
7
|
+
|
|
8
|
+
from .image_processor import (
|
|
9
|
+
encode_base64_from_local_path,
|
|
10
|
+
encode_base64_from_pil,
|
|
11
|
+
encode_image_to_base64,
|
|
12
|
+
encode_to_base64,
|
|
13
|
+
decode_base64_to_pil,
|
|
14
|
+
decode_base64_to_file,
|
|
15
|
+
decode_base64_to_bytes,
|
|
16
|
+
DEFAULT_CACHE_DIR,
|
|
17
|
+
get_pil_image,
|
|
18
|
+
get_pil_image_sync,
|
|
19
|
+
LANCZOS,
|
|
20
|
+
ImageCacheConfig,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
# 导入消息处理功能
|
|
24
|
+
from .messages_processor import (
|
|
25
|
+
process_content_recursive,
|
|
26
|
+
messages_preprocess,
|
|
27
|
+
batch_process_messages,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ImageProcessor:
|
|
32
|
+
"""便捷的图像处理类,封装了image_processor.py中的异步方法,提供更简单的接口。
|
|
33
|
+
|
|
34
|
+
这个类会自动管理aiohttp.ClientSession的生命周期,使得调用异步图像处理方法更加方便。
|
|
35
|
+
|
|
36
|
+
# 异步使用
|
|
37
|
+
async with ImageProcessor() as processor:
|
|
38
|
+
# 从URL编码图像,自动处理session
|
|
39
|
+
base64_data = await processor.encode_from_url("https://example.com/image.jpg")
|
|
40
|
+
|
|
41
|
+
# 使用新的图像缩放选项
|
|
42
|
+
resized_base64 = await processor.encode_image(
|
|
43
|
+
"https://example.com/large_image.jpg",
|
|
44
|
+
max_width=800,
|
|
45
|
+
max_height=600,
|
|
46
|
+
max_pixels=1000000
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# 同步使用
|
|
50
|
+
processor = ImageProcessor()
|
|
51
|
+
try:
|
|
52
|
+
# 从本地文件编码
|
|
53
|
+
local_base64 = processor.encode_from_local_path("image.jpg")
|
|
54
|
+
|
|
55
|
+
# 使用run_async调用异步方法
|
|
56
|
+
url_base64 = run_async(processor.encode_from_url("https://example.com/image.jpg"))
|
|
57
|
+
finally:
|
|
58
|
+
# 记得关闭session
|
|
59
|
+
run_async(processor.close())
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, session: Optional[aiohttp.ClientSession] = None):
|
|
64
|
+
"""初始化ImageProcessor
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
session: 可选的aiohttp.ClientSession实例。如果不提供,将在需要时自动创建。
|
|
68
|
+
"""
|
|
69
|
+
self._session = session
|
|
70
|
+
self._own_session = session is None
|
|
71
|
+
self._session_initialized = False
|
|
72
|
+
|
|
73
|
+
async def _ensure_session(self) -> aiohttp.ClientSession:
|
|
74
|
+
"""确保session已初始化
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
aiohttp.ClientSession实例
|
|
78
|
+
"""
|
|
79
|
+
if self._session is None:
|
|
80
|
+
self._session = aiohttp.ClientSession()
|
|
81
|
+
self._own_session = True
|
|
82
|
+
self._session_initialized = True
|
|
83
|
+
return self._session
|
|
84
|
+
|
|
85
|
+
async def close(self):
|
|
86
|
+
"""关闭session(如果是由本类创建的)"""
|
|
87
|
+
if (
|
|
88
|
+
self._own_session
|
|
89
|
+
and self._session_initialized
|
|
90
|
+
and self._session is not None
|
|
91
|
+
):
|
|
92
|
+
await self._session.close()
|
|
93
|
+
self._session = None
|
|
94
|
+
self._session_initialized = False
|
|
95
|
+
|
|
96
|
+
async def __aenter__(self):
|
|
97
|
+
"""支持异步上下文管理器"""
|
|
98
|
+
await self._ensure_session()
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
102
|
+
"""退出异步上下文管理器时关闭session"""
|
|
103
|
+
await self.close()
|
|
104
|
+
|
|
105
|
+
# 同步方法(不需要session)
|
|
106
|
+
def encode_from_local_path(
|
|
107
|
+
self, file_path: str, return_with_mime: bool = True
|
|
108
|
+
) -> str:
|
|
109
|
+
"""从本地文件路径编码图像为base64字符串
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
file_path: 本地图像文件路径
|
|
113
|
+
return_with_mime: 是否在结果中包含MIME类型前缀
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
base64编码的字符串
|
|
117
|
+
"""
|
|
118
|
+
return encode_base64_from_local_path(file_path, return_with_mime)
|
|
119
|
+
|
|
120
|
+
def encode_from_pil(self, image: Image.Image, return_with_mime: bool = True) -> str:
|
|
121
|
+
"""从PIL.Image对象编码为base64字符串
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
image: PIL.Image对象
|
|
125
|
+
return_with_mime: 是否在结果中包含MIME类型前缀
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
base64编码的字符串
|
|
129
|
+
"""
|
|
130
|
+
return encode_base64_from_pil(image, return_with_mime)
|
|
131
|
+
|
|
132
|
+
def encode_from_url_sync(
|
|
133
|
+
self, url: str, cache_config: Optional[ImageCacheConfig] = None
|
|
134
|
+
) -> str:
|
|
135
|
+
"""从URL同步编码图像为base64字符串
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
url: 图像URL
|
|
139
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
base64编码的字符串
|
|
143
|
+
"""
|
|
144
|
+
image = get_pil_image_sync(url, cache_config=cache_config)
|
|
145
|
+
return encode_base64_from_pil(image)
|
|
146
|
+
|
|
147
|
+
def decode_to_pil(self, base64_string: str) -> Image.Image:
|
|
148
|
+
"""将base64字符串解码为PIL.Image对象
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
base64_string: base64编码的图像字符串
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
PIL.Image对象
|
|
155
|
+
"""
|
|
156
|
+
return decode_base64_to_pil(base64_string)
|
|
157
|
+
|
|
158
|
+
def decode_to_file(
|
|
159
|
+
self, base64_string: str, output_path: str, format: str = "JPEG"
|
|
160
|
+
) -> None:
|
|
161
|
+
"""将base64字符串解码并保存为文件
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
base64_string: base64编码的图像字符串
|
|
165
|
+
output_path: 输出文件路径
|
|
166
|
+
format: 图像格式
|
|
167
|
+
"""
|
|
168
|
+
decode_base64_to_file(base64_string, output_path, format)
|
|
169
|
+
|
|
170
|
+
def decode_to_bytes(self, base64_string: str) -> bytes:
|
|
171
|
+
"""将base64字符串解码为字节数据
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
base64_string: base64编码的图像字符串
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
字节数据
|
|
178
|
+
"""
|
|
179
|
+
return decode_base64_to_bytes(base64_string)
|
|
180
|
+
|
|
181
|
+
# 异步方法(需要session)
|
|
182
|
+
async def encode_from_url(
|
|
183
|
+
self,
|
|
184
|
+
url: str,
|
|
185
|
+
return_with_mime: bool = True,
|
|
186
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
187
|
+
) -> str:
|
|
188
|
+
"""从URL异步编码图像为base64字符串
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
url: 图像URL
|
|
192
|
+
return_with_mime: 是否在结果中包含MIME类型前缀
|
|
193
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
base64编码的字符串
|
|
197
|
+
"""
|
|
198
|
+
session = await self._ensure_session()
|
|
199
|
+
result = await encode_image_to_base64(
|
|
200
|
+
url, session, return_with_mime=return_with_mime, cache_config=cache_config
|
|
201
|
+
)
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
async def get_pil_image(
|
|
205
|
+
self,
|
|
206
|
+
image_source: str,
|
|
207
|
+
max_width: Optional[int] = None,
|
|
208
|
+
max_height: Optional[int] = None,
|
|
209
|
+
max_pixels: Optional[int] = None,
|
|
210
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
211
|
+
return_cache_path: bool = False,
|
|
212
|
+
) -> Union[Image.Image, Tuple[Image.Image, str]]:
|
|
213
|
+
"""获取图像,支持多种输入源和大小限制
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
image_source: 图像源,可以是文件路径、URL
|
|
217
|
+
max_width: 可选的最大宽度
|
|
218
|
+
max_height: 可选的最大高度
|
|
219
|
+
max_pixels: 可选的最大像素数量
|
|
220
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
221
|
+
return_cache_path: 是否返回缓存路径
|
|
222
|
+
Returns:
|
|
223
|
+
PIL.Image对象,如果return_cache_path为True,则返回(image, cache_path)元组
|
|
224
|
+
"""
|
|
225
|
+
session = await self._ensure_session()
|
|
226
|
+
if return_cache_path:
|
|
227
|
+
image, cache_path = await get_pil_image(
|
|
228
|
+
image_source,
|
|
229
|
+
session,
|
|
230
|
+
cache_config=cache_config,
|
|
231
|
+
return_cache_path=return_cache_path,
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
image = await get_pil_image(
|
|
235
|
+
image_source,
|
|
236
|
+
session,
|
|
237
|
+
cache_config=cache_config,
|
|
238
|
+
return_cache_path=return_cache_path,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# Resize image based on provided constraints
|
|
242
|
+
if max_width and max_height:
|
|
243
|
+
# Use thumbnail to maintain aspect ratio while fitting within max dimensions
|
|
244
|
+
image.thumbnail((max_width, max_height), LANCZOS)
|
|
245
|
+
elif max_width:
|
|
246
|
+
# Use thumbnail with unlimited height
|
|
247
|
+
image.thumbnail((max_width, float("inf")), LANCZOS)
|
|
248
|
+
elif max_height:
|
|
249
|
+
# Use thumbnail with unlimited width
|
|
250
|
+
image.thumbnail((float("inf"), max_height), LANCZOS)
|
|
251
|
+
|
|
252
|
+
# Handle max_pixels constraint (after other resizing to avoid unnecessary work)
|
|
253
|
+
if max_pixels and (image.width * image.height > max_pixels):
|
|
254
|
+
# Calculate the ratio needed to get to max_pixels
|
|
255
|
+
ratio = (max_pixels / (image.width * image.height)) ** 0.5
|
|
256
|
+
# Use thumbnail to maintain aspect ratio
|
|
257
|
+
target_width = int(image.width * ratio)
|
|
258
|
+
target_height = int(image.height * ratio)
|
|
259
|
+
image.thumbnail((target_width, target_height), LANCZOS)
|
|
260
|
+
|
|
261
|
+
if return_cache_path:
|
|
262
|
+
return image, cache_path
|
|
263
|
+
else:
|
|
264
|
+
return image
|
|
265
|
+
|
|
266
|
+
async def encode_image(
|
|
267
|
+
self,
|
|
268
|
+
image_source: Union[str, Image.Image],
|
|
269
|
+
max_width: Optional[int] = None,
|
|
270
|
+
max_height: Optional[int] = None,
|
|
271
|
+
max_pixels: Optional[int] = None,
|
|
272
|
+
return_with_mime: bool = True,
|
|
273
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
274
|
+
) -> str:
|
|
275
|
+
"""编码图像为base64字符串,支持多种输入源和大小限制
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
image_source: 图像源,可以是文件路径、URL或PIL.Image对象
|
|
279
|
+
max_width: 可选的最大宽度限制
|
|
280
|
+
max_height: 可选的最大高度限制
|
|
281
|
+
max_pixels: 可选的最大像素数限制
|
|
282
|
+
return_with_mime: 是否在结果中包含MIME类型前缀
|
|
283
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
284
|
+
Returns:
|
|
285
|
+
base64编码的字符串
|
|
286
|
+
"""
|
|
287
|
+
session = await self._ensure_session()
|
|
288
|
+
result = await encode_image_to_base64(
|
|
289
|
+
image_source,
|
|
290
|
+
session,
|
|
291
|
+
max_width=max_width,
|
|
292
|
+
max_height=max_height,
|
|
293
|
+
max_pixels=max_pixels,
|
|
294
|
+
return_with_mime=return_with_mime,
|
|
295
|
+
cache_config=cache_config,
|
|
296
|
+
)
|
|
297
|
+
return result
|
|
298
|
+
|
|
299
|
+
async def encode_to_base64(
|
|
300
|
+
self,
|
|
301
|
+
file_source: Union[str, Image.Image],
|
|
302
|
+
return_with_mime: bool = True,
|
|
303
|
+
return_pil: bool = False,
|
|
304
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
305
|
+
) -> Union[str, Tuple[str, Image.Image], Image.Image]:
|
|
306
|
+
"""通用的编码方法,支持多种输入源和返回格式
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
file_source: 文件源,可以是文件路径、URL或PIL.Image对象
|
|
310
|
+
return_with_mime: 是否在结果中包含MIME类型前缀
|
|
311
|
+
return_pil: 是否返回PIL.Image对象
|
|
312
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
根据参数返回base64字符串、(base64字符串, PIL.Image)元组或PIL.Image对象
|
|
316
|
+
"""
|
|
317
|
+
session = await self._ensure_session()
|
|
318
|
+
result = await encode_to_base64(
|
|
319
|
+
file_source,
|
|
320
|
+
session,
|
|
321
|
+
return_with_mime=return_with_mime,
|
|
322
|
+
return_pil=return_pil,
|
|
323
|
+
cache_config=cache_config,
|
|
324
|
+
)
|
|
325
|
+
return result
|
|
326
|
+
|
|
327
|
+
async def process_content(
|
|
328
|
+
self,
|
|
329
|
+
content: Dict[str, Any],
|
|
330
|
+
inplace: bool = True,
|
|
331
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
332
|
+
**kwargs,
|
|
333
|
+
) -> Dict[str, Any]:
|
|
334
|
+
"""递归处理内容中的图像URL
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
content: 包含可能的图像URL的字典
|
|
338
|
+
inplace: 是否原地修改内容
|
|
339
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
340
|
+
**kwargs: 传递给encode_image_to_base64的额外参数
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
处理后的内容
|
|
344
|
+
"""
|
|
345
|
+
session = await self._ensure_session()
|
|
346
|
+
result = await process_content_recursive(
|
|
347
|
+
content, session, cache_config=cache_config, **kwargs
|
|
348
|
+
)
|
|
349
|
+
return result
|
|
350
|
+
|
|
351
|
+
async def preprocess_messages(
|
|
352
|
+
self,
|
|
353
|
+
messages: List[Dict[str, Any]],
|
|
354
|
+
inplace: bool = False,
|
|
355
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
356
|
+
**kwargs,
|
|
357
|
+
) -> List[Dict[str, Any]]:
|
|
358
|
+
"""预处理消息列表中的图像URL
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
messages: 消息列表
|
|
362
|
+
inplace: 是否原地修改内容
|
|
363
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
364
|
+
**kwargs: 传递给process_content_recursive的额外参数
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
处理后的消息列表
|
|
368
|
+
"""
|
|
369
|
+
session = await self._ensure_session()
|
|
370
|
+
|
|
371
|
+
result = await messages_preprocess(
|
|
372
|
+
messages, inplace=inplace, cache_config=cache_config, **kwargs
|
|
373
|
+
)
|
|
374
|
+
return result
|
|
375
|
+
|
|
376
|
+
async def batch_process_messages(
|
|
377
|
+
self,
|
|
378
|
+
messages_list: List[List[Dict[str, Any]]],
|
|
379
|
+
max_concurrent: int = 5,
|
|
380
|
+
inplace: bool = False,
|
|
381
|
+
cache_config: Optional[ImageCacheConfig] = None,
|
|
382
|
+
**kwargs,
|
|
383
|
+
) -> List[List[Dict[str, Any]]]:
|
|
384
|
+
"""批量处理多组消息列表
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
messages_list: 多组消息列表
|
|
388
|
+
max_concurrent: 最大并发处理数
|
|
389
|
+
inplace: 是否原地修改内容
|
|
390
|
+
cache_config: 图像缓存配置,如果为None则不使用缓存
|
|
391
|
+
**kwargs: 传递给messages_preprocess的额外参数
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
处理后的多组消息列表
|
|
395
|
+
"""
|
|
396
|
+
session = await self._ensure_session()
|
|
397
|
+
|
|
398
|
+
result = await batch_process_messages(
|
|
399
|
+
messages_list,
|
|
400
|
+
max_concurrent=max_concurrent,
|
|
401
|
+
inplace=inplace,
|
|
402
|
+
cache_config=cache_config,
|
|
403
|
+
**kwargs,
|
|
404
|
+
)
|
|
405
|
+
return result
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
# 便捷函数,用于在同步代码中使用异步方法
|
|
409
|
+
def run_async(coro):
|
|
410
|
+
"""运行异步协程并返回结果
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
coro: 异步协程
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
协程的结果
|
|
417
|
+
"""
|
|
418
|
+
try:
|
|
419
|
+
loop = asyncio.get_event_loop()
|
|
420
|
+
except RuntimeError:
|
|
421
|
+
# 如果没有事件循环,创建一个新的
|
|
422
|
+
loop = asyncio.new_event_loop()
|
|
423
|
+
asyncio.set_event_loop(loop)
|
|
424
|
+
|
|
425
|
+
return loop.run_until_complete(coro)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
# 示例用法
|
|
429
|
+
if __name__ == "__main__":
|
|
430
|
+
# 异步用法示例
|
|
431
|
+
async def async_example():
|
|
432
|
+
# 使用上下文管理器自动管理session生命周期
|
|
433
|
+
async with ImageProcessor() as processor:
|
|
434
|
+
# 从URL编码图像
|
|
435
|
+
base64_data = await processor.encode_from_url(
|
|
436
|
+
"https://example.com/image.jpg"
|
|
437
|
+
)
|
|
438
|
+
# print(f"Encoded image length: {len(base64_data)}")
|
|
439
|
+
|
|
440
|
+
# 使用缓存配置
|
|
441
|
+
cache_config = ImageCacheConfig.default()
|
|
442
|
+
|
|
443
|
+
# 处理消息中的图像URL
|
|
444
|
+
messages = [
|
|
445
|
+
{
|
|
446
|
+
"role": "user",
|
|
447
|
+
"content": [
|
|
448
|
+
{"type": "text", "text": "Here's an image"},
|
|
449
|
+
{"type": "image_url", "url": "https://example.com/image.jpg"},
|
|
450
|
+
],
|
|
451
|
+
}
|
|
452
|
+
]
|
|
453
|
+
processed_messages = await processor.preprocess_messages(
|
|
454
|
+
messages, cache_config=cache_config
|
|
455
|
+
)
|
|
456
|
+
print("Processed messages")
|
|
457
|
+
|
|
458
|
+
# 同步用法示例
|
|
459
|
+
def sync_example():
|
|
460
|
+
# 创建处理器
|
|
461
|
+
processor = ImageProcessor()
|
|
462
|
+
|
|
463
|
+
try:
|
|
464
|
+
# 从本地文件编码图像
|
|
465
|
+
if os.path.exists("local_image.jpg"):
|
|
466
|
+
base64_data = processor.encode_from_local_path("local_image.jpg")
|
|
467
|
+
# print(f"Encoded local image length: {len(base64_data)}")
|
|
468
|
+
|
|
469
|
+
# 创建缓存配置
|
|
470
|
+
cache_config = ImageCacheConfig(enabled=True, retry_failed=True)
|
|
471
|
+
|
|
472
|
+
# 从URL编码图像(使用run_async运行异步方法)
|
|
473
|
+
base64_data = run_async(
|
|
474
|
+
processor.encode_from_url(
|
|
475
|
+
"https://example.com/image.jpg", cache_config=cache_config
|
|
476
|
+
)
|
|
477
|
+
)
|
|
478
|
+
# print(f"Encoded remote image length: {len(base64_data)}")
|
|
479
|
+
finally:
|
|
480
|
+
# 关闭处理器(关闭session)
|
|
481
|
+
run_async(processor.close())
|
|
482
|
+
|
|
483
|
+
# 运行示例
|
|
484
|
+
# run_async(async_example())
|
|
485
|
+
# sync_example()
|