bizyengine 1.2.75__py3-none-any.whl → 1.2.77__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.
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
2
  import json
3
3
  import os
4
- import urllib
5
4
 
6
5
  import aiohttp
7
6
  from openai import OpenAI
@@ -9,6 +8,7 @@ from openai import OpenAI
9
8
  import bizyengine.core as core
10
9
  from bizyengine.core.common import get_api_key
11
10
  from bizyengine.core.common.env_var import (
11
+ BIZYAIR_DEBUG,
12
12
  BIZYAIR_PRODUCTION_TEST,
13
13
  BIZYAIR_SERVER_MODE,
14
14
  BIZYAIR_X_SERVER,
@@ -62,88 +62,53 @@ class APIClient:
62
62
  errnos.INVALID_API_KEY.message = error_message
63
63
  return None, errnos.INVALID_API_KEY
64
64
 
65
+ async def _handle_response(self, response, method, url):
66
+ try:
67
+ resp_text = await response.text()
68
+ except Exception:
69
+ resp_text = ""
70
+
71
+ try:
72
+ resp_json = json.loads(resp_text)
73
+ except Exception:
74
+ resp_json = resp_text
75
+
76
+ if response.status != 200:
77
+ print(
78
+ f"\033[31m[BizyAir]\033[0m API Error: {method} {url} {response.status} Body: {resp_text}"
79
+ )
80
+ isJson = isinstance(resp_json, dict)
81
+ return None, ErrorNo(
82
+ response.status,
83
+ resp_json.get("code", response.status) if isJson else resp_json,
84
+ None,
85
+ {
86
+ user_profile.getLang(): (
87
+ resp_json.get("message", resp_text) if isJson else resp_json
88
+ )
89
+ },
90
+ )
91
+ return resp_json, None
92
+
65
93
  async def do_get(self, url, params=None, headers=None):
66
- if params:
67
- query_string = urllib.parse.urlencode(params, doseq=True)
68
- url = f"{url}?{query_string}"
69
94
  async with await self.get_session() as session:
70
- async with session.get(url, headers=headers) as response:
71
- resp_json = await response.json()
72
- if response.status != 200:
73
- isJson = isinstance(resp_json, dict)
74
- return None, ErrorNo(
75
- response.status,
76
- resp_json.get("code", response.status) if isJson else resp_json,
77
- None,
78
- {
79
- user_profile.getLang(): (
80
- resp_json.get("message", await response.text())
81
- if isJson
82
- else resp_json
83
- )
84
- },
85
- )
86
- return resp_json, None
95
+ async with session.get(url, params=params, headers=headers) as response:
96
+ return await self._handle_response(response, "GET", url)
87
97
 
88
98
  async def do_post(self, url, data=None, headers=None):
89
99
  async with await self.get_session() as session:
90
100
  async with session.post(url, json=data, headers=headers) as response:
91
- resp_json = await response.json()
92
- if response.status != 200:
93
- isJson = isinstance(resp_json, dict)
94
- return None, ErrorNo(
95
- response.status,
96
- resp_json.get("code", response.status) if isJson else resp_json,
97
- None,
98
- {
99
- user_profile.getLang(): (
100
- resp_json.get("message", await response.text())
101
- if isJson
102
- else resp_json
103
- )
104
- },
105
- )
106
- return resp_json, None
101
+ return await self._handle_response(response, "POST", url)
107
102
 
108
103
  async def do_put(self, url, data=None, headers=None):
109
104
  async with await self.get_session() as session:
110
105
  async with session.put(url, json=data, headers=headers) as response:
111
- resp_json = await response.json()
112
- if response.status != 200:
113
- isJson = isinstance(resp_json, dict)
114
- return None, ErrorNo(
115
- response.status,
116
- resp_json.get("code", response.status) if isJson else resp_json,
117
- None,
118
- {
119
- user_profile.getLang(): (
120
- resp_json.get("message", await response.text())
121
- if isJson
122
- else resp_json
123
- )
124
- },
125
- )
126
- return resp_json, None
106
+ return await self._handle_response(response, "PUT", url)
127
107
 
128
108
  async def do_delete(self, url, data=None, headers=None):
129
109
  async with await self.get_session() as session:
130
110
  async with session.delete(url, json=data, headers=headers) as response:
131
- resp_json = await response.json()
132
- if response.status != 200:
133
- isJson = isinstance(resp_json, dict)
134
- return None, ErrorNo(
135
- response.status,
136
- resp_json.get("code", response.status) if isJson else resp_json,
137
- None,
138
- {
139
- user_profile.getLang(): (
140
- resp_json.get("message", await response.text())
141
- if isJson
142
- else resp_json
143
- )
144
- },
145
- )
146
- return resp_json, None
111
+ return await self._handle_response(response, "DELETE", url)
147
112
 
148
113
  async def user_info(self) -> tuple[dict | None, ErrorNo | None]:
149
114
  headers, err = self.auth_header()
@@ -1216,13 +1181,13 @@ class APIClient:
1216
1181
  try:
1217
1182
  data, err = await self.do_get(url, params=params, headers=headers)
1218
1183
  if err is not None:
1219
- print(f"fetch_all_models: error fetching models: {err}")
1184
+ print(f"fetch_all_models: error fetching models: {str(err)}")
1220
1185
  return []
1221
1186
 
1222
1187
  all_models = [model["id"] for model in data["data"]]
1223
1188
  return all_models
1224
1189
  except aiohttp.ClientError as e:
1225
- print(f"Error fetching models: {e}")
1190
+ print(f"Error fetching models: {str(e)}")
1226
1191
  return []
1227
1192
  except asyncio.exceptions.TimeoutError:
1228
1193
  print("Request to fetch models timed out")
@@ -22,6 +22,9 @@ class ErrorNo:
22
22
  def set_message(self, msg, lang="en"):
23
23
  self.messages[lang] = msg
24
24
 
25
+ def __str__(self) -> str:
26
+ return f"ErrorNo(http_status_code={self.http_status_code}, code={self.code}, messages={self.messages}, data={self.data})"
27
+
25
28
  message = property(fget=get_message, fset=set_message)
26
29
 
27
30
 
@@ -239,6 +239,9 @@ class Kling_2_5_I2V_API(BizyAirTrdApiBaseNode):
239
239
  "model_name": (["kling-v2-5-turbo"], {"default": "kling-v2-5-turbo"}),
240
240
  "duration": ([5, 10], {"default": 5}),
241
241
  },
242
+ "optional": {
243
+ "last_frame_image": ("IMAGE", {"tooltip": "末帧图片"}),
244
+ },
242
245
  }
243
246
 
244
247
  def handle_inputs(self, headers, prompt_id, **kwargs):
@@ -247,6 +250,7 @@ class Kling_2_5_I2V_API(BizyAirTrdApiBaseNode):
247
250
  negative_prompt = kwargs.get("negative_prompt", "")
248
251
  duration = kwargs.get("duration", 5)
249
252
  first_frame_image = kwargs.get("first_frame_image", None)
253
+ last_frame_image = kwargs.get("last_frame_image", None)
250
254
  if first_frame_image is None:
251
255
  raise ValueError("First frame image is required")
252
256
  if len(prompt) > 2500 or len(negative_prompt) > 2500:
@@ -256,7 +260,7 @@ class Kling_2_5_I2V_API(BizyAirTrdApiBaseNode):
256
260
  # 上传图片
257
261
  url = self.upload_file(
258
262
  tensor_to_bytesio(image=first_frame_image, total_pixels=4096 * 4096),
259
- f"{prompt_id}.png",
263
+ f"{prompt_id}_first.png",
260
264
  headers,
261
265
  )
262
266
  data = {
@@ -266,6 +270,13 @@ class Kling_2_5_I2V_API(BizyAirTrdApiBaseNode):
266
270
  "duration": duration,
267
271
  "first_frame_image": url,
268
272
  }
273
+ if last_frame_image is not None:
274
+ last_frame_image_url = self.upload_file(
275
+ tensor_to_bytesio(image=last_frame_image, total_pixels=4096 * 4096),
276
+ f"{prompt_id}_last.png",
277
+ headers,
278
+ )
279
+ data["last_frame_image"] = last_frame_image_url
269
280
  return data, "kling-v2-5"
270
281
 
271
282
  def handle_outputs(self, outputs):
@@ -196,3 +196,211 @@ class Wan_V2_5_T2V_API(BizyAirTrdApiBaseNode):
196
196
 
197
197
  def handle_outputs(self, outputs):
198
198
  return (outputs[0][0],)
199
+
200
+
201
+ class Wan_V2_6_I2V_API(BizyAirTrdApiBaseNode):
202
+ @classmethod
203
+ def INPUT_TYPES(cls):
204
+ return {
205
+ "required": {
206
+ "image": ("IMAGE",),
207
+ },
208
+ "optional": {
209
+ "audio": ("AUDIO",),
210
+ "prompt": (
211
+ "STRING",
212
+ {
213
+ "multiline": True,
214
+ "default": "",
215
+ },
216
+ ),
217
+ "negative_prompt": (
218
+ "STRING",
219
+ {
220
+ "multiline": True,
221
+ "default": "",
222
+ },
223
+ ),
224
+ "resolution": (
225
+ ["720P", "1080P"],
226
+ {"default": "1080P"},
227
+ ),
228
+ "duration": ([5, 10, 15], {"default": 5}),
229
+ "prompt_extend": (
230
+ "BOOLEAN",
231
+ {
232
+ "default": True,
233
+ "tooltip": "是否开启prompt智能改写。开启后使用大模型对输入prompt进行智能改写。对于较短的prompt生成效果提升明显,但会增加耗时。",
234
+ },
235
+ ),
236
+ "shot_type": (
237
+ ["single", "multi"],
238
+ {
239
+ "default": "single",
240
+ "tooltip": "指定生成视频的镜头类型,即视频是由一个连续镜头还是多个切换镜头组成。仅当prompt_extend: true时生效",
241
+ },
242
+ ),
243
+ "auto_audio": (
244
+ "BOOLEAN",
245
+ {
246
+ "default": True,
247
+ "tooltip": "是否由模型自动生成声音,优先级低于audio参数。",
248
+ },
249
+ ),
250
+ },
251
+ }
252
+
253
+ NODE_DISPLAY_NAME = "Wan2.6 Image To Video"
254
+ RETURN_TYPES = ("VIDEO", "STRING")
255
+ RETURN_NAMES = ("video", "actual_prompt")
256
+ CATEGORY = "☁️BizyAir/External APIs/WanVideo"
257
+
258
+ def handle_inputs(self, headers, prompt_id, **kwargs):
259
+ # 参数
260
+ prompt = kwargs.get("prompt", "")
261
+ negative_prompt = kwargs.get("negative_prompt", "")
262
+ audio = kwargs.get("audio", None)
263
+ resolution = kwargs.get("resolution", "1080P")
264
+ duration = kwargs.get("duration", 5)
265
+ prompt_extend = kwargs.get("prompt_extend", True)
266
+ shot_type = kwargs.get("shot_type", "single")
267
+ auto_audio = kwargs.get("auto_audio", True)
268
+ image = kwargs.get("image", None)
269
+
270
+ model = "wan2.6-i2v"
271
+ input = {
272
+ "resolution": resolution,
273
+ "prompt_extend": prompt_extend,
274
+ "duration": duration,
275
+ "audio": auto_audio,
276
+ "model": model,
277
+ "shot_type": shot_type,
278
+ }
279
+ if prompt is not None and prompt.strip() != "":
280
+ input["prompt"] = prompt
281
+ if negative_prompt is not None and negative_prompt.strip() != "":
282
+ input["negative_prompt"] = negative_prompt
283
+
284
+ # 上传图片&音频
285
+ if image is not None:
286
+ image_url = self.upload_file(
287
+ tensor_to_bytesio(image=image, total_pixels=4096 * 4096),
288
+ f"{prompt_id}.png",
289
+ headers,
290
+ )
291
+ input["img_url"] = image_url
292
+ if audio is not None:
293
+ audio_url = self.upload_file(
294
+ save_audio(audio=audio, format="mp3"), f"{prompt_id}.mp3", headers
295
+ )
296
+ input["audio_url"] = audio_url
297
+
298
+ return input, model
299
+
300
+ def handle_outputs(self, outputs):
301
+ return (outputs[0][0],)
302
+
303
+
304
+ class Wan_V2_6_T2V_API(BizyAirTrdApiBaseNode):
305
+ @classmethod
306
+ def INPUT_TYPES(cls):
307
+ return {
308
+ "required": {
309
+ "prompt": (
310
+ "STRING",
311
+ {
312
+ "multiline": True,
313
+ "default": "",
314
+ },
315
+ ),
316
+ },
317
+ "optional": {
318
+ "audio": ("AUDIO",),
319
+ "negative_prompt": (
320
+ "STRING",
321
+ {
322
+ "multiline": True,
323
+ "default": "",
324
+ },
325
+ ),
326
+ "size": (
327
+ [
328
+ "1280*720",
329
+ "720*1280",
330
+ "960*960",
331
+ "1088*832",
332
+ "832*1088",
333
+ "1920*1080",
334
+ "1080*1920",
335
+ "1440*1440",
336
+ "1632*1248",
337
+ "1248*1632",
338
+ ],
339
+ {"default": "1920*1080"},
340
+ ),
341
+ "duration": ([5, 10, 15], {"default": 5}),
342
+ "prompt_extend": (
343
+ "BOOLEAN",
344
+ {
345
+ "default": True,
346
+ "tooltip": "是否开启prompt智能改写。开启后使用大模型对输入prompt进行智能改写。对于较短的prompt生成效果提升明显,但会增加耗时。",
347
+ },
348
+ ),
349
+ "shot_type": (
350
+ ["single", "multi"],
351
+ {
352
+ "default": "single",
353
+ "tooltip": "指定生成视频的镜头类型,即视频是由一个连续镜头还是多个切换镜头组成。仅当prompt_extend: true时生效",
354
+ },
355
+ ),
356
+ "auto_audio": (
357
+ "BOOLEAN",
358
+ {
359
+ "default": True,
360
+ "tooltip": "是否由模型自动生成声音,优先级低于audio参数。",
361
+ },
362
+ ),
363
+ },
364
+ }
365
+
366
+ NODE_DISPLAY_NAME = "Wan2.6 Text To Video"
367
+ RETURN_TYPES = ("VIDEO", "STRING")
368
+ RETURN_NAMES = ("video", "actual_prompt")
369
+ CATEGORY = "☁️BizyAir/External APIs/WanVideo"
370
+
371
+ def handle_inputs(self, headers, prompt_id, **kwargs):
372
+ # 参数
373
+ model = "wan2.6-t2v"
374
+ negative_prompt = kwargs.get("negative_prompt", "")
375
+ audio = kwargs.get("audio", None)
376
+ size = kwargs.get("size", "1920*1080")
377
+ duration = kwargs.get("duration", 5)
378
+ prompt_extend = kwargs.get("prompt_extend", True)
379
+ shot_type = kwargs.get("shot_type", "single")
380
+ auto_audio = kwargs.get("auto_audio", True)
381
+ prompt = kwargs.get("prompt", "")
382
+
383
+ input = {
384
+ "size": size,
385
+ "prompt_extend": prompt_extend,
386
+ "duration": duration,
387
+ "audio": auto_audio,
388
+ "model": model,
389
+ "shot_type": shot_type,
390
+ }
391
+ if prompt is not None and prompt.strip() != "":
392
+ input["prompt"] = prompt
393
+ if negative_prompt is not None and negative_prompt.strip() != "":
394
+ input["negative_prompt"] = negative_prompt
395
+
396
+ # 上传音频
397
+ if audio is not None:
398
+ audio_url = self.upload_file(
399
+ save_audio(audio=audio, format="mp3"), f"{prompt_id}.mp3", headers
400
+ )
401
+ input["audio_url"] = audio_url
402
+
403
+ return input, model
404
+
405
+ def handle_outputs(self, outputs):
406
+ return (outputs[0][0],)
bizyengine/misc/utils.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import base64
3
3
  import concurrent.futures
4
+ import errno
4
5
  import json
5
6
  import logging
6
7
  import os
@@ -373,8 +374,8 @@ class SingleFlight(Generic[R]):
373
374
  # 读取结果
374
375
  with call.mu:
375
376
  if call.err is not None:
376
- return call.result, True, call.err
377
- return call.result, True, None
377
+ return call.result, not first, call.err
378
+ return call.result, not first, None
378
379
 
379
380
 
380
381
  _MODELS_CACHE = TTLCache[str, list[str]](ttl_sec=600)
@@ -383,7 +384,20 @@ _SF = SingleFlight[None]()
383
384
 
384
385
  def cache_models(request_api_key: str):
385
386
  # TODO: 效果待验证,目前节点只会被ComfyUI串行执行,所以不会出现竞争
386
- _SF.do("_cache_models", lambda: _cache_models(request_api_key))
387
+ # 重试最多五次
388
+ max_retries = 5
389
+ for i in range(max_retries):
390
+ try:
391
+ _, shared, e = _SF.do(
392
+ "_cache_models", lambda: _cache_models(request_api_key)
393
+ )
394
+ if e is not None:
395
+ raise e
396
+ return
397
+ except Exception:
398
+ logging.error(f"Failed to cache models on try #{i+1}")
399
+ if i < max_retries - 1:
400
+ time.sleep(5)
387
401
 
388
402
 
389
403
  def _cache_models(request_api_key: str):
@@ -394,7 +408,7 @@ def _cache_models(request_api_key: str):
394
408
  asyncio.run, api_client.fetch_all_llm_models(request_api_key)
395
409
  ).result()
396
410
  if len(all_models) == 0:
397
- return
411
+ raise errno.NO_MODEL_FOUND
398
412
  llm_models = [
399
413
  model
400
414
  for model in all_models
bizyengine/version.txt CHANGED
@@ -1 +1 @@
1
- 1.2.75
1
+ 1.2.77
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bizyengine
3
- Version: 1.2.75
3
+ Version: 1.2.77
4
4
  Summary: [a/BizyAir](https://github.com/siliconflow/BizyAir) Comfy Nodes that can run in any environment.
5
5
  Author-email: SiliconFlow <yaochi@siliconflow.cn>
6
6
  Project-URL: Repository, https://github.com/siliconflow/BizyAir
@@ -1,8 +1,8 @@
1
1
  bizyengine/__init__.py,sha256=GP9V-JM07fz7uv_qTB43QEA2rKdrVJxi5I7LRnn_3ZQ,914
2
- bizyengine/version.txt,sha256=siYnn5Q-O1exTQkq_wKI1vLHZcw7-2EhcWF5q44YGxE,7
2
+ bizyengine/version.txt,sha256=jgjXi4gpvDak_oc4lNqmFXG-uh20Gz7PivgcatO_r5s,7
3
3
  bizyengine/bizy_server/__init__.py,sha256=SP9oSblnPo4KQyh7yOGD26YCskFAcQHAZy04nQBNRIw,200
4
- bizyengine/bizy_server/api_client.py,sha256=fF2VApJjPcPWGQwYWSEaIN12c8WT95lj1_QHX83WbeQ,44630
5
- bizyengine/bizy_server/errno.py,sha256=ikb4Z3MRMTjosi9AC1epaOwE3kJsD6CcFcFp56AKF-Y,16986
4
+ bizyengine/bizy_server/api_client.py,sha256=a2OaFe2kJSQ1aZk15Es5Pg6sNl2qLt_nh3-IezbfVNk,42872
5
+ bizyengine/bizy_server/errno.py,sha256=xbQVryHlGTMgQ2msyqM89BL7OmD9md8d4bi3jgcgD4k,17147
6
6
  bizyengine/bizy_server/error_handler.py,sha256=MGrfO1AEqbfEgMWPL8B6Ypew_zHiQAdYGlhN9bZohrY,167
7
7
  bizyengine/bizy_server/execution.py,sha256=ayaEf6eGJKQsVZV-1_UlGlvwwmlH7FEek31Uq-MbUjA,1644
8
8
  bizyengine/bizy_server/profile.py,sha256=f4juAzJ73gCm0AhagYpt9WnG8HEI6xze_U96-omBLqU,3044
@@ -51,10 +51,10 @@ bizyengine/bizyair_extras/third_party_api/nodes_flux.py,sha256=9o7imVDn9qXnUokkA
51
51
  bizyengine/bizyair_extras/third_party_api/nodes_gemini.py,sha256=uI0PnSwoCUvn5_J2gK8X_ZcjvTMhnfO7X0NyZwWLl3M,17335
52
52
  bizyengine/bizyair_extras/third_party_api/nodes_gpt.py,sha256=pvIlwjjHnk_XCa4eJERBcsWonaBd24xP0jFVQLJXdQc,3098
53
53
  bizyengine/bizyair_extras/third_party_api/nodes_hailuo.py,sha256=hBmt6AHVXzsbO-Uq3Go-06yNLocV6sCtutKCVUz4P9E,3746
54
- bizyengine/bizyair_extras/third_party_api/nodes_kling.py,sha256=ROrMLXuJ2ubSvvsXXbnqeEnl_mAKxIKSWLh_okKd3TQ,18290
54
+ bizyengine/bizyair_extras/third_party_api/nodes_kling.py,sha256=zyQF9NM0vnOeOzuCayj3oA2x_s9Nm-S23YcgGuiC5ig,18796
55
55
  bizyengine/bizyair_extras/third_party_api/nodes_sora.py,sha256=alxI3zNDSUKdc2IOOv5csIWFcHSAqL_55H9Zp4BdcN4,6976
56
56
  bizyengine/bizyair_extras/third_party_api/nodes_veo3.py,sha256=H-6zWsUSTKaMMIUrMaH205-hnegvXxs1SQmKi4uY8rI,6489
57
- bizyengine/bizyair_extras/third_party_api/nodes_wan_api.py,sha256=qkbXFHlnirqUTqnN-X5mu7MyHRYjtGv6e233PjlyUxg,6776
57
+ bizyengine/bizyair_extras/third_party_api/nodes_wan_api.py,sha256=S6xUhiK2bvgRdBklLBw1ANeu5e_8qgd4Xp1aBgHapp8,14169
58
58
  bizyengine/bizyair_extras/third_party_api/trd_nodes_base.py,sha256=s4v8sPyvSu9-GaPQFFKq3w6V5uqQnciFgq7nrQGECiI,7895
59
59
  bizyengine/bizyair_extras/utils/aliyun_oss.py,sha256=H6wGZq1DqP7BHJ_frBJVvUVttgXprJprOnxytePIuos,3050
60
60
  bizyengine/bizyair_extras/utils/audio.py,sha256=cCmX080jtxsHFa7mCgn13R6cyfqE-1Gq37ZnRJdZNU8,3183
@@ -102,8 +102,8 @@ bizyengine/misc/nodes_controlnet_union_sdxl.py,sha256=fYyu_XMY7mcX1Ad9x30q1tYB8m
102
102
  bizyengine/misc/route_sam.py,sha256=-bMIR2QalfnszipGxSxvDAHGJa5gPSrjkYPb5baaRg4,1561
103
103
  bizyengine/misc/segment_anything.py,sha256=wNKYwlYPMszfwj23524geFZJjZaG4eye65SGaUnh77I,8941
104
104
  bizyengine/misc/supernode.py,sha256=STN9gaxfTSErH8OiHeZa47d8z-G9S0I7fXuJvHQOBFM,4532
105
- bizyengine/misc/utils.py,sha256=nXXTPkj4WBvds4EWjI9c-ydeWwmXl8Vwrdu-4Fh62g8,12914
106
- bizyengine-1.2.75.dist-info/METADATA,sha256=v9iayDEVC6sn_kO8GNs8p3j4O7Oh2MF6kQNEL-1fDHY,735
107
- bizyengine-1.2.75.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
- bizyengine-1.2.75.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
109
- bizyengine-1.2.75.dist-info/RECORD,,
105
+ bizyengine/misc/utils.py,sha256=GMRWKhOP-MCueVyCO-doflb7dH5dM32DyLcSPEVOXWA,13333
106
+ bizyengine-1.2.77.dist-info/METADATA,sha256=bPL9bUbVuQ1bO_Az3StZsew7-y16gt-HB6fms6iVZ40,735
107
+ bizyengine-1.2.77.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
+ bizyengine-1.2.77.dist-info/top_level.txt,sha256=2zapzqxX-we5cRyJkGf9bd5JinRtXp3-_uDI-xCAnc0,11
109
+ bizyengine-1.2.77.dist-info/RECORD,,