beswarm 0.3.1__tar.gz → 0.3.3__tar.gz

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 (140) hide show
  1. {beswarm-0.3.1 → beswarm-0.3.3}/PKG-INFO +1 -1
  2. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/agents/planact.py +1 -2
  3. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/architext/architext/core.py +56 -2
  4. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/architext/test/test.py +164 -0
  5. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/request.py +4 -2
  6. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/response.py +3 -2
  7. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/utils.py +44 -1
  8. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/models/audio.py +2 -2
  9. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/models/base.py +2 -2
  10. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/models/chatgpt.py +49 -30
  11. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/image.py +2 -2
  12. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/utils/prompt.py +0 -4
  13. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/utils/scripts.py +0 -8
  14. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_whisper.py +1 -1
  15. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/PKG-INFO +1 -1
  16. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/SOURCES.txt +0 -2
  17. {beswarm-0.3.1 → beswarm-0.3.3}/pyproject.toml +1 -1
  18. beswarm-0.3.1/beswarm/aient/test/test_search.py +0 -18
  19. beswarm-0.3.1/beswarm/aient/test/test_yjh.py +0 -21
  20. {beswarm-0.3.1 → beswarm-0.3.3}/MANIFEST.in +0 -0
  21. {beswarm-0.3.1 → beswarm-0.3.3}/README.md +0 -0
  22. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/__init__.py +0 -0
  23. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/agents/chatgroup.py +0 -0
  24. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/__init__.py +0 -0
  25. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/architext/architext/__init__.py +0 -0
  26. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/architext/test/openai_client.py +0 -0
  27. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/architext/test/test_save_load.py +0 -0
  28. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/__init__.py +0 -0
  29. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/log_config.py +0 -0
  30. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/models.py +0 -0
  31. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/test/test_base_api.py +0 -0
  32. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/test/test_geminimask.py +0 -0
  33. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/test/test_image.py +0 -0
  34. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/core/test/test_payload.py +0 -0
  35. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/models/__init__.py +0 -0
  36. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/__init__.py +0 -0
  37. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/arXiv.py +0 -0
  38. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/config.py +0 -0
  39. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/excute_command.py +0 -0
  40. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/get_time.py +0 -0
  41. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/list_directory.py +0 -0
  42. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/read_file.py +0 -0
  43. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/read_image.py +0 -0
  44. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/readonly.py +0 -0
  45. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/registry.py +0 -0
  46. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/run_python.py +0 -0
  47. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/websearch.py +0 -0
  48. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/plugins/write_file.py +0 -0
  49. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/aient/utils/__init__.py +0 -0
  50. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_Web_crawler.py +0 -0
  51. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_ddg_search.py +0 -0
  52. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_google_search.py +0 -0
  53. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_ollama.py +0 -0
  54. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_plugin.py +0 -0
  55. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/aient/test/test_url.py +0 -0
  56. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/bemcp/__init__.py +0 -0
  57. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/bemcp/decorator.py +0 -0
  58. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/bemcp/main.py +0 -0
  59. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/bemcp/utils.py +0 -0
  60. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/test/client.py +0 -0
  61. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/bemcp/test/server.py +0 -0
  62. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/broker.py +0 -0
  63. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/cli.py +0 -0
  64. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/core.py +0 -0
  65. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/knowledge_graph.py +0 -0
  66. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/prompt.py +0 -0
  67. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/README.md +0 -0
  68. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  69. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  70. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  71. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  72. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  73. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  74. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  75. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  76. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  77. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  78. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  79. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  80. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  81. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  82. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  83. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  84. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  85. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  86. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  87. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  88. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  89. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  90. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  91. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  92. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  93. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  94. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/README.md +0 -0
  95. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/c-tags.scm +0 -0
  96. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  97. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  98. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/dart-tags.scm +0 -0
  99. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  100. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  101. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/elm-tags.scm +0 -0
  102. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/go-tags.scm +0 -0
  103. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  104. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/java-tags.scm +0 -0
  105. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  106. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  107. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  108. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/php-tags.scm +0 -0
  109. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/python-tags.scm +0 -0
  110. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/ql-tags.scm +0 -0
  111. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  112. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/rust-tags.scm +0 -0
  113. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/scala-tags.scm +0 -0
  114. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  115. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/taskmanager.py +0 -0
  116. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/__init__.py +0 -0
  117. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/click.py +0 -0
  118. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/completion.py +0 -0
  119. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/deep_search.py +0 -0
  120. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/edit_file.py +0 -0
  121. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/graph.py +0 -0
  122. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/planner.py +0 -0
  123. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/repomap.py +0 -0
  124. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/request_input.py +0 -0
  125. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/screenshot.py +0 -0
  126. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/search_arxiv.py +0 -0
  127. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/search_web.py +0 -0
  128. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/subtasks.py +0 -0
  129. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/worker.py +0 -0
  130. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/tools/write_csv.py +0 -0
  131. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm/utils.py +0 -0
  132. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/dependency_links.txt +0 -0
  133. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/entry_points.txt +0 -0
  134. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/requires.txt +0 -0
  135. {beswarm-0.3.1 → beswarm-0.3.3}/beswarm.egg-info/top_level.txt +0 -0
  136. {beswarm-0.3.1 → beswarm-0.3.3}/setup.cfg +0 -0
  137. {beswarm-0.3.1 → beswarm-0.3.3}/test/test_TaskManager.py +0 -0
  138. {beswarm-0.3.1 → beswarm-0.3.3}/test/test_broker.py +0 -0
  139. {beswarm-0.3.1 → beswarm-0.3.3}/test/test_graph.py +0 -0
  140. {beswarm-0.3.1 → beswarm-0.3.3}/test/test_new_TaskManager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -204,8 +204,7 @@ class WorkerAgent(BaseAgent):
204
204
  self.broker.publish(message, self.error_topic)
205
205
  else:
206
206
  self.broker.publish({"status": "new_message", "result": "\n✅ 工作智能体:\n" + response}, self.status_topic)
207
- if len(self.agent.conversation["default"]) > 1 and self.agent.conversation["default"][-1].role == "user":
208
- self.agent.conversation["default"].pop(-1)
207
+ self.agent.conversation["default"][-1].rstrip(Texts)
209
208
  self.broker.publish({
210
209
  "conversation": self.agent.conversation["default"]
211
210
  }, self.publish_topic)
@@ -104,9 +104,10 @@ class ContextProvider(ABC):
104
104
  return NotImplemented
105
105
 
106
106
  class Texts(ContextProvider):
107
- def __init__(self, text: Optional[Union[str, Callable[[], str]]] = None, name: Optional[str] = None, visible: bool = True):
107
+ def __init__(self, text: Optional[Union[str, Callable[[], str]]] = None, name: Optional[str] = None, visible: bool = True, newline: bool = False):
108
108
  if text is None and name is None:
109
109
  raise ValueError("Either 'text' or 'name' must be provided.")
110
+ self.newline = newline
110
111
 
111
112
  # Ensure that non-callable inputs are treated as strings
112
113
  if not callable(text):
@@ -127,6 +128,11 @@ class Texts(ContextProvider):
127
128
  else:
128
129
  _name = name
129
130
  super().__init__(_name, visible=visible)
131
+ if not self._is_dynamic:
132
+ self._cached_content = self.content
133
+ # The content is cached, but it's still "stale" from the perspective
134
+ # of the async refresh cycle. Let the first refresh formalize it.
135
+ self._is_stale = True
130
136
 
131
137
  async def refresh(self):
132
138
  if self._is_dynamic:
@@ -190,6 +196,10 @@ class Tools(ContextProvider):
190
196
  def __init__(self, tools_json: Optional[List[Dict]] = None, name: str = "tools", visible: bool = True):
191
197
  super().__init__(name, visible=visible)
192
198
  self._tools_json = tools_json or []
199
+ # Pre-render and cache the content, but leave it stale for the first refresh
200
+ if self._tools_json:
201
+ self._cached_content = f"<tools>{str(self._tools_json)}</tools>"
202
+ self._is_stale = True
193
203
  def update(self, tools_json: List[Dict]):
194
204
  self._tools_json = tools_json
195
205
  self.mark_stale()
@@ -288,6 +298,9 @@ class Images(ContextProvider):
288
298
  def __init__(self, url: str, name: Optional[str] = None, visible: bool = True):
289
299
  super().__init__(name or url, visible=visible)
290
300
  self.url = url
301
+ if self.url.startswith("data:"):
302
+ self._cached_content = self.url
303
+ self._is_stale = True
291
304
  def update(self, url: str):
292
305
  self.url = url
293
306
  self.mark_stale()
@@ -315,6 +328,8 @@ class Message(ABC):
315
328
  self.role = role
316
329
  processed_items = []
317
330
  for item in initial_items:
331
+ if item is None:
332
+ continue
318
333
  if isinstance(item, str):
319
334
  # Check if the string contains placeholders from f-string rendering
320
335
  import re
@@ -371,8 +386,11 @@ class Message(ABC):
371
386
  for item in self._items:
372
387
  block = item.get_content_block()
373
388
  if block and block.content is not None:
389
+ # Check if it's a Texts provider with newline=True
390
+ # and it's not the very first item with content.
391
+ if isinstance(item, Texts) and hasattr(item, 'newline') and item.newline and final_parts:
392
+ final_parts.append("\n\n")
374
393
  final_parts.append(block.content)
375
-
376
394
  return "".join(final_parts)
377
395
 
378
396
  def pop(self, name: str) -> Optional[ContextProvider]:
@@ -466,11 +484,47 @@ class Message(ABC):
466
484
  # and our custom __eq__ on ContextProvider handles the comparison logic.
467
485
  return item in self._items
468
486
 
487
+ def has(self, provider_type: type) -> bool:
488
+ """Checks if the message contains a provider of a specific type."""
489
+ if not isinstance(provider_type, type) or not issubclass(provider_type, ContextProvider):
490
+ raise TypeError("provider_type must be a subclass of ContextProvider")
491
+ return any(isinstance(p, provider_type) for p in self._items)
492
+
493
+ def lstrip(self, provider_type: type):
494
+ """
495
+ 从消息的左侧(开头)移除所有指定类型的 provider。
496
+ 移除操作会一直持续,直到遇到一个不同类型的 provider 为止。
497
+ """
498
+ while self._items and type(self._items[0]) is provider_type:
499
+ self.pop(self._items[0].name)
500
+
501
+ def rstrip(self, provider_type: type):
502
+ """
503
+ 从消息的右侧(末尾)移除所有指定类型的 provider。
504
+ 移除操作会一直持续,直到遇到一个不同类型的 provider 为止。
505
+ """
506
+ while self._items and type(self._items[-1]) is provider_type:
507
+ self.pop(self._items[-1].name)
508
+
509
+ def strip(self, provider_type: type):
510
+ """
511
+ 从消息的两侧移除所有指定类型的 provider。
512
+ """
513
+ self.lstrip(provider_type)
514
+ self.rstrip(provider_type)
515
+
469
516
  def __bool__(self) -> bool:
470
517
  return bool(self._items)
471
518
  def get(self, key: str, default: Any = None) -> Any:
472
519
  """提供类似字典的 .get() 方法来访问属性。"""
473
520
  return getattr(self, key, default)
521
+
522
+ async def render_latest(self) -> Optional[Dict[str, Any]]:
523
+ """Refreshes all providers in the message and returns the rendered dictionary."""
524
+ tasks = [provider.refresh() for provider in self._items]
525
+ await asyncio.gather(*tasks)
526
+ return self.to_dict()
527
+
474
528
  def to_dict(self) -> Optional[Dict[str, Any]]:
475
529
  is_multimodal = any(isinstance(p, Images) for p in self._items)
476
530
 
@@ -1434,6 +1434,170 @@ Files: {Files(visible=True, name="files")}
1434
1434
  self.assertTrue(message in messages_collection)
1435
1435
  self.assertFalse(UserMessage("not in collection") in messages_collection)
1436
1436
 
1437
+ async def test_zz_none_input_ignored(self):
1438
+ """测试在Message初始化时,None值是否被自动忽略"""
1439
+ # 1. 在初始化列表中包含 None
1440
+ message = UserMessage("Hello", None, "World")
1441
+ self.assertEqual(len(message.provider()), 2)
1442
+ self.assertIsInstance(message.provider()[0], Texts)
1443
+ self.assertIsInstance(message.provider()[1], Texts)
1444
+ rendered = await message.render_latest()
1445
+ self.assertEqual(rendered['content'], "HelloWorld")
1446
+
1447
+ # 2. 测试只有 None
1448
+ message_none = SystemMessage(None)
1449
+ self.assertEqual(len(message_none.provider()), 0)
1450
+ self.assertFalse(message_none)
1451
+
1452
+ # 3. 测试混合 provider 和 None
1453
+ message_mixed = SystemMessage(Texts("hi"), None)
1454
+ self.assertEqual(len(message_mixed.provider()), 1)
1455
+ self.assertIsInstance(message_mixed.provider()[0], Texts)
1456
+
1457
+ async def test_zaa_has_method_for_provider_type_check(self):
1458
+ """测试 Message.has(type) 方法是否能正确检查 provider 类型"""
1459
+ # 1. 创建一个混合类型的消息
1460
+ message_with_text = UserMessage(Texts("hi"), Images("url"))
1461
+
1462
+ # 2. 测试存在的情况
1463
+ # This line is expected to fail with an AttributeError before implementation
1464
+ self.assertTrue(message_with_text.has(Texts))
1465
+ self.assertTrue(message_with_text.has(Images))
1466
+
1467
+ # 3. 测试不存在的情况
1468
+ self.assertFalse(message_with_text.has(Tools))
1469
+
1470
+ # 4. 测试空消息
1471
+ empty_message = UserMessage()
1472
+ self.assertFalse(empty_message.has(Texts))
1473
+
1474
+ # 5. 测试传入无效类型
1475
+ with self.assertRaises(TypeError):
1476
+ message_with_text.has(str)
1477
+
1478
+ with self.assertRaises(TypeError):
1479
+ # Also test with a class that is not a subclass of ContextProvider
1480
+ class NotAProvider: pass
1481
+ message_with_text.has(NotAProvider)
1482
+
1483
+ async def test_zab_lstrip_and_rstrip(self):
1484
+ """测试 lstrip, rstrip, 和 strip 方法是否能正确移除两侧的特定类型的 provider"""
1485
+ # 1. 定义一个用于测试的子类
1486
+ class SpecialTexts(Texts):
1487
+ pass
1488
+ url = "data:image/png;base64,FAKE_IMG"
1489
+
1490
+ # 2. 创建一个复杂的测试消息
1491
+ message = UserMessage(
1492
+ Texts("leading1"),
1493
+ Texts("leading2"),
1494
+ Images(url, name="image1"),
1495
+ Texts("middle"),
1496
+ SpecialTexts("special_middle"),
1497
+ Images(url, name="image2"),
1498
+ Texts("trailing1"),
1499
+ SpecialTexts("special_trailing"), # rstrip(Texts) should stop here
1500
+ Texts("trailing2")
1501
+ )
1502
+
1503
+ # 3. 测试 rstrip(Texts)
1504
+ r_stripped_message = UserMessage(*message.provider()) # 创建副本
1505
+ r_stripped_message.rstrip(Texts)
1506
+ # 应移除 "trailing2",但在 "special_trailing" 处停止
1507
+ self.assertEqual(len(r_stripped_message), 8)
1508
+ self.assertIs(type(r_stripped_message[-1]), SpecialTexts)
1509
+
1510
+ # 4. 测试 lstrip(Texts)
1511
+ l_stripped_message = UserMessage(*message.provider()) # 创建副本
1512
+ l_stripped_message.lstrip(Texts)
1513
+ # 应移除 "leading1" 和 "leading2",但在 "image1" 处停止
1514
+ self.assertEqual(len(l_stripped_message), 7)
1515
+ self.assertIs(type(l_stripped_message[0]), Images)
1516
+
1517
+ # 5. 测试 strip(Texts)
1518
+ stripped_message = UserMessage(*message.provider()) # 创建副本
1519
+ stripped_message.strip(Texts)
1520
+ # 应同时移除 "leading1", "leading2", 和 "trailing2"
1521
+ self.assertEqual(len(stripped_message), 6)
1522
+ self.assertIs(type(stripped_message[0]), Images)
1523
+ self.assertIs(type(stripped_message[-1]), SpecialTexts)
1524
+
1525
+ # 6. 测试在一个只包含一种类型的消息上进行剥离
1526
+ only_texts = UserMessage(Texts("a"), Texts("b"))
1527
+ only_texts.strip(Texts)
1528
+ self.assertEqual(len(only_texts), 0)
1529
+
1530
+ # 7. 测试剥离一个不包含目标类型的消息
1531
+ only_images = UserMessage(Images("url1"), Images("url2"))
1532
+ only_images.strip(Texts)
1533
+ self.assertEqual(len(only_images), 2) # 不应改变
1534
+
1535
+ # 8. 测试在一个空消息上进行剥离
1536
+ empty_message = UserMessage()
1537
+ empty_message.strip(Texts)
1538
+ self.assertEqual(len(empty_message), 0)
1539
+
1540
+ # 9. 测试剥离子类
1541
+ message_ending_with_special = UserMessage(Texts("a"), SpecialTexts("b"))
1542
+ message_ending_with_special.rstrip(SpecialTexts)
1543
+ self.assertEqual(len(message_ending_with_special), 1)
1544
+ self.assertIsInstance(message_ending_with_special[0], Texts)
1545
+
1546
+ async def test_zac_texts_join_parameter(self):
1547
+ """测试 Texts provider 是否支持通过参数控制拼接方式"""
1548
+ # 1. 测试默认行为:直接拼接
1549
+ message_default = UserMessage(
1550
+ Texts("First line."),
1551
+ Texts("Second line.")
1552
+ )
1553
+ rendered_default = await message_default.render_latest()
1554
+ self.assertEqual(rendered_default['content'], "First line.Second line.")
1555
+
1556
+ # 2. 测试新功能:使用 \n\n 拼接
1557
+ # 假设新参数为 `newline=True`
1558
+ message_newline = UserMessage(
1559
+ Texts("First paragraph."),
1560
+ Texts("Second paragraph.", newline=True)
1561
+ )
1562
+ rendered_newline = await message_newline.render_latest()
1563
+ self.assertEqual(rendered_newline['content'], "First paragraph.\n\nSecond paragraph.")
1564
+
1565
+ # 3. 测试多个 provider 的情况
1566
+ message_multiple = UserMessage(
1567
+ Texts("First."),
1568
+ Texts("Second.", newline=True),
1569
+ Texts("Third.", newline=True)
1570
+ )
1571
+ rendered_multiple = await message_multiple.render_latest()
1572
+ self.assertEqual(rendered_multiple['content'], "First.\n\nSecond.\n\nThird.")
1573
+
1574
+ # 4. 测试只有一个 provider 的情况
1575
+ message_single = UserMessage(
1576
+ Texts("Only one.", newline=True)
1577
+ )
1578
+ rendered_single = await message_single.render_latest()
1579
+ self.assertEqual(rendered_single['content'], "Only one.")
1580
+
1581
+ async def test_zad_simple_render_without_refresh(self):
1582
+ """测试 Messages(UserMessage('hi')).render() 是否能直接同步渲染"""
1583
+ # This test checks if a simple message can be rendered synchronously
1584
+ # without an explicit `await refresh()` or `await render_latest()`.
1585
+ # Calling the synchronous render method directly on a new instance
1586
+ rendered = Messages(UserMessage("hi", Images(url="data:image/png;base64,FAKE"))).render()
1587
+
1588
+ # The current implementation will likely fail here, returning []
1589
+ self.assertEqual(len(rendered), 1)
1590
+ self.assertEqual(rendered[0]['role'], 'user')
1591
+
1592
+ # Now we expect a list for multimodal content
1593
+ content = rendered[0]['content']
1594
+ self.assertIsInstance(content, list)
1595
+ self.assertEqual(len(content), 2)
1596
+ self.assertEqual(content[0]['type'], 'text')
1597
+ self.assertEqual(content[0]['text'], 'hi')
1598
+ self.assertEqual(content[1]['type'], 'image_url')
1599
+ self.assertEqual(content[1]['image_url']['url'], "data:image/png;base64,FAKE")
1600
+
1437
1601
 
1438
1602
  # ==============================================================================
1439
1603
  # 6. 演示
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  import json
3
+ import copy
3
4
  import httpx
4
5
  import base64
5
6
  import asyncio
@@ -57,7 +58,7 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
57
58
  try:
58
59
  request_messages = [Message(role="user", content=request.prompt)]
59
60
  except:
60
- request_messages = request.messages
61
+ request_messages = copy.deepcopy(request.messages)
61
62
  for msg in request_messages:
62
63
  if msg.role == "assistant":
63
64
  msg.role = "model"
@@ -399,7 +400,8 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
399
400
  systemInstruction = None
400
401
  system_prompt = ""
401
402
  function_arguments = None
402
- for msg in request.messages:
403
+ request_messages = copy.deepcopy(request.messages)
404
+ for msg in request_messages:
403
405
  if msg.role == "assistant":
404
406
  msg.role = "model"
405
407
  tool_calls = None
@@ -8,7 +8,7 @@ from datetime import datetime
8
8
 
9
9
  from .log_config import logger
10
10
 
11
- from .utils import safe_get, generate_sse_response, generate_no_stream_response, end_of_line, parse_json_safely
11
+ from .utils import safe_get, generate_sse_response, generate_no_stream_response, end_of_line, parse_json_safely, upload_image_to_0x0st
12
12
 
13
13
  async def check_response(response, error_log):
14
14
  if response and not (200 <= response.status_code < 300):
@@ -277,7 +277,8 @@ async def fetch_gpt_response_stream(client, url, headers, payload, timeout):
277
277
  openrouter_reasoning = safe_get(line, "choices", 0, "delta", "reasoning", default="")
278
278
  openrouter_base64_image = safe_get(line, "choices", 0, "delta", "images", 0, "image_url", "url", default="")
279
279
  if openrouter_base64_image:
280
- sse_string = await generate_sse_response(timestamp, payload["model"], content=f"\n\n![image]({openrouter_base64_image})")
280
+ image_url = await upload_image_to_0x0st(openrouter_base64_image)
281
+ sse_string = await generate_sse_response(timestamp, payload["model"], content=f"\n\n![image]({image_url})")
281
282
  yield sse_string
282
283
  continue
283
284
  azure_databricks_claude_summary_content = safe_get(line, "choices", 0, "delta", "content", 0, "summary", 0, "text", default="")
@@ -228,7 +228,12 @@ async def update_initial_model(provider):
228
228
  def safe_get(data, *keys, default=None):
229
229
  for key in keys:
230
230
  try:
231
- data = data[key] if isinstance(data, (dict, list)) else data.get(key)
231
+ if isinstance(data, (dict, list)):
232
+ data = data[key]
233
+ elif isinstance(key, str) and hasattr(data, key):
234
+ data = getattr(data, key)
235
+ else:
236
+ data = data.get(key)
232
237
  except (KeyError, IndexError, AttributeError, TypeError):
233
238
  return default
234
239
  if not data:
@@ -797,6 +802,44 @@ def parse_json_safely(json_str):
797
802
  # 两种方法都失败,抛出异常
798
803
  raise Exception(f"无法解析JSON字符串: {e}, {json_str}")
799
804
 
805
+ async def upload_image_to_0x0st(base64_image: str):
806
+ """
807
+ Uploads a base64 encoded image to 0x0.st.
808
+
809
+ Args:
810
+ base64_image: The base64 encoded image string.
811
+
812
+ Returns:
813
+ The URL of the uploaded image.
814
+ """
815
+ if "," in base64_image:
816
+ base64_image_split = base64_image.split(",")[1]
817
+
818
+ image_data = base64.b64decode(base64_image_split)
819
+
820
+ img_format = get_image_format(image_data)
821
+ if not img_format:
822
+ img_format = 'png' # 如果无法检测到格式,则默认为 png
823
+
824
+ content_type = f'image/{img_format}'
825
+ file_name = f'image.{img_format}'
826
+
827
+ files = {'file': (file_name, image_data, content_type)}
828
+ data = {'expires': '24', 'secret': '123456'}
829
+
830
+ async with httpx.AsyncClient() as client:
831
+ try:
832
+ response = await client.post("https://0x0.st", files=files, data=data)
833
+ response.raise_for_status()
834
+ return response.text.strip()
835
+ except httpx.RequestError as e:
836
+ logger.error(f"请求 0x0.st 时出错: {e}")
837
+ # raise HTTPException(status_code=500, detail="上传图片到 0x0.st 失败")
838
+ except httpx.HTTPStatusError as e:
839
+ logger.error(f"上传图片到 0x0.st 时发生 HTTP 错误: {e.response.status_code}")
840
+ # raise HTTPException(status_code=e.response.status_code, detail=f"上传图片到 0x0.st 失败: {e.response.text}")
841
+ return base64_image
842
+
800
843
  if __name__ == "__main__":
801
844
  provider = {
802
845
  "base_url": "https://gateway.ai.cloudflare.com/v1/%7Baccount_id%7D/%7Bgateway_id%7D/google-vertex-ai",
@@ -4,13 +4,13 @@ import json
4
4
  from .base import BaseLLM
5
5
 
6
6
  API = os.environ.get('API', None)
7
- API_URL = os.environ.get('API_URL', None)
7
+ BASE_URL = os.environ.get('BASE_URL', None)
8
8
 
9
9
  class whisper(BaseLLM):
10
10
  def __init__(
11
11
  self,
12
12
  api_key: str,
13
- api_url: str = (os.environ.get("API_URL") or "https://api.openai.com/v1/audio/transcriptions"),
13
+ api_url: str = (os.environ.get("BASE_URL") or "https://api.openai.com/v1/audio/transcriptions"),
14
14
  timeout: float = 20,
15
15
  ):
16
16
  super().__init__(api_key, api_url=api_url, timeout=timeout)
@@ -11,8 +11,8 @@ class BaseLLM:
11
11
  def __init__(
12
12
  self,
13
13
  api_key: str = None,
14
- engine: str = os.environ.get("GPT_ENGINE") or "gpt-3.5-turbo",
15
- api_url: str = (os.environ.get("API_URL", None) or "https://api.openai.com/v1/chat/completions"),
14
+ engine: str = os.environ.get("MODEL") or "gpt-3.5-turbo",
15
+ api_url: str = (os.environ.get("BASE_URL", None) or "https://api.openai.com/v1/chat/completions"),
16
16
  system_prompt: str = prompt.chatgpt_system_prompt,
17
17
  proxy: str = None,
18
18
  timeout: float = 600,
@@ -6,6 +6,7 @@ import httpx
6
6
  import asyncio
7
7
  import logging
8
8
  import inspect
9
+ from collections import defaultdict
9
10
  from typing import Union, Optional, Callable
10
11
 
11
12
  from .base import BaseLLM
@@ -16,6 +17,21 @@ from ..core.request import prepare_request_payload
16
17
  from ..core.response import fetch_response_stream, fetch_response
17
18
  from ..architext.architext import Messages, SystemMessage, UserMessage, AssistantMessage, ToolCalls, ToolResults, Texts, RoleMessage, Images, Files
18
19
 
20
+ class ToolResult(Texts):
21
+ def __init__(self, tool_name: str, tool_args: str, tool_response: str, name: Optional[str] = None, visible: bool = True, newline: bool = True):
22
+ super().__init__(text=tool_response, name=name or f"tool_result_{tool_name}", visible=visible, newline=newline)
23
+ self.tool_name = tool_name
24
+ self.tool_args = tool_args
25
+
26
+ async def render(self) -> Optional[str]:
27
+ tool_response = await super().render()
28
+ if tool_response is None:
29
+ tool_response = ""
30
+ if self.tool_args:
31
+ return f"[{self.tool_name}({self.tool_args}) Result]:\n\n{tool_response}"
32
+ else:
33
+ return f"[{self.tool_name} Result]:\n\n{tool_response}"
34
+
19
35
  class APITimeoutError(Exception):
20
36
  """Custom exception for API timeout errors."""
21
37
  pass
@@ -73,8 +89,8 @@ class chatgpt(BaseLLM):
73
89
  def __init__(
74
90
  self,
75
91
  api_key: str = None,
76
- engine: str = os.environ.get("GPT_ENGINE") or "gpt-4o",
77
- api_url: str = (os.environ.get("API_URL") or "https://api.openai.com/v1/chat/completions"),
92
+ engine: str = os.environ.get("MODEL") or "gpt-4o",
93
+ api_url: str = (os.environ.get("BASE_URL") or "https://api.openai.com/v1/chat/completions"),
78
94
  system_prompt: str = "You are ChatGPT, a large language model trained by OpenAI. Respond conversationally",
79
95
  proxy: str = None,
80
96
  timeout: float = 600,
@@ -97,9 +113,7 @@ class chatgpt(BaseLLM):
97
113
  Initialize Chatbot with API key (from https://platform.openai.com/account/api-keys)
98
114
  """
99
115
  super().__init__(api_key, engine, api_url, system_prompt, proxy, timeout, max_tokens, temperature, top_p, presence_penalty, frequency_penalty, reply_count, truncate_limit, use_plugins=use_plugins, print_log=print_log)
100
- self.conversation: dict[str, Messages] = {
101
- "default": Messages(SystemMessage(self.system_prompt)),
102
- }
116
+ self.conversation: dict[str, Messages] = defaultdict(lambda: Messages(SystemMessage(self.system_prompt)))
103
117
  if cache_messages:
104
118
  self.conversation["default"] = cache_messages
105
119
  self.function_calls_counter = {}
@@ -111,8 +125,12 @@ class chatgpt(BaseLLM):
111
125
  else:
112
126
  # 如果没有提供 logger,创建一个默认的,它只会打印到控制台
113
127
  self.logger = logging.getLogger("chatgpt_default")
128
+ self.logger.propagate = False
114
129
  if not self.logger.handlers: # 防止重复添加 handler
115
- self.logger.addHandler(logging.StreamHandler())
130
+ handler = logging.StreamHandler()
131
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
132
+ handler.setFormatter(formatter)
133
+ self.logger.addHandler(handler)
116
134
  self.logger.setLevel(logging.INFO if print_log else logging.WARNING)
117
135
 
118
136
  # 注册和处理传入的工具
@@ -173,8 +191,8 @@ class chatgpt(BaseLLM):
173
191
  self.conversation[convo_id].append(ToolCalls(tool_calls))
174
192
  self.conversation[convo_id].append(ToolResults(tool_call_id=function_call_id, content=message))
175
193
  else:
176
- last_user_message = self.conversation[convo_id][-1]["content"]
177
- if last_user_message != message:
194
+ last_user_message = self.conversation[convo_id][-1]
195
+ if last_user_message != UserMessage(message):
178
196
  image_message_list = UserMessage()
179
197
  if isinstance(function_arguments, str):
180
198
  functions_list = json.loads(function_arguments)
@@ -268,7 +286,7 @@ class chatgpt(BaseLLM):
268
286
  "messages": await self.conversation[convo_id].render_latest() if pass_history else Messages(
269
287
  SystemMessage(self.system_prompt, self.conversation[convo_id].provider("files")),
270
288
  UserMessage(prompt)
271
- ),
289
+ ).render(),
272
290
  "stream": stream,
273
291
  "temperature": kwargs.get("temperature", self.temperature)
274
292
  }
@@ -565,7 +583,7 @@ class chatgpt(BaseLLM):
565
583
  tool_calls = function_parameter
566
584
 
567
585
  # 处理所有工具调用
568
- all_responses = []
586
+ all_responses = UserMessage()
569
587
 
570
588
  for tool_info in tool_calls:
571
589
  tool_name = tool_info['function_name']
@@ -585,27 +603,28 @@ class chatgpt(BaseLLM):
585
603
  tool_response = chunk.replace("function_response:", "")
586
604
  else:
587
605
  yield chunk
588
- if tool_name == "read_file" and "<tool_error>" not in tool_response:
589
- self.conversation[convo_id].provider("files").update(tool_info['parameter']["file_path"], tool_response)
590
- all_responses.append(f"[{tool_name}({tool_args}) Result]:\n\nRead file successfully! The file content has been updated in the tag <latest_file_content>.")
591
- elif tool_name == "get_knowledge_graph_tree" and "<tool_error>" not in tool_response:
592
- self.conversation[convo_id].provider("knowledge_graph").visible = True
593
- all_responses.append(f"[{tool_name}({tool_args}) Result]:\n\nGet knowledge graph tree successfully! The knowledge graph tree has been updated in the tag <knowledge_graph_tree>.")
594
- elif tool_name == "write_to_file" and "<tool_error>" not in tool_response:
595
- all_responses.append(f"[{tool_name} Result]:\n\n{tool_response}")
596
- elif tool_name == "read_image" and "<tool_error>" not in tool_response:
597
- tool_info["base64_image"] = tool_response
598
- all_responses.append(f"[{tool_name}({tool_args}) Result]:\n\nRead image successfully!")
599
- elif tool_response.startswith("data:image/") and ";base64," in tool_response and "<tool_error>" not in tool_response:
600
- tool_info["base64_image"] = tool_response
601
- all_responses.append(f"[{tool_name}({tool_args}) Result]:\n\nRead image successfully!")
602
- else:
603
- all_responses.append(f"[{tool_name}({tool_args}) Result]:\n\n{tool_response}")
606
+ final_tool_response = tool_response
607
+ if "<tool_error>" not in tool_response:
608
+ if tool_name == "read_file":
609
+ self.conversation[convo_id].provider("files").update(tool_info['parameter']["file_path"], tool_response)
610
+ final_tool_response = "Read file successfully! The file content has been updated in the tag <latest_file_content>."
611
+ elif tool_name == "get_knowledge_graph_tree":
612
+ self.conversation[convo_id].provider("knowledge_graph").visible = True
613
+ final_tool_response = "Get knowledge graph tree successfully! The knowledge graph tree has been updated in the tag <knowledge_graph_tree>."
614
+ elif tool_name == "write_to_file":
615
+ tool_args = None
616
+ elif tool_name == "read_image":
617
+ tool_info["base64_image"] = tool_response
618
+ final_tool_response = "Read image successfully!"
619
+ elif tool_response.startswith("data:image/") and ";base64," in tool_response:
620
+ tool_info["base64_image"] = tool_response
621
+ final_tool_response = "Read image successfully!"
622
+ all_responses.append(ToolResult(tool_name, tool_args, final_tool_response))
604
623
 
605
624
  # 合并所有工具响应
606
- function_response = "\n\n".join(all_responses).strip()
625
+ function_response = all_responses
607
626
  if missing_required_params:
608
- function_response += "\n\n" + "\n\n".join(missing_required_params)
627
+ function_response.append(Texts("\n\n".join(missing_required_params)))
609
628
 
610
629
  # 使用第一个工具的名称和参数作为历史记录
611
630
  function_call_name = tool_calls[0]['function_name']
@@ -673,7 +692,7 @@ class chatgpt(BaseLLM):
673
692
  # 准备会话
674
693
  self.system_prompt = system_prompt or self.system_prompt
675
694
  if convo_id not in self.conversation or pass_history <= 2:
676
- self.reset(convo_id=convo_id, system_prompt=system_prompt)
695
+ self.reset(convo_id=convo_id, system_prompt=self.system_prompt)
677
696
  self.add_to_conversation(prompt, role, convo_id=convo_id, function_name=function_name, total_tokens=total_tokens, function_arguments=function_arguments, pass_history=pass_history, function_call_id=function_call_id)
678
697
 
679
698
  # 获取请求体
@@ -930,7 +949,7 @@ class chatgpt(BaseLLM):
930
949
  """
931
950
  self.system_prompt = system_prompt or self.system_prompt
932
951
  self.conversation[convo_id] = Messages(
933
- SystemMessage(Texts("system_prompt", self.system_prompt), self.conversation[convo_id].provider("files")),
952
+ SystemMessage(self.system_prompt, self.conversation[convo_id].provider("files")),
934
953
  )
935
954
  self.tokens_usage[convo_id] = 0
936
955
  self.current_tokens[convo_id] = 0
@@ -5,13 +5,13 @@ from ..models.base import BaseLLM
5
5
  from .registry import register_tool
6
6
 
7
7
  API = os.environ.get('API', None)
8
- API_URL = os.environ.get('API_URL', None)
8
+ BASE_URL = os.environ.get('BASE_URL', None)
9
9
 
10
10
  class dalle3(BaseLLM):
11
11
  def __init__(
12
12
  self,
13
13
  api_key: str,
14
- api_url: str = (os.environ.get("API_URL") or "https://api.openai.com/v1/images/generations"),
14
+ api_url: str = (os.environ.get("BASE_URL") or "https://api.openai.com/v1/images/generations"),
15
15
  timeout: float = 20,
16
16
  ):
17
17
  super().__init__(api_key, api_url=api_url, timeout=timeout)
@@ -90,10 +90,6 @@ chatgpt_system_prompt = (
90
90
  "You are ChatGPT, a large language model trained by OpenAI. Use simple characters to represent mathematical symbols. Do not use LaTeX commands. Respond conversationally"
91
91
  )
92
92
 
93
- claude_system_prompt = (
94
- "You are Claude, a large language model trained by Anthropic. Use simple characters to represent mathematical symbols. Do not use LaTeX commands. Respond conversationally in {}."
95
- )
96
-
97
93
  search_system_prompt = (
98
94
  "You are ChatGPT, a large language model trained by OpenAI. Respond conversationally in {}."
99
95
  "You can break down the task into multiple steps and search the web to answer my questions one by one."
@@ -134,14 +134,6 @@ def is_surrounded_by_chinese(text, index):
134
134
  def replace_char(string, index, new_char):
135
135
  return string[:index] + new_char + string[index+1:]
136
136
 
137
- def claude_replace(text):
138
- Punctuation_mapping = {",": ",", ":": ":", "!": "!", "?": "?", ";": ";"}
139
- key_list = list(Punctuation_mapping.keys())
140
- for i in range(len(text)):
141
- if is_surrounded_by_chinese(text, i) and (text[i] in key_list):
142
- text = replace_char(text, i, Punctuation_mapping[text[i]])
143
- return text
144
-
145
137
  def safe_get(data, *keys, default=None):
146
138
  for key in keys:
147
139
  try:
@@ -10,5 +10,5 @@ files = {
10
10
  'model': (None, 'whisper-1')
11
11
  }
12
12
 
13
- response = requests.post(os.environ.get('API_URL', None), headers=headers, files=files)
13
+ response = requests.post(os.environ.get('BASE_URL', None), headers=headers, files=files)
14
14
  print(response.text)