aient 1.2.39__tar.gz → 1.2.40__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 (54) hide show
  1. {aient-1.2.39 → aient-1.2.40}/PKG-INFO +1 -1
  2. {aient-1.2.39 → aient-1.2.40}/aient/models/chatgpt.py +19 -1
  3. {aient-1.2.39 → aient-1.2.40}/aient/utils/scripts.py +55 -0
  4. {aient-1.2.39 → aient-1.2.40}/aient.egg-info/PKG-INFO +1 -1
  5. {aient-1.2.39 → aient-1.2.40}/pyproject.toml +1 -1
  6. {aient-1.2.39 → aient-1.2.40}/LICENSE +0 -0
  7. {aient-1.2.39 → aient-1.2.40}/README.md +0 -0
  8. {aient-1.2.39 → aient-1.2.40}/aient/__init__.py +0 -0
  9. {aient-1.2.39 → aient-1.2.40}/aient/architext/architext/__init__.py +0 -0
  10. {aient-1.2.39 → aient-1.2.40}/aient/architext/architext/core.py +0 -0
  11. {aient-1.2.39 → aient-1.2.40}/aient/architext/test/openai_client.py +0 -0
  12. {aient-1.2.39 → aient-1.2.40}/aient/architext/test/test.py +0 -0
  13. {aient-1.2.39 → aient-1.2.40}/aient/architext/test/test_save_load.py +0 -0
  14. {aient-1.2.39 → aient-1.2.40}/aient/core/__init__.py +0 -0
  15. {aient-1.2.39 → aient-1.2.40}/aient/core/log_config.py +0 -0
  16. {aient-1.2.39 → aient-1.2.40}/aient/core/models.py +0 -0
  17. {aient-1.2.39 → aient-1.2.40}/aient/core/request.py +0 -0
  18. {aient-1.2.39 → aient-1.2.40}/aient/core/response.py +0 -0
  19. {aient-1.2.39 → aient-1.2.40}/aient/core/test/test_base_api.py +0 -0
  20. {aient-1.2.39 → aient-1.2.40}/aient/core/test/test_geminimask.py +0 -0
  21. {aient-1.2.39 → aient-1.2.40}/aient/core/test/test_image.py +0 -0
  22. {aient-1.2.39 → aient-1.2.40}/aient/core/test/test_payload.py +0 -0
  23. {aient-1.2.39 → aient-1.2.40}/aient/core/utils.py +0 -0
  24. {aient-1.2.39 → aient-1.2.40}/aient/models/__init__.py +0 -0
  25. {aient-1.2.39 → aient-1.2.40}/aient/models/audio.py +0 -0
  26. {aient-1.2.39 → aient-1.2.40}/aient/models/base.py +0 -0
  27. {aient-1.2.39 → aient-1.2.40}/aient/plugins/__init__.py +0 -0
  28. {aient-1.2.39 → aient-1.2.40}/aient/plugins/arXiv.py +0 -0
  29. {aient-1.2.39 → aient-1.2.40}/aient/plugins/config.py +0 -0
  30. {aient-1.2.39 → aient-1.2.40}/aient/plugins/excute_command.py +0 -0
  31. {aient-1.2.39 → aient-1.2.40}/aient/plugins/get_time.py +0 -0
  32. {aient-1.2.39 → aient-1.2.40}/aient/plugins/image.py +0 -0
  33. {aient-1.2.39 → aient-1.2.40}/aient/plugins/list_directory.py +0 -0
  34. {aient-1.2.39 → aient-1.2.40}/aient/plugins/read_file.py +0 -0
  35. {aient-1.2.39 → aient-1.2.40}/aient/plugins/read_image.py +0 -0
  36. {aient-1.2.39 → aient-1.2.40}/aient/plugins/readonly.py +0 -0
  37. {aient-1.2.39 → aient-1.2.40}/aient/plugins/registry.py +0 -0
  38. {aient-1.2.39 → aient-1.2.40}/aient/plugins/run_python.py +0 -0
  39. {aient-1.2.39 → aient-1.2.40}/aient/plugins/websearch.py +0 -0
  40. {aient-1.2.39 → aient-1.2.40}/aient/plugins/write_file.py +0 -0
  41. {aient-1.2.39 → aient-1.2.40}/aient/utils/__init__.py +0 -0
  42. {aient-1.2.39 → aient-1.2.40}/aient/utils/prompt.py +0 -0
  43. {aient-1.2.39 → aient-1.2.40}/aient.egg-info/SOURCES.txt +0 -0
  44. {aient-1.2.39 → aient-1.2.40}/aient.egg-info/dependency_links.txt +0 -0
  45. {aient-1.2.39 → aient-1.2.40}/aient.egg-info/requires.txt +0 -0
  46. {aient-1.2.39 → aient-1.2.40}/aient.egg-info/top_level.txt +0 -0
  47. {aient-1.2.39 → aient-1.2.40}/setup.cfg +0 -0
  48. {aient-1.2.39 → aient-1.2.40}/test/test_Web_crawler.py +0 -0
  49. {aient-1.2.39 → aient-1.2.40}/test/test_ddg_search.py +0 -0
  50. {aient-1.2.39 → aient-1.2.40}/test/test_google_search.py +0 -0
  51. {aient-1.2.39 → aient-1.2.40}/test/test_ollama.py +0 -0
  52. {aient-1.2.39 → aient-1.2.40}/test/test_plugin.py +0 -0
  53. {aient-1.2.39 → aient-1.2.40}/test/test_url.py +0 -0
  54. {aient-1.2.39 → aient-1.2.40}/test/test_whisper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.2.39
3
+ Version: 1.2.40
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -12,7 +12,7 @@ from typing import Union, Optional, Callable
12
12
  from .base import BaseLLM
13
13
  from ..plugins.registry import registry
14
14
  from ..plugins import PLUGINS, get_tools_result_async, function_call_list, update_tools_config
15
- from ..utils.scripts import safe_get, async_generator_to_sync, parse_function_xml, parse_continuous_json, convert_functions_to_xml, remove_xml_tags_and_content
15
+ from ..utils.scripts import safe_get, async_generator_to_sync, parse_function_xml, parse_continuous_json, convert_functions_to_xml, remove_xml_tags_and_content, find_most_frequent_phrase
16
16
  from ..core.request import prepare_request_payload
17
17
  from ..core.response import fetch_response_stream, fetch_response
18
18
  from ..architext.architext import Messages, SystemMessage, UserMessage, AssistantMessage, ToolCalls, ToolResults, Texts, RoleMessage, Images, Files
@@ -81,6 +81,14 @@ class TaskComplete(Exception):
81
81
  super().__init__(f"Task completed with message: {message}")
82
82
 
83
83
 
84
+ class RepetitiveResponseError(Exception):
85
+ """Custom exception for detecting repetitive and meaningless generated strings."""
86
+ def __init__(self, message, phrase, count):
87
+ super().__init__(message)
88
+ self.phrase = phrase
89
+ self.count = count
90
+
91
+
84
92
  class chatgpt(BaseLLM):
85
93
  """
86
94
  Official ChatGPT API
@@ -438,6 +446,13 @@ class chatgpt(BaseLLM):
438
446
 
439
447
  if not full_response.strip() and not need_function_call:
440
448
  raise EmptyResponseError("Response is empty")
449
+ most_frequent_phrase, most_frequent_phrase_count = find_most_frequent_phrase(full_response)
450
+ if most_frequent_phrase_count > 100:
451
+ raise RepetitiveResponseError(
452
+ f"Detected repetitive and meaningless content. The phrase '{most_frequent_phrase}' appeared {most_frequent_phrase_count} times.",
453
+ most_frequent_phrase,
454
+ most_frequent_phrase_count
455
+ )
441
456
 
442
457
  if self.print_log:
443
458
  self.logger.info(f"total_tokens: {total_tokens}")
@@ -800,6 +815,9 @@ class chatgpt(BaseLLM):
800
815
  except EmptyResponseError as e:
801
816
  self.logger.warning(f"{e}, retrying...")
802
817
  continue
818
+ except RepetitiveResponseError as e:
819
+ self.logger.warning(f"{e}, retrying...")
820
+ continue
803
821
  except TaskComplete as e:
804
822
  raise
805
823
  except ModelNotFoundError as e:
@@ -3,10 +3,65 @@ import re
3
3
  import json
4
4
  import fnmatch
5
5
  import requests
6
+ import collections
6
7
  import urllib.parse
7
8
 
8
9
  from ..core.utils import get_image_message
9
10
 
11
+ def find_most_frequent_phrase(s, min_len=4, max_phrase_len=20):
12
+ """
13
+ 查找字符串中出现次数最多的短语(单词序列)。
14
+ 此版本经过性能优化,并增加了最大短语长度限制。
15
+
16
+ Args:
17
+ s: 输入字符串。
18
+ min_len: 短语的最小字符长度。
19
+ max_phrase_len: 要搜索的最大短语长度(以单词为单位)。
20
+
21
+ Returns:
22
+ 一个元组 (most_frequent_phrase, count),其中
23
+ most_frequent_phrase 是出现次数最多的短语,
24
+ count 是它的出现次数。
25
+ 如果没有找到符合条件的重复短语,则返回 ("", 0)。
26
+ """
27
+ # start_time = time.time()
28
+ if not s or len(s) < min_len:
29
+ return "", 0
30
+
31
+ words = [word for word in re.split(r'[\s\n]+', s) if word]
32
+ if not words:
33
+ return "", 0
34
+ n = len(words)
35
+
36
+ phrase_counts = collections.defaultdict(int)
37
+
38
+ # 确定要检查的实际最大长度
39
+ effective_max_len = min(n // 2, max_phrase_len)
40
+
41
+ # 优化的核心:直接在单词列表上生成并统计所有可能的短语(n-grams)
42
+ for length in range(1, effective_max_len + 1):
43
+ for i in range(n - length + 1):
44
+ phrase_tuple = tuple(words[i:i + length])
45
+ phrase_counts[phrase_tuple] += 1
46
+ # 筛选出重复次数大于1且满足最小长度要求的短语
47
+ best_phrase = ""
48
+ max_count = 0
49
+
50
+ for phrase_tuple, count in phrase_counts.items():
51
+ if count > 1:
52
+ phrase = " ".join(phrase_tuple)
53
+ if len(phrase) >= min_len:
54
+ if count > max_count:
55
+ max_count = count
56
+ best_phrase = phrase
57
+ elif count == max_count and len(phrase) > len(best_phrase):
58
+ best_phrase = phrase
59
+
60
+ if max_count > 0:
61
+ return best_phrase, max_count
62
+ else:
63
+ return "", 0
64
+
10
65
  def get_doc_from_url(url):
11
66
  filename = urllib.parse.unquote(url.split("/")[-1])
12
67
  response = requests.get(url, stream=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.2.39
3
+ Version: 1.2.40
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aient"
3
- version = "1.2.39"
3
+ version = "1.2.40"
4
4
  description = "Aient: The Awakening of Agent."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes