Initial commit with all project files
This commit is contained in:
commit
637c71ba40
4
.env
Normal file
4
.env
Normal 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
83
README.md
Normal 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
|
||||||
BIN
__pycache__/app.cpython-313.pyc
Normal file
BIN
__pycache__/app.cpython-313.pyc
Normal file
Binary file not shown.
BIN
__pycache__/config.cpython-313.pyc
Normal file
BIN
__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
4
agents/__init__.py
Normal file
4
agents/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from .code_explainer import code_explainer
|
||||||
|
from .bug_fixer import bug_fixer
|
||||||
|
|
||||||
|
__all__ = ["code_explainer", "bug_fixer"]
|
||||||
BIN
agents/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
agents/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
agents/__pycache__/bug_fixer.cpython-313.pyc
Normal file
BIN
agents/__pycache__/bug_fixer.cpython-313.pyc
Normal file
Binary file not shown.
BIN
agents/__pycache__/code_explainer.cpython-313.pyc
Normal file
BIN
agents/__pycache__/code_explainer.cpython-313.pyc
Normal file
Binary file not shown.
64
agents/bug_fixer.py
Normal file
64
agents/bug_fixer.py
Normal 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
64
agents/code_explainer.py
Normal 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
135
app.py
Normal 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()
|
||||||
99
code_explanation_fixer.egg-info/PKG-INFO
Normal file
99
code_explanation_fixer.egg-info/PKG-INFO
Normal 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
|
||||||
16
code_explanation_fixer.egg-info/SOURCES.txt
Normal file
16
code_explanation_fixer.egg-info/SOURCES.txt
Normal 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
|
||||||
1
code_explanation_fixer.egg-info/dependency_links.txt
Normal file
1
code_explanation_fixer.egg-info/dependency_links.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
9
code_explanation_fixer.egg-info/requires.txt
Normal file
9
code_explanation_fixer.egg-info/requires.txt
Normal 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
|
||||||
4
code_explanation_fixer.egg-info/top_level.txt
Normal file
4
code_explanation_fixer.egg-info/top_level.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
agents
|
||||||
|
models
|
||||||
|
services
|
||||||
|
utils
|
||||||
54
config.py
Normal file
54
config.py
Normal 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
352
gui_app.py
Normal 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
9
models/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from .schemas import CodeRequest, CodeExplanation, BugFix, CodeResponse, ChatMessage
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"CodeRequest",
|
||||||
|
"CodeExplanation",
|
||||||
|
"BugFix",
|
||||||
|
"CodeResponse",
|
||||||
|
"ChatMessage"
|
||||||
|
]
|
||||||
BIN
models/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/schemas.cpython-313.pyc
Normal file
BIN
models/__pycache__/schemas.cpython-313.pyc
Normal file
Binary file not shown.
31
models/schemas.py
Normal file
31
models/schemas.py
Normal 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
32
pyproject.toml
Normal 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
3
services/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .ai_service import ai_service
|
||||||
|
|
||||||
|
__all__ = ["ai_service"]
|
||||||
BIN
services/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
services/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
services/__pycache__/ai_service.cpython-313.pyc
Normal file
BIN
services/__pycache__/ai_service.cpython-313.pyc
Normal file
Binary file not shown.
87
services/ai_service.py
Normal file
87
services/ai_service.py
Normal 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
112
static/index.html
Normal 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>© 2026 代码解释与修复助手 | 基于硅基流动AI服务</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
204
static/script.js
Normal file
204
static/script.js
Normal 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
370
static/styles.css
Normal 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
309
streamlit_app.py
Normal 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
53
test_code_with_bugs.py
Normal 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
7
utils/__init__.py
Normal 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"
|
||||||
|
]
|
||||||
BIN
utils/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
utils/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/code_parser.cpython-313.pyc
Normal file
BIN
utils/__pycache__/code_parser.cpython-313.pyc
Normal file
Binary file not shown.
32
utils/code_parser.py
Normal file
32
utils/code_parser.py
Normal 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 []
|
||||||
Loading…
Reference in New Issue
Block a user