bizyengine 1.2.45__py3-none-any.whl → 1.2.71__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 (40) hide show
  1. bizyengine/bizy_server/errno.py +21 -0
  2. bizyengine/bizy_server/server.py +130 -160
  3. bizyengine/bizy_server/utils.py +3 -0
  4. bizyengine/bizyair_extras/__init__.py +38 -31
  5. bizyengine/bizyair_extras/third_party_api/__init__.py +15 -0
  6. bizyengine/bizyair_extras/third_party_api/nodes_doubao.py +535 -0
  7. bizyengine/bizyair_extras/third_party_api/nodes_flux.py +173 -0
  8. bizyengine/bizyair_extras/third_party_api/nodes_gemini.py +403 -0
  9. bizyengine/bizyair_extras/third_party_api/nodes_gpt.py +101 -0
  10. bizyengine/bizyair_extras/third_party_api/nodes_hailuo.py +115 -0
  11. bizyengine/bizyair_extras/third_party_api/nodes_kling.py +404 -0
  12. bizyengine/bizyair_extras/third_party_api/nodes_sora.py +218 -0
  13. bizyengine/bizyair_extras/third_party_api/nodes_veo3.py +193 -0
  14. bizyengine/bizyair_extras/third_party_api/nodes_wan_api.py +198 -0
  15. bizyengine/bizyair_extras/third_party_api/trd_nodes_base.py +183 -0
  16. bizyengine/bizyair_extras/utils/aliyun_oss.py +92 -0
  17. bizyengine/bizyair_extras/utils/audio.py +88 -0
  18. bizyengine/bizybot/__init__.py +12 -0
  19. bizyengine/bizybot/client.py +774 -0
  20. bizyengine/bizybot/config.py +129 -0
  21. bizyengine/bizybot/coordinator.py +556 -0
  22. bizyengine/bizybot/exceptions.py +186 -0
  23. bizyengine/bizybot/mcp/__init__.py +3 -0
  24. bizyengine/bizybot/mcp/manager.py +520 -0
  25. bizyengine/bizybot/mcp/models.py +46 -0
  26. bizyengine/bizybot/mcp/registry.py +129 -0
  27. bizyengine/bizybot/mcp/routing.py +378 -0
  28. bizyengine/bizybot/models.py +344 -0
  29. bizyengine/core/__init__.py +1 -0
  30. bizyengine/core/commands/servers/prompt_server.py +10 -1
  31. bizyengine/core/common/client.py +8 -7
  32. bizyengine/core/common/utils.py +30 -1
  33. bizyengine/core/image_utils.py +12 -283
  34. bizyengine/misc/llm.py +32 -15
  35. bizyengine/misc/utils.py +179 -2
  36. bizyengine/version.txt +1 -1
  37. {bizyengine-1.2.45.dist-info → bizyengine-1.2.71.dist-info}/METADATA +3 -1
  38. {bizyengine-1.2.45.dist-info → bizyengine-1.2.71.dist-info}/RECORD +40 -16
  39. {bizyengine-1.2.45.dist-info → bizyengine-1.2.71.dist-info}/WHEEL +0 -0
  40. {bizyengine-1.2.45.dist-info → bizyengine-1.2.71.dist-info}/top_level.txt +0 -0
@@ -201,6 +201,27 @@ class errnos:
201
201
  400, 400150, None, {"en": "Invalid prompt", "zh": "工作流错误"}
202
202
  )
203
203
 
204
+ # 聊天输入相关
205
+ MISSING_MESSAGE_OR_HISTORY = ErrorNo(
206
+ 400,
207
+ 400151,
208
+ None,
209
+ {
210
+ "en": "Missing message or conversation_history",
211
+ "zh": "缺少 message 或 conversation_history",
212
+ },
213
+ )
214
+
215
+ INVALID_CONVERSATION_HISTORY = ErrorNo(
216
+ 400,
217
+ 400152,
218
+ None,
219
+ {
220
+ "en": "Invalid conversation_history format",
221
+ "zh": "conversation_history 格式无效",
222
+ },
223
+ )
224
+
204
225
  INVALID_API_KEY = ErrorNo(
205
226
  401, 401000, None, {"en": "Invalid API key", "zh": "无效的API密钥"}
206
227
  )
@@ -1,11 +1,7 @@
1
1
  import asyncio
2
- import configparser
3
2
  import json
4
3
  import logging
5
- import os
6
- import random
7
4
  import re
8
- import shutil
9
5
  import threading
10
6
  import time
11
7
  import urllib.parse
@@ -13,11 +9,11 @@ import uuid
13
9
 
14
10
  import aiohttp
15
11
  import execution
16
- import openai
17
12
  from server import PromptServer
18
13
 
19
- from bizyengine.core.common.env_var import BIZYAIR_SERVER_ADDRESS, BIZYAIR_SERVER_MODE
20
- from bizyengine.core.configs.conf import ModelRule, config_manager
14
+ from bizyengine.bizybot.config import Config, LLMConfig, MCPServerConfig
15
+ from bizyengine.bizybot.coordinator import Coordinator
16
+ from bizyengine.core.common.env_var import BIZYAIR_DEBUG, BIZYAIR_SERVER_MODE
21
17
 
22
18
  from .api_client import APIClient
23
19
  from .errno import ErrorNo, errnos
@@ -45,6 +41,10 @@ BIZYAIR_DATA_DICT = {}
45
41
  BIZYAIR_DATA_DICT_UPDATED_AT = 0.0
46
42
 
47
43
  logging.basicConfig(level=logging.DEBUG)
44
+ # 禁用MCP与OpenAI使用的httpx等相关的DEBUG,INFO日志, 仅在BIZYAIR_DEBUG模式下启用
45
+ if not BIZYAIR_DEBUG:
46
+ logging.getLogger("mcp").setLevel(logging.WARNING)
47
+ logging.getLogger("httpx").setLevel(logging.WARNING)
48
48
 
49
49
 
50
50
  def _get_request_api_key(request_headers):
@@ -460,7 +460,17 @@ class BizyAirServer:
460
460
  async with session.get(url) as response:
461
461
  if response.status != 200:
462
462
  return ErrResponse(errnos.FAILED_TO_FETCH_WORKFLOW_JSON)
463
- json_content = await response.json()
463
+ try:
464
+ # 先尝试直接解析JSON
465
+ json_content = await response.json()
466
+ except aiohttp.client_exceptions.ContentTypeError:
467
+ # 如果Content-Type不是application/json,则获取文本内容并手动解析
468
+ text_content = await response.text()
469
+ try:
470
+ json_content = json.loads(text_content)
471
+ except json.JSONDecodeError as e:
472
+ logging.error(f"Failed to parse JSON from response: {e}")
473
+ return ErrResponse(errnos.FAILED_TO_FETCH_WORKFLOW_JSON)
464
474
 
465
475
  return OKResponse(json_content)
466
476
 
@@ -808,177 +818,137 @@ class BizyAirServer:
808
818
  return ErrResponse(err)
809
819
 
810
820
  @self.prompt_server.routes.post(f"/{MODEL_API}/chat")
811
- async def chat_completions(request):
812
- request_api_key, err = _get_request_api_key(request.headers)
813
- if err:
814
- return ErrResponse(err)
815
-
816
- response = None # 确保变量在退出前定义
817
- resp = None # 响应对象引用
818
- req_id = f"req-{id(request)}" # 为请求生成唯一ID
819
-
821
+ async def chat(request):
820
822
  try:
823
+ # 获取API密钥
824
+ request_api_key, err = _get_request_api_key(request.headers)
825
+ if err:
826
+ return ErrResponse(err)
827
+
821
828
  # 解析请求数据
822
829
  request_data = await request.json()
823
830
 
824
- # 转发请求到模型服务
825
- with self.api_client.forward_model_request(
826
- request_data, request_api_key
827
- ) as response:
828
- # 创建并准备流式响应
829
- resp = aiohttp.web.StreamResponse(
831
+ # 提取参数
832
+ current_message = request_data.get("message")
833
+ conversation_history = request_data.get("conversation_history", [])
834
+ model_config = request_data.get("model_config", {})
835
+
836
+ # 验证输入
837
+ if not current_message and not conversation_history:
838
+ return ErrResponse(errnos.MISSING_MESSAGE_OR_HISTORY)
839
+
840
+ # 验证对话历史格式
841
+ if conversation_history:
842
+ from bizyengine.bizybot.models import Conversation
843
+
844
+ if not Conversation.validate_conversation_history(
845
+ conversation_history
846
+ ):
847
+ return ErrResponse(errnos.INVALID_CONVERSATION_HISTORY)
848
+
849
+ if request_api_key:
850
+ api_key = request_api_key
851
+ if not BIZYAIR_SERVER_MODE:
852
+ from bizyengine.core.common.client import get_api_key
853
+
854
+ api_key = get_api_key()
855
+
856
+ if not api_key:
857
+ return ErrResponse(errnos.INVALID_API_KEY)
858
+
859
+ # 创建LLM配置
860
+ llm_config = LLMConfig(api_key=api_key, timeout=30.0)
861
+ config = Config(
862
+ llm=llm_config,
863
+ mcp_servers={
864
+ "bizyair-mcp": MCPServerConfig(
865
+ transport="streamable_http",
866
+ url="https://api.bizyair.cn/w/v1/mcp/32",
867
+ headers={
868
+ "Authorization": "Bearer " + api_key,
869
+ "X-BizyBot-Client": "bizybot",
870
+ },
871
+ ),
872
+ "bizyait-image-gen": MCPServerConfig(
873
+ transport="streamable_http",
874
+ url="https://api.bizyair.cn/w/v1/mcp/67",
875
+ headers={
876
+ "Authorization": "Bearer " + api_key,
877
+ "X-BizyBot-Client": "bizybot",
878
+ },
879
+ ),
880
+ "bizyait-image-edit": MCPServerConfig(
881
+ transport="streamable_http",
882
+ url="https://api.bizyair.cn/w/v1/mcp/68",
883
+ headers={
884
+ "Authorization": "Bearer " + api_key,
885
+ "X-BizyBot-Client": "bizybot",
886
+ },
887
+ ),
888
+ },
889
+ )
890
+
891
+ coordinator = Coordinator(config)
892
+ try:
893
+ await coordinator.initialize()
894
+
895
+ response = aiohttp.web.StreamResponse(
830
896
  status=200,
831
- reason="OK",
832
897
  headers={
833
898
  "Content-Type": "text/event-stream",
834
899
  "Cache-Control": "no-cache",
835
900
  "Connection": "keep-alive",
836
- "X-Accel-Buffering": "no", # 禁用Nginx缓冲
837
901
  },
838
902
  )
839
- await resp.prepare(request)
903
+ await response.prepare(request)
840
904
 
841
- # 开始流式传输
842
- any_chunk_sent = False # 跟踪是否发送了任何数据块
843
905
  try:
844
- for bytes in response.iter_bytes(1024):
845
- if bytes:
846
- await resp.write(bytes)
847
- any_chunk_sent = True
848
- await resp.drain() # 确保数据被立即发送
849
- except Exception as e:
850
- print(
851
- f"\033[31m[聊天请求-{req_id}]\033[0m 流式传输错误: {str(e)}"
906
+ import uuid
907
+
908
+ temp_conversation_id = str(uuid.uuid4())
909
+ conversation_event = {
910
+ "type": "conversation_started",
911
+ "conversation_id": temp_conversation_id,
912
+ }
913
+ await response.write(
914
+ f"data: {json.dumps(conversation_event, ensure_ascii=False)}\n\n".encode(
915
+ "utf-8"
916
+ )
852
917
  )
853
- # 如果尚未发送任何数据块,尝试发送错误信息
854
- if not any_chunk_sent and not resp.prepared:
855
- return ErrResponse(errnos.MODEL_API_ERROR)
856
- elif not any_chunk_sent:
857
- try:
858
- error_msg = json.dumps(
859
- {"error": f"流式传输错误: {str(e)}"}
860
- )
861
- await resp.write(
862
- f"data: {error_msg}\n\n".encode("utf-8")
863
- )
864
- await resp.write(b"data: [DONE]\n\n")
865
- except Exception as write_err:
866
- print(
867
- f"\033[31m[聊天请求-{req_id}]\033[0m 写入错误消息时出错: {str(write_err)}"
918
+
919
+ async for event in coordinator.process_message(
920
+ message=current_message,
921
+ conversation_history=conversation_history,
922
+ llm_config_override=model_config,
923
+ ):
924
+ formatted_event = coordinator.format_streaming_event(event)
925
+ await response.write(
926
+ f"data: {json.dumps(formatted_event, ensure_ascii=False)}\n\n".encode(
927
+ "utf-8"
868
928
  )
929
+ )
869
930
 
870
- try:
871
- await resp.write_eof()
931
+ await response.write(b"data: [DONE]\n\n")
872
932
  except Exception as e:
873
- print(
874
- f"\033[31m[聊天请求-{req_id}]\033[0m 结束响应时出错: {str(e)}"
875
- )
876
-
877
- return resp
933
+ error_event = {"type": "error", "error": str(e)}
934
+ try:
935
+ await response.write(
936
+ f"data: {json.dumps(error_event, ensure_ascii=False)}\n\n".encode(
937
+ "utf-8"
938
+ )
939
+ )
940
+ except Exception:
941
+ pass
878
942
 
879
- except openai.APIConnectionError as e:
880
- print("The server could not be reached")
881
- print(
882
- e.__cause__
883
- ) # an underlying Exception, likely raised within httpx.
884
- except openai.RateLimitError:
885
- print("A 429 status code was received; we should back off a bit.")
886
- except openai.APIStatusError as e:
887
- print("Another non-200-range status code was received")
888
- print(e.status_code)
889
- print(e.response)
890
- except Exception as e:
891
- print(
892
- f"\033[31m[聊天请求-{req_id}]\033[0m 处理请求时发生错误: {str(e)}"
893
- )
894
- # 如果响应已经准备好,尝试发送错误信息
895
- if resp and resp.prepared:
943
+ return response
944
+ finally:
896
945
  try:
897
- error_msg = json.dumps({"error": f"服务器错误: {str(e)}"})
898
- await resp.write(f"data: {error_msg}\n\n".encode("utf-8"))
899
- await resp.write(b"data: [DONE]\n\n")
900
- await resp.write_eof()
901
- except:
902
- pass
903
- return resp
904
-
905
- return ErrResponse(errnos.MODEL_API_ERROR)
946
+ await coordinator.cleanup()
947
+ except Exception:
948
+ logging.exception("Coordinator cleanup failed")
906
949
 
907
- @self.prompt_server.routes.post(f"/{MODEL_API}/image-edit")
908
- async def image_edit(request):
909
- try:
910
- request_api_key, err = _get_request_api_key(request.headers)
911
- if err:
912
- return ErrResponse(err)
913
- auth_header = request.headers.get("Authorization", "")
914
- cookie_str = request.headers.get("Cookie", "")
915
- cookie_api_key = _get_api_key_from_cookie(cookie_str)
916
- request_data = await request.json()
917
- target_url = f"{BIZYAIR_SERVER_ADDRESS}{config_manager.get_rules('comfyagent-flux1-kontext')[0].route}"
918
- forward_payload = {
919
- "prompt": request_data.get("prompt", "请编辑这张图片"),
920
- "image": request_data.get("image", ""),
921
- "seed": request_data.get("seed", random.randint(1, 9999999999)),
922
- "num_inference_steps": request_data.get("num_inference_steps", 20),
923
- "guidance_scale": request_data.get("guidance_scale", 2.5),
924
- }
925
- async with aiohttp.ClientSession() as session:
926
- headers = {
927
- "Content-Type": "application/json",
928
- "User-Agent": "BizyAir Server",
929
- "x-bizyair-client-version": "1.2.21",
930
- }
931
- if request_api_key:
932
- headers["Authorization"] = f"Bearer {request_api_key}"
933
- elif cookie_api_key:
934
- headers["Authorization"] = f"Bearer {cookie_api_key}"
935
- elif auth_header:
936
- if not auth_header.startswith("Bearer "):
937
- headers["Authorization"] = f"Bearer {auth_header}"
938
- else:
939
- headers["Authorization"] = auth_header
940
- else:
941
- from bizyengine.core.common.env_var import load_api_key
942
-
943
- has_key, file_api_key = load_api_key()
944
- if has_key and file_api_key:
945
- headers["Authorization"] = f"Bearer {file_api_key}"
946
- logging.debug("Using API key from api_key.ini file")
947
- async with session.post(
948
- target_url, headers=headers, json=forward_payload, timeout=120
949
- ) as response:
950
- response_data = await response.json()
951
- logging.debug(response_data)
952
-
953
- if response.status == 200:
954
- return OKResponse(response_data)
955
- else:
956
- return ErrResponse(errnos.MODEL_API_ERROR)
957
-
958
- except Exception:
959
- return ErrResponse(errnos.MODEL_API_ERROR)
960
-
961
- @self.prompt_server.routes.post(f"/{MODEL_API}/images")
962
- async def image_generations(request):
963
- try:
964
- request_api_key, err = _get_request_api_key(request.headers)
965
- if err:
966
- return ErrResponse(err)
967
-
968
- # 解析请求数据
969
- request_data = await request.json()
970
-
971
- # 转发图像生成请求
972
- result, err = await self.api_client.forward_image_request(
973
- request_data, request_api_key
974
- )
975
- if err is not None:
976
- return ErrResponse(err)
977
-
978
- # 返回结果
979
- return OKResponse(result)
980
-
981
- except Exception:
950
+ except Exception as e:
951
+ print(f"\033[31m[BizyAir]\033[0m Chat request failed: {str(e)}")
982
952
  return ErrResponse(errnos.MODEL_API_ERROR)
983
953
 
984
954
  # 服务器模式独占
@@ -990,7 +960,7 @@ class BizyAirServer:
990
960
  async def list_share_model_files(request):
991
961
  shareId = request.match_info["shareId"]
992
962
  if not is_string_valid(shareId):
993
- return ErrResponse("INVALID_SHARE_ID")
963
+ return ErrResponse(errnos.INVALID_SHARE_ID)
994
964
  payload = {}
995
965
  query_params = ["type", "name", "ext_name"]
996
966
  for param in query_params:
@@ -127,6 +127,9 @@ def is_allow_ext_name(local_file_name):
127
127
  def decrypt_apikey(apikey_ciphertext):
128
128
  if not BIZYAIR_SERVER_MODE_RSA_PRIVATE_KEY_PATH:
129
129
  return apikey_ciphertext, None
130
+ # v4.public开头不用解密
131
+ if apikey_ciphertext.startswith("v4.public"):
132
+ return apikey_ciphertext, None
130
133
  global _RSA_CIPHER
131
134
  if not _RSA_CIPHER:
132
135
  with open(BIZYAIR_SERVER_MODE_RSA_PRIVATE_KEY_PATH, "rb") as f:
@@ -1,31 +1,38 @@
1
- from .nodes_advanced_refluxcontrol import *
2
- from .nodes_cogview4 import *
3
- from .nodes_comfyui_detail_daemon import *
4
- from .nodes_comfyui_instantid import *
5
- from .nodes_comfyui_layerstyle_advance import *
6
- from .nodes_comfyui_pulid_flux import *
7
- from .nodes_controlnet import *
8
- from .nodes_custom_sampler import *
9
- from .nodes_dataset import *
10
- from .nodes_differential_diffusion import *
11
- from .nodes_flux import *
12
- from .nodes_hunyuan3d import *
13
- from .nodes_image_utils import *
14
- from .nodes_ip2p import *
15
- from .nodes_ipadapter_plus.nodes_ipadapter_plus import *
16
- from .nodes_janus_pro import *
17
- from .nodes_kolors_mz import *
18
- from .nodes_model_advanced import *
19
- from .nodes_nunchaku import *
20
- from .nodes_reactor import *
21
- from .nodes_sam2 import *
22
- from .nodes_sd3 import *
23
- from .nodes_segment_anything import *
24
- from .nodes_testing_utils import *
25
- from .nodes_trellis import *
26
- from .nodes_ultimatesdupscale import *
27
- from .nodes_upscale_model import *
28
- from .nodes_utils import *
29
- from .nodes_wan_i2v import *
30
- from .nodes_wan_video import *
31
- from .route_bizyair_tools import *
1
+ modules = [
2
+ ".nodes_advanced_refluxcontrol",
3
+ ".nodes_cogview4",
4
+ ".nodes_comfyui_detail_daemon",
5
+ ".nodes_comfyui_instantid",
6
+ ".nodes_comfyui_layerstyle_advance",
7
+ ".nodes_comfyui_pulid_flux",
8
+ ".nodes_controlnet",
9
+ ".nodes_custom_sampler",
10
+ ".nodes_dataset",
11
+ ".nodes_differential_diffusion",
12
+ ".nodes_flux",
13
+ ".nodes_hunyuan3d",
14
+ ".nodes_image_utils",
15
+ ".nodes_ip2p",
16
+ ".nodes_ipadapter_plus.nodes_ipadapter_plus",
17
+ ".nodes_janus_pro",
18
+ ".nodes_kolors_mz",
19
+ ".nodes_model_advanced",
20
+ ".nodes_nunchaku",
21
+ ".nodes_reactor",
22
+ ".nodes_sam2",
23
+ ".nodes_sd3",
24
+ ".nodes_segment_anything",
25
+ ".nodes_testing_utils",
26
+ ".nodes_trellis",
27
+ ".nodes_ultimatesdupscale",
28
+ ".nodes_upscale_model",
29
+ ".nodes_utils",
30
+ ".nodes_wan_i2v",
31
+ ".nodes_wan_video",
32
+ ".route_bizyair_tools",
33
+ ".third_party_api",
34
+ ]
35
+ from bizyengine.core.common.utils import safe_star_import
36
+
37
+ for mod in modules:
38
+ safe_star_import(mod, package=__package__)
@@ -0,0 +1,15 @@
1
+ modules = [
2
+ ".nodes_hailuo",
3
+ ".nodes_gemini",
4
+ ".nodes_gpt",
5
+ ".nodes_kling",
6
+ ".nodes_doubao",
7
+ ".nodes_flux",
8
+ ".nodes_sora",
9
+ ".nodes_veo3",
10
+ ".nodes_wan_api",
11
+ ]
12
+ from bizyengine.core.common.utils import safe_star_import
13
+
14
+ for mod in modules:
15
+ safe_star_import(mod, package=__package__)