1. 修改了文件上传的功能

This commit is contained in:
2026-01-12 11:22:46 +08:00
parent 6e1b4b58ba
commit 45276a7787
15 changed files with 439 additions and 1140 deletions

View File

@@ -32,7 +32,20 @@
"Bash(find:*)",
"Bash(./test_upload.sh:*)",
"Bash(./test_all.sh)",
"Bash(/data/code/FT_Platform/YG_FT_Platform/test_data_dir.sh:*)"
"Bash(/data/code/FT_Platform/YG_FT_Platform/test_data_dir.sh:*)",
"Bash(ls:*)",
"Bash(python:*)",
"Bash(pip install:*)",
"Bash(findstr:*)",
"Bash(taskkill:*)",
"Bash(wmic:*)",
"Bash(for:*)",
"Bash(do echo \"Testing $url:\")",
"Bash(done)",
"Bash(./stop.sh:*)",
"Bash(./xrequest/Scripts/python.exe -m pip:*)",
"Bash(echo \"1. 访问: http://localhost:9999/web/pages/main.html\")",
"Bash(echo:*)"
]
}
}

View File

@@ -1,129 +0,0 @@
# FastAPI 服务器
## 功能特性
这个 FastAPI 服务器为大模型微调平台提供了 RESTful API 接口。
## API 端点
### 基础信息
- `GET /` - 根路径,返回欢迎信息
- `GET /api/health` - 健康检查
### 用户认证
- `POST /api/login` - 用户登录
```json
{
"username": "admin",
"password": "your_password"
}
```
### 数据集管理
- `GET /api/datasets` - 获取数据集列表
- `POST /api/datasets` - 创建新数据集
```json
{
"name": "新数据集名称",
"description": "数据集描述",
"size": "数据集大小"
}
```
- `POST /api/datasets/upload` - 上传数据集文件(支持 JSON 和 JSONL 格式)
```bash
curl -X POST "http://10.10.10.77:8001/api/datasets/upload" \
-F "file=@dataset.json" \
-F "description=数据集描述"
```
**支持的文件格式**: .json, .jsonl
**文件大小限制**: 100MB
- `GET /api/datasets/files` - 获取data目录中保存的文件列表
- `DELETE /api/datasets/{dataset_id}` - 删除数据集
### 模型管理
- `GET /api/models` - 获取模型列表
- `POST /api/models/config` - 配置模型参数
```json
{
"model_name": "GPT-4",
"learning_rate": 0.001,
"batch_size": 32,
"epochs": 100
}
```
### 训练管理
- `GET /api/training/status` - 获取训练状态
- `POST /api/training/start` - 开始训练任务
- `POST /api/training/stop/{task_id}` - 停止训练任务
- `GET /api/model/{model_id}/metrics` - 获取模型指标
### 系统监控
- `GET /api/system/stats` - 获取系统统计信息
## 启动服务器
### 方法 1: 使用启动脚本(推荐)
```bash
cd src
./run.sh
```
### 方法 2: 手动启动
```bash
# 安装依赖
pip3 install -r requirements.txt
# 启动服务器
uvicorn main:app --host 0.0.0.0 --port 8001 --reload
```
## 访问地址
- **服务器**: http://10.10.10.77:8001
- **API 文档**: http://10.10.10.77:8001/docs
- **替代文档**: http://10.10.10.77:8001/redoc
## 示例请求
### 登录
```bash
curl -X POST "http://10.10.10.77:8001/api/login" \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "123456"}'
```
### 获取数据集列表
```bash
curl -X GET "http://10.10.10.77:8001/api/datasets"
```
### 上传数据集文件
```bash
curl -X POST "http://10.10.10.77:8001/api/datasets/upload" \
-F "file=@dataset.json" \
-F "description=数据集描述"
```
### 获取data目录文件列表
```bash
curl -X GET "http://10.10.10.77:8001/api/datasets/files"
```
### 获取系统统计
```bash
curl -X GET "http://10.10.10.77:8001/api/system/stats"
```
## 依赖
- Python 3.7+
- FastAPI 0.104.1
- Uvicorn 0.24.0
- Pydantic 2.5.0
## 注意事项
- 服务器默认运行在端口 8001
- 使用 `--reload` 参数启用热重载
- 所有 API 响应都遵循统一格式

View File

@@ -1,381 +0,0 @@
from fastapi import FastAPI, File, UploadFile, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uvicorn
import os
import json
import re
import time
app = FastAPI(title="大模型微调平台 API", version="1.0.0")
# 请求模型
class UserModel(BaseModel):
username: str
password: str
class DatasetModel(BaseModel):
name: str
description: Optional[str] = None
size: str
class ModelConfigModel(BaseModel):
model_name: str
learning_rate: float
batch_size: int
epochs: int
# 响应模型
class ResponseModel(BaseModel):
code: int
message: str
data: Optional[dict] = None
# 模拟数据存储
datasets = [
{"id": 1, "name": "中文对话数据集", "size": "1.2GB", "status": "已处理"},
{"id": 2, "name": "英文文本分类数据集", "size": "856MB", "status": "处理中"},
{"id": 3, "name": "图像识别数据集", "size": "2.5GB", "status": "待处理"},
]
models = [
{"id": 1, "name": "GPT-4", "status": "训练中", "accuracy": "92%"},
{"id": 2, "name": "BERT", "status": "已完成", "accuracy": "89%"},
{"id": 3, "name": "LLaMA", "status": "已完成", "accuracy": "95%"},
]
@app.get("/")
async def root():
"""根路径"""
return {"message": "大模型微调平台 API 服务"}
@app.get("/api/health")
async def health_check():
"""健康检查"""
return ResponseModel(code=200, message="服务运行正常", data={"status": "healthy"})
@app.post("/api/login", response_model=ResponseModel)
async def login(user: UserModel):
"""用户登录"""
if user.username == "admin" and user.password:
return ResponseModel(
code=200,
message="登录成功",
data={"token": "mock_token_12345", "user": user.username}
)
else:
return ResponseModel(code=401, message="用户名或密码错误")
@app.get("/api/datasets", response_model=ResponseModel)
async def get_datasets():
"""获取数据集列表"""
return ResponseModel(code=200, message="获取成功", data={"datasets": datasets})
@app.post("/api/datasets", response_model=ResponseModel)
async def create_dataset(dataset: DatasetModel):
"""创建数据集"""
new_dataset = {
"id": len(datasets) + 1,
"name": dataset.name,
"description": dataset.description,
"size": "0MB",
"status": "待处理"
}
datasets.append(new_dataset)
return ResponseModel(code=201, message="创建成功", data={"dataset": new_dataset})
@app.post("/api/datasets/upload", response_model=ResponseModel)
async def upload_dataset(file: UploadFile = File(...), description: Optional[str] = None):
"""上传数据集文件(仅支持 JSON 和 JSONL 格式)"""
# 检查文件类型
allowed_extensions = ['.json', '.jsonl']
file_extension = os.path.splitext(file.filename)[1].lower()
if file_extension not in allowed_extensions:
raise HTTPException(
status_code=400,
detail=f"不支持的文件类型。只能上传 {', '.join(allowed_extensions)} 格式的文件"
)
# 检查文件大小(限制为 100MB
max_size = 100 * 1024 * 1024 # 100MB
contents = await file.read()
file_size = len(contents)
if file_size > max_size:
raise HTTPException(
status_code=400,
detail=f"文件大小超过限制。最大支持 100MB当前文件大小: {file_size / (1024*1024):.2f}MB"
)
try:
# 验证文件内容
if file_extension == '.json':
# 验证 JSON 文件
json.loads(contents.decode('utf-8'))
elif file_extension == '.jsonl':
# 验证 JSONL 文件(每行必须是有效的 JSON
lines = contents.decode('utf-8').strip().split('\n')
for i, line in enumerate(lines):
if line.strip():
try:
json.loads(line)
except json.JSONDecodeError as e:
raise HTTPException(
status_code=400,
detail=f"JSONL 文件格式错误:第 {i+1} 行不是有效的 JSON 格式"
)
# 生成文件大小字符串
if file_size < 1024:
size_str = f"{file_size}B"
elif file_size < 1024 * 1024:
size_str = f"{file_size / 1024:.2f}KB"
else:
size_str = f"{file_size / (1024*1024):.2f}MB"
# 计算行数(用于统计)
lines_count = len(contents.decode('utf-8').strip().split('\n')) if contents else 0
# 保存文件到 data 目录
data_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'data')
os.makedirs(data_dir, exist_ok=True)
# 生成唯一文件名(避免冲突)
base_name = os.path.splitext(file.filename)[0]
timestamp = int(time.time())
saved_filename = f"{base_name}_{timestamp}{file_extension}"
saved_path = os.path.join(data_dir, saved_filename)
# 写入文件
with open(saved_path, 'wb') as f:
f.write(contents)
# 创建新数据集记录
new_dataset = {
"id": len(datasets) + 1,
"name": file.filename,
"description": description or f"上传的数据集文件,包含 {lines_count} 行数据",
"size": size_str,
"status": "已处理",
"upload_time": "刚刚",
"file_extension": file_extension,
"records_count": lines_count,
"saved_path": saved_path # 添加保存路径信息
}
# 添加到数据集列表
datasets.append(new_dataset)
return ResponseModel(
code=200,
message="文件上传成功",
data={
"dataset": new_dataset,
"file_info": {
"filename": file.filename,
"size": size_str,
"extension": file_extension,
"records": lines_count
}
}
)
except json.JSONDecodeError:
raise HTTPException(
status_code=400,
detail="JSON 文件格式错误:文件内容不是有效的 JSON 格式"
)
except UnicodeDecodeError:
raise HTTPException(
status_code=400,
detail="文件编码错误:请确保文件使用 UTF-8 编码"
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"文件处理错误:{str(e)}"
)
@app.get("/api/datasets/files", response_model=ResponseModel)
async def list_dataset_files():
"""列出data目录中所有保存的数据集文件"""
try:
data_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'data')
if not os.path.exists(data_dir):
return ResponseModel(
code=200,
message="获取成功",
data={"files": [], "total": 0, "directory": data_dir}
)
files = []
for filename in os.listdir(data_dir):
file_path = os.path.join(data_dir, filename)
if os.path.isfile(file_path):
stat = os.stat(file_path)
files.append({
"filename": filename,
"size": stat.st_size,
"size_human": format_size(stat.st_size),
"modified_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(stat.st_mtime)),
"path": file_path
})
# 按修改时间排序(最新的在前)
files.sort(key=lambda x: x["modified_time"], reverse=True)
return ResponseModel(
code=200,
message="获取成功",
data={
"files": files,
"total": len(files),
"directory": data_dir
}
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"获取文件列表失败:{str(e)}"
)
def format_size(size_bytes):
"""格式化文件大小"""
if size_bytes < 1024:
return f"{size_bytes}B"
elif size_bytes < 1024 * 1024:
return f"{size_bytes / 1024:.2f}KB"
else:
return f"{size_bytes / (1024*1024):.2f}MB"
@app.delete("/api/datasets/{dataset_id}", response_model=ResponseModel)
async def delete_dataset(dataset_id: int):
"""删除数据集"""
global datasets
for i, dataset in enumerate(datasets):
if dataset["id"] == dataset_id:
deleted_dataset = datasets.pop(i)
return ResponseModel(
code=200,
message="删除成功",
data={"deleted_dataset": deleted_dataset}
)
raise HTTPException(status_code=404, detail="数据集不存在")
@app.get("/api/models", response_model=ResponseModel)
async def get_models():
"""获取模型列表"""
return ResponseModel(code=200, message="获取成功", data={"models": models})
@app.post("/api/models/config", response_model=ResponseModel)
async def config_model(config: ModelConfigModel):
"""配置模型参数"""
return ResponseModel(
code=200,
message="配置成功",
data={
"model_name": config.model_name,
"learning_rate": config.learning_rate,
"batch_size": config.batch_size,
"epochs": config.epochs,
"status": "已配置"
}
)
@app.get("/api/training/status")
async def get_training_status():
"""获取训练状态"""
return ResponseModel(
code=200,
message="获取成功",
data={
"current_task": "GPT-4微调",
"progress": 75,
"eta": "2小时",
"loss": 0.23,
"accuracy": 0.89
}
)
@app.get("/api/system/stats")
async def get_system_stats():
"""获取系统统计信息"""
import random
return ResponseModel(
code=200,
message="获取成功",
data={
"cpu_usage": random.randint(30, 80),
"memory_usage": random.randint(40, 70),
"gpu_usage": random.randint(50, 90),
"active_tasks": 5,
"completed_tasks": 158
}
)
@app.post("/api/training/start")
async def start_training(model_name: str, dataset_id: int):
"""开始训练任务"""
return ResponseModel(
code=200,
message="训练任务已启动",
data={
"task_id": random.randint(1000, 9999),
"model_name": model_name,
"dataset_id": dataset_id,
"status": "running"
}
)
@app.post("/api/training/stop/{task_id}")
async def stop_training(task_id: int):
"""停止训练任务"""
return ResponseModel(
code=200,
message=f"训练任务 {task_id} 已停止",
data={"task_id": task_id, "status": "stopped"}
)
@app.get("/api/model/{model_id}/metrics")
async def get_model_metrics(model_id: int):
"""获取模型指标"""
return ResponseModel(
code=200,
message="获取成功",
data={
"model_id": model_id,
"accuracy": round(random.uniform(0.85, 0.98), 3),
"precision": round(random.uniform(0.80, 0.95), 3),
"recall": round(random.uniform(0.82, 0.96), 3),
"f1_score": round(random.uniform(0.83, 0.97), 3),
"training_time": f"{random.randint(2, 24)}小时",
"parameters": random.randint(1000000, 100000000)
}
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8001)

View File

@@ -1,4 +0,0 @@
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.0
python-multipart==0.0.6

View File

@@ -1,43 +0,0 @@
#!/bin/bash
echo "🚀 启动 FastAPI 服务器..."
# 确保在正确的目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "📂 当前目录: $SCRIPT_DIR"
# 检查Python是否安装
if ! command -v python3 &> /dev/null; then
echo "❌ 错误: Python3 未安装"
echo "请先安装 Python3"
exit 1
fi
# 检查pip是否安装
if ! command -v pip3 &> /dev/null; then
echo "❌ 错误: pip3 未安装"
echo "请先安装 pip3"
exit 1
fi
# 安装依赖
echo "📦 安装依赖包..."
pip3 install -r requirements.txt
if [ $? -ne 0 ]; then
echo "❌ 依赖安装失败"
exit 1
fi
echo ""
echo "🌐 服务器地址: http://localhost:8001"
echo "📚 API 文档: http://localhost:8001/docs"
echo "🔍 替代文档: http://localhost:8001/redoc"
echo ""
echo "按 Ctrl+C 停止服务器"
echo ""
# 启动服务器
python3 -m uvicorn main:app --host 0.0.0.0 --port 8001 --reload

View File

@@ -1,47 +0,0 @@
#!/bin/bash
echo "🧪 测试 FastAPI 服务器"
echo "=================================="
echo ""
BASE_URL="http://localhost:8001"
# 测试 1: 根路径
echo "1. 测试根路径..."
curl -s "$BASE_URL/" | python3 -m json.tool
echo ""
# 测试 2: 健康检查
echo "2. 测试健康检查..."
curl -s "$BASE_URL/api/health" | python3 -m json.tool
echo ""
# 测试 3: 用户登录
echo "3. 测试用户登录..."
curl -s -X POST "$BASE_URL/api/login" \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "123456"}' | python3 -m json.tool
echo ""
# 测试 4: 获取数据集列表
echo "4. 测试获取数据集列表..."
curl -s "$BASE_URL/api/datasets" | python3 -m json.tool
echo ""
# 测试 5: 获取模型列表
echo "5. 测试获取模型列表..."
curl -s "$BASE_URL/api/models" | python3 -m json.tool
echo ""
# 测试 6: 系统统计
echo "6. 测试系统统计..."
curl -s "$BASE_URL/api/system/stats" | python3 -m json.tool
echo ""
# 测试 7: 训练状态
echo "7. 测试训练状态..."
curl -s "$BASE_URL/api/training/status" | python3 -m json.tool
echo ""
echo "=================================="
echo "✅ 所有测试完成!"

View File

@@ -1,88 +0,0 @@
#!/bin/bash
echo "🧪 测试大模型微调平台 - 所有服务"
echo "=================================="
echo ""
BASE_URL="http://localhost"
# 检查服务是否运行
echo "1. 检查服务状态..."
echo ""
# 检查端口 8000 (Web 前端)
if curl -s "${BASE_URL}:8000" > /dev/null 2>&1; then
echo "✅ Web 前端服务正在运行 (端口 8000)"
else
echo "❌ Web 前端服务未运行 (端口 8000)"
fi
# 检查端口 8001 (FastAPI)
if curl -s "${BASE_URL}:8001" > /dev/null 2>&1; then
echo "✅ FastAPI 服务正在运行 (端口 8001)"
else
echo "❌ FastAPI 服务未运行 (端口 8001)"
fi
echo ""
echo "=================================="
echo ""
# 获取本机IP
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "📱 访问地址:"
echo ""
echo "前端页面:"
echo " - 主页: http://$SERVER_IP:8000/pages/main.html"
echo " - 登录: http://$SERVER_IP:8000/pages/login.html"
echo ""
echo "API 服务:"
echo " - API 根路径: http://$SERVER_IP:8001/"
echo " - API 健康检查: http://$SERVER_IP:8001/api/health"
echo " - API 文档: http://$SERVER_IP:8001/docs"
echo ""
echo "=================================="
echo "2. 测试 API 接口..."
echo ""
# 测试 API
echo "测试根路径:"
curl -s "${BASE_URL}:8001/" | python3 -m json.tool 2>/dev/null || curl -s "${BASE_URL}:8001/"
echo ""
echo "测试健康检查:"
curl -s "${BASE_URL}:8001/api/health" | python3 -m json.tool 2>/dev/null || echo "请求失败"
echo ""
echo "测试数据集 API:"
curl -s "${BASE_URL}:8001/api/datasets" | python3 -m json.tool 2>/dev/null || echo "请求失败"
echo ""
echo "=================================="
echo "3. 测试前端页面..."
echo ""
# 测试前端页面
echo "测试主页:"
if curl -s -I "${BASE_URL}:8000/pages/main.html" | grep -q "200 OK"; then
echo "✅ 主页可访问"
else
echo "❌ 主页无法访问"
fi
echo "测试登录页:"
if curl -s -I "${BASE_URL}:8000/pages/login.html" | grep -q "200 OK"; then
echo "✅ 登录页可访问"
else
echo "❌ 登录页无法访问"
fi
echo ""
echo "=================================="
echo "✅ 测试完成!"
echo ""
echo "💡 如果服务未运行,请使用以下命令启动:"
echo " ./total_start.sh"
echo ""

View File

@@ -1,53 +0,0 @@
#!/bin/bash
echo "🧪 测试data目录功能"
echo "=================================="
echo ""
API_URL="http://10.10.10.77:8001/api"
echo "1. 测试获取文件列表..."
curl -s "${API_URL}/datasets/files" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f'✅ 共 {data[\"data\"][\"total\"]} 个文件')
print('')
for f in data['data']['files']:
print(f' 📄 {f[\"filename\"]} - {f[\"size_human\"]}')
"
echo ""
echo "2. 测试上传新文件..."
cat > /tmp/test_upload.json << 'INNER_EOF'
[{"text": "测试上传", "label": "test"}]
INNER_EOF
curl -s -X POST "${API_URL}/datasets/upload" \
-F "file=@/tmp/test_upload.json" \
-F "description=测试data目录上传" | python3 -c "
import json, sys
data = json.load(sys.stdin)
if data['code'] == 200:
print('✅ 文件上传成功')
print(f' 保存路径: {data[\"data\"][\"dataset\"][\"saved_path\"]}')
else:
print('❌ 上传失败')
"
echo ""
echo "3. 再次获取文件列表..."
curl -s "${API_URL}/datasets/files" | python3 -c "
import json, sys
data = json.load(sys.stdin)
print(f'✅ 当前共 {data[\"data\"][\"total\"]} 个文件')
"
echo ""
echo "=================================="
echo "✅ 测试完成!"
echo ""
echo "📁 data目录位置"
echo " /data/code/FT_Platform/YG_FT_Platform/data/"
echo ""
echo "🔍 查看文件:"
echo " ls -lh /data/code/FT_Platform/YG_FT_Platform/data/"

View File

@@ -1,200 +0,0 @@
#!/bin/bash
echo "🚀 大模型微调平台 - 一键启动"
echo "=================================="
echo ""
# 确保在正确的目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "📂 当前目录: $SCRIPT_DIR"
echo ""
# 获取本机IP地址
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "🌐 本机 IP 地址: $SERVER_IP"
echo ""
# 检查Python是否安装
if ! command -v python3 &> /dev/null; then
echo "❌ 错误: Python3 未安装"
echo "请先安装 Python3"
exit 1
fi
echo "请选择启动方式:"
echo "1) 启动所有服务FastAPI + Web前端"
echo "2) 只启动 FastAPI 服务(端口 8001"
echo "3) 只启动 Web 前端服务(端口 8000"
echo "4) 交互式选择"
echo ""
read -p "请输入选择 (1-4): " choice
case $choice in
1)
echo ""
echo "✅ 启动所有服务..."
echo ""
# 检查并启动 FastAPI 服务
echo "🔧 启动 FastAPI 服务..."
cd "$SCRIPT_DIR/src"
if [ ! -d "node_modules" ] 2>/dev/null && [ ! -f "main.py" ]; then
echo "⚠️ 警告: 未找到 FastAPI 源码文件"
fi
# 启动 FastAPI (后台运行)
cd "$SCRIPT_DIR/src"
python3 -m uvicorn main:app --host 0.0.0.0 --port 8001 &
FASTAPI_PID=$!
echo "✅ FastAPI 服务已启动 (PID: $FASTAPI_PID)"
echo " API 地址: http://localhost:8001"
echo " API 文档: http://localhost:8001/docs"
echo ""
# 等待 FastAPI 启动
sleep 2
# 启动 Web 前端服务
echo "🌐 启动 Web 前端服务..."
cd "$SCRIPT_DIR/web"
python3 -m http.server 8000 &
WEB_PID=$!
echo "✅ Web 前端服务已启动 (PID: $WEB_PID)"
echo " 前端地址: http://localhost:8000"
echo ""
echo "=================================="
echo "🎉 所有服务启动完成!"
echo ""
echo "📱 访问地址:"
echo " - 前端页面: http://$SERVER_IP:8000/pages/main.html"
echo " - 登录页面: http://$SERVER_IP:8000/pages/login.html"
echo " - API 服务: http://$SERVER_IP:8001"
echo " - API 文档: http://$SERVER_IP:8001/docs"
echo ""
echo "⚠️ 按 Ctrl+C 停止所有服务"
echo ""
# 等待用户中断
trap "echo ''; echo '🛑 正在停止服务...'; kill $FASTAPI_PID $WEB_PID 2>/dev/null; echo '✅ 所有服务已停止'; exit 0" INT
# 保持脚本运行
while true; do
sleep 1
done
;;
2)
echo ""
echo "🔧 启动 FastAPI 服务..."
cd "$SCRIPT_DIR/src"
# 检查源码文件是否存在
if [ ! -f "main.py" ]; then
echo "❌ 错误: 未找到 main.py 文件"
echo "请确保在正确的目录中"
exit 1
fi
echo "✅ FastAPI 服务启动中..."
echo " API 地址: http://localhost:8001"
echo " API 文档: http://localhost:8001/docs"
echo ""
echo "⚠️ 按 Ctrl+C 停止服务"
echo ""
python3 -m uvicorn main:app --host 0.0.0.0 --port 8001 --reload
;;
3)
echo ""
echo "🌐 启动 Web 前端服务..."
cd "$SCRIPT_DIR/web"
# 检查页面文件是否存在
if [ ! -f "pages/main.html" ]; then
echo "❌ 错误: 未找到 pages/main.html 文件"
echo "请确保在正确的目录中"
exit 1
fi
echo "✅ Web 前端服务启动中..."
echo " 前端地址: http://localhost:8000"
echo ""
echo "⚠️ 按 Ctrl+C 停止服务"
echo ""
python3 -m http.server 8000
;;
4)
echo ""
echo "🔧 检查服务状态..."
echo ""
# 检查 FastAPI
if curl -s http://localhost:8001 > /dev/null 2>&1; then
echo "✅ FastAPI 服务正在运行 (端口 8001)"
else
echo "❌ FastAPI 服务未运行 (端口 8001)"
fi
# 检查 Web 服务
if curl -s http://localhost:8000 > /dev/null 2>&1; then
echo "✅ Web 前端服务正在运行 (端口 8000)"
else
echo "❌ Web 前端服务未运行 (端口 8000)"
fi
echo ""
read -p "是否启动 FastAPI 服务?(y/n): " start_fastapi
if [[ $start_fastapi == "y" || $start_fastapi == "Y" ]]; then
cd "$SCRIPT_DIR/src"
python3 -m uvicorn main:app --host 0.0.0.0 --port 8001 &
FASTAPI_PID=$!
echo "✅ FastAPI 服务已启动 (PID: $FASTAPI_PID)"
fi
echo ""
read -p "是否启动 Web 前端服务?(y/n): " start_web
if [[ $start_web == "y" || $start_web == "Y" ]]; then
cd "$SCRIPT_DIR/web"
python3 -m http.server 8000 &
WEB_PID=$!
echo "✅ Web 前端服务已启动 (PID: $WEB_PID)"
fi
if [[ $start_fastapi == "y" || $start_fastapi == "Y" || $start_web == "y" || $start_web == "Y" ]]; then
echo ""
echo "=================================="
echo "🎉 服务启动完成!"
echo ""
echo "📱 访问地址:"
echo " - 前端页面: http://$SERVER_IP:8000/pages/main.html"
echo " - 登录页面: http://$SERVER_IP:8000/pages/login.html"
echo " - API 服务: http://$SERVER_IP:8001"
echo " - API 文档: http://$SERVER_IP:8001/docs"
echo ""
echo "⚠️ 按 Ctrl+C 停止服务"
echo ""
# 等待用户中断
trap "echo ''; echo '🛑 正在停止服务...'; kill $FASTAPI_PID $WEB_PID 2>/dev/null; echo '✅ 所有服务已停止'; exit 0" INT
# 保持脚本运行
while true; do
sleep 1
done
else
echo "未启动任何服务"
fi
;;
*)
echo "❌ 无效选择,请运行脚本重新选择"
exit 1
;;
esac

View File

@@ -1,95 +0,0 @@
# 🔥 大模型微调平台
> **静态HTML页面使用假数据模拟系统监控**
## 🚀 快速启动
### 方式1: 直接打开文件(推荐)
```bash
cd web
./start.sh
```
选择 `1` 直接打开文件
### 方式2: HTTP服务器可通过IP访问
```bash
cd web
./start.sh
```
选择 `2` 启动HTTP服务器
或直接运行:
```bash
./start-http-server.sh
```
## 📊 访问应用
### 直接打开文件
- **主页**: `file:///data/code/FT_Platform/YG_FT_Platform/web/pages/main.html`
- **登录**: `file:///data/code/FT_Platform/YG_FT_Platform/web/pages/login.html`
### HTTP服务器访问端口8000
- **主页**: `http://10.10.10.77:8000/pages/main.html`
- **登录**: `http://10.10.10.77:8000/pages/login.html`
## ✅ 模拟系统数据
现在显示的是**模拟数据**:
-**CPU使用率**: 随机模拟数据
-**内存使用率**: 随机模拟数据
-**GPU使用率**: 随机模拟数据
每2秒自动更新一次数据
## 🔧 技术架构
- **前端**: HTML + CSS + JavaScript
- **图表**: Chart.js
- **样式**: Tailwind CSS
- **服务器**: Python HTTP服务器可选
## 📱 特性
- 静态HTML页面无需后端服务
- 模拟数据自动更新
- 响应式设计 (支持手机/平板)
- 20个数据点滚动显示
- 彩色编码 (CPU红色, GPU绿色, 内存蓝色)
## 🛑 停止服务器
### 停止HTTP服务器
```bash
# 按 Ctrl+C
```
## 🐛 故障排除
### 问题: 找不到Python
**解决**: 安装Python或使用方式1直接打开文件
### 问题: 端口8000被占用
**解决**:
```bash
# 找到占用端口的进程
lsof -i :8000
# 或使用其他端口
python3 -m http.server 8001
```
### 问题: IP地址无法访问
**解决**:
1. 确保使用HTTP服务器方式启动
2. 检查防火墙设置确保端口8000开放
3. 使用正确的IP地址
### 问题: 数据不更新
**解决**: 刷新页面或重新启动
## 📞 获取帮助
如果遇到问题:
1. 首先尝试方式1直接打开文件
2. 如果需要IP访问使用方式2启动HTTP服务器
3. 检查Python是否安装

0
web/nul Normal file
View File

View File

@@ -755,7 +755,7 @@
};
// 数据集管理相关功能
const API_BASE = 'http://10.10.10.77:8001/api';
const API_BASE = 'http://localhost:3000/api';
// 加载数据集列表
async function loadDatasets() {
@@ -763,8 +763,11 @@
const response = await fetch(`${API_BASE}/datasets`);
const result = await response.json();
if (result.code === 200) {
renderDatasetList(result.data.datasets);
// 适配StandardResponse格式: {status: 1, response: {...}}
if (result.status === 1 && result.response && result.response.datasets) {
renderDatasetList(result.response.datasets);
} else if (result.status === 0) {
console.error('加载数据集列表失败:', result.response?.error || '未知错误');
}
} catch (error) {
console.error('加载数据集列表失败:', error);
@@ -788,11 +791,12 @@
<div class="flex justify-between items-center">
<div>
<h3 class="font-medium text-dashboard-text">${dataset.name}</h3>
<p class="text-sm text-dashboard-textLight mt-1">${dataset.size || '未知大小'}${dataset.records_count || dataset.description || '未知'}</p>
<p class="text-sm text-dashboard-textLight mt-1">${dataset.size_display || dataset.size_mb + ' MB' || '未知大小'}${dataset.description || '无描述'}</p>
</div>
<div class="flex items-center space-x-2">
<span class="px-2 py-1 ${statusClass} text-xs rounded">${statusText}</span>
<button class="text-dashboard-primary hover:underline text-sm">查看详情</button>
<button onclick="viewDatasetDetails('${dataset.file_id}')" class="text-dashboard-primary hover:underline text-sm">查看详情</button>
<button onclick="deleteDataset('${dataset.file_id}', '${dataset.name}')" class="text-red-500 hover:text-red-700 text-sm">删除</button>
</div>
</div>
`;
@@ -814,6 +818,7 @@
}
}
// 查看数据集详情
// 处理文件上传
async function handleFileUpload(input) {
const file = input.files[0];
@@ -849,12 +854,14 @@
const result = await response.json();
if (result.code === 200) {
// 适配StandardResponse格式: {status: 1, response: {...}}
if (result.status === 1) {
alert('上传成功!');
// 重新加载数据集列表
loadDatasets();
} else {
alert('上传失败: ' + (result.detail || result.message || '未知错误'));
const errorMsg = result.response?.error || result.message || '未知错误';
alert('上传失败: ' + errorMsg);
}
} catch (error) {
console.error('上传失败:', error);
@@ -872,6 +879,151 @@
// 跳转到登录页面
window.location.href = 'login.html';
}
// 查看数据集详情
async function viewDatasetDetails(fileId) {
try {
// 调用API获取文件内容
const response = await fetch(`${API_BASE}/datasets/${fileId}/content?limit=5`);
const result = await response.json();
if (result.status === 1) {
const data = result.response;
let contentHtml = '';
if (Array.isArray(data.preview)) {
// 如果是数组显示前5条记录
contentHtml = '<div style="max-height: 400px; overflow-y: auto;"><pre>' +
JSON.stringify(data.preview, null, 2) +
'</pre></div>';
} else {
// 如果是对象,直接显示
contentHtml = '<div style="max-height: 400px; overflow-y: auto;"><pre>' +
JSON.stringify(data.preview, null, 2) +
'</pre></div>';
}
// 显示模态框
showDatasetModal(data.filename, contentHtml);
} else {
alert('获取文件内容失败: ' + (result.response?.error || '未知错误'));
}
} catch (error) {
console.error('获取文件详情失败:', error);
alert('获取文件详情失败: 网络错误');
}
}
// 显示数据集详情模态框
function showDatasetModal(title, content) {
const modal = document.createElement('div');
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
`;
const modalContent = document.createElement('div');
modalContent.style.cssText = `
background: white;
padding: 20px;
border-radius: 8px;
max-width: 800px;
max-height: 600px;
overflow: hidden;
display: flex;
flex-direction: column;
`;
const modalHeader = document.createElement('div');
modalHeader.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
`;
const titleElement = document.createElement('h3');
titleElement.textContent = title;
titleElement.style.cssText = 'margin: 0; color: #333;';
const closeButton = document.createElement('button');
closeButton.textContent = '×';
closeButton.style.cssText = `
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
`;
closeButton.onmouseover = () => closeButton.style.background = '#f0f0f0';
closeButton.onmouseout = () => closeButton.style.background = 'none';
const closeModal = () => {
document.body.removeChild(modal);
};
closeButton.onclick = closeModal;
modal.onclick = (e) => {
if (e.target === modal) closeModal();
};
modalHeader.appendChild(titleElement);
modalHeader.appendChild(closeButton);
const contentDiv = document.createElement('div');
contentDiv.innerHTML = content;
modalContent.appendChild(modalHeader);
modalContent.appendChild(contentDiv);
modal.appendChild(modalContent);
document.body.appendChild(modal);
}
// 删除数据集
async function deleteDataset(fileId, filename) {
// 确认删除对话框
const confirmMessage = `确定要删除数据集 "${filename}" 吗?\n\n此操作不可撤销!`;
if (!confirm(confirmMessage)) {
return;
}
try {
const response = await fetch(`${API_BASE}/datasets/${fileId}`, {
method: 'DELETE'
});
const result = await response.json();
if (result.status === 1) {
alert('删除成功!');
// 重新加载数据集列表
loadDatasets();
} else {
alert('删除失败: ' + (result.response?.error || '未知错误'));
}
} catch (error) {
console.error('删除失败:', error);
alert('删除失败: 网络错误');
}
}
</script>
</body>

View File

@@ -1,36 +1,135 @@
#!/bin/bash
echo "🚀 启动 HTTP 服务器..."
echo "🚀 启动 HTTP 服务器"
echo "===================="
echo ""
# 确保在正确的目录
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "📂 当前目录: $SCRIPT_DIR"
echo ""
# 获取本机IP地址
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "🌐 本机 IP 地址: $SERVER_IP"
# 检测操作系统类型
echo "🔍 检测操作系统..."
OSTYPE_LOWER=$(echo "$OSTYPE" | tr '[:upper:]' '[:lower:]')
# 检测是否在 WSL 中
IS_WSL=0
if [[ -n "$WSLENV" ]] || grep -qi microsoft /proc/version 2>/dev/null; then
IS_WSL=1
OS_TYPE="WSL (Windows Subsystem for Linux)"
echo "📟 检测到 WSL 环境"
elif [[ "$OSTYPE_LOWER" == "linux-gnu"* ]]; then
OS_TYPE="Linux"
echo "🐧 检测到 Linux 环境"
elif [[ "$OSTYPE_LOWER" == "darwin"* ]]; then
OS_TYPE="macOS"
echo "🍎 检测到 macOS 环境"
elif [[ "$OSTYPE_LOWER" == "msys" ]] || [[ "$OSTYPE_LOWER" == "cygwin" ]]; then
OS_TYPE="Windows (MSYS/Cygwin)"
echo "🪟 检测到 Windows (MSYS/Cygwin) 环境"
else
OS_TYPE="Unknown"
echo "⚠️ 未识别的操作系统: $OSTYPE"
fi
echo "✅ 操作系统类型: $OS_TYPE"
echo ""
# 根据操作系统选择 Python 命令
PYTHON_CMD=""
PYTHON_VERSION=""
# 检查Python是否可用
if command -v python3 &> /dev/null; then
PYTHON_CMD="python3"
PYTHON_VERSION=$(python3 --version 2>&1)
elif command -v python &> /dev/null; then
PYTHON_CMD="python"
PYTHON_VERSION=$(python --version 2>&1)
else
echo "❌ 错误: 未找到 Python"
echo "请安装 Python 或手动打开文件"
echo ""
echo "💡 解决方案:"
echo " 1. 安装 Python 3.x"
echo " 2. 确保 python 或 python3 命令可用"
echo " 3. Windows 用户可以使用: start.bat"
echo ""
exit 1
fi
echo "✅ 使用 Python 命令: $PYTHON_CMD"
echo "✅ Python 版本: $PYTHON_VERSION"
echo ""
# 获取本机IP地址
SERVER_IP=""
case "$OS_TYPE" in
"Linux"|"macOS")
# Linux/macOS 使用 hostname -I
if command -v hostname &> /dev/null; then
SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}' | head -n1)
if [ -n "$SERVER_IP" ] && [ "$SERVER_IP" != "localhost" ]; then
echo "🌐 检测到 IP 地址: $SERVER_IP"
else
echo "🌐 未检测到有效 IP将使用 localhost"
SERVER_IP="localhost"
fi
fi
;;
"WSL (Windows Subsystem for Linux)")
echo "💡 WSL 环境提示:"
echo " - 如果无法访问 localhost请检查 WSL 网络配置"
echo " - 建议在 Windows 浏览器中访问服务"
echo ""
echo "🌐 建议使用: http://localhost:8000 访问"
SERVER_IP="localhost"
;;
"Windows (MSYS/Cygwin)"|*)
# Windows 下使用 localhost 更可靠
echo "🌐 Windows 环境使用 localhost 访问"
SERVER_IP="localhost"
;;
esac
if [ -z "$SERVER_IP" ]; then
SERVER_IP="localhost"
fi
echo ""
echo "📱 访问地址:"
echo " - 主页: http://$SERVER_IP:8000/pages/main.html"
echo " - 登录: http://$SERVER_IP:8000/pages/login.html"
echo " 主页: http://$SERVER_IP:8000/pages/main.html"
echo " 登录: http://$SERVER_IP:8000/pages/login.html"
echo ""
echo "⚠️ 服务器将在端口 8000 启动"
echo "按 Ctrl+C 停止服务器"
echo ""
# 启动 HTTP 服务器
echo "🔧 启动中..."
echo ""
# WSL 环境特殊处理
if [ $IS_WSL -eq 1 ]; then
echo "💡 WSL 启动提示:"
echo " - 服务器在 WSL 中启动"
echo " - 如果 Windows 浏览器无法访问,可能需要配置 WSL 网络"
echo " - 或使用 Windows 的 Python 启动: python -m http.server 8000"
echo ""
fi
# 启动服务器
$PYTHON_CMD -m http.server 8000
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo ""
echo "❌ 服务器启动失败 (退出码: $EXIT_CODE)"
echo ""
echo "💡 故障排除:"
echo " 1. 检查端口 8000 是否被占用"
echo " 2. 确认 Python 3 已正确安装"
echo " 3. 尝试使用其他端口: $PYTHON_CMD -m http.server 9000"
echo ""
fi

157
web/start.bat Normal file
View File

@@ -0,0 +1,157 @@
@echo off
chcp 65001 >nul
title FT-Platform Web 前端
echo.
echo 🚀 启动大模型微调平台 (Web 前端)
echo ========================================
echo.
:: 确保在正确的目录中
cd /d "%~dp0"
echo 📂 当前目录: %CD%
echo.
:: 检测运行环境
if not "%WSLENV%"=="" (
echo 📟 检测到 WSL 环境
set "IS_WSL=1"
) else (
echo 📟 检测到 Windows 环境
set "IS_WSL=0"
)
echo.
echo 请选择启动方式:
echo 1) 直接打开文件(本地访问)
echo 2) 启动HTTP服务器推荐跨域访问
echo 3) 使用 Python 启动 HTTP 服务器
echo.
set /p choice="请输入选择 (1-3): "
if "%choice%"=="1" goto open_file
if "%choice%"=="2" goto start_http
if "%choice%"=="3" goto start_python
echo ❌ 无效选择
pause
exit /b 1
:open_file
echo.
echo 🌐 打开本地文件...
echo.
echo 主页: file://%CD%\pages\main.html
echo 登录: file://%CD%\pages\login.html
echo.
:: 尝试打开浏览器
if exist "pages\main.html" (
start "FT-Platform 主页" "pages\main.html"
echo ✅ 已尝试在浏览器中打开主页
) else (
echo ❌ 未找到 pages\main.html 文件
)
echo.
echo 💡 如果浏览器未自动打开,请手动双击打开:
echo %CD%\pages\main.html
echo.
pause
goto end
:start_http
echo.
echo 🌐 启动 HTTP 服务器...
echo.
:: 检查 Python 命令
python --version >nul 2>&1
if %errorlevel% equ 0 (
set "PYTHON_CMD=python"
goto run_server
)
python3 --version >nul 2>&1
if %errorlevel% equ 0 (
set "PYTHON_CMD=python3"
goto run_server
)
echo ❌ 未找到 Python
echo.
echo 💡 请安装 Python 或选择方式 1 直接打开文件
echo.
pause
goto end
:start_python
echo.
echo 🌐 使用 Python 启动 HTTP 服务器...
echo.
:: 尝试多种 Python 命令
where python >nul 2>&1
if %errorlevel% equ 0 (
set "PYTHON_CMD=python"
goto run_server
)
where python3 >nul 2>&1
if %errorlevel% equ 0 (
set "PYTHON_CMD=python3"
goto run_server
)
echo ❌ 未找到 Python 命令
echo.
echo 💡 请检查 Python 是否已安装并添加到 PATH
echo.
pause
goto end
:run_server
echo ✅ 使用命令: %PYTHON_CMD%
echo.
:: 获取本机IP如果可能
for /f "tokens=2 delims=:" %%a in ('ipconfig ^| findstr /i "IPv4" ^| findstr /v "127.0.0.1"') do (
set "SERVER_IP=%%a"
goto :ip_found
)
:ip_found
if defined SERVER_IP (
echo 🌐 检测到 IP: %SERVER_IP%
) else (
echo 🌐 使用 localhost 访问
set "SERVER_IP=localhost"
)
echo.
echo 📱 访问地址:
echo 主页: http://%SERVER_IP%:8000/pages/main.html
echo 登录: http://%SERVER_IP%:8000/pages/login.html
echo.
echo ⚠️ 服务器启动在端口 8000
echo 按 Ctrl+C 停止服务器
echo.
if "%IS_WSL%"=="1" (
echo 💡 WSL 环境提示: 如果无法访问 localhost请检查网络配置
echo.
)
:: 启动服务器
echo 🔧 启动中...
echo.
%PYTHON_CMD% -m http.server 8000
if %errorlevel% neq 0 (
echo.
echo ❌ 启动失败,请检查 Python 环境
pause
)
:end

View File

@@ -1,82 +0,0 @@
#!/bin/bash
echo "🚀 启动大模型微调平台..."
echo ""
# 确保在正确的目录中
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "📂 当前目录: $SCRIPT_DIR"
echo ""
# 获取本机IP地址
SERVER_IP=$(hostname -I | awk '{print $1}')
echo "请选择启动方式:"
echo "1) 直接打开文件(本地访问)"
echo "2) 启动HTTP服务器可通过IP访问"
echo ""
read -p "请输入选择 (1-2): " choice
case $choice in
1)
echo ""
echo "🌐 打开本地文件..."
echo " - 主页: file://$SCRIPT_DIR/pages/main.html"
echo " - 登录: file://$SCRIPT_DIR/pages/login.html"
echo ""
# 检测操作系统并打开浏览器
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
open "pages/main.html"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
# Linux
xdg-open "pages/main.html"
elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then
# Windows (Git Bash or Cygwin)
start "pages/main.html"
else
echo "请手动打开以下文件:"
echo " $SCRIPT_DIR/pages/main.html"
fi
echo "✅ 已在浏览器中打开主页"
;;
2)
echo ""
echo "🌐 本机 IP 地址: $SERVER_IP"
echo ""
# 检查Python是否可用
if command -v python3 &> /dev/null; then
PYTHON_CMD="python3"
elif command -v python &> /dev/null; then
PYTHON_CMD="python"
else
echo "❌ 错误: 未找到 Python"
echo "请安装 Python 或使用方式 1 直接打开文件"
exit 1
fi
echo "📱 访问地址:"
echo " - 主页: http://$SERVER_IP:8000/pages/main.html"
echo " - 登录: http://$SERVER_IP:8000/pages/login.html"
echo ""
echo "⚠️ 服务器将在端口 8000 启动"
echo "按 Ctrl+C 停止服务器"
echo ""
# 启动HTTP服务器
$PYTHON_CMD -m http.server 8000
;;
*)
echo "❌ 无效选择,请运行脚本重新选择"
exit 1
;;
esac