auto-coder 0.1.264__py3-none-any.whl → 0.1.266__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.264.dist-info → auto_coder-0.1.266.dist-info}/METADATA +2 -2
- {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/RECORD +53 -51
- autocoder/agent/planner.py +4 -4
- autocoder/auto_coder.py +26 -21
- autocoder/auto_coder_server.py +7 -7
- autocoder/chat_auto_coder.py +150 -49
- autocoder/commands/auto_command.py +83 -5
- autocoder/commands/tools.py +48 -50
- autocoder/common/__init__.py +0 -1
- autocoder/common/auto_coder_lang.py +43 -3
- autocoder/common/code_auto_generate.py +3 -3
- autocoder/common/code_auto_generate_diff.py +3 -6
- autocoder/common/code_auto_generate_editblock.py +3 -3
- autocoder/common/code_auto_generate_strict_diff.py +3 -3
- autocoder/common/code_auto_merge_diff.py +37 -3
- autocoder/common/code_auto_merge_editblock.py +43 -1
- autocoder/common/code_auto_merge_strict_diff.py +39 -4
- autocoder/common/command_completer.py +3 -0
- autocoder/common/command_generator.py +24 -8
- autocoder/common/command_templates.py +2 -2
- autocoder/common/conf_import_export.py +105 -0
- autocoder/common/conf_validator.py +1 -1
- autocoder/common/files.py +41 -2
- autocoder/common/image_to_page.py +11 -11
- autocoder/common/index_import_export.py +38 -18
- autocoder/common/mcp_hub.py +3 -3
- autocoder/common/mcp_server.py +2 -2
- autocoder/common/shells.py +254 -13
- autocoder/common/stats_panel.py +126 -0
- autocoder/dispacher/actions/action.py +6 -18
- autocoder/dispacher/actions/copilot.py +2 -2
- autocoder/dispacher/actions/plugins/action_regex_project.py +1 -3
- autocoder/dispacher/actions/plugins/action_translate.py +1 -1
- autocoder/index/entry.py +2 -2
- autocoder/index/filter/normal_filter.py +1 -1
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +5 -5
- autocoder/models.py +2 -2
- autocoder/pyproject/__init__.py +5 -5
- autocoder/rag/cache/byzer_storage_cache.py +4 -4
- autocoder/rag/cache/file_monitor_cache.py +2 -2
- autocoder/rag/cache/simple_cache.py +4 -4
- autocoder/rag/long_context_rag.py +2 -2
- autocoder/regexproject/__init__.py +3 -2
- autocoder/suffixproject/__init__.py +3 -2
- autocoder/tsproject/__init__.py +3 -2
- autocoder/utils/conversation_store.py +1 -1
- autocoder/utils/operate_config_api.py +3 -3
- autocoder/version.py +1 -1
- {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/top_level.txt +0 -0
autocoder/common/shells.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
import sys
|
|
3
2
|
import os
|
|
4
3
|
import locale
|
|
5
4
|
import subprocess
|
|
6
5
|
import platform
|
|
6
|
+
import tempfile
|
|
7
|
+
import uuid
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
from rich.panel import Panel
|
|
9
10
|
from rich.text import Text
|
|
@@ -21,18 +22,170 @@ def get_terminal_name() -> str:
|
|
|
21
22
|
else:
|
|
22
23
|
return _get_unix_terminal_name()
|
|
23
24
|
|
|
25
|
+
def is_running_in_powershell() -> bool:
|
|
26
|
+
"""
|
|
27
|
+
检查当前 Python 进程是否在 PowerShell 环境中运行
|
|
28
|
+
Returns:
|
|
29
|
+
bool: True 表示在 PowerShell 环境中,False 表示不在
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
# 方法1: 检查特定的 PowerShell 环境变量
|
|
33
|
+
if any(key for key in os.environ if 'POWERSHELL' in key.upper()):
|
|
34
|
+
return True
|
|
35
|
+
|
|
36
|
+
# 方法2: 尝试执行 PowerShell 特定命令
|
|
37
|
+
try:
|
|
38
|
+
result = subprocess.run(
|
|
39
|
+
['powershell', '-NoProfile', '-Command', '$PSVersionTable'],
|
|
40
|
+
capture_output=True,
|
|
41
|
+
timeout=1
|
|
42
|
+
)
|
|
43
|
+
if result.returncode == 0:
|
|
44
|
+
return True
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
# 方法3: 检查父进程
|
|
49
|
+
try:
|
|
50
|
+
import psutil
|
|
51
|
+
current_process = psutil.Process()
|
|
52
|
+
parent = current_process.parent()
|
|
53
|
+
if parent:
|
|
54
|
+
parent_name = parent.name().lower()
|
|
55
|
+
if 'powershell' in parent_name or 'pwsh' in parent_name:
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
# 递归检查父进程链
|
|
59
|
+
while parent and parent.pid != 1: # 1 是系统初始进程
|
|
60
|
+
if 'powershell' in parent.name().lower() or 'pwsh' in parent.name().lower():
|
|
61
|
+
return True
|
|
62
|
+
parent = parent.parent()
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
# 方法4: 检查命令行参数
|
|
67
|
+
try:
|
|
68
|
+
import sys
|
|
69
|
+
if any('powershell' in arg.lower() for arg in sys.argv):
|
|
70
|
+
return True
|
|
71
|
+
except Exception:
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
return False
|
|
75
|
+
except Exception:
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
def is_running_in_cmd() -> bool:
|
|
79
|
+
"""
|
|
80
|
+
检查当前 Python 进程是否在 CMD 环境中运行
|
|
81
|
+
Returns:
|
|
82
|
+
bool: True 表示在 CMD 环境中,False 表示不在
|
|
83
|
+
"""
|
|
84
|
+
# 如果在 PowerShell 中,直接返回 False
|
|
85
|
+
if is_running_in_powershell():
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
# 方法1: 检查特定的 CMD 环境变量
|
|
90
|
+
env = os.environ
|
|
91
|
+
# CMD 特有的环境变量
|
|
92
|
+
if 'PROMPT' in env and not any(key for key in env if 'POWERSHELL' in key.upper()):
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
# 方法2: 检查 ComSpec 环境变量
|
|
96
|
+
comspec = env.get('ComSpec', '').lower()
|
|
97
|
+
if 'cmd.exe' in comspec:
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
# 方法3: 检查父进程
|
|
101
|
+
try:
|
|
102
|
+
import psutil
|
|
103
|
+
current_process = psutil.Process()
|
|
104
|
+
parent = current_process.parent()
|
|
105
|
+
if parent:
|
|
106
|
+
parent_name = parent.name().lower()
|
|
107
|
+
if 'cmd.exe' in parent_name:
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
# 递归检查父进程链
|
|
111
|
+
while parent and parent.pid != 1: # 1 是系统初始进程
|
|
112
|
+
if 'cmd.exe' in parent.name().lower():
|
|
113
|
+
return True
|
|
114
|
+
parent = parent.parent()
|
|
115
|
+
except Exception:
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
return False
|
|
119
|
+
except Exception:
|
|
120
|
+
return False
|
|
121
|
+
|
|
24
122
|
def _get_windows_terminal_name() -> str:
|
|
25
123
|
"""Windows 系统终端检测"""
|
|
26
|
-
#
|
|
27
|
-
|
|
124
|
+
# 检查环境变量
|
|
125
|
+
env = os.environ
|
|
126
|
+
|
|
127
|
+
# 首先使用新方法检查是否在 PowerShell 环境中
|
|
128
|
+
if is_running_in_powershell():
|
|
129
|
+
# 进一步区分是否在 VSCode 的 PowerShell 终端
|
|
130
|
+
if 'VSCODE_GIT_IPC_HANDLE' in env:
|
|
131
|
+
return 'vscode-powershell'
|
|
28
132
|
return 'powershell'
|
|
29
133
|
|
|
134
|
+
# 检查是否在 CMD 环境中
|
|
135
|
+
if is_running_in_cmd():
|
|
136
|
+
# 区分是否在 VSCode 的 CMD 终端
|
|
137
|
+
if 'VSCODE_GIT_IPC_HANDLE' in env:
|
|
138
|
+
return 'vscode-cmd'
|
|
139
|
+
return 'cmd'
|
|
140
|
+
|
|
30
141
|
# 检查是否在 Git Bash
|
|
31
|
-
if 'MINGW' in platform.system()
|
|
142
|
+
if ('MINGW' in platform.system() or
|
|
143
|
+
'MSYSTEM' in env or
|
|
144
|
+
any('bash.exe' in path.lower() for path in env.get('PATH', '').split(os.pathsep))):
|
|
145
|
+
# 区分是否在 VSCode 的 Git Bash 终端
|
|
146
|
+
if 'VSCODE_GIT_IPC_HANDLE' in env:
|
|
147
|
+
return 'vscode-git-bash'
|
|
32
148
|
return 'git-bash'
|
|
33
149
|
|
|
150
|
+
# 检查是否在 VSCode 的集成终端
|
|
151
|
+
if 'VSCODE_GIT_IPC_HANDLE' in env:
|
|
152
|
+
if 'WT_SESSION' in env: # Windows Terminal
|
|
153
|
+
return 'vscode-windows-terminal'
|
|
154
|
+
return 'vscode-terminal'
|
|
155
|
+
|
|
156
|
+
# 检查是否在 Windows Terminal
|
|
157
|
+
if 'WT_SESSION' in env:
|
|
158
|
+
return 'windows-terminal'
|
|
159
|
+
|
|
160
|
+
# 检查是否在 Cygwin
|
|
161
|
+
if 'CYGWIN' in platform.system():
|
|
162
|
+
return 'cygwin'
|
|
163
|
+
|
|
164
|
+
# 检查 TERM 环境变量
|
|
165
|
+
term = env.get('TERM', '').lower()
|
|
166
|
+
if term:
|
|
167
|
+
if 'xterm' in term:
|
|
168
|
+
return 'xterm'
|
|
169
|
+
elif 'cygwin' in term:
|
|
170
|
+
return 'cygwin'
|
|
171
|
+
|
|
172
|
+
# 检查进程名
|
|
173
|
+
try:
|
|
174
|
+
import psutil
|
|
175
|
+
parent = psutil.Process().parent()
|
|
176
|
+
if parent:
|
|
177
|
+
parent_name = parent.name().lower()
|
|
178
|
+
if 'powershell' in parent_name:
|
|
179
|
+
return 'powershell'
|
|
180
|
+
elif 'windowsterminal' in parent_name:
|
|
181
|
+
return 'windows-terminal'
|
|
182
|
+
elif 'cmd.exe' in parent_name:
|
|
183
|
+
return 'cmd'
|
|
184
|
+
except (ImportError, Exception):
|
|
185
|
+
pass
|
|
186
|
+
|
|
34
187
|
# 默认返回 cmd.exe
|
|
35
|
-
return 'cmd
|
|
188
|
+
return 'cmd'
|
|
36
189
|
|
|
37
190
|
def _get_unix_terminal_name() -> str:
|
|
38
191
|
"""Linux/Mac 系统终端检测"""
|
|
@@ -138,28 +291,109 @@ def execute_shell_command(command: str):
|
|
|
138
291
|
|
|
139
292
|
Args:
|
|
140
293
|
command (str): The shell command to execute
|
|
141
|
-
encoding (str, optional): Override default encoding. Defaults to None.
|
|
142
294
|
"""
|
|
143
295
|
console = Console()
|
|
144
296
|
result_manager = ResultManager()
|
|
297
|
+
temp_file = None
|
|
145
298
|
try:
|
|
146
|
-
# Get terminal encoding
|
|
299
|
+
# Get terminal encoding and name
|
|
147
300
|
encoding = get_terminal_encoding()
|
|
301
|
+
terminal_name = get_terminal_name()
|
|
302
|
+
|
|
303
|
+
# Windows系统特殊处理
|
|
304
|
+
if sys.platform == 'win32':
|
|
305
|
+
# 设置控制台代码页为 UTF-8
|
|
306
|
+
os.system('chcp 65001 > nul')
|
|
307
|
+
# 强制使用 UTF-8 编码
|
|
308
|
+
encoding = 'utf-8'
|
|
309
|
+
# 设置环境变量
|
|
310
|
+
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
|
311
|
+
|
|
312
|
+
# Create temp script file
|
|
313
|
+
if sys.platform == 'win32':
|
|
314
|
+
if is_running_in_powershell():
|
|
315
|
+
# Create temp PowerShell script with UTF-8 BOM
|
|
316
|
+
temp_file = tempfile.NamedTemporaryFile(
|
|
317
|
+
mode='wb',
|
|
318
|
+
suffix='.ps1',
|
|
319
|
+
delete=False
|
|
320
|
+
)
|
|
321
|
+
# 添加 UTF-8 BOM
|
|
322
|
+
temp_file.write(b'\xef\xbb\xbf')
|
|
323
|
+
# 设置输出编码
|
|
324
|
+
ps_command = f'$OutputEncoding = [Console]::OutputEncoding = [Text.Encoding]::UTF8\n{command}'
|
|
325
|
+
temp_file.write(ps_command.encode('utf-8'))
|
|
326
|
+
temp_file.close()
|
|
327
|
+
# Execute the temp script with PowerShell
|
|
328
|
+
command = f'powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "{temp_file.name}"'
|
|
329
|
+
elif is_running_in_cmd():
|
|
330
|
+
# Create temp batch script with UTF-8
|
|
331
|
+
temp_file = tempfile.NamedTemporaryFile(
|
|
332
|
+
mode='wb',
|
|
333
|
+
suffix='.cmd',
|
|
334
|
+
delete=False
|
|
335
|
+
)
|
|
336
|
+
# 添加 UTF-8 BOM
|
|
337
|
+
temp_file.write(b'\xef\xbb\xbf')
|
|
338
|
+
# 写入命令内容,确保UTF-8输出
|
|
339
|
+
content = f"""@echo off
|
|
340
|
+
chcp 65001 > nul
|
|
341
|
+
set PYTHONIOENCODING=utf-8
|
|
342
|
+
{command}
|
|
343
|
+
"""
|
|
344
|
+
temp_file.write(content.encode('utf-8'))
|
|
345
|
+
temp_file.close()
|
|
346
|
+
# Execute the temp batch script
|
|
347
|
+
command = f'cmd.exe /c "{temp_file.name}"'
|
|
348
|
+
else:
|
|
349
|
+
# Create temp shell script for Unix-like systems
|
|
350
|
+
temp_file = tempfile.NamedTemporaryFile(
|
|
351
|
+
mode='w',
|
|
352
|
+
suffix='.sh',
|
|
353
|
+
encoding='utf-8',
|
|
354
|
+
delete=False
|
|
355
|
+
)
|
|
356
|
+
temp_file.write('#!/bin/bash\n' + command)
|
|
357
|
+
temp_file.close()
|
|
358
|
+
# Make the script executable
|
|
359
|
+
os.chmod(temp_file.name, 0o755)
|
|
360
|
+
command = temp_file.name
|
|
148
361
|
|
|
149
|
-
# Start subprocess
|
|
362
|
+
# Start subprocess with UTF-8 encoding
|
|
363
|
+
startupinfo = None
|
|
364
|
+
if sys.platform == 'win32':
|
|
365
|
+
startupinfo = subprocess.STARTUPINFO()
|
|
366
|
+
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
367
|
+
|
|
368
|
+
# 创建子进程时设置环境变量
|
|
369
|
+
env = os.environ.copy()
|
|
370
|
+
env['PYTHONIOENCODING'] = 'utf-8'
|
|
371
|
+
|
|
150
372
|
process = subprocess.Popen(
|
|
151
373
|
command,
|
|
152
374
|
stdout=subprocess.PIPE,
|
|
153
375
|
stderr=subprocess.PIPE,
|
|
154
|
-
shell=True
|
|
376
|
+
shell=True,
|
|
377
|
+
encoding='utf-8', # 直接指定 UTF-8 编码
|
|
378
|
+
errors='replace', # 处理无法解码的字符
|
|
379
|
+
env=env, # 传递修改后的环境变量
|
|
380
|
+
startupinfo=startupinfo
|
|
155
381
|
)
|
|
156
382
|
|
|
157
|
-
# Safe decoding helper
|
|
383
|
+
# Safe decoding helper (for binary output)
|
|
158
384
|
def safe_decode(byte_stream, encoding):
|
|
385
|
+
if isinstance(byte_stream, str):
|
|
386
|
+
return byte_stream.strip()
|
|
159
387
|
try:
|
|
160
|
-
|
|
388
|
+
# 首先尝试 UTF-8
|
|
389
|
+
return byte_stream.decode('utf-8').strip()
|
|
161
390
|
except UnicodeDecodeError:
|
|
162
|
-
|
|
391
|
+
try:
|
|
392
|
+
# 如果失败,尝试 GBK
|
|
393
|
+
return byte_stream.decode('gbk').strip()
|
|
394
|
+
except UnicodeDecodeError:
|
|
395
|
+
# 最后使用替换模式
|
|
396
|
+
return byte_stream.decode(encoding, errors='replace').strip()
|
|
163
397
|
|
|
164
398
|
output = []
|
|
165
399
|
with Live(console=console, refresh_per_second=4) as live:
|
|
@@ -238,4 +472,11 @@ def execute_shell_command(command: str):
|
|
|
238
472
|
})
|
|
239
473
|
console.print(
|
|
240
474
|
f"[bold red]Unexpected error:[/bold red] [yellow]{str(e)}[/yellow]"
|
|
241
|
-
)
|
|
475
|
+
)
|
|
476
|
+
finally:
|
|
477
|
+
# Clean up temp file
|
|
478
|
+
if temp_file and os.path.exists(temp_file.name):
|
|
479
|
+
try:
|
|
480
|
+
os.unlink(temp_file.name)
|
|
481
|
+
except Exception:
|
|
482
|
+
pass
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.panel import Panel
|
|
11
|
+
from rich.columns import Columns
|
|
12
|
+
from rich.text import Text
|
|
13
|
+
import math
|
|
14
|
+
|
|
15
|
+
class StatsPanel:
|
|
16
|
+
def __init__(self, console: Console = None):
|
|
17
|
+
self.console = console if console else Console()
|
|
18
|
+
|
|
19
|
+
def _format_speed_bar(self, speed: float) -> Text:
|
|
20
|
+
"""生成速度可视化进度条(保持原30-60区间)"""
|
|
21
|
+
if speed < 30:
|
|
22
|
+
color = "red"
|
|
23
|
+
level = "低"
|
|
24
|
+
elif 30 <= speed < 60:
|
|
25
|
+
color = "yellow"
|
|
26
|
+
level = "中"
|
|
27
|
+
else:
|
|
28
|
+
color = "green"
|
|
29
|
+
level = "高"
|
|
30
|
+
|
|
31
|
+
bar_length = min(int(speed), 100)
|
|
32
|
+
bar = Text("▮" * bar_length, style=color)
|
|
33
|
+
bar.append(f" {speed:.1f} tokens/s ({level})", style="bold white")
|
|
34
|
+
return bar
|
|
35
|
+
|
|
36
|
+
def _format_progress_bar(self, value: int, max_value: int, label: str, color: str) -> Text:
|
|
37
|
+
"""生成通用进度条"""
|
|
38
|
+
progress = min(value / max_value, 1.0)
|
|
39
|
+
bar_length = int(progress * 20)
|
|
40
|
+
bar = Text("▮" * bar_length, style=color)
|
|
41
|
+
bar.append(f" {value} ({label})", style="bold white")
|
|
42
|
+
return bar
|
|
43
|
+
|
|
44
|
+
def generate(
|
|
45
|
+
self,
|
|
46
|
+
model_names: str,
|
|
47
|
+
duration: float,
|
|
48
|
+
sampling_count: int,
|
|
49
|
+
input_tokens: int,
|
|
50
|
+
output_tokens: int,
|
|
51
|
+
input_cost: float,
|
|
52
|
+
output_cost: float,
|
|
53
|
+
speed: float,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""新版紧凑布局"""
|
|
56
|
+
# 复合标题(带图标和关键数据)
|
|
57
|
+
title = Text.assemble(
|
|
58
|
+
"📊 ", ("代码生成统计", "bold cyan underline"),
|
|
59
|
+
" │ ⚡", (f"{speed:.1f}t/s ", "bold green"),
|
|
60
|
+
"│ 💰", (f"${input_cost + output_cost:.4f}", "bold yellow")
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# 处理耗时颜色逻辑(新增15-30-60区间)
|
|
64
|
+
duration_color = "green"
|
|
65
|
+
if 15 <= duration < 30:
|
|
66
|
+
duration_color = "yellow"
|
|
67
|
+
elif duration >= 30:
|
|
68
|
+
duration_color = "red"
|
|
69
|
+
|
|
70
|
+
# 处理成本颜色逻辑(新增0.5-1区间)
|
|
71
|
+
def get_cost_color(cost: float) -> str:
|
|
72
|
+
if cost < 0.5: return "green"
|
|
73
|
+
elif 0.5 <= cost < 1: return "yellow"
|
|
74
|
+
else: return "red"
|
|
75
|
+
|
|
76
|
+
# 紧凑网格布局
|
|
77
|
+
grid = [
|
|
78
|
+
Panel(
|
|
79
|
+
Text.assemble(
|
|
80
|
+
("🤖 模型: ", "bold"), model_names + "\n",
|
|
81
|
+
self._format_mini_progress(duration, 60.0, duration_color), # 耗时max=60
|
|
82
|
+
(" ⏱", duration_color), f" {duration:.1f}s │ ",
|
|
83
|
+
self._format_mini_progress(sampling_count, 100, "blue"),
|
|
84
|
+
(" 🔢", "blue"), f" {sampling_count}\n",
|
|
85
|
+
("📥", "green"), " ",
|
|
86
|
+
self._format_mini_progress(input_tokens, 65536.0, "green"), # token分母改为65536
|
|
87
|
+
f" {input_tokens} ({input_tokens/65536*100:.2f}%) │ ", # 新增百分比显示
|
|
88
|
+
("📤", "bright_green"), " ",
|
|
89
|
+
self._format_mini_progress(output_tokens, 65536.0, "bright_green"),
|
|
90
|
+
f" {output_tokens} ({output_tokens/65536*100:.2f}%)" # 新增百分比显示
|
|
91
|
+
),
|
|
92
|
+
border_style="cyan",
|
|
93
|
+
padding=(0, 2)
|
|
94
|
+
),
|
|
95
|
+
Panel(
|
|
96
|
+
Text.assemble(
|
|
97
|
+
("💵 成本: ", "bold"),
|
|
98
|
+
self._format_mini_progress(input_cost, 1.0, get_cost_color(input_cost)), # 成本max=1
|
|
99
|
+
(" IN", get_cost_color(input_cost)), f" {input_cost:.3f}\n",
|
|
100
|
+
("💸 ", "bold"),
|
|
101
|
+
self._format_mini_progress(output_cost, 1.0, get_cost_color(output_cost)),
|
|
102
|
+
(" OUT", get_cost_color(output_cost)), f" {output_cost:.3f}\n",
|
|
103
|
+
self._format_speed_bar(speed)
|
|
104
|
+
),
|
|
105
|
+
border_style="yellow",
|
|
106
|
+
padding=(0, 1)
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
# 组合布局
|
|
111
|
+
main_panel = Panel(
|
|
112
|
+
Columns(grid, equal=True, expand=True),
|
|
113
|
+
title=title,
|
|
114
|
+
border_style="bright_blue",
|
|
115
|
+
padding=(1, 2)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
self.console.print(main_panel)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _format_mini_progress(self, value: float, max_value: float, color: str) -> Text:
|
|
122
|
+
"""紧凑型进度条(支持浮点数)"""
|
|
123
|
+
progress = min(value / max_value, 1.0)
|
|
124
|
+
filled = "▮" * int(progress * 10)
|
|
125
|
+
empty = "▯" * (10 - len(filled))
|
|
126
|
+
return Text(filled + empty, style=color)
|
|
@@ -86,7 +86,7 @@ class ActionTSProject(BaseAction):
|
|
|
86
86
|
max_iter=self.args.image_max_iter,
|
|
87
87
|
)
|
|
88
88
|
html_code = ""
|
|
89
|
-
with open(html_path, "r") as f:
|
|
89
|
+
with open(html_path, "r",encoding="utf-8") as f:
|
|
90
90
|
html_code = f.read()
|
|
91
91
|
|
|
92
92
|
source_code_list.sources.append(SourceCode(
|
|
@@ -190,9 +190,7 @@ class ActionTSProject(BaseAction):
|
|
|
190
190
|
conversations=generate_result.conversations[0],
|
|
191
191
|
model=self.llm.default_model_name,
|
|
192
192
|
)
|
|
193
|
-
|
|
194
|
-
with open(args.target_file, "w") as file:
|
|
195
|
-
file.write(content)
|
|
193
|
+
|
|
196
194
|
|
|
197
195
|
|
|
198
196
|
class ActionPyScriptProject(BaseAction):
|
|
@@ -300,11 +298,7 @@ class ActionPyScriptProject(BaseAction):
|
|
|
300
298
|
instruction=self.args.query,
|
|
301
299
|
conversations=generate_result.conversations[0],
|
|
302
300
|
model=self.llm.default_model_name,
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
end_time = time.time()
|
|
306
|
-
with open(self.args.target_file, "w") as file:
|
|
307
|
-
file.write(content)
|
|
301
|
+
)
|
|
308
302
|
|
|
309
303
|
|
|
310
304
|
class ActionPyProject(BaseAction):
|
|
@@ -435,9 +429,7 @@ class ActionPyProject(BaseAction):
|
|
|
435
429
|
instruction=self.args.query,
|
|
436
430
|
conversations=generate_result.conversations[0],
|
|
437
431
|
model=self.llm.default_model_name,
|
|
438
|
-
)
|
|
439
|
-
with open(args.target_file, "w") as file:
|
|
440
|
-
file.write(content)
|
|
432
|
+
)
|
|
441
433
|
|
|
442
434
|
|
|
443
435
|
class ActionSuffixProject(BaseAction):
|
|
@@ -551,9 +543,7 @@ class ActionSuffixProject(BaseAction):
|
|
|
551
543
|
instruction=self.args.query,
|
|
552
544
|
conversations=merge_result.conversations[0],
|
|
553
545
|
model=self.llm.default_model_name,
|
|
554
|
-
)
|
|
555
|
-
with open(args.target_file, "w") as file:
|
|
556
|
-
file.write(content)
|
|
546
|
+
)
|
|
557
547
|
else:
|
|
558
548
|
content = generate_result.contents[0]
|
|
559
549
|
|
|
@@ -563,7 +553,5 @@ class ActionSuffixProject(BaseAction):
|
|
|
563
553
|
conversations=generate_result.conversations[0],
|
|
564
554
|
model=self.llm.default_model_name,
|
|
565
555
|
)
|
|
566
|
-
|
|
567
|
-
with open(args.target_file, "w") as file:
|
|
568
|
-
file.write(content)
|
|
556
|
+
|
|
569
557
|
|
|
@@ -343,7 +343,7 @@ class ActionCopilot:
|
|
|
343
343
|
logger.info(
|
|
344
344
|
"model is not specified and we will generate prompt to the target file"
|
|
345
345
|
)
|
|
346
|
-
with open(args.target_file, "w") as f:
|
|
346
|
+
with open(args.target_file, "w",encoding="utf-8") as f:
|
|
347
347
|
f.write(q)
|
|
348
348
|
return True
|
|
349
349
|
|
|
@@ -379,7 +379,7 @@ class ActionCopilot:
|
|
|
379
379
|
logger.info(result)
|
|
380
380
|
|
|
381
381
|
# 将结果写入文件
|
|
382
|
-
with open(args.target_file, "w") as f:
|
|
382
|
+
with open(args.target_file, "w",encoding="utf-8") as f:
|
|
383
383
|
f.write("=================CONVERSATION==================\n\n")
|
|
384
384
|
for conversation in conversations:
|
|
385
385
|
f.write(f"{conversation['role']}: {conversation['content']}\n")
|
|
@@ -209,6 +209,6 @@ class ActionTranslate:
|
|
|
209
209
|
new_filename = f"{filename}{new_file_mark}{extension}"
|
|
210
210
|
|
|
211
211
|
logger.info(f"Writing to {new_filename}...")
|
|
212
|
-
with open(new_filename, "w") as file:
|
|
212
|
+
with open(new_filename, "w",encoding="utf-8") as file:
|
|
213
213
|
file.write(readme.content)
|
|
214
214
|
return True
|
autocoder/index/entry.py
CHANGED
|
@@ -110,8 +110,8 @@ def build_index_and_filter_files(
|
|
|
110
110
|
printer.print_in_terminal("quick_filter_start", style="blue", model_name=model_name)
|
|
111
111
|
quick_filter = QuickFilter(index_manager,stats,sources)
|
|
112
112
|
quick_filter_result = quick_filter.filter(index_manager.read_index(),args.query)
|
|
113
|
-
if quick_filter_result.has_error:
|
|
114
|
-
|
|
113
|
+
# if quick_filter_result.has_error:
|
|
114
|
+
# raise KeyboardInterrupt(printer.get_message_from_key_with_format("quick_filter_failed",error=quick_filter_result.error_message))
|
|
115
115
|
|
|
116
116
|
# Merge quick filter results into final_files
|
|
117
117
|
if args.context_prune:
|
|
@@ -31,7 +31,7 @@ class NormalFilterResult(BaseModel):
|
|
|
31
31
|
files: Dict[str, TargetFile]
|
|
32
32
|
has_error: bool
|
|
33
33
|
error_message: Optional[str] = None
|
|
34
|
-
file_positions: Optional[Dict[str, int]]
|
|
34
|
+
file_positions: Optional[Dict[str, int]] = {}
|
|
35
35
|
|
|
36
36
|
class NormalFilter():
|
|
37
37
|
def __init__(self, index_manager: IndexManager,stats:Dict[str,Any],sources:List[SourceCode]):
|
|
@@ -154,7 +154,7 @@ class QuickFilter():
|
|
|
154
154
|
else:
|
|
155
155
|
# 其他chunks直接使用with_llm
|
|
156
156
|
meta_holder = MetaHolder()
|
|
157
|
-
start_time = time.monotonic()
|
|
157
|
+
start_time = time.monotonic()
|
|
158
158
|
file_number_list = self.quick_filter_files.with_llm(self.index_manager.index_filter_llm).with_meta(
|
|
159
159
|
meta_holder).with_return_type(FileNumberList).run(chunk, self.args.query)
|
|
160
160
|
end_time = time.monotonic()
|
autocoder/index/index.py
CHANGED
|
@@ -342,7 +342,7 @@ class IndexManager:
|
|
|
342
342
|
|
|
343
343
|
def build_index(self):
|
|
344
344
|
if os.path.exists(self.index_file):
|
|
345
|
-
with open(self.index_file, "r") as file:
|
|
345
|
+
with open(self.index_file, "r",encoding="utf-8") as file:
|
|
346
346
|
index_data = json.load(file)
|
|
347
347
|
else:
|
|
348
348
|
index_data = {}
|
|
@@ -433,13 +433,13 @@ class IndexManager:
|
|
|
433
433
|
index_data[module_name] = result
|
|
434
434
|
updated_sources.append(module_name)
|
|
435
435
|
if len(updated_sources) > 5:
|
|
436
|
-
with open(self.index_file, "w") as file:
|
|
436
|
+
with open(self.index_file, "w",encoding="utf-8") as file:
|
|
437
437
|
json.dump(index_data, file, ensure_ascii=False, indent=2)
|
|
438
438
|
updated_sources = []
|
|
439
439
|
|
|
440
440
|
# 如果 updated_sources 或 keys_to_remove 有值,则保存索引文件
|
|
441
441
|
if updated_sources or keys_to_remove:
|
|
442
|
-
with open(self.index_file, "w") as file:
|
|
442
|
+
with open(self.index_file, "w",encoding="utf-8") as file:
|
|
443
443
|
json.dump(index_data, file, ensure_ascii=False, indent=2)
|
|
444
444
|
|
|
445
445
|
print("")
|
|
@@ -461,14 +461,14 @@ class IndexManager:
|
|
|
461
461
|
if not os.path.exists(self.index_file):
|
|
462
462
|
return []
|
|
463
463
|
|
|
464
|
-
with open(self.index_file, "r") as file:
|
|
464
|
+
with open(self.index_file, "r",encoding="utf-8") as file:
|
|
465
465
|
return file.read()
|
|
466
466
|
|
|
467
467
|
def read_index(self) -> List[IndexItem]:
|
|
468
468
|
if not os.path.exists(self.index_file):
|
|
469
469
|
return []
|
|
470
470
|
|
|
471
|
-
with open(self.index_file, "r") as file:
|
|
471
|
+
with open(self.index_file, "r",encoding="utf-8") as file:
|
|
472
472
|
index_data = json.load(file)
|
|
473
473
|
|
|
474
474
|
index_items = []
|
autocoder/models.py
CHANGED
|
@@ -97,7 +97,7 @@ def load_models() -> List[Dict]:
|
|
|
97
97
|
if model.get("api_key_path",""):
|
|
98
98
|
api_key_file = os.path.join(api_key_dir, model["api_key_path"])
|
|
99
99
|
if os.path.exists(api_key_file):
|
|
100
|
-
with open(api_key_file, "r") as f:
|
|
100
|
+
with open(api_key_file, "r",encoding="utf-8") as f:
|
|
101
101
|
model["api_key"] = f.read()
|
|
102
102
|
return target_models
|
|
103
103
|
|
|
@@ -269,7 +269,7 @@ def update_model_with_api_key(name: str, api_key: str) -> Dict:
|
|
|
269
269
|
api_key_dir = os.path.expanduser("~/.auto-coder/keys")
|
|
270
270
|
os.makedirs(api_key_dir, exist_ok=True)
|
|
271
271
|
api_key_file = os.path.join(api_key_dir, api_key_path)
|
|
272
|
-
with open(api_key_file, "w") as f:
|
|
272
|
+
with open(api_key_file, "w",encoding="utf-8") as f:
|
|
273
273
|
f.write(api_key.strip())
|
|
274
274
|
|
|
275
275
|
# 如果是新模型,添加到模型列表中
|
autocoder/pyproject/__init__.py
CHANGED
|
@@ -174,7 +174,8 @@ class PyProject:
|
|
|
174
174
|
return False
|
|
175
175
|
|
|
176
176
|
def output(self):
|
|
177
|
-
|
|
177
|
+
with open(self.target_file, "r",encoding="utf-8") as file:
|
|
178
|
+
return file.read()
|
|
178
179
|
|
|
179
180
|
def is_python_file(self, file_path):
|
|
180
181
|
return file_path.endswith(".py")
|
|
@@ -182,9 +183,8 @@ class PyProject:
|
|
|
182
183
|
def read_file_content(self, file_path):
|
|
183
184
|
if self.args.auto_merge == "strict_diff":
|
|
184
185
|
result = []
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
result.append(f"{line_number}:{line}")
|
|
186
|
+
for line_number, line in FileUtils.read_file_with_line_numbers(file_path,line_number_start=1):
|
|
187
|
+
result.append(f"{line_number}:{line}")
|
|
188
188
|
return "\n".join(result)
|
|
189
189
|
|
|
190
190
|
return FileUtils.read_file(file_path)
|
|
@@ -357,7 +357,7 @@ class PyProject:
|
|
|
357
357
|
self.clone_repository()
|
|
358
358
|
|
|
359
359
|
if self.target_file:
|
|
360
|
-
with open(self.target_file, "w") as file:
|
|
360
|
+
with open(self.target_file, "w",encoding="utf-8") as file:
|
|
361
361
|
|
|
362
362
|
for code in self.get_rest_source_codes():
|
|
363
363
|
self.sources.append(code)
|