auto-coder 0.1.205__py3-none-any.whl → 0.1.207__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.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/METADATA +1 -1
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/RECORD +16 -10
- autocoder/agent/auto_filegroup.py +202 -0
- autocoder/auto_coder_rag.py +168 -33
- autocoder/benchmark.py +138 -0
- autocoder/chat_auto_coder.py +9 -3
- autocoder/common/chunk_validation.py +91 -0
- autocoder/common/recall_validation.py +58 -0
- autocoder/data/tokenizer.json +199865 -0
- autocoder/rag/token_counter.py +3 -3
- autocoder/utils/operate_config_api.py +148 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.205.dist-info → auto_coder-0.1.207.dist-info}/top_level.txt +0 -0
autocoder/benchmark.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from openai import AsyncOpenAI
|
|
2
|
+
import asyncio
|
|
3
|
+
import time
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.table import Table
|
|
6
|
+
import numpy as np
|
|
7
|
+
import ray
|
|
8
|
+
from loguru import logger
|
|
9
|
+
import byzerllm
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def benchmark_openai(
|
|
14
|
+
model: str, parallel: int, api_key: str, base_url: str = None, rounds: int = 1, query: str = "Hello, how are you?"
|
|
15
|
+
):
|
|
16
|
+
client = AsyncOpenAI(api_key=api_key, base_url=base_url if base_url else None)
|
|
17
|
+
start_time = time.time()
|
|
18
|
+
|
|
19
|
+
async def single_request():
|
|
20
|
+
try:
|
|
21
|
+
t1 = time.time()
|
|
22
|
+
response = await client.chat.completions.create(
|
|
23
|
+
model=model,
|
|
24
|
+
messages=[{"role": "user", "content": query}],
|
|
25
|
+
)
|
|
26
|
+
t2 = time.time()
|
|
27
|
+
return t2 - t1
|
|
28
|
+
except Exception as e:
|
|
29
|
+
logger.error(f"Request failed: {e}")
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
all_results = []
|
|
33
|
+
for round_num in range(rounds):
|
|
34
|
+
print(f"Running round {round_num + 1}/{rounds}")
|
|
35
|
+
tasks = [single_request() for _ in range(parallel)]
|
|
36
|
+
results = await asyncio.gather(*tasks)
|
|
37
|
+
all_results.extend(results)
|
|
38
|
+
|
|
39
|
+
results = all_results
|
|
40
|
+
|
|
41
|
+
# Filter out None values from failed requests
|
|
42
|
+
results = [r for r in results if r is not None]
|
|
43
|
+
|
|
44
|
+
end_time = time.time()
|
|
45
|
+
total_time = end_time - start_time
|
|
46
|
+
|
|
47
|
+
if not results:
|
|
48
|
+
print("All requests failed")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
# Calculate statistics
|
|
52
|
+
avg_time = np.mean(results)
|
|
53
|
+
p50 = np.percentile(results, 50)
|
|
54
|
+
p90 = np.percentile(results, 90)
|
|
55
|
+
p95 = np.percentile(results, 95)
|
|
56
|
+
p99 = np.percentile(results, 99)
|
|
57
|
+
|
|
58
|
+
# Create rich table for output
|
|
59
|
+
console = Console()
|
|
60
|
+
table = Table(title=f"OpenAI Client Benchmark Results (Parallel={parallel})")
|
|
61
|
+
|
|
62
|
+
table.add_column("Metric", style="cyan")
|
|
63
|
+
table.add_column("Value (seconds)", style="magenta")
|
|
64
|
+
|
|
65
|
+
table.add_row("Total Time", f"{total_time:.2f}")
|
|
66
|
+
table.add_row("Average Response Time", f"{avg_time:.2f}")
|
|
67
|
+
table.add_row("Median (P50)", f"{p50:.2f}")
|
|
68
|
+
table.add_row("P90", f"{p90:.2f}")
|
|
69
|
+
table.add_row("P95", f"{p95:.2f}")
|
|
70
|
+
table.add_row("P99", f"{p99:.2f}")
|
|
71
|
+
table.add_row("Requests/Second", f"{parallel/total_time:.2f}")
|
|
72
|
+
|
|
73
|
+
console.print(table)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def benchmark_byzerllm(model: str, parallel: int, rounds: int = 1, query: str = "Hello, how are you?"):
|
|
77
|
+
byzerllm.connect_cluster(address="auto")
|
|
78
|
+
llm = byzerllm.ByzerLLM()
|
|
79
|
+
llm.setup_default_model_name(model)
|
|
80
|
+
|
|
81
|
+
def single_request(llm):
|
|
82
|
+
try:
|
|
83
|
+
t1 = time.time()
|
|
84
|
+
llm.chat_oai(
|
|
85
|
+
conversations=[{"role": "user", "content": query}]
|
|
86
|
+
)
|
|
87
|
+
t2 = time.time()
|
|
88
|
+
return t2 - t1
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Request failed: {e}")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
start_time = time.time()
|
|
94
|
+
all_results = []
|
|
95
|
+
for round_num in range(rounds):
|
|
96
|
+
print(f"Running round {round_num + 1}/{rounds}")
|
|
97
|
+
with ThreadPoolExecutor(max_workers=parallel) as executor:
|
|
98
|
+
# submit tasks to the executor
|
|
99
|
+
futures = [executor.submit(single_request, llm) for _ in range(parallel)]
|
|
100
|
+
# get results from futures
|
|
101
|
+
results = [future.result() for future in futures]
|
|
102
|
+
all_results.extend(results)
|
|
103
|
+
|
|
104
|
+
results = all_results
|
|
105
|
+
|
|
106
|
+
# Filter out None values from failed requests
|
|
107
|
+
results = [r for r in results if r is not None]
|
|
108
|
+
|
|
109
|
+
end_time = time.time()
|
|
110
|
+
total_time = end_time - start_time
|
|
111
|
+
|
|
112
|
+
if not results:
|
|
113
|
+
print("All requests failed")
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
# Calculate statistics
|
|
117
|
+
avg_time = np.mean(results)
|
|
118
|
+
p50 = np.percentile(results, 50)
|
|
119
|
+
p90 = np.percentile(results, 90)
|
|
120
|
+
p95 = np.percentile(results, 95)
|
|
121
|
+
p99 = np.percentile(results, 99)
|
|
122
|
+
|
|
123
|
+
# Create rich table for output
|
|
124
|
+
console = Console()
|
|
125
|
+
table = Table(title=f"ByzerLLM Client Benchmark Results (Parallel={parallel})")
|
|
126
|
+
|
|
127
|
+
table.add_column("Metric", style="cyan")
|
|
128
|
+
table.add_column("Value (seconds)", style="magenta")
|
|
129
|
+
|
|
130
|
+
table.add_row("Total Time", f"{total_time:.2f}")
|
|
131
|
+
table.add_row("Average Response Time", f"{avg_time:.2f}")
|
|
132
|
+
table.add_row("Median (P50)", f"{p50:.2f}")
|
|
133
|
+
table.add_row("P90", f"{p90:.2f}")
|
|
134
|
+
table.add_row("P95", f"{p95:.2f}")
|
|
135
|
+
table.add_row("P99", f"{p99:.2f}")
|
|
136
|
+
table.add_row("Requests/Second", f"{parallel/total_time:.2f}")
|
|
137
|
+
|
|
138
|
+
console.print(table)
|
autocoder/chat_auto_coder.py
CHANGED
|
@@ -58,6 +58,7 @@ from prompt_toolkit.patch_stdout import patch_stdout
|
|
|
58
58
|
import byzerllm
|
|
59
59
|
from byzerllm.utils import format_str_jinja2
|
|
60
60
|
from autocoder.chat_auto_coder_lang import get_message
|
|
61
|
+
from autocoder.utils import operate_config_api
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class SymbolItem(BaseModel):
|
|
@@ -1426,12 +1427,16 @@ def convert_yaml_to_config(yaml_file: str):
|
|
|
1426
1427
|
setattr(args, key, value)
|
|
1427
1428
|
return args
|
|
1428
1429
|
|
|
1429
|
-
def commit():
|
|
1430
|
+
def commit(query: str):
|
|
1430
1431
|
def prepare_commit_yaml():
|
|
1431
1432
|
auto_coder_main(["next", "chat_action"])
|
|
1432
1433
|
|
|
1433
1434
|
prepare_commit_yaml()
|
|
1434
1435
|
|
|
1436
|
+
# no_diff = query.strip().startswith("/no_diff")
|
|
1437
|
+
# if no_diff:
|
|
1438
|
+
# query = query.replace("/no_diff", "", 1).strip()
|
|
1439
|
+
|
|
1435
1440
|
latest_yaml_file = get_last_yaml_file("actions")
|
|
1436
1441
|
|
|
1437
1442
|
conf = memory.get("conf", {})
|
|
@@ -1471,7 +1476,7 @@ def commit():
|
|
|
1471
1476
|
os.remove(temp_yaml)
|
|
1472
1477
|
|
|
1473
1478
|
llm = byzerllm.ByzerLLM.from_default_model(args.code_model or args.model)
|
|
1474
|
-
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
1479
|
+
uncommitted_changes = git_utils.get_uncommitted_changes(".")
|
|
1475
1480
|
commit_message = git_utils.generate_commit_message.with_llm(
|
|
1476
1481
|
llm).run(uncommitted_changes)
|
|
1477
1482
|
memory["conversation"].append({"role": "user", "content": commit_message})
|
|
@@ -2304,7 +2309,8 @@ def main():
|
|
|
2304
2309
|
elif user_input.startswith("/revert"):
|
|
2305
2310
|
revert()
|
|
2306
2311
|
elif user_input.startswith("/commit"):
|
|
2307
|
-
commit()
|
|
2312
|
+
query = user_input[len("/commit"):].strip()
|
|
2313
|
+
commit(query)
|
|
2308
2314
|
elif user_input.startswith("/help"):
|
|
2309
2315
|
show_help()
|
|
2310
2316
|
elif user_input.startswith("/exclude_dirs"):
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
import byzerllm
|
|
3
|
+
from loguru import logger
|
|
4
|
+
import json
|
|
5
|
+
from byzerllm.utils.client.code_utils import extract_code
|
|
6
|
+
|
|
7
|
+
## This function is generated by auto-coder.chat in Korea
|
|
8
|
+
def validate_chunk(llm: byzerllm.ByzerLLM, content: Optional[List[str]] = None, query: Optional[str] = None) -> str:
|
|
9
|
+
"""
|
|
10
|
+
验证文本分块模型的效果
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
llm: ByzerLLM实例
|
|
14
|
+
content: 待验证的内容列表
|
|
15
|
+
query: 相关问题
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
验证结果
|
|
19
|
+
"""
|
|
20
|
+
if content is None:
|
|
21
|
+
content = [
|
|
22
|
+
"""
|
|
23
|
+
class TokenLimiter:
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
count_tokens: Callable[[str], int],
|
|
27
|
+
full_text_limit: int,
|
|
28
|
+
segment_limit: int,
|
|
29
|
+
buff_limit: int,
|
|
30
|
+
llm:ByzerLLM,
|
|
31
|
+
disable_segment_reorder: bool,
|
|
32
|
+
):
|
|
33
|
+
self.count_tokens = count_tokens
|
|
34
|
+
self.full_text_limit = full_text_limit
|
|
35
|
+
self.segment_limit = segment_limit
|
|
36
|
+
self.buff_limit = buff_limit
|
|
37
|
+
self.llm = llm
|
|
38
|
+
|
|
39
|
+
def limit_tokens(self, relevant_docs: List[SourceCode]):
|
|
40
|
+
pass
|
|
41
|
+
"""
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
if query is None:
|
|
45
|
+
query = "What are the main methods in TokenLimiter class?"
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
from autocoder.rag.token_limiter import TokenLimiter
|
|
49
|
+
def count_tokens(text:str):
|
|
50
|
+
return 0
|
|
51
|
+
token_limiter = TokenLimiter(
|
|
52
|
+
llm=llm,
|
|
53
|
+
count_tokens=count_tokens,
|
|
54
|
+
full_text_limit=1000,
|
|
55
|
+
segment_limit=1000,
|
|
56
|
+
buff_limit=1000,
|
|
57
|
+
disable_segment_reorder=False
|
|
58
|
+
)
|
|
59
|
+
conversations = [
|
|
60
|
+
{"role": "user", "content": query}
|
|
61
|
+
]
|
|
62
|
+
result = token_limiter.extract_relevance_range_from_docs_with_conversation.with_llm(llm).run(conversations, content)
|
|
63
|
+
|
|
64
|
+
# 结果验证和解析
|
|
65
|
+
validation_result = []
|
|
66
|
+
for doc_idx, doc in enumerate(content):
|
|
67
|
+
doc_lines = doc.split('\n')
|
|
68
|
+
source_code_with_line_number = ""
|
|
69
|
+
for idx, line in enumerate(doc_lines):
|
|
70
|
+
source_code_with_line_number += f"{idx+1} {line}\n"
|
|
71
|
+
|
|
72
|
+
json_str = extract_code(result)[0][1]
|
|
73
|
+
json_objs = json.loads(json_str)
|
|
74
|
+
|
|
75
|
+
for json_obj in json_objs:
|
|
76
|
+
start_line = json_obj["start_line"] - 1
|
|
77
|
+
end_line = json_obj["end_line"]
|
|
78
|
+
if start_line >= 0 and end_line > start_line and end_line <= len(doc_lines):
|
|
79
|
+
chunk = "\n".join(doc_lines[start_line:end_line])
|
|
80
|
+
validation_result.append(
|
|
81
|
+
f"Document {doc_idx + 1} - Extracted Range (lines {json_obj['start_line']}-{json_obj['end_line']}):\n{chunk}"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if not validation_result:
|
|
85
|
+
return "No valid ranges extracted from the documents."
|
|
86
|
+
|
|
87
|
+
return "\n\n".join(validation_result)
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.error(f"Error validating chunk model: {str(e)}")
|
|
91
|
+
return f"Error: {str(e)}"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
import byzerllm
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from autocoder.rag.doc_filter import _check_relevance_with_conversation
|
|
5
|
+
from autocoder.rag.relevant_utils import parse_relevance
|
|
6
|
+
|
|
7
|
+
def validate_recall(llm: byzerllm.ByzerLLM, content: Optional[List[str]] = None, query: Optional[str] = None) -> bool:
|
|
8
|
+
"""
|
|
9
|
+
验证召回模型的效果
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
llm: ByzerLLM实例
|
|
13
|
+
content: 待验证的内容列表
|
|
14
|
+
query: 查询语句
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
验证成功返回True,失败返回False
|
|
18
|
+
"""
|
|
19
|
+
if content is None:
|
|
20
|
+
content = [
|
|
21
|
+
"""
|
|
22
|
+
# ByzerLLM API Guide
|
|
23
|
+
|
|
24
|
+
ByzerLLM provides a simple API for interacting with language models.
|
|
25
|
+
Here's how to use it:
|
|
26
|
+
|
|
27
|
+
1. Initialize the client
|
|
28
|
+
2. Send requests
|
|
29
|
+
3. Process responses
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
```python
|
|
33
|
+
import byzerllm
|
|
34
|
+
llm = byzerllm.ByzerLLM()
|
|
35
|
+
response = llm.chat(prompt="Hello")
|
|
36
|
+
```
|
|
37
|
+
"""
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
if query is None:
|
|
41
|
+
query = "How do I use the ByzerLLM API?"
|
|
42
|
+
|
|
43
|
+
conversations = [
|
|
44
|
+
{"role": "user", "content": query}
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
relevance_str = _check_relevance_with_conversation.with_llm(llm).run(conversations, content)
|
|
49
|
+
relevance = parse_relevance(relevance_str)
|
|
50
|
+
|
|
51
|
+
if relevance is None:
|
|
52
|
+
logger.error("Failed to parse relevance result")
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
return relevance.is_relevant
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error(f"Error validating recall: {str(e)}")
|
|
58
|
+
return False
|