Initial commit with all project files

This commit is contained in:
TraeAI 2026-01-08 21:48:24 +08:00
commit 637c71ba40
36 changed files with 2138 additions and 0 deletions

4
.env Normal file
View File

@ -0,0 +1,4 @@
SILICONFLOW_API_KEY=sk-owfxudwvbipsofngckympnhtbcknwgqmoprgkfhbafeahmkv
SILICONFLOW_MODEL=deepseek-ai/DeepSeek-V2.5
APP_HOST=0.0.0.0
APP_PORT=8000

83
README.md Normal file
View File

@ -0,0 +1,83 @@
# 代码解释与修复助手 - AI编程学习工具
一个智能代码解释与修复工具,帮助编程学习者理解代码并提供修复建议。
## 功能特点
- **代码解释**: 对代码进行逐行或分段的详细解释
- **Bug修复**: 识别代码问题并提供修复建议
- **多语言支持**: 支持 Python、JavaScript、Java、C++、Go、Rust 等多种编程语言
- **图形界面**: 简洁美观的界面参考豆包AI问答方式
## 快速开始
### 安装依赖
```bash
# 安装核心依赖
pip install -r requirements.txt
# 安装图形界面依赖
pip install -r requirements_gui.txt
```
### 运行应用
#### 图形界面版本(推荐)
```bash
python gui_app.py
```
#### Web API 版本
```bash
python app.py
```
访问 http://localhost:8000 查看 API 文档
## 图形界面使用说明
1. 启动 `gui_app.py` 后,会弹出一个窗口
2. 在代码输入框中粘贴或输入您的代码
3. 选择任务类型:
- 📖 代码解释:获取代码的详细解释
- 🔧 代码修复:分析并修复代码问题
4. 选择编程语言(可选择 auto 自动检测)
5. 按 **Enter****Ctrl+Enter** 发送请求
6. 等待 AI 分析,结果会显示在下方
## 配置说明
在项目根目录创建 `.env` 文件:
```
# 硅基流动 API Key必需
SILICONFLOW_API_KEY=your_api_key_here
# 可选配置
SILICONFLOW_MODEL=deepseek-ai/DeepSeek-V2.5
```
获取 API Key访问 https://cloud.siliconflow.cn 注册账号
## 项目结构
```
code-explainer-fixer/
├── gui_app.py # 图形界面版本(推荐使用)
├── app.py # Web API 版本
├── config.py # 配置文件
├── requirements.txt # 核心依赖
├── requirements_gui.txt # GUI 依赖
├── .env # API 配置(需手动创建)
├── agents/ # 智能体模块
├── services/ # 服务层
├── models/ # 数据模型
└── utils/ # 工具函数
```
## 技术栈
- **图形界面**: CustomTkinter现代化Tkinter
- **AI 服务**: 硅基流动OpenAI 兼容 API
- **Web 框架**: FastAPI + Uvicorn

Binary file not shown.

Binary file not shown.

4
agents/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from .code_explainer import code_explainer
from .bug_fixer import bug_fixer
__all__ = ["code_explainer", "bug_fixer"]

Binary file not shown.

Binary file not shown.

Binary file not shown.

64
agents/bug_fixer.py Normal file
View File

@ -0,0 +1,64 @@
from services.ai_service import ai_service
from models.schemas import BugFix
from typing import Optional
import re
class BugFixer:
"""Bug修复智能体"""
def __init__(self):
self.service = ai_service
def fix(self, code: str, language: str, error_description: Optional[str] = None) -> BugFix:
"""修复代码问题"""
result = self.service.generate_fix(code, language, error_description)
fixed_code = result.get("fixed_code", "")
problems = self._extract_problems(result.get("analysis", ""))
fixes = self._extract_fixes(result.get("analysis", ""))
return BugFix(
original_code=code,
fixed_code=fixed_code or code,
problems_found=problems,
fixes_applied=fixes,
explanation=result.get("analysis", "")
)
def _extract_problems(self, analysis: str) -> list:
"""提取发现的问题"""
problems = []
lines = analysis.split('\n')
in_problems_section = False
for line in lines:
if any(keyword in line.lower() for keyword in ['问题', 'problem', '错误', 'issue', 'bug']):
if not in_problems_section:
in_problems_section = True
continue
if in_problems_section and line.strip():
if any(keyword in line.lower() for keyword in ['修复', 'fix', '建议', '建议', 'solution']):
break
problems.append(line.strip())
return problems if problems else ["代码可能存在问题"]
def _extract_fixes(self, analysis: str) -> list:
"""提取修复内容"""
fixes = []
lines = analysis.split('\n')
in_fixes_section = False
for line in lines:
if any(keyword in line.lower() for keyword in ['修复', 'fix', 'solution', '修改']):
in_fixes_section = True
continue
if in_fixes_section and line.strip():
if line.strip().startswith(('1.', '2.', '3.', '', '-', '*')):
fixes.append(line.strip())
return fixes if fixes else None
bug_fixer = BugFixer()

64
agents/code_explainer.py Normal file
View File

@ -0,0 +1,64 @@
from services.ai_service import ai_service
from models.schemas import CodeExplanation
from typing import List, Optional
class CodeExplainer:
"""代码解释智能体"""
def __init__(self):
self.service = ai_service
def explain(self, code: str, language: str, depth: str = "detailed") -> CodeExplanation:
"""解释代码"""
explanation_text = self.service.generate_explanation(code, language, depth)
return CodeExplanation(
explanation=explanation_text,
line_by_line=self._parse_line_explanations(explanation_text),
key_concepts=self._extract_concepts(explanation_text),
suggestions=self._extract_suggestions(explanation_text)
)
def _parse_line_explanations(self, explanation: str) -> List[dict]:
"""解析逐行解释"""
lines = explanation.split('\n')
parsed = []
current_item = {}
for line in lines:
if line.strip().startswith(('', 'Line', '')):
if current_item:
parsed.append(current_item)
current_item = {"line": line}
elif current_item:
current_item["explanation"] = current_item.get("explanation", "") + line + "\n"
if current_item:
parsed.append(current_item)
return parsed if parsed else None
def _extract_concepts(self, explanation: str) -> List[str]:
"""提取关键概念"""
import re
patterns = [
r'关键概念[:]\s*(.+?)(?:\n|$)',
r'概念[:]\s*(.+?)(?:\n|$)',
r'(?:concept|term|关键字)[s]*[:]\s*(.+?)(?:\n|$)'
]
concepts = []
for pattern in patterns:
matches = re.findall(pattern, explanation, re.IGNORECASE)
concepts.extend(matches)
return concepts if concepts else None
def _extract_suggestions(self, explanation: str) -> List[str]:
"""提取建议"""
import re
pattern = r'(?:建议|tips?|提示|最佳实践)[:]\s*(.+?)(?:\n|$)'
matches = re.findall(pattern, explanation, re.IGNORECASE)
return matches if matches else None
code_explainer = CodeExplainer()

135
app.py Normal file
View File

@ -0,0 +1,135 @@
"""
Code Explainer & Fixer - AI编程学习助手主应用
"""
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from contextlib import asynccontextmanager
from config import config
from models.schemas import CodeRequest, CodeResponse
from agents import code_explainer, bug_fixer
from utils import detect_language
@asynccontextmanager
async def lifespan(app: FastAPI):
yield
app = FastAPI(
title="代码解释与修复助手",
description="帮助编程学习者理解代码并提供修复建议的AI工具",
version="1.0.0",
lifespan=lifespan
)
# 配置静态文件服务
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/", response_class=HTMLResponse)
async def root():
return open("static/index.html", "r", encoding="utf-8").read()
@app.get("/health")
async def health_check():
return {"status": "healthy", "service": "code-explainer-fixer"}
@app.post("/explain", response_model=CodeResponse)
async def explain_code(request: CodeRequest):
"""解释代码功能"""
try:
if request.language not in config.SUPPORTED_LANGUAGES:
raise HTTPException(status_code=400, detail=f"不支持的语言: {request.language}")
explanation = code_explainer.explain(
code=request.code,
language=request.language,
depth=request.depth
)
return CodeResponse(
success=True,
task_type="explain",
result=explanation
)
except Exception as e:
return CodeResponse(
success=False,
task_type="explain",
result=None,
error=str(e)
)
@app.post("/fix", response_model=CodeResponse)
async def fix_code(request: CodeRequest):
"""修复代码问题"""
try:
if request.language not in config.SUPPORTED_LANGUAGES:
raise HTTPException(status_code=400, detail=f"不支持的语言: {request.language}")
fix_result = bug_fixer.fix(
code=request.code,
language=request.language
)
return CodeResponse(
success=True,
task_type="fix",
result=fix_result
)
except Exception as e:
return CodeResponse(
success=False,
task_type="fix",
result=None,
error=str(e)
)
@app.post("/auto", response_model=CodeResponse)
async def auto_process(request: CodeRequest):
"""自动检测并处理代码"""
try:
language = request.language
if language == "auto":
language = detect_language(request.code)
if language == "unknown":
raise HTTPException(status_code=400, detail="无法自动检测语言,请指定语言类型")
if request.task_type == "explain":
return await explain_code(CodeRequest(
code=request.code,
language=language,
task_type="explain",
depth=request.depth
))
else:
return await fix_code(CodeRequest(
code=request.code,
language=language,
task_type="fix"
))
except HTTPException:
raise
except Exception as e:
return CodeResponse(
success=False,
task_type=request.task_type,
result=None,
error=str(e)
)
def main():
"""主入口函数"""
print("🚀 启动代码解释与修复助手...")
print(f"🌐 服务地址: http://{config.APP_HOST}:{config.APP_PORT}")
print("📚 API文档: http://localhost:8000/docs")
uvicorn.run(
"app:app",
host=config.APP_HOST,
port=config.APP_PORT,
reload=True
)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,99 @@
Metadata-Version: 2.4
Name: code-explanation-fixer
Version: 0.1.0
Summary: 代码解释与修复助手
Requires-Python: <4.0,>=3.8
Description-Content-Type: text/markdown
Requires-Dist: openai>=1.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: fastapi>=0.100.0
Requires-Dist: uvicorn>=0.23.0
Requires-Dist: rich>=13.0.0
Requires-Dist: customtkinter>=5.2.0
Requires-Dist: streamlit>=1.20.0
Requires-Dist: httpx>=0.28.0
# 代码解释与修复助手 - AI编程学习工具
一个智能代码解释与修复工具,帮助编程学习者理解代码并提供修复建议。
## 功能特点
- **代码解释**: 对代码进行逐行或分段的详细解释
- **Bug修复**: 识别代码问题并提供修复建议
- **多语言支持**: 支持 Python、JavaScript、Java、C++、Go、Rust 等多种编程语言
- **图形界面**: 简洁美观的界面参考豆包AI问答方式
## 快速开始
### 安装依赖
```bash
# 安装核心依赖
pip install -r requirements.txt
# 安装图形界面依赖
pip install -r requirements_gui.txt
```
### 运行应用
#### 图形界面版本(推荐)
```bash
python gui_app.py
```
#### Web API 版本
```bash
python app.py
```
访问 http://localhost:8000 查看 API 文档
## 图形界面使用说明
1. 启动 `gui_app.py` 后,会弹出一个窗口
2. 在代码输入框中粘贴或输入您的代码
3. 选择任务类型:
- 📖 代码解释:获取代码的详细解释
- 🔧 代码修复:分析并修复代码问题
4. 选择编程语言(可选择 auto 自动检测)
5. 按 **Enter** 或 **Ctrl+Enter** 发送请求
6. 等待 AI 分析,结果会显示在下方
## 配置说明
在项目根目录创建 `.env` 文件:
```
# 硅基流动 API Key必需
SILICONFLOW_API_KEY=your_api_key_here
# 可选配置
SILICONFLOW_MODEL=deepseek-ai/DeepSeek-V2.5
```
获取 API Key访问 https://cloud.siliconflow.cn 注册账号
## 项目结构
```
code-explainer-fixer/
├── gui_app.py # 图形界面版本(推荐使用)
├── app.py # Web API 版本
├── config.py # 配置文件
├── requirements.txt # 核心依赖
├── requirements_gui.txt # GUI 依赖
├── .env # API 配置(需手动创建)
├── agents/ # 智能体模块
├── services/ # 服务层
├── models/ # 数据模型
└── utils/ # 工具函数
```
## 技术栈
- **图形界面**: CustomTkinter现代化Tkinter
- **AI 服务**: 硅基流动OpenAI 兼容 API
- **Web 框架**: FastAPI + Uvicorn

View File

@ -0,0 +1,16 @@
README.md
pyproject.toml
agents/__init__.py
agents/bug_fixer.py
agents/code_explainer.py
code_explanation_fixer.egg-info/PKG-INFO
code_explanation_fixer.egg-info/SOURCES.txt
code_explanation_fixer.egg-info/dependency_links.txt
code_explanation_fixer.egg-info/requires.txt
code_explanation_fixer.egg-info/top_level.txt
models/__init__.py
models/schemas.py
services/__init__.py
services/ai_service.py
utils/__init__.py
utils/code_parser.py

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,9 @@
openai>=1.0.0
python-dotenv>=1.0.0
pydantic>=2.0.0
fastapi>=0.100.0
uvicorn>=0.23.0
rich>=13.0.0
customtkinter>=5.2.0
streamlit>=1.20.0
httpx>=0.28.0

View File

@ -0,0 +1,4 @@
agents
models
services
utils

54
config.py Normal file
View File

@ -0,0 +1,54 @@
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
# 硅基流动 API 配置
SILICONFLOW_API_KEY = os.getenv("SILICONFLOW_API_KEY")
SILICONFLOW_BASE_URL = os.getenv("SILICONFLOW_BASE_URL", "https://api.siliconflow.cn/v1")
SILICONFLOW_MODEL = os.getenv("SILICONFLOW_MODEL", "deepseek-ai/DeepSeek-V2.5")
# OpenAI 兼容配置(保留但默认使用 SiliconFlow
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4")
# 应用配置
APP_HOST = os.getenv("APP_HOST", "0.0.0.0")
APP_PORT = int(os.getenv("APP_PORT", "8000"))
# 支持的编程语言
SUPPORTED_LANGUAGES = [
"python",
"javascript",
"typescript",
"java",
"cpp",
"c",
"go",
"rust",
"ruby",
"php"
]
# 解释详细程度
EXPLANATION_DEPTH = {
"basic": "简单解释每行代码的作用",
"detailed": "详细解释,包括语法、原理和最佳实践",
"comprehensive": "全面深入的分析,包括复杂度、性能考虑等"
}
# 硅基流动支持的模型列表
SILICONFLOW_MODELS = [
"deepseek-ai/DeepSeek-V2.5",
"deepseek-ai/DeepSeek-V2",
"Qwen/Qwen2.5-72B-Instruct",
"Qwen/Qwen2.5-32B-Instruct",
"Qwen/Qwen2.5-7B-Instruct",
"01-ai/Yi-1.5-34B-Chat",
"01-ai/Yi-1.5-9B-Chat",
"meta-llama/Llama-3.1-405B-Instruct",
"meta-llama/Llama-3.1-70B-Instruct"
]
config = Config()

352
gui_app.py Normal file
View File

@ -0,0 +1,352 @@
import customtkinter as ctk
from tkinter import scrolledtext
import threading
import queue
import time
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
SILICONFLOW_API_KEY = os.getenv("SILICONFLOW_API_KEY")
SILICONFLOW_BASE_URL = os.getenv("SILICONFLOW_BASE_URL", "https://api.siliconflow.cn/v1")
SILICONFLOW_MODEL = os.getenv("SILICONFLOW_MODEL", "deepseek-ai/DeepSeek-V2.5")
config = Config()
class CodeExplanationApp(ctk.CTk):
def __init__(self):
super().__init__()
self.title("代码解释与修复助手")
self.geometry("1100x750")
self.resizable(True, True)
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")
self.setup_ui()
self.message_queue = queue.Queue()
self.check_queue()
def setup_ui(self):
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.main_frame = ctk.CTkFrame(self, corner_radius=0)
self.main_frame.grid(row=0, column=0, sticky="nsew")
self.main_frame.grid_columnconfigure(0, weight=1)
self.main_frame.grid_rowconfigure(0, weight=1)
self.header_frame = ctk.CTkFrame(self.main_frame, height=50, corner_radius=0)
self.header_frame.grid(row=0, column=0, sticky="ew", padx=0, pady=0)
self.header_frame.grid_columnconfigure(0, weight=1)
self.title_label = ctk.CTkLabel(
self.header_frame,
text="🤖 代码解释与修复助手",
font=("Microsoft YaHei", 20, "bold")
)
self.title_label.grid(row=0, column=0, padx=15, pady=12)
self.content_frame = ctk.CTkFrame(self.main_frame, corner_radius=0)
self.content_frame.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
self.content_frame.grid_columnconfigure(0, weight=2)
self.content_frame.grid_columnconfigure(1, weight=3)
self.content_frame.grid_rowconfigure(0, weight=1)
self.left_panel = ctk.CTkFrame(self.content_frame, corner_radius=8)
self.left_panel.grid(row=0, column=0, sticky="nsew", padx=(0, 8))
self.left_panel.grid_columnconfigure(0, weight=1)
self.left_panel.grid_rowconfigure(0, weight=1)
self.left_panel.grid_rowconfigure(1, weight=1)
self.input_frame = ctk.CTkFrame(self.left_panel, corner_radius=6)
self.input_frame.grid(row=0, column=0, sticky="nsew", padx=8, pady=8)
self.input_frame.grid_columnconfigure(0, weight=1)
self.input_frame.grid_rowconfigure(1, weight=1)
self.input_label = ctk.CTkLabel(
self.input_frame,
text="📝 输入您的代码:",
font=("Microsoft YaHei", 13, "bold")
)
self.input_label.grid(row=0, column=0, sticky="w", padx=10, pady=(8, 4))
self.code_input = ctk.CTkTextbox(
self.input_frame,
font=("Consolas", 13),
corner_radius=6
)
self.code_input.grid(row=1, column=0, sticky="nsew", padx=10, pady=(0, 8))
self.button_frame = ctk.CTkFrame(self.left_panel, corner_radius=6)
self.button_frame.grid(row=1, column=0, sticky="ew", padx=8, pady=(0, 8))
self.button_frame.grid_columnconfigure(0, weight=1)
self.options_frame = ctk.CTkFrame(self.button_frame, corner_radius=6)
self.options_frame.grid(row=0, column=0, sticky="ew", padx=8, pady=8)
self.options_frame.grid_columnconfigure((0, 1, 2), weight=1)
self.task_type = ctk.StringVar(value="explain")
ctk.CTkRadioButton(
self.options_frame,
text="<EFBFBD> 代码解释",
variable=self.task_type,
value="explain",
font=("Microsoft YaHei", 11)
).grid(row=0, column=0, padx=15, pady=6)
ctk.CTkRadioButton(
self.options_frame,
text="<EFBFBD> 代码修复",
variable=self.task_type,
value="fix",
font=("Microsoft YaHei", 11)
).grid(row=0, column=1, padx=15, pady=6)
self.language_var = ctk.StringVar(value="auto")
self.language_combo = ctk.CTkComboBox(
self.options_frame,
values=["auto", "python", "javascript", "java", "cpp", "c", "go", "rust", "ruby", "php"],
variable=self.language_var,
font=("Microsoft YaHei", 11)
)
self.language_combo.grid(row=0, column=2, padx=15, pady=6)
self.button_inner_frame = ctk.CTkFrame(self.button_frame, corner_radius=0, fg_color="transparent")
self.button_inner_frame.grid(row=1, column=0, sticky="e", padx=8, pady=(0, 8))
self.submit_button = ctk.CTkButton(
self.button_inner_frame,
text="<EFBFBD> 开始分析",
command=self.on_submit_clicked,
font=("Microsoft YaHei", 12, "bold"),
height=30,
corner_radius=6
)
self.submit_button.grid(row=0, column=0, padx=4)
self.clear_button = ctk.CTkButton(
self.button_inner_frame,
text="<EFBFBD> 清空",
command=self.on_clear_clicked,
font=("Microsoft YaHei", 11),
height=30,
corner_radius=6,
fg_color="gray",
hover_color="darkgray"
)
self.clear_button.grid(row=0, column=1, padx=4)
self.right_panel = ctk.CTkFrame(self.content_frame, corner_radius=8)
self.right_panel.grid(row=0, column=1, sticky="nsew", padx=(8, 0))
self.right_panel.grid_columnconfigure(0, weight=1)
self.right_panel.grid_rowconfigure(0, weight=1)
self.right_panel.grid_rowconfigure(1, weight=2)
self.process_frame = ctk.CTkFrame(self.right_panel, corner_radius=6)
self.process_frame.grid(row=0, column=0, sticky="nsew", padx=8, pady=8)
self.process_frame.grid_columnconfigure(0, weight=1)
self.process_frame.grid_rowconfigure(1, weight=1)
self.process_label = ctk.CTkLabel(
self.process_frame,
text="⚙️ 进程状态",
font=("Microsoft YaHei", 13, "bold")
)
self.process_label.grid(row=0, column=0, sticky="w", padx=10, pady=(8, 4))
self.process_text = ctk.CTkTextbox(
self.process_frame,
font=("Consolas", 11),
corner_radius=6,
state="disabled"
)
self.process_text.grid(row=1, column=0, sticky="nsew", padx=10, pady=(0, 8))
self.result_frame = ctk.CTkFrame(self.right_panel, corner_radius=6)
self.result_frame.grid(row=1, column=0, sticky="nsew", padx=8, pady=(0, 8))
self.result_frame.grid_columnconfigure(0, weight=1)
self.result_frame.grid_rowconfigure(1, weight=1)
self.result_label = ctk.CTkLabel(
self.result_frame,
text="💡 AI 分析结果",
font=("Microsoft YaHei", 13, "bold")
)
self.result_label.grid(row=0, column=0, sticky="w", padx=10, pady=(8, 4))
self.result_text = ctk.CTkTextbox(
self.result_frame,
font=("Microsoft YaHei", 12),
corner_radius=6,
state="disabled"
)
self.result_text.grid(row=1, column=0, sticky="nsew", padx=10, pady=(0, 8))
self.status_label = ctk.CTkLabel(
self,
text="就绪 - 请输入代码后点击「🚀 开始分析」按钮",
font=("Microsoft YaHei", 10)
)
self.status_label.grid(row=2, column=0, sticky="ew", padx=15, pady=(0, 8))
def log_process(self, message):
self.process_text.configure(state="normal")
timestamp = time.strftime("%H:%M:%S", time.localtime())
self.process_text.insert("end", f"[{timestamp}] {message}\n")
self.process_text.see("end")
self.process_text.configure(state="disabled")
def on_submit_clicked(self):
code = self.code_input.get("0.0", "end").strip()
if code:
self.process_code(code)
else:
self.status_label.configure(text="请先输入代码!")
def on_clear_clicked(self):
self.code_input.delete("0.0", "end")
self.result_text.configure(state="normal")
self.result_text.delete("0.0", "end")
self.result_text.configure(state="disabled")
self.process_text.configure(state="normal")
self.process_text.delete("0.0", "end")
self.process_text.configure(state="disabled")
self.status_label.configure(text="已清空,请输入新的代码")
def process_code(self, code):
task = self.task_type.get()
language = self.language_var.get()
self.process_text.configure(state="normal")
self.process_text.delete("0.0", "end")
self.process_text.configure(state="disabled")
self.log_process("🚀 任务已启动")
self.log_process(f"📋 任务类型: {'代码解释' if task == 'explain' else '代码修复'}")
self.log_process(f"🌐 检测语言: {language}")
self.log_process(f"📏 代码长度: {len(code)} 字符")
self.status_label.configure(text="正在处理...")
self.result_text.configure(state="normal")
self.result_text.delete("0.0", "end")
self.result_text.insert("0.0", "🚀 正在实时生成响应...\n\n")
self.result_text.configure(state="disabled")
threading.Thread(target=self.call_ai, args=(code, task, language), daemon=True).start()
def call_ai(self, code, task, language):
try:
api_key = config.SILICONFLOW_API_KEY
if not api_key:
self.message_queue.put(("error", "请在 .env 文件中设置 SILICONFLOW_API_KEY"))
return
self.log_process("🔌 正在连接 SiliconFlow API...")
self.log_process(f"🤖 使用模型: {config.SILICONFLOW_MODEL}")
client = OpenAI(api_key=api_key, base_url=config.SILICONFLOW_BASE_URL)
if task == "explain":
prompt = f"""
请作为一位耐心的编程导师解释以下{language}代码
请提供
1. 代码整体功能的概述
2. 逐行或分段的详细解释
3. 关键概念和语法的说明
4. 相关的最佳实践建议
代码
```{language}
{code}
```
"""
else:
prompt = f"""
请作为一位经验丰富的开发者分析并修复以下{language}代码中的问题
请提供
1. 发现的问题列表
2. 修复后的完整代码
3. 每个修复的详细说明
4. 相关的最佳实践建议
代码
```{language}
{code}
```
"""
self.log_process("📤 正在发送请求...")
start_time = time.time()
stream = client.chat.completions.create(
model=config.SILICONFLOW_MODEL,
messages=[{"role": "user", "content": prompt}],
temperature=0.7 if task == "explain" else 0.5,
stream=True
)
self.log_process("📥 正在接收响应...")
full_response = ""
chunk_count = 0
for chunk in stream:
if chunk.choices[0].delta.content:
content = chunk.choices[0].delta.content
full_response += content
chunk_count += 1
self.message_queue.put(("stream", content))
elapsed_time = time.time() - start_time
self.log_process(f"✅ 响应接收完成")
self.log_process(f"📊 收到 {chunk_count} 个数据块")
self.log_process(f"⏱️ 耗时: {elapsed_time:.2f}")
self.log_process(f"📏 结果长度: {len(full_response)} 字符")
self.message_queue.put(("success", full_response))
except Exception as e:
self.log_process(f"❌ 发生错误: {str(e)}")
self.message_queue.put(("error", f"调用 AI 服务失败:{str(e)}"))
def check_queue(self):
try:
while not self.message_queue.empty():
msg_type, content = self.message_queue.get_nowait()
if msg_type == "stream":
self.result_text.configure(state="normal")
self.result_text.insert("end", content)
self.result_text.see("end")
self.result_text.configure(state="disabled")
self.status_label.configure(text="正在生成响应中...")
else:
self.result_text.configure(state="normal")
if msg_type == "success":
if content and not content.startswith(""):
self.result_text.insert("end", f"\n\n{content}")
self.status_label.configure(text="✅ 处理完成")
self.log_process("🎉 任务完成!")
else:
self.result_text.insert("end", f"\n\n❌ 错误:{content}")
self.status_label.configure(text="❌ 发生错误")
self.result_text.configure(state="disabled")
except:
pass
self.after(50, self.check_queue)
def main():
app = CodeExplanationApp()
app.mainloop()
if __name__ == "__main__":
main()

9
models/__init__.py Normal file
View File

@ -0,0 +1,9 @@
from .schemas import CodeRequest, CodeExplanation, BugFix, CodeResponse, ChatMessage
__all__ = [
"CodeRequest",
"CodeExplanation",
"BugFix",
"CodeResponse",
"ChatMessage"
]

Binary file not shown.

Binary file not shown.

31
models/schemas.py Normal file
View File

@ -0,0 +1,31 @@
from typing import List, Optional
from pydantic import BaseModel
class CodeRequest(BaseModel):
code: str
language: str
task_type: str # "explain" 或 "fix"
depth: str = "detailed"
class CodeExplanation(BaseModel):
explanation: str
line_by_line: Optional[List[dict]] = None
key_concepts: Optional[List[str]] = None
suggestions: Optional[List[str]] = None
class BugFix(BaseModel):
original_code: str
fixed_code: str
problems_found: List[str]
fixes_applied: List[str]
explanation: str
class CodeResponse(BaseModel):
success: bool
task_type: str
result: CodeExplanation | BugFix
error: Optional[str] = None
class ChatMessage(BaseModel):
role: str
content: str

32
pyproject.toml Normal file
View File

@ -0,0 +1,32 @@
[project]
name = "code-explanation-fixer"
version = "0.1.0"
description = "代码解释与修复助手"
authors = []
readme = "README.md"
requires-python = ">=3.8,<4.0"
dependencies = [
"openai>=1.0.0",
"python-dotenv>=1.0.0",
"pydantic>=2.0.0",
"fastapi>=0.100.0",
"uvicorn>=0.23.0",
"rich>=13.0.0",
"customtkinter>=5.2.0",
"streamlit>=1.20.0", # 添加Streamlit依赖
"httpx>=0.28.0", # 添加HTTP客户端依赖
]
[tool.setuptools.packages.find]
where = ["."]
exclude = ["static"] # 排除static目录它不是Python包
[tool.uv]
required-version = "0.9.22"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.pytest.ini_options]
pythonpath = "."

3
services/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from .ai_service import ai_service
__all__ = ["ai_service"]

Binary file not shown.

Binary file not shown.

87
services/ai_service.py Normal file
View File

@ -0,0 +1,87 @@
from openai import OpenAI
from config import config
from typing import Optional
class AIService:
def __init__(self):
api_key = config.SILICONFLOW_API_KEY or config.OPENAI_API_KEY
base_url = config.SILICONFLOW_BASE_URL
if not api_key:
raise ValueError("请设置 SILICONFLOW_API_KEY 或 OPENAI_API_KEY 环境变量")
self.client = OpenAI(
api_key=api_key,
base_url=base_url
)
self.model = config.SILICONFLOW_MODEL
def generate_explanation(self, code: str, language: str, depth: str) -> str:
"""生成代码解释"""
depth_instruction = config.EXPLANATION_DEPTH.get(depth, config.EXPLANATION_DEPTH["detailed"])
prompt = f"""
请作为一位耐心的编程导师解释以下{language}代码
解释要求{depth_instruction}
代码
```{language}
{code}
```
请提供
1. 代码整体功能的概述
2. 逐行或分段的详细解释
3. 关键概念和语法的说明
4. 相关的最佳实践建议
"""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0.7
)
return response.choices[0].message.content
def generate_fix(self, code: str, language: str, error_description: Optional[str] = None) -> dict:
"""生成代码修复建议"""
prompt = f"""
请作为一位经验丰富的开发者分析并修复以下{language}代码中的问题
{('错误描述: ' + error_description) if error_description else ''}
代码
```{language}
{code}
```
请提供
1. 发现的问题列表
2. 修复后的完整代码
3. 每个修复的详细说明
4. 相关的最佳实践建议
"""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0.5
)
content = response.choices[0].message.content
return {
"analysis": content,
"fixed_code": self._extract_code_from_response(content)
}
def _extract_code_from_response(self, response: str) -> str:
"""从AI响应中提取代码块"""
import re
pattern = r'```[\w]*\n([\s\S]*?)```'
matches = re.findall(pattern, response)
return matches[0] if matches else ""
ai_service = AIService()

112
static/index.html Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>代码解释与修复助手</title>
<link rel="stylesheet" href="styles.css">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<!-- 顶部标题栏 -->
<header class="header">
<div class="title-section">
<i class="fas fa-code header-icon"></i>
<h1>代码解释与修复助手</h1>
</div>
<p class="subtitle">帮助编程学习者理解代码并提供修复建议的AI工具</p>
</header>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧输入面板 -->
<div class="panel input-panel">
<div class="panel-header">
<h2><i class="fas fa-edit"></i> 代码输入</h2>
</div>
<div class="form-group">
<label for="codeInput"><i class="fas fa-code"></i> 请输入您的代码:</label>
<textarea id="codeInput" placeholder="在此输入您需要分析的代码..."></textarea>
</div>
<div class="options-container">
<div class="form-group">
<label for="languageSelect"><i class="fas fa-language"></i> 编程语言:</label>
<select id="languageSelect">
<option value="python">Python</option>
<option value="javascript">JavaScript</option>
<option value="typescript">TypeScript</option>
<option value="java">Java</option>
<option value="cpp">C++</option>
<option value="c">C</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="ruby">Ruby</option>
<option value="php">PHP</option>
</select>
</div>
<div class="form-group">
<label for="taskTypeSelect"><i class="fas fa-tasks"></i> 任务类型:</label>
<select id="taskTypeSelect">
<option value="explain">代码解释</option>
<option value="fix">代码修复</option>
</select>
</div>
<div class="form-group" id="depthGroup">
<label for="depthSelect"><i class="fas fa-depth-chart"></i> 详细程度:</label>
<select id="depthSelect">
<option value="basic">基础</option>
<option value="detailed" selected>详细</option>
<option value="comprehensive">全面</option>
</select>
</div>
</div>
<div class="button-group">
<button id="startBtn" class="btn btn-primary">
<i class="fas fa-play"></i> 开始分析
</button>
<button id="clearBtn" class="btn btn-secondary">
<i class="fas fa-trash"></i> 清空
</button>
</div>
</div>
<!-- 右侧结果面板 -->
<div class="panel result-panel">
<div class="panel-header">
<h2><i class="fas fa-clipboard-check"></i> 分析结果</h2>
<div id="statusIndicator" class="status status-idle">
<i class="fas fa-circle"></i> 就绪
</div>
</div>
<div class="result-container">
<div id="loadingIndicator" class="loading" style="display: none;">
<div class="spinner"></div>
<p>正在分析代码...请稍候</p>
</div>
<div id="resultContent" class="result-content">
<div class="empty-state">
<i class="fas fa-lightbulb"></i>
<p>输入代码并点击"开始分析"按钮获取AI分析结果</p>
</div>
</div>
</div>
</div>
</div>
<!-- 底部信息 -->
<footer class="footer">
<p>&copy; 2026 代码解释与修复助手 | 基于硅基流动AI服务</p>
</footer>
</div>
<script src="script.js"></script>
</body>
</html>

204
static/script.js Normal file
View File

@ -0,0 +1,204 @@
// 代码解释与修复助手 - 前端JavaScript交互逻辑
// DOM元素
const codeInput = document.getElementById('codeInput');
const languageSelect = document.getElementById('languageSelect');
const taskTypeSelect = document.getElementById('taskTypeSelect');
const depthSelect = document.getElementById('depthSelect');
const depthGroup = document.getElementById('depthGroup');
const startBtn = document.getElementById('startBtn');
const clearBtn = document.getElementById('clearBtn');
const statusIndicator = document.getElementById('statusIndicator');
const loadingIndicator = document.getElementById('loadingIndicator');
const resultContent = document.getElementById('resultContent');
// 任务类型切换
function toggleDepthOption() {
if (taskTypeSelect.value === 'explain') {
depthGroup.style.display = 'block';
} else {
depthGroup.style.display = 'none';
}
}
// 初始化事件监听
function initEventListeners() {
// 任务类型选择变化
taskTypeSelect.addEventListener('change', toggleDepthOption);
// 开始分析按钮
startBtn.addEventListener('click', analyzeCode);
// 清空按钮
clearBtn.addEventListener('click', clearAll);
// 键盘快捷键
codeInput.addEventListener('keydown', (e) => {
// Ctrl+Enter 或 Cmd+Enter 触发分析
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
e.preventDefault();
analyzeCode();
}
});
}
// 更新状态显示
function updateStatus(status, message) {
statusIndicator.className = `status status-${status}`;
statusIndicator.innerHTML = `<i class="fas fa-circle"></i> ${message}`;
}
// 显示加载状态
function showLoading() {
loadingIndicator.style.display = 'flex';
resultContent.style.display = 'none';
}
// 隐藏加载状态
function hideLoading() {
loadingIndicator.style.display = 'none';
resultContent.style.display = 'block';
}
// 显示结果
function showResult(data) {
if (data.success) {
resultContent.innerHTML = `
<div class="result-header">
<h3>
<i class="fas fa-check-circle success-icon"></i>
分析完成
</h3>
<div class="task-info">
<span class="language-tag">${getLanguageName(languageSelect.value)}</span>
<span class="task-type">${taskTypeSelect.value === 'explain' ? '代码解释' : '代码修复'}</span>
</div>
</div>
<div class="result-body">
${formatResult(data.result)}
</div>
`;
} else {
resultContent.innerHTML = `
<div class="error-state">
<i class="fas fa-exclamation-circle error-icon"></i>
<h3>分析失败</h3>
<p class="error-message">${data.error || '发生未知错误'}</p>
</div>
`;
}
}
// 格式化结果为HTML
function formatResult(result) {
if (!result) return '<p>无结果</p>';
// 简单的Markdown到HTML转换
let html = result
.replace(/^# (.*$)/gm, '<h3>$1</h3>')
.replace(/^## (.*$)/gm, '<h4>$1</h4>')
.replace(/`(.*?)`/g, '<code>$1</code>')
.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
.replace(/\n/g, '<br>');
return html;
}
// 获取语言名称
function getLanguageName(langCode) {
const languages = {
'python': 'Python',
'javascript': 'JavaScript',
'typescript': 'TypeScript',
'java': 'Java',
'cpp': 'C++',
'c': 'C',
'go': 'Go',
'rust': 'Rust',
'ruby': 'Ruby',
'php': 'PHP'
};
return languages[langCode] || langCode;
}
// 分析代码
async function analyzeCode() {
const code = codeInput.value.trim();
const language = languageSelect.value;
const taskType = taskTypeSelect.value;
const depth = taskType === 'explain' ? depthSelect.value : undefined;
// 验证输入
if (!code) {
alert('请输入代码后再进行分析');
codeInput.focus();
return;
}
// 更新状态
updateStatus('loading', '正在分析...');
showLoading();
try {
// 发送请求
const response = await fetch('/auto', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
code: code,
language: language,
task_type: taskType,
depth: depth
})
});
const data = await response.json();
// 显示结果
hideLoading();
showResult(data);
updateStatus(data.success ? 'success' : 'error', data.success ? '分析完成' : '分析失败');
} catch (error) {
hideLoading();
updateStatus('error', '请求失败');
resultContent.innerHTML = `
<div class="error-state">
<i class="fas fa-exclamation-circle error-icon"></i>
<h3>网络错误</h3>
<p class="error-message">无法连接到服务器请检查网络连接</p>
</div>
`;
console.error('请求错误:', error);
}
}
// 清空所有内容
function clearAll() {
codeInput.value = '';
languageSelect.value = 'python';
taskTypeSelect.value = 'explain';
depthSelect.value = 'detailed';
toggleDepthOption();
resultContent.innerHTML = `
<div class="empty-state">
<i class="fas fa-lightbulb"></i>
<p>输入代码并点击"开始分析"按钮获取AI分析结果</p>
</div>
`;
updateStatus('idle', '就绪');
codeInput.focus();
}
// 初始化应用
function initApp() {
toggleDepthOption();
initEventListeners();
codeInput.focus();
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initApp);

370
static/styles.css Normal file
View File

@ -0,0 +1,370 @@
/* 全局样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
line-height: 1.6;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
/* 头部样式 */
.header {
background: rgba(255, 255, 255, 0.95);
padding: 30px;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
margin-bottom: 30px;
text-align: center;
}
.title-section {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 10px;
}
.header-icon {
font-size: 2.5rem;
color: #667eea;
}
.header h1 {
font-size: 2.5rem;
color: #4a5568;
font-weight: 700;
}
.subtitle {
font-size: 1.1rem;
color: #718096;
font-weight: 400;
}
/* 主要内容区域 */
.main-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 30px;
}
/* 面板样式 */
.panel {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
overflow: hidden;
display: flex;
flex-direction: column;
}
.panel-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 30px;
display: flex;
justify-content: space-between;
align-items: center;
}
.panel-header h2 {
font-size: 1.5rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 10px;
}
/* 输入面板样式 */
.input-panel {
min-height: 700px;
}
.form-group {
padding: 20px 30px;
}
.form-group label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #4a5568;
display: flex;
align-items: center;
gap: 8px;
}
.form-group textarea,
.form-group select {
width: 100%;
padding: 15px;
border: 2px solid #e2e8f0;
border-radius: 10px;
font-size: 1rem;
font-family: 'Courier New', Courier, monospace;
resize: vertical;
transition: border-color 0.3s ease;
}
.form-group textarea {
min-height: 300px;
line-height: 1.6;
}
.form-group select {
height: 50px;
background-color: white;
}
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.options-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
padding: 0 30px;
}
.button-group {
display: flex;
gap: 15px;
padding: 20px 30px;
margin-top: auto;
}
/* 按钮样式 */
.btn {
flex: 1;
padding: 15px 30px;
border: none;
border-radius: 10px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
transition: all 0.3s ease;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}
.btn-secondary {
background-color: #e2e8f0;
color: #4a5568;
}
.btn-secondary:hover {
background-color: #cbd5e0;
transform: translateY(-2px);
}
/* 结果面板样式 */
.result-panel {
min-height: 700px;
}
.status {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
padding: 8px 15px;
border-radius: 20px;
}
.status-idle {
background-color: rgba(255, 255, 255, 0.2);
color: white;
}
.status-processing {
background-color: rgba(255, 255, 0, 0.2);
color: #f59e0b;
}
.status-success {
background-color: rgba(0, 255, 0, 0.2);
color: #10b981;
}
.status-error {
background-color: rgba(255, 0, 0, 0.2);
color: #ef4444;
}
.result-container {
padding: 30px;
flex: 1;
display: flex;
flex-direction: column;
}
/* 加载指示器 */
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 50px 0;
gap: 20px;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid #e2e8f0;
border-top: 5px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 结果内容 */
.result-content {
flex: 1;
overflow-y: auto;
max-height: 500px;
}
.empty-state {
text-align: center;
padding: 80px 0;
color: #a0aec0;
}
.empty-state i {
font-size: 4rem;
margin-bottom: 20px;
}
/* 结果文本样式 */
.result-text {
white-space: pre-wrap;
font-family: 'Courier New', Courier, monospace;
line-height: 1.8;
color: #4a5568;
}
/* 底部信息 */
.footer {
background: rgba(255, 255, 255, 0.95);
padding: 20px 30px;
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
text-align: center;
color: #718096;
font-size: 0.9rem;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.main-content {
grid-template-columns: 1fr;
}
.header h1 {
font-size: 2rem;
}
.header-icon {
font-size: 2rem;
}
}
@media (max-width: 768px) {
.container {
padding: 15px;
}
.header {
padding: 20px;
}
.header h1 {
font-size: 1.8rem;
}
.subtitle {
font-size: 1rem;
}
.panel {
margin-bottom: 20px;
}
.panel-header {
padding: 15px 20px;
}
.form-group {
padding: 15px 20px;
}
.options-container {
grid-template-columns: 1fr;
padding: 0 20px;
}
.button-group {
padding: 15px 20px;
}
.result-container {
padding: 20px;
}
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #a1a1a1;
}

309
streamlit_app.py Normal file
View File

@ -0,0 +1,309 @@
import streamlit as st
import time
from config import config
from agents import code_explainer, bug_fixer
from utils import detect_language
# 设置页面配置
st.set_page_config(
page_title="代码解释与修复助手",
page_icon="🤖",
layout="wide",
initial_sidebar_state="expanded"
)
# 自定义CSS样式
st.markdown("""
<style>
/* 全局样式 */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
}
/* 标题样式 */
.stApp h1 {
color: #2c3e50;
font-size: 2.5rem;
margin-bottom: 1rem;
text-align: center;
}
.stApp h2 {
color: #34495e;
font-size: 1.5rem;
margin-top: 1.5rem;
margin-bottom: 1rem;
}
/* 容器样式 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
/* 卡片样式 */
.card {
background-color: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
margin-bottom: 1.5rem;
}
/* 按钮样式 */
.stButton > button {
background-color: #3498db;
color: white;
border: none;
border-radius: 8px;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s ease;
}
.stButton > button:hover {
background-color: #2980b9;
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(52, 152, 219, 0.3);
}
/* 输入区域样式 */
.stTextArea > div > div {
border-radius: 8px;
border: 2px solid #e0e0e0;
}
.stTextArea > div > div:focus-within {
border-color: #3498db;
}
/* 选择框样式 */
.stSelectbox > div > div {
border-radius: 8px;
border: 2px solid #e0e0e0;
}
/* 结果区域样式 */
.result-container {
background-color: #f8f9fa;
border-radius: 8px;
padding: 1.5rem;
margin-top: 1rem;
border-left: 4px solid #3498db;
}
/* 错误提示样式 */
.error-container {
background-color: #fff5f5;
border-radius: 8px;
padding: 1.5rem;
margin-top: 1rem;
border-left: 4px solid #e74c3c;
color: #c0392b;
}
/* 加载动画样式 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
}
/* 响应式布局 */
@media (max-width: 768px) {
.container {
padding: 1rem;
}
.stApp h1 {
font-size: 2rem;
}
}
</style>
""", unsafe_allow_html=True)
# 页面标题和描述
st.title("🤖 代码解释与修复助手")
st.markdown("""
<div style='text-align: center; color: #6c757d; font-size: 1.1rem; margin-bottom: 2rem;'>
输入您的代码选择功能AI将为您提供专业的代码解释或修复建议
</div>
""", unsafe_allow_html=True)
# 创建两列布局
col1, col2 = st.columns([1, 1], gap="large")
# 左侧:输入区域
with col1:
with st.container():
st.subheader("📝 代码输入")
# 代码输入框
code_input = st.text_area(
"请输入您需要分析的代码:",
height=300,
placeholder="在此输入您的代码...\n例如:\ndef hello():\n print('Hello World')",
label_visibility="collapsed"
)
# 语言选择
language = st.selectbox(
"编程语言:",
options=[(lang.capitalize(), lang) for lang in config.SUPPORTED_LANGUAGES],
format_func=lambda x: x[0],
key="language"
)
# 任务类型选择
task_type = st.selectbox(
"任务类型:",
options=[("代码解释", "explain"), ("代码修复", "fix")],
format_func=lambda x: x[0],
key="task_type"
)
# 解释详细程度(仅在代码解释时显示)
depth = None
if task_type[1] == "explain":
# 使用简单的字符串选项,完全避免元组带来的状态管理问题
depth_options = ["基础", "详细", "全面"]
depth_values = {"基础": "basic", "详细": "detailed", "全面": "comprehensive"}
# 设置默认值为"详细"
depth_str = st.select_slider(
"解释详细程度:",
options=depth_options,
value="详细",
key="depth_str"
)
# 构建需要的返回值格式
depth = (depth_str, depth_values[depth_str])
# 开始分析按钮
start_button = st.button(
"🚀 开始分析",
type="primary",
use_container_width=True
)
# 右侧:结果区域
with col2:
with st.container():
st.subheader("📊 分析结果")
# 结果显示区域
result_placeholder = st.empty()
# 初始状态
with result_placeholder.container():
st.markdown("""
<div style='text-align: center; color: #95a5a6; padding: 3rem 0;'>
<div style='font-size: 3rem; margin-bottom: 1rem;'>💡</div>
<p style='font-size: 1.1rem;'>输入代码并点击"开始分析"按钮获取AI分析结果</p>
</div>
""", unsafe_allow_html=True)
# 处理分析请求
if start_button:
# 验证输入
if not code_input.strip():
with result_placeholder.container():
st.error("请输入代码后再进行分析!")
else:
# 显示加载状态
with result_placeholder.container():
with st.spinner("🤖 AI正在分析代码...请稍候"):
# 添加视觉反馈
loading_bar = st.progress(0)
for i in range(100):
time.sleep(0.01) # 模拟进度
loading_bar.progress(i + 1)
try:
# 调用相应的处理函数
if task_type[1] == "explain":
# 代码解释
result = code_explainer.explain(
code=code_input,
language=language[1],
depth=depth[1]
)
# 显示解释结果
with result_placeholder.container():
st.success("✅ 代码解释完成!")
st.markdown("""
<div class='result-container'>
<h3 style='color: #27ae60; margin-bottom: 1rem;'>📚 代码解释</h3>
<div style='white-space: pre-wrap; line-height: 1.6;'>{}</div>
</div>
""".format(result), unsafe_allow_html=True)
else:
# 代码修复
result = bug_fixer.fix(
code=code_input,
language=language[1]
)
# 显示修复结果
with result_placeholder.container():
st.success("✅ 代码修复完成!")
# 显示问题分析
st.markdown("""
<div class='result-container'>
<h3 style='color: #e67e22; margin-bottom: 1rem;'>🔍 问题分析</h3>
<ul style='line-height: 1.8;'>
""", unsafe_allow_html=True)
# 解析并显示问题
if hasattr(result, 'problems_found'):
for problem in result.problems_found:
st.markdown(f"- {problem}")
st.markdown("""
</ul>
</div>
""", unsafe_allow_html=True)
# 显示修复方案
st.markdown("""
<div class='result-container'>
<h3 style='color: #27ae60; margin-bottom: 1rem;'>🔧 修复方案</h3>
""", unsafe_allow_html=True)
if hasattr(result, 'fixed_code'):
st.code(result.fixed_code, language=language[1])
# 显示修复说明
if hasattr(result, 'explanation'):
st.markdown("""
<h4 style='color: #3498db; margin-top: 1rem; margin-bottom: 0.5rem;'>📝 修复说明</h4>
<div style='line-height: 1.6;'>{}</div>
</div>
""".format(result.explanation), unsafe_allow_html=True)
except Exception as e:
# 显示错误信息
with result_placeholder.container():
st.error("❌ 分析失败!")
st.markdown("""
<div class='error-container'>
<h4>错误信息</h4>
<p>{}</p>
</div>
""".format(str(e)), unsafe_allow_html=True)
# 页脚信息
st.markdown("""
<div style='text-align: center; color: #95a5a6; font-size: 0.9rem; margin-top: 3rem; padding-top: 1rem; border-top: 1px solid #ecf0f1;'>
<p>基于硅基流动AI服务 | 支持多种编程语言</p>
</div>
""", unsafe_allow_html=True)

53
test_code_with_bugs.py Normal file
View File

@ -0,0 +1,53 @@
"""
测试代码 - 包含多个常见错误和问题
"""
def calculate_average(numbers)
total = 0
count = 0
for num in numbers
total += num
count += 1
average = total / count
return average
def find_max(numbers):
max_value = 0
for num in numbers:
if num > max_value:
max_value = num
return max_value
def process_data(data):
result = []
for item in data:
if item > 0:
result.append(item * 2)
if item < 0:
result.append(abs(item))
return result
def create_user(name, age):
user = {
"name": name,
"age": age,
}
return user
def main():
numbers = [10, 20, -5, 30, 15, -10]
avg = calculate_average(numbers)
print("平均值:", avg)
max_num = find_max(numbers)
print("最大值:", max_num)
processed = process_data(numbers)
print("处理结果:", processed)
user = create_user("张三", 25)
print("用户信息:", user)
if __name__ == "__main__":
main()

7
utils/__init__.py Normal file
View File

@ -0,0 +1,7 @@
from .code_parser import parse_code_structure, detect_language, extract_code_blocks
__all__ = [
"parse_code_structure",
"detect_language",
"extract_code_blocks"
]

Binary file not shown.

Binary file not shown.

32
utils/code_parser.py Normal file
View File

@ -0,0 +1,32 @@
from typing import List
def parse_code_structure(code: str) -> dict:
"""解析代码结构,返回基本信息"""
lines = code.split('\n')
return {
"total_lines": len(lines),
"non_empty_lines": len([l for l in lines if l.strip()]),
"code_lines": lines
}
def detect_language(code: str) -> str:
"""简单检测代码语言"""
code_stripped = code.strip()
if code_stripped.startswith(('def ', 'import ', 'from ', 'class ', 'if __name__')):
return 'python'
elif 'function' in code or 'const' in code or 'let' in code or '=>' in code:
return 'javascript'
elif 'public class' in code or 'private void' in code:
return 'java'
elif 'std::' in code or '#include <iostream>' in code:
return 'cpp'
return 'unknown'
def extract_code_blocks(text: str) -> List[str]:
"""从文本中提取代码块"""
import re
pattern = r'```[\w]*\n([\s\S]*?)```'
matches = re.findall(pattern, text)
return matches if matches else []