pangxiang commited on
Commit
5207fa8
·
verified ·
1 Parent(s): 82af507

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +927 -54
app.py CHANGED
@@ -1,70 +1,943 @@
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
  """
4
- CodeGPSPro — DeepSeek 两窗版(带临时凭证)
5
- 左:代码编辑器 右:AI 聊天
6
  """
7
  import gradio as gr
 
 
 
 
 
8
 
9
- # =====================================================================
10
- # 示范函数:这里替换为真正的 DeepSeek API 调用
11
- # =====================================================================
12
- def call_deepseek(api_key, model, full_prompt):
13
- """这里应接入真实接口;当前为示例"""
14
- return f"模型: {model}\n键: {api_key[:4]}... (示例)\n——我已看见编辑器中的全部代码。"
 
 
 
15
 
16
- # =====================================================================
17
- # 聊天处理逻辑
18
- # =====================================================================
19
- def chat_round(message, history, code_text, creds):
20
- api_key, model = creds.get("api_key",""), creds.get("model","")
21
- if not api_key.strip():
22
- history.append(("系统", "⚠️ 未填写 API Key"))
23
- return history, ""
24
- prompt = f"用户消息:{message}\n\n当前完整代码:\n```{code_text}```"
25
- ai_reply = call_deepseek(api_key, model, prompt)
26
- history.append((message, ai_reply))
27
- return history, ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- # =====================================================================
30
- # Gradio UI
31
- # =====================================================================
32
  def create_ui():
33
- creds = gr.State({"api_key":"", "model":"deepseek-chat"})
34
-
35
- with gr.Blocks(title="CodeGPS Pro — DeepSeek AI 双窗版") as app:
36
- gr.Markdown("## 👁 CodeGPS Pro — DeepSeek AI 聊天修复版")
37
-
38
- with gr.Accordion("🔐 临时凭证(仅当前会话有效)", open=False):
39
- api_in = gr.Textbox(label="API KEY", type="password", placeholder="输入你的 DeepSeek API Key")
40
- model_in = gr.Textbox(label="模型名", value="deepseek-chat")
41
- save_btn = gr.Button("💾 暂存到内存")
42
- clear_btn = gr.Button("🗑️ 清除")
43
- info = gr.Markdown("凭证不会写入磁盘,页面关闭即删除。")
44
-
45
- def save_creds(a, m):
46
- return {"api_key":a, "model":m}, f"✅ 暂存成功:{m}"
47
- def clear_creds():
48
- return {"api_key":"", "model":""}, "🔐 已清除 API Key"
49
-
50
- save_btn.click(save_creds, [api_in, model_in], [creds, info])
51
- clear_btn.click(clear_creds, [], [creds, info])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- with gr.Row():
54
- code = gr.Code(label="📝 编辑器", language="python", lines=28)
55
- chatbot = gr.Chatbot(label="🤖 DeepSeek AI 聊天窗口")
 
 
56
 
57
- msg = gr.Textbox(label="👤 输入内容", placeholder="描述要修复的部分,或直接对话…")
58
- send = gr.Button("发送")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- send.click(
61
- chat_round,
62
- inputs=[msg, chatbot, code, creds],
63
- outputs=[chatbot, msg]
 
 
 
 
 
 
 
64
  )
65
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  return app
67
 
68
  if __name__ == "__main__":
69
- ui = create_ui()
70
- ui.launch(server_port=7860)
 
1
  #!/usr/bin/env python3
2
  # -*- coding: utf-8 -*-
3
  """
4
+ CodeGPS Pro - 完全实用版
5
+ 真正能用的大模型代码眼睛 - 所有功能都能独立工作
6
  """
7
  import gradio as gr
8
+ import re
9
+ import difflib
10
+ from typing import Dict, List, Tuple, Optional
11
+ from dataclasses import dataclass
12
+ import json
13
 
14
+ # ==================== 核心引擎 ====================
15
+ @dataclass
16
+ class CodeBlock:
17
+ start_line: int
18
+ end_line: int
19
+ type: str
20
+ name: str
21
+ content: str
22
+ parent: Optional[str] = None
23
 
24
+ class CodeGPSEngine:
25
+ """核心代码处理引擎"""
26
+
27
+ def __init__(self):
28
+ self.reset()
29
+
30
+ def reset(self):
31
+ """重置状态"""
32
+ self.original_code = ""
33
+ self.current_code = ""
34
+ self.lines = []
35
+ self.language = "unknown"
36
+ self.blocks = []
37
+ self.history = []
38
+ self.is_loaded = False
39
+
40
+ def auto_load(self, code: str) -> str:
41
+ """自动加载代码(无需手动触发)"""
42
+ if not code or not code.strip():
43
+ self.reset()
44
+ return "⚠️ 代码为空"
45
+
46
+ self.original_code = code
47
+ self.current_code = code
48
+ self.lines = code.split('\n')
49
+ self.language = self._detect_language(code)
50
+ self.blocks = self._parse_blocks()
51
+ self.is_loaded = True
52
+
53
+ return f"✅ 已加载 | 语言:{self.language.upper()} | 行数:{len(self.lines)} | 代码块:{len(self.blocks)}"
54
+
55
+ def _detect_language(self, code: str) -> str:
56
+ """快速检测语言"""
57
+ patterns = {
58
+ 'python': [r'def\s+\w+', r'class\s+\w+', r'import\s+\w+', r':\s*$'],
59
+ 'javascript': [r'function\s+', r'const\s+\w+\s*=', r'=>', r'console\.'],
60
+ 'java': [r'public\s+class', r'private\s+\w+', r'System\.'],
61
+ 'cpp': [r'#include', r'std::', r'int\s+main'],
62
+ 'go': [r'package\s+', r'func\s+', r':='],
63
+ 'php': [r'<\?php', r'\$\w+', r'function\s+\w+'],
64
+ 'ruby': [r'def\s+\w+', r'end\s*$', r'require\s+'],
65
+ 'rust': [r'fn\s+\w+', r'let\s+\w+', r'impl\s+'],
66
+ }
67
+
68
+ for lang, pats in patterns.items():
69
+ matches = sum(1 for p in pats if re.search(p, code, re.MULTILINE))
70
+ if matches >= 2:
71
+ return lang
72
+ return 'plaintext'
73
+
74
+ def _parse_blocks(self) -> List[CodeBlock]:
75
+ """解析代码块"""
76
+ blocks = []
77
+
78
+ if self.language == 'python':
79
+ blocks = self._parse_python()
80
+ elif self.language in ['javascript', 'java', 'cpp', 'go']:
81
+ blocks = self._parse_braces()
82
+
83
+ return blocks
84
+
85
+ def _parse_python(self) -> List[CodeBlock]:
86
+ """解析Python代码"""
87
+ blocks = []
88
+ i = 0
89
+ current_class = None
90
+
91
+ while i < len(self.lines):
92
+ line = self.lines[i]
93
+ stripped = line.lstrip()
94
+ indent = len(line) - len(stripped)
95
+
96
+ # 类定义
97
+ if re.match(r'class\s+(\w+)', stripped):
98
+ name = re.match(r'class\s+(\w+)', stripped).group(1)
99
+ start = i + 1
100
+ end = self._find_python_block_end(i, indent)
101
+ blocks.append(CodeBlock(
102
+ start_line=start,
103
+ end_line=end,
104
+ type='class',
105
+ name=name,
106
+ content='\n'.join(self.lines[i:end])
107
+ ))
108
+ current_class = name
109
+ i = end
110
+ continue
111
+
112
+ # 函数/方法定义
113
+ if re.match(r'def\s+(\w+)', stripped):
114
+ name = re.match(r'def\s+(\w+)', stripped).group(1)
115
+ start = i + 1
116
+ end = self._find_python_block_end(i, indent)
117
+ blocks.append(CodeBlock(
118
+ start_line=start,
119
+ end_line=end,
120
+ type='method' if current_class else 'function',
121
+ name=name,
122
+ content='\n'.join(self.lines[i:end]),
123
+ parent=current_class
124
+ ))
125
+ i = end
126
+ continue
127
+
128
+ i += 1
129
+
130
+ return blocks
131
+
132
+ def _find_python_block_end(self, start: int, base_indent: int) -> int:
133
+ """查找Python代码块结束位置"""
134
+ i = start + 1
135
+ while i < len(self.lines):
136
+ line = self.lines[i]
137
+ if line.strip():
138
+ indent = len(line) - len(line.lstrip())
139
+ if indent <= base_indent:
140
+ return i
141
+ i += 1
142
+ return len(self.lines)
143
+
144
+ def _parse_braces(self) -> List[CodeBlock]:
145
+ """解析花括号语言"""
146
+ blocks = []
147
+ stack = []
148
+
149
+ patterns = {
150
+ 'function': r'(?:function\s+(\w+)|(\w+)\s*\([^)]*\)\s*\{|fn\s+(\w+)|func\s+(\w+))',
151
+ 'class': r'class\s+(\w+)',
152
+ }
153
+
154
+ for i, line in enumerate(self.lines, 1):
155
+ # 检测函数
156
+ func_match = re.search(patterns['function'], line)
157
+ if func_match:
158
+ name = next((g for g in func_match.groups() if g), 'anonymous')
159
+ stack.append(('function', name, i, 0))
160
+
161
+ # 检测类
162
+ class_match = re.search(patterns['class'], line)
163
+ if class_match:
164
+ name = class_match.group(1)
165
+ stack.append(('class', name, i, 0))
166
+
167
+ # 花括号计数
168
+ open_count = line.count('{')
169
+ close_count = line.count('}')
170
+
171
+ if stack:
172
+ stack[-1] = (stack[-1][0], stack[-1][1], stack[-1][2], stack[-1][3] + open_count - close_count)
173
+
174
+ if stack[-1][3] == 0 and (open_count > 0 or close_count > 0):
175
+ block_type, name, start, _ = stack.pop()
176
+ blocks.append(CodeBlock(
177
+ start_line=start,
178
+ end_line=i,
179
+ type=block_type,
180
+ name=name,
181
+ content='\n'.join(self.lines[start-1:i])
182
+ ))
183
+
184
+ return blocks
185
+
186
+ # ==================== 查询功能 ====================
187
+
188
+ def get_line(self, line_num: int) -> Dict:
189
+ """获取单行"""
190
+ if not self.is_loaded:
191
+ return {'success': False, 'error': '❌ 请先输入代码'}
192
+
193
+ if not 1 <= line_num <= len(self.lines):
194
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{len(self.lines)})'}
195
+
196
+ return {
197
+ 'success': True,
198
+ 'content': self.lines[line_num - 1],
199
+ 'formatted': f"第{line_num}行: {self.lines[line_num - 1]}"
200
+ }
201
+
202
+ def get_lines(self, start: int, end: int) -> Dict:
203
+ """获取多行"""
204
+ if not self.is_loaded:
205
+ return {'success': False, 'error': '❌ 请先输入代码'}
206
+
207
+ total = len(self.lines)
208
+ if not (1 <= start <= total and 1 <= end <= total):
209
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{total})'}
210
+
211
+ if start > end:
212
+ start, end = end, start
213
+
214
+ lines_output = []
215
+ for i in range(max(1, start - 2), min(total + 1, end + 3)):
216
+ marker = '>>> ' if start <= i <= end else ' '
217
+ lines_output.append(f"{marker}{i:4d} | {self.lines[i-1]}")
218
+
219
+ return {
220
+ 'success': True,
221
+ 'content': '\n'.join(self.lines[start-1:end]),
222
+ 'formatted': '\n'.join(lines_output)
223
+ }
224
+
225
+ def get_function(self, name: str) -> Dict:
226
+ """获取函数"""
227
+ if not self.is_loaded:
228
+ return {'success': False, 'error': '❌ 请先输入代码'}
229
+
230
+ for block in self.blocks:
231
+ if block.type in ['function', 'method'] and block.name == name:
232
+ lines_output = []
233
+ for i in range(block.start_line, block.end_line + 1):
234
+ lines_output.append(f"{i:4d} | {self.lines[i-1]}")
235
+
236
+ return {
237
+ 'success': True,
238
+ 'content': block.content,
239
+ 'formatted': f"📍 函数: {name} [第{block.start_line}-{block.end_line}行]\n" + '\n'.join(lines_output)
240
+ }
241
+
242
+ return {'success': False, 'error': f'❌ 未找到函数: {name}'}
243
+
244
+ def get_class(self, name: str) -> Dict:
245
+ """获取类"""
246
+ if not self.is_loaded:
247
+ return {'success': False, 'error': '❌ 请先输入代码'}
248
+
249
+ for block in self.blocks:
250
+ if block.type == 'class' and block.name == name:
251
+ lines_output = []
252
+ for i in range(block.start_line, block.end_line + 1):
253
+ lines_output.append(f"{i:4d} | {self.lines[i-1]}")
254
+
255
+ return {
256
+ 'success': True,
257
+ 'content': block.content,
258
+ 'formatted': f"📦 类: {name} [第{block.start_line}-{block.end_line}行]\n" + '\n'.join(lines_output)
259
+ }
260
+
261
+ return {'success': False, 'error': f'❌ 未找到类: {name}'}
262
+
263
+ def search_text(self, keyword: str) -> Dict:
264
+ """搜索文本"""
265
+ if not self.is_loaded:
266
+ return {'success': False, 'error': '❌ 请先输入代码'}
267
+
268
+ results = []
269
+ for i, line in enumerate(self.lines, 1):
270
+ if keyword in line:
271
+ results.append(f"{i:4d} | {line}")
272
+
273
+ if results:
274
+ return {
275
+ 'success': True,
276
+ 'formatted': f"🔍 找到 {len(results)} 处匹配:\n" + '\n'.join(results[:50]) # 最多显示50个
277
+ }
278
+
279
+ return {'success': False, 'error': f'❌ 未找到: {keyword}'}
280
+
281
+ def list_all(self) -> str:
282
+ """列出所有代码块"""
283
+ if not self.is_loaded:
284
+ return "❌ 请先输入代码"
285
+
286
+ output = [f"📋 代码结构 [{self.language.upper()}] 共{len(self.lines)}行\n"]
287
+
288
+ if not self.blocks:
289
+ output.append("⚠️ 未检测到明显的函数/类结构")
290
+ return '\n'.join(output)
291
+
292
+ # 按类型分组
293
+ classes = [b for b in self.blocks if b.type == 'class']
294
+ functions = [b for b in self.blocks if b.type == 'function']
295
+ methods = [b for b in self.blocks if b.type == 'method']
296
+
297
+ if classes:
298
+ output.append("📦 类定义:")
299
+ for b in classes:
300
+ output.append(f" ├─ {b.name} (第{b.start_line}-{b.end_line}行)")
301
+
302
+ if functions:
303
+ output.append("\n🔧 函数定义:")
304
+ for b in functions:
305
+ output.append(f" ├─ {b.name}() (第{b.start_line}-{b.end_line}行)")
306
+
307
+ if methods:
308
+ output.append("\n⚙️ 方法定义:")
309
+ for b in methods:
310
+ parent = f" [{b.parent}]" if b.parent else ""
311
+ output.append(f" ├─ {b.name}(){parent} (第{b.start_line}-{b.end_line}行)")
312
+
313
+ return '\n'.join(output)
314
+
315
+ # ==================== 修改功能 ====================
316
+
317
+ def replace_line(self, line_num: int, new_content: str) -> Dict:
318
+ """替换单行"""
319
+ if not self.is_loaded:
320
+ return {'success': False, 'error': '❌ 请先输入代码'}
321
+
322
+ if not 1 <= line_num <= len(self.lines):
323
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{len(self.lines)})'}
324
+
325
+ old = self.lines[line_num - 1]
326
+ self.lines[line_num - 1] = new_content
327
+ self.current_code = '\n'.join(self.lines)
328
+ self._save_history('replace_line', line_num, old)
329
+
330
+ return {
331
+ 'success': True,
332
+ 'message': f'✅ 已替换第{line_num}行',
333
+ 'diff': self._make_diff(old, new_content)
334
+ }
335
+
336
+ def replace_lines(self, start: int, end: int, new_content: str) -> Dict:
337
+ """替换多行"""
338
+ if not self.is_loaded:
339
+ return {'success': False, 'error': '❌ 请先输入代码'}
340
+
341
+ total = len(self.lines)
342
+ if not (1 <= start <= total and 1 <= end <= total):
343
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{total})'}
344
+
345
+ if start > end:
346
+ start, end = end, start
347
+
348
+ old = '\n'.join(self.lines[start-1:end])
349
+ new_lines = new_content.split('\n')
350
+ self.lines[start-1:end] = new_lines
351
+ self.current_code = '\n'.join(self.lines)
352
+ self._save_history('replace_lines', (start, end), old)
353
+
354
+ return {
355
+ 'success': True,
356
+ 'message': f'✅ 已替换第{start}-{end}行 ({end-start+1}行 → {len(new_lines)}行)',
357
+ 'diff': self._make_diff(old, new_content)
358
+ }
359
+
360
+ def insert_after(self, line_num: int, new_content: str) -> Dict:
361
+ """在指定行后插入"""
362
+ if not self.is_loaded:
363
+ return {'success': False, 'error': '❌ 请先输入代码'}
364
+
365
+ if not 0 <= line_num <= len(self.lines):
366
+ return {'success': False, 'error': f'❌ 行号超出范围 (0-{len(self.lines)})'}
367
+
368
+ new_lines = new_content.split('\n')
369
+ self.lines[line_num:line_num] = new_lines
370
+ self.current_code = '\n'.join(self.lines)
371
+ self._save_history('insert', line_num, None)
372
+
373
+ return {
374
+ 'success': True,
375
+ 'message': f'✅ 已在第{line_num}行后插入{len(new_lines)}行'
376
+ }
377
+
378
+ def delete_lines(self, start: int, end: int) -> Dict:
379
+ """删除行"""
380
+ if not self.is_loaded:
381
+ return {'success': False, 'error': '❌ 请先输入代码'}
382
+
383
+ total = len(self.lines)
384
+ if not (1 <= start <= total and 1 <= end <= total):
385
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{total})'}
386
+
387
+ if start > end:
388
+ start, end = end, start
389
+
390
+ deleted = '\n'.join(self.lines[start-1:end])
391
+ del self.lines[start-1:end]
392
+ self.current_code = '\n'.join(self.lines)
393
+ self._save_history('delete', (start, end), deleted)
394
+
395
+ return {
396
+ 'success': True,
397
+ 'message': f'✅ 已删除第{start}-{end}行 (共{end-start+1}行)',
398
+ 'deleted': deleted
399
+ }
400
+
401
+ def find_replace(self, find_text: str, replace_text: str, max_replace: int = -1) -> Dict:
402
+ """查找替换"""
403
+ if not self.is_loaded:
404
+ return {'success': False, 'error': '❌ 请先输入代码'}
405
+
406
+ old_code = self.current_code
407
+ count = 0
408
+ changes = []
409
+
410
+ for i, line in enumerate(self.lines):
411
+ if find_text in line:
412
+ if max_replace == -1 or count < max_replace:
413
+ old_line = line
414
+ new_line = line.replace(find_text, replace_text)
415
+ self.lines[i] = new_line
416
+ count += 1
417
+ changes.append(f"第{i+1}行: {old_line} → {new_line}")
418
+
419
+ if count > 0:
420
+ self.current_code = '\n'.join(self.lines)
421
+ self._save_history('find_replace', find_text, old_code)
422
+
423
+ return {
424
+ 'success': True,
425
+ 'message': f'✅ 已替换 {count} 处',
426
+ 'changes': '\n'.join(changes[:20]) # 最多显示20条
427
+ }
428
+
429
+ return {'success': False, 'error': f'❌ 未找到: {find_text}'}
430
+
431
+ def indent_lines(self, start: int, end: int, spaces: int = 4) -> Dict:
432
+ """缩进调整"""
433
+ if not self.is_loaded:
434
+ return {'success': False, 'error': '❌ 请先输入代码'}
435
+
436
+ total = len(self.lines)
437
+ if not (1 <= start <= total and 1 <= end <= total):
438
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{total})'}
439
+
440
+ indent_str = ' ' * abs(spaces)
441
+
442
+ for i in range(start-1, end):
443
+ if spaces > 0:
444
+ self.lines[i] = indent_str + self.lines[i]
445
+ else:
446
+ # 反向缩进
447
+ self.lines[i] = self.lines[i].lstrip()[:abs(spaces)] + self.lines[i].lstrip()[abs(spaces):]
448
+
449
+ self.current_code = '\n'.join(self.lines)
450
+ self._save_history('indent', (start, end), None)
451
+
452
+ return {
453
+ 'success': True,
454
+ 'message': f'✅ 已调整第{start}-{end}行缩进 ({spaces} 空格)'
455
+ }
456
+
457
+ def comment_lines(self, start: int, end: int, uncomment: bool = False) -> Dict:
458
+ """注释/取消注释"""
459
+ if not self.is_loaded:
460
+ return {'success': False, 'error': '❌ 请先输入代码'}
461
+
462
+ total = len(self.lines)
463
+ if not (1 <= start <= total and 1 <= end <= total):
464
+ return {'success': False, 'error': f'❌ 行号超出范围 (1-{total})'}
465
+
466
+ # 根据语言选择注释符
467
+ comment_map = {
468
+ 'python': '#',
469
+ 'javascript': '//',
470
+ 'java': '//',
471
+ 'cpp': '//',
472
+ 'go': '//',
473
+ 'php': '//',
474
+ 'ruby': '#',
475
+ 'rust': '//',
476
+ }
477
+
478
+ comment_symbol = comment_map.get(self.language, '#')
479
+
480
+ for i in range(start-1, end):
481
+ if uncomment:
482
+ self.lines[i] = self.lines[i].lstrip().lstrip(comment_symbol).lstrip()
483
+ else:
484
+ self.lines[i] = f"{comment_symbol} {self.lines[i]}"
485
+
486
+ self.current_code = '\n'.join(self.lines)
487
+ self._save_history('comment', (start, end), None)
488
+
489
+ action = '取消注释' if uncomment else '注释'
490
+ return {
491
+ 'success': True,
492
+ 'message': f'✅ 已{action}第{start}-{end}行'
493
+ }
494
+
495
+ def _make_diff(self, old: str, new: str) -> str:
496
+ """生成差异对比"""
497
+ diff = difflib.unified_diff(
498
+ old.split('\n'),
499
+ new.split('\n'),
500
+ lineterm='',
501
+ fromfile='修改前',
502
+ tofile='修改后'
503
+ )
504
+ return '\n'.join(diff)
505
+
506
+ def _save_history(self, operation: str, target, old_content):
507
+ """保存历史"""
508
+ self.history.append({
509
+ 'operation': operation,
510
+ 'target': target,
511
+ 'old': old_content
512
+ })
513
+
514
+ def undo(self) -> Dict:
515
+ """撤销"""
516
+ if not self.history:
517
+ return {'success': False, 'error': '❌ 没有可撤销的操作'}
518
+
519
+ # 简单实现:重新加载原始代码
520
+ self.current_code = self.original_code
521
+ self.lines = self.original_code.split('\n')
522
+ self.history = []
523
+
524
+ return {'success': True, 'message': '✅ 已撤销所有修改'}
525
+
526
+ def get_current_code(self) -> str:
527
+ """获取当前代码"""
528
+ return self.current_code
529
 
530
+ # ==================== UI界面 ====================
 
 
531
  def create_ui():
532
+ engine = CodeGPSEngine()
533
+
534
+ # 主题色
535
+ theme = gr.themes.Soft(
536
+ primary_hue="purple",
537
+ secondary_hue="blue",
538
+ )
539
+
540
+ with gr.Blocks(title="CodeGPS Pro", theme=theme) as app:
541
+ gr.HTML("""
542
+ <div style="text-align:center; background:linear-gradient(135deg,#667eea,#764ba2); color:white; padding:40px; border-radius:15px; margin-bottom:30px;">
543
+ <h1 style="font-size:3rem; margin:0;">🎯 CodeGPS Pro</h1>
544
+ <p style="font-size:1.3rem; opacity:0.95; margin-top:10px;">大模型的精准代码手术刀 - 立即可用</p>
545
+ </div>
546
+ """)
547
+
548
+ # 状态显示
549
+ status_display = gr.Textbox(label="📊 状态", value="等待输入代码...", interactive=False, max_lines=1)
550
+
551
+ with gr.Tabs():
552
+ # ========== Tab 1: 代码编辑器 ==========
553
+ with gr.TabItem("📝 代码编辑器"):
554
+ with gr.Row():
555
+ with gr.Column(scale=1):
556
+ code_input = gr.Code(
557
+ label="代码输入区",
558
+ language="python",
559
+ lines=30
560
+ )
561
+
562
+ with gr.Row():
563
+ load_example_btn = gr.Button("📥 加载示例代码", variant="secondary")
564
+ clear_code_btn = gr.Button("🗑️ 清空", variant="secondary")
565
+
566
+ with gr.Column(scale=1):
567
+ gr.Markdown("### 🗺️ 代码结构")
568
+ structure_output = gr.Textbox(
569
+ label="",
570
+ lines=30,
571
+ interactive=False,
572
+ show_label=False
573
+ )
574
+
575
+ # ========== Tab 2: 精准查询 ==========
576
+ with gr.TabItem("🔍 查询代码"):
577
+ gr.Markdown("""
578
+ ### 使用方法
579
+ - **查询单行**: 输入行号,如 `15`
580
+ - **查询范围**: 输入 `10-20` 或分别输入起止行号
581
+ - **查询函数**: 输入函数名,如 `main`
582
+ - **查询类**: 输入类名
583
+ - **搜索文本**: 输入关键词搜索
584
+ """)
585
+
586
+ with gr.Row():
587
+ with gr.Column():
588
+ gr.Markdown("#### 快捷查询")
589
+
590
+ with gr.Group():
591
+ gr.Markdown("**查询单行**")
592
+ query_line_num = gr.Number(label="行号", value=1, precision=0)
593
+ query_line_btn = gr.Button("查询单行", variant="primary")
594
+
595
+ with gr.Group():
596
+ gr.Markdown("**查询范围**")
597
+ with gr.Row():
598
+ query_start = gr.Number(label="起始行", value=1, precision=0)
599
+ query_end = gr.Number(label="结束行", value=10, precision=0)
600
+ query_range_btn = gr.Button("查询范围", variant="primary")
601
+
602
+ with gr.Group():
603
+ gr.Markdown("**查询函数/类**")
604
+ query_name = gr.Textbox(label="名称", placeholder="如: main")
605
+ with gr.Row():
606
+ query_func_btn = gr.Button("查询函数")
607
+ query_class_btn = gr.Button("查询类")
608
+
609
+ with gr.Group():
610
+ gr.Markdown("**搜索文本**")
611
+ search_keyword = gr.Textbox(label="关键词", placeholder="如: print")
612
+ search_btn = gr.Button("搜索", variant="primary")
613
+
614
+ with gr.Column():
615
+ query_result = gr.Textbox(
616
+ label="📍 查询结果",
617
+ lines=35,
618
+ interactive=False,
619
+ elem_classes="code-display"
620
+ )
621
+
622
+ # ========== Tab 3: 精准修改 ==========
623
+ with gr.TabItem("✏️ 修改代码"):
624
+ with gr.Row():
625
+ with gr.Column():
626
+ modify_mode = gr.Radio(
627
+ label="修改模式",
628
+ choices=[
629
+ "替换单行",
630
+ "替换多行",
631
+ "插入代码",
632
+ "删除行",
633
+ "查找替换",
634
+ "调整缩进",
635
+ "添加注释"
636
+ ],
637
+ value="替换单行"
638
+ )
639
+
640
+ # 通用参数
641
+ with gr.Group() as single_line_group:
642
+ modify_line = gr.Number(label="目标行号", value=1, precision=0)
643
+
644
+ with gr.Group(visible=False) as range_group:
645
+ with gr.Row():
646
+ modify_start = gr.Number(label="起始行", value=1, precision=0)
647
+ modify_end = gr.Number(label="结束行", value=1, precision=0)
648
+
649
+ with gr.Group(visible=False) as find_replace_group:
650
+ find_text = gr.Textbox(label="查找文本")
651
+ replace_text = gr.Textbox(label="替换为")
652
+
653
+ with gr.Group(visible=False) as indent_group:
654
+ indent_spaces = gr.Slider(-8, 8, value=4, step=4, label="缩进空格数(负数为反向)")
655
+
656
+ new_code_input = gr.Code(
657
+ label="新代码内容",
658
+ language="python",
659
+ lines=10
660
+ )
661
+
662
+ with gr.Row():
663
+ execute_modify_btn = gr.Button("🚀 执行修改", variant="primary", scale=2)
664
+ undo_btn = gr.Button("↩️ 撤销全部", variant="secondary", scale=1)
665
+
666
+ with gr.Column():
667
+ modify_result = gr.Textbox(
668
+ label="📊 修改结果",
669
+ lines=10,
670
+ interactive=False
671
+ )
672
+
673
+ diff_output = gr.Textbox(
674
+ label="🔄 变更对比",
675
+ lines=25,
676
+ interactive=False,
677
+ elem_classes="code-display"
678
+ )
679
+
680
+ # ========== Tab 4: 导出与预览 ==========
681
+ with gr.TabItem("📤 导出代码"):
682
+ with gr.Column():
683
+ gr.Markdown("### 当前完整代码")
684
+
685
+ refresh_btn = gr.Button("🔄 刷新预览", variant="primary")
686
+
687
+ current_code_output = gr.Code(
688
+ label="",
689
+ language="python",
690
+ lines=40,
691
+ show_label=False
692
+ )
693
+
694
+ with gr.Row():
695
+ download_btn = gr.File(label="下载代码文件")
696
+
697
+ gr.Markdown("### 📊 修改统计")
698
+ stats_output = gr.Textbox(
699
+ label="",
700
+ lines=5,
701
+ interactive=False
702
+ )
703
+
704
+ # ==================== 事件绑定 ====================
705
+
706
+ # 自动加载代码(核心)
707
+ def auto_load_handler(code):
708
+ status = engine.auto_load(code)
709
+ structure = engine.list_all() if engine.is_loaded else ""
710
+ return status, structure
711
+
712
+ code_input.change(
713
+ fn=auto_load_handler,
714
+ inputs=[code_input],
715
+ outputs=[status_display, structure_output]
716
+ )
717
+
718
+ # 加载示例
719
+ def load_example():
720
+ example = '''def calculate_sum(a, b):
721
+ """计算两数之和"""
722
+ return a + b
723
 
724
+ def calculate_average(numbers):
725
+ """计算平均值"""
726
+ if not numbers:
727
+ return 0
728
+ return sum(numbers) / len(numbers)
729
 
730
+ class Calculator:
731
+ def __init__(self):
732
+ self.result = 0
733
+
734
+ def add(self, value):
735
+ """加法"""
736
+ self.result += value
737
+ return self.result
738
+
739
+ def subtract(self, value):
740
+ """减法"""
741
+ self.result -= value
742
+ return self.result
743
+
744
+ def reset(self):
745
+ """重置"""
746
+ self.result = 0
747
 
748
+ if __name__ == "__main__":
749
+ calc = Calculator()
750
+ calc.add(10)
751
+ calc.add(5)
752
+ print(f"结果: {calc.result}")
753
+ '''
754
+ return example
755
+
756
+ load_example_btn.click(
757
+ fn=load_example,
758
+ outputs=[code_input]
759
  )
760
+
761
+ clear_code_btn.click(
762
+ fn=lambda: "",
763
+ outputs=[code_input]
764
+ )
765
+
766
+ # 查询功能
767
+ def query_line(line_num):
768
+ result = engine.get_line(int(line_num))
769
+ if result['success']:
770
+ return result['formatted']
771
+ return result['error']
772
+
773
+ query_line_btn.click(
774
+ fn=query_line,
775
+ inputs=[query_line_num],
776
+ outputs=[query_result]
777
+ )
778
+
779
+ def query_range(start, end):
780
+ result = engine.get_lines(int(start), int(end))
781
+ if result['success']:
782
+ return result['formatted']
783
+ return result['error']
784
+
785
+ query_range_btn.click(
786
+ fn=query_range,
787
+ inputs=[query_start, query_end],
788
+ outputs=[query_result]
789
+ )
790
+
791
+ def query_function(name):
792
+ result = engine.get_function(name)
793
+ if result['success']:
794
+ return result['formatted']
795
+ return result['error']
796
+
797
+ query_func_btn.click(
798
+ fn=query_function,
799
+ inputs=[query_name],
800
+ outputs=[query_result]
801
+ )
802
+
803
+ def query_class(name):
804
+ result = engine.get_class(name)
805
+ if result['success']:
806
+ return result['formatted']
807
+ return result['error']
808
+
809
+ query_class_btn.click(
810
+ fn=query_class,
811
+ inputs=[query_name],
812
+ outputs=[query_result]
813
+ )
814
+
815
+ def search_text_handler(keyword):
816
+ result = engine.search_text(keyword)
817
+ if result['success']:
818
+ return result['formatted']
819
+ return result['error']
820
+
821
+ search_btn.click(
822
+ fn=search_text_handler,
823
+ inputs=[search_keyword],
824
+ outputs=[query_result]
825
+ )
826
+
827
+ # 修改模式切换
828
+ def update_modify_ui(mode):
829
+ if mode in ["替换多行", "删除行", "调整缩进", "添加注释"]:
830
+ return (
831
+ gr.update(visible=False), # single_line_group
832
+ gr.update(visible=True), # range_group
833
+ gr.update(visible=False), # find_replace_group
834
+ gr.update(visible=mode=="调整缩进"), # indent_group
835
+ gr.update(visible=mode not in ["删除行", "调整缩进", "添加注释"]) # new_code_input
836
+ )
837
+ elif mode == "查找替换":
838
+ return (
839
+ gr.update(visible=False),
840
+ gr.update(visible=False),
841
+ gr.update(visible=True),
842
+ gr.update(visible=False),
843
+ gr.update(visible=False)
844
+ )
845
+ else: # 替换单行, 插入代码
846
+ return (
847
+ gr.update(visible=True),
848
+ gr.update(visible=False),
849
+ gr.update(visible=False),
850
+ gr.update(visible=False),
851
+ gr.update(visible=True)
852
+ )
853
+
854
+ modify_mode.change(
855
+ fn=update_modify_ui,
856
+ inputs=[modify_mode],
857
+ outputs=[single_line_group, range_group, find_replace_group, indent_group, new_code_input]
858
+ )
859
+
860
+ # 执行修改
861
+ def execute_modify(mode, line, start, end, new_code, find, replace, indent):
862
+ result = None
863
+
864
+ if mode == "替换单行":
865
+ result = engine.replace_line(int(line), new_code)
866
+ elif mode == "替换多行":
867
+ result = engine.replace_lines(int(start), int(end), new_code)
868
+ elif mode == "插入代码":
869
+ result = engine.insert_after(int(line), new_code)
870
+ elif mode == "删除行":
871
+ result = engine.delete_lines(int(start), int(end))
872
+ elif mode == "查找替换":
873
+ result = engine.find_replace(find, replace)
874
+ elif mode == "调整缩进":
875
+ result = engine.indent_lines(int(start), int(end), int(indent))
876
+ elif mode == "添加注释":
877
+ result = engine.comment_lines(int(start), int(end))
878
+
879
+ if result and result['success']:
880
+ # 更新代码编辑器
881
+ new_full_code = engine.get_current_code()
882
+ status = engine.auto_load(new_full_code)
883
+
884
+ diff = result.get('diff', result.get('changes', ''))
885
+ return (
886
+ result.get('message', '✅ 操作成功'),
887
+ diff,
888
+ new_full_code,
889
+ status
890
+ )
891
+
892
+ return (
893
+ result.get('error', '❌ 操作失败') if result else '❌ 未知错误',
894
+ '',
895
+ code_input.value,
896
+ status_display.value
897
+ )
898
+
899
+ execute_modify_btn.click(
900
+ fn=execute_modify,
901
+ inputs=[
902
+ modify_mode,
903
+ modify_line,
904
+ modify_start,
905
+ modify_end,
906
+ new_code_input,
907
+ find_text,
908
+ replace_text,
909
+ indent_spaces
910
+ ],
911
+ outputs=[modify_result, diff_output, code_input, status_display]
912
+ )
913
+
914
+ # 撤销
915
+ def undo_handler():
916
+ result = engine.undo()
917
+ if result['success']:
918
+ code = engine.get_current_code()
919
+ status = engine.auto_load(code)
920
+ return result['message'], code, status
921
+ return result['error'], code_input.value, status_display.value
922
+
923
+ undo_btn.click(
924
+ fn=undo_handler,
925
+ outputs=[modify_result, code_input, status_display]
926
+ )
927
+
928
+ # 刷新预览
929
+ def refresh_preview():
930
+ code = engine.get_current_code()
931
+ stats = f"总行数: {len(engine.lines)}\n修改次数: {len(engine.history)}\n语言: {engine.language}"
932
+ return code, stats
933
+
934
+ refresh_btn.click(
935
+ fn=refresh_preview,
936
+ outputs=[current_code_output, stats_output]
937
+ )
938
+
939
  return app
940
 
941
  if __name__ == "__main__":
942
+ app = create_ui()
943
+ app.launch(server_name="0.0.0.0", server_port=7860, share=True)