auto-coder 0.1.316__py3-none-any.whl → 0.1.318__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.316.dist-info → auto_coder-0.1.318.dist-info}/METADATA +2 -2
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/RECORD +41 -20
- autocoder/auto_coder_runner.py +1 -2
- autocoder/common/__init__.py +3 -0
- autocoder/common/auto_coder_lang.py +24 -0
- autocoder/common/code_auto_merge_editblock.py +2 -42
- autocoder/common/git_utils.py +2 -2
- autocoder/common/token_cost_caculate.py +103 -42
- autocoder/common/v2/__init__.py +0 -0
- autocoder/common/v2/code_auto_generate.py +199 -0
- autocoder/common/v2/code_auto_generate_diff.py +361 -0
- autocoder/common/v2/code_auto_generate_editblock.py +380 -0
- autocoder/common/v2/code_auto_generate_strict_diff.py +269 -0
- autocoder/common/v2/code_auto_merge.py +211 -0
- autocoder/common/v2/code_auto_merge_diff.py +354 -0
- autocoder/common/v2/code_auto_merge_editblock.py +523 -0
- autocoder/common/v2/code_auto_merge_strict_diff.py +259 -0
- autocoder/common/v2/code_diff_manager.py +266 -0
- autocoder/common/v2/code_editblock_manager.py +282 -0
- autocoder/common/v2/code_manager.py +238 -0
- autocoder/common/v2/code_strict_diff_manager.py +241 -0
- autocoder/dispacher/actions/action.py +16 -0
- autocoder/dispacher/actions/plugins/action_regex_project.py +6 -0
- autocoder/events/event_manager_singleton.py +2 -2
- autocoder/helper/__init__.py +0 -0
- autocoder/helper/project_creator.py +570 -0
- autocoder/linters/linter_factory.py +44 -25
- autocoder/linters/models.py +220 -0
- autocoder/linters/python_linter.py +1 -7
- autocoder/linters/reactjs_linter.py +580 -0
- autocoder/linters/shadow_linter.py +390 -0
- autocoder/linters/vue_linter.py +576 -0
- autocoder/memory/active_context_manager.py +0 -4
- autocoder/memory/active_package.py +12 -12
- autocoder/shadows/__init__.py +0 -0
- autocoder/shadows/shadow_manager.py +235 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.316.dist-info → auto_coder-0.1.318.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
from typing import List, Dict, Tuple
|
|
2
|
+
from autocoder.common.types import Mode, CodeGenerateResult
|
|
3
|
+
from autocoder.common import AutoCoderArgs
|
|
4
|
+
import byzerllm
|
|
5
|
+
from autocoder.common import sys_prompt
|
|
6
|
+
from autocoder.privacy.model_filter import ModelPathFilter
|
|
7
|
+
import json
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
9
|
+
from autocoder.common.utils_code_auto_generate import chat_with_continue,stream_chat_with_continue,ChatWithContinueResult
|
|
10
|
+
from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
11
|
+
from autocoder.common.stream_out_type import CodeGenerateStreamOutType
|
|
12
|
+
from autocoder.common.auto_coder_lang import get_message_with_format
|
|
13
|
+
from autocoder.common.printer import Printer
|
|
14
|
+
from autocoder.rag.token_counter import count_tokens
|
|
15
|
+
from autocoder.utils import llms as llm_utils
|
|
16
|
+
from autocoder.common import SourceCodeList
|
|
17
|
+
from autocoder.memory.active_context_manager import ActiveContextManager
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CodeAutoGenerate:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
llm: byzerllm.ByzerLLM,
|
|
24
|
+
args: AutoCoderArgs,
|
|
25
|
+
action=None,
|
|
26
|
+
) -> None:
|
|
27
|
+
self.llm = llm
|
|
28
|
+
self.args = args
|
|
29
|
+
self.action = action
|
|
30
|
+
self.generate_times_same_model = args.generate_times_same_model
|
|
31
|
+
if not self.llm:
|
|
32
|
+
raise ValueError(
|
|
33
|
+
"Please provide a valid model instance to use for code generation."
|
|
34
|
+
)
|
|
35
|
+
self.llms = self.llm.get_sub_client("code_model") or [self.llm]
|
|
36
|
+
if not isinstance(self.llms, list):
|
|
37
|
+
self.llms = [self.llms]
|
|
38
|
+
|
|
39
|
+
def single_round_run(
|
|
40
|
+
self, query: str, source_code_list: SourceCodeList
|
|
41
|
+
) -> CodeGenerateResult:
|
|
42
|
+
|
|
43
|
+
# Apply model filter for code_llm
|
|
44
|
+
printer = Printer()
|
|
45
|
+
for llm in self.llms:
|
|
46
|
+
model_filter = ModelPathFilter.from_model_object(llm, self.args)
|
|
47
|
+
filtered_sources = []
|
|
48
|
+
for source in source_code_list.sources:
|
|
49
|
+
if model_filter.is_accessible(source.module_name):
|
|
50
|
+
filtered_sources.append(source)
|
|
51
|
+
else:
|
|
52
|
+
printer.print_in_terminal("index_file_filtered",
|
|
53
|
+
style="yellow",
|
|
54
|
+
file_path=source.module_name,
|
|
55
|
+
model_name=",".join(llm_utils.get_llm_names(llm)))
|
|
56
|
+
|
|
57
|
+
source_code_list = SourceCodeList(filtered_sources)
|
|
58
|
+
|
|
59
|
+
llm_config = {"human_as_model": self.args.human_as_model}
|
|
60
|
+
|
|
61
|
+
source_content = source_code_list.to_str()
|
|
62
|
+
|
|
63
|
+
active_context_manager = ActiveContextManager(self.llm, self.args.source_dir)
|
|
64
|
+
|
|
65
|
+
# 获取包上下文信息
|
|
66
|
+
package_context = ""
|
|
67
|
+
|
|
68
|
+
if self.args.enable_active_context:
|
|
69
|
+
# 获取活动上下文信息
|
|
70
|
+
result = active_context_manager.load_active_contexts_for_files(
|
|
71
|
+
[source.module_name for source in source_code_list.sources]
|
|
72
|
+
)
|
|
73
|
+
# 将活动上下文信息格式化为文本
|
|
74
|
+
if result.contexts:
|
|
75
|
+
package_context_parts = []
|
|
76
|
+
for dir_path, context in result.contexts.items():
|
|
77
|
+
package_context_parts.append(f"<package_info>{context.content}</package_info>")
|
|
78
|
+
|
|
79
|
+
package_context = "\n".join(package_context_parts)
|
|
80
|
+
|
|
81
|
+
init_prompt = self.single_round_instruction.prompt(
|
|
82
|
+
instruction=query, content=source_content, context=self.args.context,
|
|
83
|
+
package_context=package_context
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
87
|
+
file.write(init_prompt)
|
|
88
|
+
|
|
89
|
+
conversations = []
|
|
90
|
+
|
|
91
|
+
if self.args.system_prompt and self.args.system_prompt.strip() == "claude":
|
|
92
|
+
conversations.append(
|
|
93
|
+
{"role": "system", "content": sys_prompt.claude_sys_prompt.prompt()})
|
|
94
|
+
elif self.args.system_prompt:
|
|
95
|
+
conversations.append(
|
|
96
|
+
{"role": "system", "content": self.args.system_prompt})
|
|
97
|
+
|
|
98
|
+
conversations.append({"role": "user", "content": init_prompt})
|
|
99
|
+
|
|
100
|
+
conversations_list = []
|
|
101
|
+
results = []
|
|
102
|
+
input_tokens_count = 0
|
|
103
|
+
generated_tokens_count = 0
|
|
104
|
+
|
|
105
|
+
input_tokens_cost = 0
|
|
106
|
+
generated_tokens_cost = 0
|
|
107
|
+
|
|
108
|
+
model_names = []
|
|
109
|
+
|
|
110
|
+
printer = Printer()
|
|
111
|
+
estimated_input_tokens = count_tokens(
|
|
112
|
+
json.dumps(conversations, ensure_ascii=False))
|
|
113
|
+
printer.print_in_terminal("estimated_input_tokens_in_generate",
|
|
114
|
+
style="yellow",
|
|
115
|
+
estimated_input_tokens_in_generate=estimated_input_tokens,
|
|
116
|
+
generate_mode="diff"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if not self.args.human_as_model:
|
|
120
|
+
with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
|
|
121
|
+
futures = []
|
|
122
|
+
for llm in self.llms:
|
|
123
|
+
|
|
124
|
+
model_names_list = llm_utils.get_llm_names(llm)
|
|
125
|
+
model_name = None
|
|
126
|
+
if model_names_list:
|
|
127
|
+
model_name = model_names_list[0]
|
|
128
|
+
|
|
129
|
+
for i in range(self.generate_times_same_model):
|
|
130
|
+
model_names.append(model_name)
|
|
131
|
+
if i==0:
|
|
132
|
+
def job():
|
|
133
|
+
stream_generator = stream_chat_with_continue(
|
|
134
|
+
llm=llm,
|
|
135
|
+
conversations=conversations,
|
|
136
|
+
llm_config=llm_config,
|
|
137
|
+
args=self.args
|
|
138
|
+
)
|
|
139
|
+
full_response, last_meta = stream_out(
|
|
140
|
+
stream_generator,
|
|
141
|
+
model_name=model_name,
|
|
142
|
+
title=get_message_with_format(
|
|
143
|
+
"code_generate_title", model_name=model_name),
|
|
144
|
+
args=self.args,
|
|
145
|
+
extra_meta={
|
|
146
|
+
"stream_out_type": CodeGenerateStreamOutType.CODE_GENERATE.value
|
|
147
|
+
})
|
|
148
|
+
return ChatWithContinueResult(
|
|
149
|
+
content=full_response,
|
|
150
|
+
input_tokens_count=last_meta.input_tokens_count,
|
|
151
|
+
generated_tokens_count=last_meta.generated_tokens_count
|
|
152
|
+
)
|
|
153
|
+
futures.append(executor.submit(job))
|
|
154
|
+
else:
|
|
155
|
+
futures.append(executor.submit(
|
|
156
|
+
chat_with_continue,
|
|
157
|
+
llm=llm,
|
|
158
|
+
conversations=conversations,
|
|
159
|
+
llm_config=llm_config,
|
|
160
|
+
args=self.args
|
|
161
|
+
))
|
|
162
|
+
|
|
163
|
+
temp_results = [future.result() for future in futures]
|
|
164
|
+
|
|
165
|
+
for result,model_name in zip(temp_results,model_names):
|
|
166
|
+
results.append(result.content)
|
|
167
|
+
input_tokens_count += result.input_tokens_count
|
|
168
|
+
generated_tokens_count += result.generated_tokens_count
|
|
169
|
+
model_info = llm_utils.get_model_info(model_name,self.args.product_mode)
|
|
170
|
+
input_cost = model_info.get("input_price", 0) if model_info else 0
|
|
171
|
+
output_cost = model_info.get("output_price", 0) if model_info else 0
|
|
172
|
+
input_tokens_cost += input_cost * result.input_tokens_count / 1000000
|
|
173
|
+
generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
|
|
174
|
+
|
|
175
|
+
for result in results:
|
|
176
|
+
conversations_list.append(
|
|
177
|
+
conversations + [{"role": "assistant", "content": result}])
|
|
178
|
+
else:
|
|
179
|
+
for _ in range(self.args.human_model_num):
|
|
180
|
+
single_result = chat_with_continue(
|
|
181
|
+
llm=self.llms[0],
|
|
182
|
+
conversations=conversations,
|
|
183
|
+
llm_config=llm_config,
|
|
184
|
+
args=self.args
|
|
185
|
+
)
|
|
186
|
+
results.append(single_result.content)
|
|
187
|
+
input_tokens_count += single_result.input_tokens_count
|
|
188
|
+
generated_tokens_count += single_result.generated_tokens_count
|
|
189
|
+
conversations_list.append(
|
|
190
|
+
conversations + [{"role": "assistant", "content": single_result.content}])
|
|
191
|
+
|
|
192
|
+
statistics = {
|
|
193
|
+
"input_tokens_count": input_tokens_count,
|
|
194
|
+
"generated_tokens_count": generated_tokens_count,
|
|
195
|
+
"input_tokens_cost": input_tokens_cost,
|
|
196
|
+
"generated_tokens_cost": generated_tokens_cost
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return CodeGenerateResult(contents=results, conversations=conversations_list, metadata=statistics)
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
from typing import List, Dict, Tuple
|
|
2
|
+
from autocoder.common.types import Mode, CodeGenerateResult
|
|
3
|
+
from autocoder.common import AutoCoderArgs
|
|
4
|
+
import byzerllm
|
|
5
|
+
from autocoder.common import sys_prompt
|
|
6
|
+
from autocoder.privacy.model_filter import ModelPathFilter
|
|
7
|
+
import json
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
9
|
+
from autocoder.common.utils_code_auto_generate import chat_with_continue,stream_chat_with_continue,ChatWithContinueResult
|
|
10
|
+
from autocoder.utils.auto_coder_utils.chat_stream_out import stream_out
|
|
11
|
+
from autocoder.common.stream_out_type import CodeGenerateStreamOutType
|
|
12
|
+
from autocoder.common.auto_coder_lang import get_message_with_format
|
|
13
|
+
from autocoder.common.printer import Printer
|
|
14
|
+
from autocoder.rag.token_counter import count_tokens
|
|
15
|
+
from autocoder.utils import llms as llm_utils
|
|
16
|
+
from autocoder.common import SourceCodeList
|
|
17
|
+
from autocoder.memory.active_context_manager import ActiveContextManager
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CodeAutoGenerateDiff:
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
llm: byzerllm.ByzerLLM,
|
|
24
|
+
args: AutoCoderArgs,
|
|
25
|
+
action=None,
|
|
26
|
+
) -> None:
|
|
27
|
+
self.llm = llm
|
|
28
|
+
self.args = args
|
|
29
|
+
self.action = action
|
|
30
|
+
self.generate_times_same_model = args.generate_times_same_model
|
|
31
|
+
if not self.llm:
|
|
32
|
+
raise ValueError(
|
|
33
|
+
"Please provide a valid model instance to use for code generation."
|
|
34
|
+
)
|
|
35
|
+
self.llms = self.llm.get_sub_client("code_model") or [self.llm]
|
|
36
|
+
if not isinstance(self.llms, list):
|
|
37
|
+
self.llms = [self.llms]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@byzerllm.prompt()
|
|
41
|
+
def single_round_instruction(self, instruction: str,
|
|
42
|
+
content: str,
|
|
43
|
+
context: str = "",
|
|
44
|
+
package_context: str = ""
|
|
45
|
+
) -> str:
|
|
46
|
+
"""
|
|
47
|
+
如果你需要生成代码,对于每个需要更改的文件,你需要按 unified diff 的格式进行生成。
|
|
48
|
+
|
|
49
|
+
# Unified Diff Rules:
|
|
50
|
+
|
|
51
|
+
Every unified diff must use this format:
|
|
52
|
+
1. The file path line starting with "--- " for the old file
|
|
53
|
+
2. The file path line starting with "+++ " for the new file
|
|
54
|
+
3. The hunk header line starting with "@@ " (without line numbers)
|
|
55
|
+
4. Lines starting with " " for context lines
|
|
56
|
+
5. Lines starting with "-" for lines to remove
|
|
57
|
+
6. Lines starting with "+" for lines to add
|
|
58
|
+
|
|
59
|
+
The user's patch tool needs CORRECT patches that apply cleanly against the current contents of the file!
|
|
60
|
+
Think carefully and make sure you include and mark all lines that need to be removed or changed as `-` lines.
|
|
61
|
+
Make sure you mark all new or modified lines with `+`.
|
|
62
|
+
Don't leave out any lines or the diff patch won't apply correctly.
|
|
63
|
+
|
|
64
|
+
Indentation matters in the diffs!
|
|
65
|
+
|
|
66
|
+
Start a new hunk for each section of the file that needs changes.
|
|
67
|
+
|
|
68
|
+
Only output hunks that specify changes with `+` or `-` lines.
|
|
69
|
+
Skip any hunks that are entirely unchanging ` ` lines.
|
|
70
|
+
|
|
71
|
+
Output hunks in whatever order makes the most sense.
|
|
72
|
+
Hunks don't need to be in any particular order.
|
|
73
|
+
|
|
74
|
+
When editing a function, method, loop, etc use a hunk to replace the *entire* code block.
|
|
75
|
+
Delete the entire existing version with `-` lines and then add a new, updated version with `+` lines.
|
|
76
|
+
This will help you generate correct code and correct diffs.
|
|
77
|
+
|
|
78
|
+
To move code within a file, use 2 hunks: 1 to delete it from its current location, 1 to insert it in the new location.
|
|
79
|
+
|
|
80
|
+
To make a new file, show a diff from `--- /dev/null` to `+++ path/to/new/file.ext`.
|
|
81
|
+
|
|
82
|
+
The path start with `---` or `+++` should be the absolute path of the file or relative path from the project root.
|
|
83
|
+
|
|
84
|
+
下面我们来看一个例子:
|
|
85
|
+
|
|
86
|
+
当前项目目录结构:
|
|
87
|
+
1. 项目根目录: /tmp/projects/mathweb
|
|
88
|
+
2. 项目子目录/文件列表(类似tree 命令输出)
|
|
89
|
+
flask/
|
|
90
|
+
app.py
|
|
91
|
+
templates/
|
|
92
|
+
index.html
|
|
93
|
+
static/
|
|
94
|
+
style.css
|
|
95
|
+
|
|
96
|
+
用户需求: Change get_factorial() to use math.factorial
|
|
97
|
+
|
|
98
|
+
回答: To make this change we need to modify `/tmp/projects/mathweb/flask/app.py` to:
|
|
99
|
+
|
|
100
|
+
1. Import the math package.
|
|
101
|
+
2. Remove the existing factorial() function.
|
|
102
|
+
3. Update get_factorial() to call math.factorial instead.
|
|
103
|
+
|
|
104
|
+
Here are the unified diffs:
|
|
105
|
+
|
|
106
|
+
```diff
|
|
107
|
+
--- /tmp/projects/mathweb/flask/app.py
|
|
108
|
+
+++ /tmp/projects/mathweb/flask/app.py
|
|
109
|
+
@@ ... @@
|
|
110
|
+
-from flask import Flask
|
|
111
|
+
+import math
|
|
112
|
+
+from flask import Flask
|
|
113
|
+
@@ ... @@
|
|
114
|
+
-def factorial(n):
|
|
115
|
+
- "compute factorial"
|
|
116
|
+
-
|
|
117
|
+
- if n == 0:
|
|
118
|
+
- return 1
|
|
119
|
+
- else:
|
|
120
|
+
- return n * factorial(n-1)
|
|
121
|
+
-
|
|
122
|
+
@@ ... @@
|
|
123
|
+
- return str(factorial(n))
|
|
124
|
+
+ return str(math.factorial(n))
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
用户需求: Refactor hello() into its own file.
|
|
128
|
+
|
|
129
|
+
回答:To make this change we need to modify `main.py` and make a new file `hello.py`:
|
|
130
|
+
|
|
131
|
+
1. Make a new hello.py file with hello() in it.
|
|
132
|
+
2. Remove hello() from main.py and replace it with an import.
|
|
133
|
+
|
|
134
|
+
Here are the unified diffs:
|
|
135
|
+
|
|
136
|
+
```diff
|
|
137
|
+
--- /dev/null
|
|
138
|
+
+++ /tmp/projects/mathweb/hello.py
|
|
139
|
+
@@ ... @@
|
|
140
|
+
+def hello():
|
|
141
|
+
+ "print a greeting"
|
|
142
|
+
+
|
|
143
|
+
+ print("hello")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```diff
|
|
147
|
+
--- /tmp/projects/mathweb/main.py
|
|
148
|
+
+++ /tmp/projects/mathweb/main.py
|
|
149
|
+
@@ ... @@
|
|
150
|
+
-def hello():
|
|
151
|
+
- "print a greeting"
|
|
152
|
+
-
|
|
153
|
+
- print("hello")
|
|
154
|
+
+from hello import hello
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
现在让我们开始一个新的任务:
|
|
158
|
+
|
|
159
|
+
{%- if structure %}
|
|
160
|
+
{{ structure }}
|
|
161
|
+
{%- endif %}
|
|
162
|
+
|
|
163
|
+
{%- if content %}
|
|
164
|
+
下面是一些文件路径以及每个文件对应的源码:
|
|
165
|
+
<files>
|
|
166
|
+
{{ content }}
|
|
167
|
+
</files>
|
|
168
|
+
{%- endif %}
|
|
169
|
+
|
|
170
|
+
{%- if package_context %}
|
|
171
|
+
下面是上面文件的一些信息(包括最近的变更情况):
|
|
172
|
+
<package_context>
|
|
173
|
+
{{ package_context }}
|
|
174
|
+
</package_context>
|
|
175
|
+
{%- endif %}
|
|
176
|
+
|
|
177
|
+
{%- if context %}
|
|
178
|
+
<extra_context>
|
|
179
|
+
{{ context }}
|
|
180
|
+
</extra_context>
|
|
181
|
+
{%- endif %}
|
|
182
|
+
|
|
183
|
+
下面是用户的需求:
|
|
184
|
+
|
|
185
|
+
{{ instruction }}
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
if not self.args.include_project_structure:
|
|
189
|
+
return {
|
|
190
|
+
"structure": "",
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
"structure": (
|
|
195
|
+
self.action.pp.get_tree_like_directory_structure()
|
|
196
|
+
if self.action
|
|
197
|
+
else ""
|
|
198
|
+
),
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
def single_round_run(
|
|
202
|
+
self, query: str, source_code_list: SourceCodeList
|
|
203
|
+
) -> CodeGenerateResult:
|
|
204
|
+
|
|
205
|
+
# Apply model filter for code_llm
|
|
206
|
+
printer = Printer()
|
|
207
|
+
for llm in self.llms:
|
|
208
|
+
model_filter = ModelPathFilter.from_model_object(llm, self.args)
|
|
209
|
+
filtered_sources = []
|
|
210
|
+
for source in source_code_list.sources:
|
|
211
|
+
if model_filter.is_accessible(source.module_name):
|
|
212
|
+
filtered_sources.append(source)
|
|
213
|
+
else:
|
|
214
|
+
printer.print_in_terminal("index_file_filtered",
|
|
215
|
+
style="yellow",
|
|
216
|
+
file_path=source.module_name,
|
|
217
|
+
model_name=",".join(llm_utils.get_llm_names(llm)))
|
|
218
|
+
|
|
219
|
+
source_code_list = SourceCodeList(filtered_sources)
|
|
220
|
+
|
|
221
|
+
llm_config = {"human_as_model": self.args.human_as_model}
|
|
222
|
+
|
|
223
|
+
source_content = source_code_list.to_str()
|
|
224
|
+
|
|
225
|
+
active_context_manager = ActiveContextManager(self.llm, self.args.source_dir)
|
|
226
|
+
|
|
227
|
+
# 获取包上下文信息
|
|
228
|
+
package_context = ""
|
|
229
|
+
|
|
230
|
+
if self.args.enable_active_context:
|
|
231
|
+
# 获取活动上下文信息
|
|
232
|
+
result = active_context_manager.load_active_contexts_for_files(
|
|
233
|
+
[source.module_name for source in source_code_list.sources]
|
|
234
|
+
)
|
|
235
|
+
# 将活动上下文信息格式化为文本
|
|
236
|
+
if result.contexts:
|
|
237
|
+
package_context_parts = []
|
|
238
|
+
for dir_path, context in result.contexts.items():
|
|
239
|
+
package_context_parts.append(f"<package_info>{context.content}</package_info>")
|
|
240
|
+
|
|
241
|
+
package_context = "\n".join(package_context_parts)
|
|
242
|
+
|
|
243
|
+
init_prompt = self.single_round_instruction.prompt(
|
|
244
|
+
instruction=query, content=source_content, context=self.args.context,
|
|
245
|
+
package_context=package_context
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
with open(self.args.target_file, "w",encoding="utf-8") as file:
|
|
249
|
+
file.write(init_prompt)
|
|
250
|
+
|
|
251
|
+
conversations = []
|
|
252
|
+
|
|
253
|
+
if self.args.system_prompt and self.args.system_prompt.strip() == "claude":
|
|
254
|
+
conversations.append(
|
|
255
|
+
{"role": "system", "content": sys_prompt.claude_sys_prompt.prompt()})
|
|
256
|
+
elif self.args.system_prompt:
|
|
257
|
+
conversations.append(
|
|
258
|
+
{"role": "system", "content": self.args.system_prompt})
|
|
259
|
+
|
|
260
|
+
conversations.append({"role": "user", "content": init_prompt})
|
|
261
|
+
|
|
262
|
+
conversations_list = []
|
|
263
|
+
results = []
|
|
264
|
+
input_tokens_count = 0
|
|
265
|
+
generated_tokens_count = 0
|
|
266
|
+
|
|
267
|
+
input_tokens_cost = 0
|
|
268
|
+
generated_tokens_cost = 0
|
|
269
|
+
|
|
270
|
+
model_names = []
|
|
271
|
+
|
|
272
|
+
printer = Printer()
|
|
273
|
+
estimated_input_tokens = count_tokens(
|
|
274
|
+
json.dumps(conversations, ensure_ascii=False))
|
|
275
|
+
printer.print_in_terminal("estimated_input_tokens_in_generate",
|
|
276
|
+
style="yellow",
|
|
277
|
+
estimated_input_tokens_in_generate=estimated_input_tokens,
|
|
278
|
+
generate_mode="diff"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
if not self.args.human_as_model:
|
|
282
|
+
with ThreadPoolExecutor(max_workers=len(self.llms) * self.generate_times_same_model) as executor:
|
|
283
|
+
futures = []
|
|
284
|
+
for llm in self.llms:
|
|
285
|
+
|
|
286
|
+
model_names_list = llm_utils.get_llm_names(llm)
|
|
287
|
+
model_name = None
|
|
288
|
+
if model_names_list:
|
|
289
|
+
model_name = model_names_list[0]
|
|
290
|
+
|
|
291
|
+
for i in range(self.generate_times_same_model):
|
|
292
|
+
model_names.append(model_name)
|
|
293
|
+
if i==0:
|
|
294
|
+
def job():
|
|
295
|
+
stream_generator = stream_chat_with_continue(
|
|
296
|
+
llm=llm,
|
|
297
|
+
conversations=conversations,
|
|
298
|
+
llm_config=llm_config,
|
|
299
|
+
args=self.args
|
|
300
|
+
)
|
|
301
|
+
full_response, last_meta = stream_out(
|
|
302
|
+
stream_generator,
|
|
303
|
+
model_name=model_name,
|
|
304
|
+
title=get_message_with_format(
|
|
305
|
+
"code_generate_title", model_name=model_name),
|
|
306
|
+
args=self.args,
|
|
307
|
+
extra_meta={
|
|
308
|
+
"stream_out_type": CodeGenerateStreamOutType.CODE_GENERATE.value
|
|
309
|
+
})
|
|
310
|
+
return ChatWithContinueResult(
|
|
311
|
+
content=full_response,
|
|
312
|
+
input_tokens_count=last_meta.input_tokens_count,
|
|
313
|
+
generated_tokens_count=last_meta.generated_tokens_count
|
|
314
|
+
)
|
|
315
|
+
futures.append(executor.submit(job))
|
|
316
|
+
else:
|
|
317
|
+
futures.append(executor.submit(
|
|
318
|
+
chat_with_continue,
|
|
319
|
+
llm=llm,
|
|
320
|
+
conversations=conversations,
|
|
321
|
+
llm_config=llm_config,
|
|
322
|
+
args=self.args
|
|
323
|
+
))
|
|
324
|
+
|
|
325
|
+
temp_results = [future.result() for future in futures]
|
|
326
|
+
|
|
327
|
+
for result,model_name in zip(temp_results,model_names):
|
|
328
|
+
results.append(result.content)
|
|
329
|
+
input_tokens_count += result.input_tokens_count
|
|
330
|
+
generated_tokens_count += result.generated_tokens_count
|
|
331
|
+
model_info = llm_utils.get_model_info(model_name,self.args.product_mode)
|
|
332
|
+
input_cost = model_info.get("input_price", 0) if model_info else 0
|
|
333
|
+
output_cost = model_info.get("output_price", 0) if model_info else 0
|
|
334
|
+
input_tokens_cost += input_cost * result.input_tokens_count / 1000000
|
|
335
|
+
generated_tokens_cost += output_cost * result.generated_tokens_count / 1000000
|
|
336
|
+
|
|
337
|
+
for result in results:
|
|
338
|
+
conversations_list.append(
|
|
339
|
+
conversations + [{"role": "assistant", "content": result}])
|
|
340
|
+
else:
|
|
341
|
+
for _ in range(self.args.human_model_num):
|
|
342
|
+
single_result = chat_with_continue(
|
|
343
|
+
llm=self.llms[0],
|
|
344
|
+
conversations=conversations,
|
|
345
|
+
llm_config=llm_config,
|
|
346
|
+
args=self.args
|
|
347
|
+
)
|
|
348
|
+
results.append(single_result.content)
|
|
349
|
+
input_tokens_count += single_result.input_tokens_count
|
|
350
|
+
generated_tokens_count += single_result.generated_tokens_count
|
|
351
|
+
conversations_list.append(
|
|
352
|
+
conversations + [{"role": "assistant", "content": single_result.content}])
|
|
353
|
+
|
|
354
|
+
statistics = {
|
|
355
|
+
"input_tokens_count": input_tokens_count,
|
|
356
|
+
"generated_tokens_count": generated_tokens_count,
|
|
357
|
+
"input_tokens_cost": input_tokens_cost,
|
|
358
|
+
"generated_tokens_cost": generated_tokens_cost
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return CodeGenerateResult(contents=results, conversations=conversations_list, metadata=statistics)
|