From 45276a778735fd9c93a76318733f03de56faa296 Mon Sep 17 00:00:00 2001 From: "DESKTOP-72TV0V4\\caoxiaozhu" Date: Mon, 12 Jan 2026 11:22:46 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E6=94=B9=E4=BA=86=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E4=BC=A0=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 15 +- src/README.md | 129 ------------ src/main.py | 381 ------------------------------------ src/requirements.txt | 4 - src/run.sh | 43 ---- src/test_api.sh | 47 ----- test_all.sh | 88 --------- test_data_dir.sh | 53 ----- total_start.sh | 200 ------------------- web/README.md | 95 --------- web/nul | 0 web/pages/main.html | 166 +++++++++++++++- web/start-http-server.sh | 119 ++++++++++- web/start.bat | 157 +++++++++++++++ web/start.sh | 82 -------- 15 files changed, 439 insertions(+), 1140 deletions(-) delete mode 100644 src/README.md delete mode 100644 src/main.py delete mode 100644 src/requirements.txt delete mode 100755 src/run.sh delete mode 100755 src/test_api.sh delete mode 100755 test_all.sh delete mode 100755 test_data_dir.sh delete mode 100755 total_start.sh delete mode 100644 web/README.md create mode 100644 web/nul create mode 100644 web/start.bat delete mode 100755 web/start.sh diff --git a/.claude/settings.local.json b/.claude/settings.local.json index a3e993e..e407ea4 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -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:*)" ] } } diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 8375ea4..0000000 --- a/src/README.md +++ /dev/null @@ -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 响应都遵循统一格式 diff --git a/src/main.py b/src/main.py deleted file mode 100644 index 0baa457..0000000 --- a/src/main.py +++ /dev/null @@ -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) diff --git a/src/requirements.txt b/src/requirements.txt deleted file mode 100644 index c007f43..0000000 --- a/src/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -python-multipart==0.0.6 diff --git a/src/run.sh b/src/run.sh deleted file mode 100755 index 6184731..0000000 --- a/src/run.sh +++ /dev/null @@ -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 diff --git a/src/test_api.sh b/src/test_api.sh deleted file mode 100755 index 966558b..0000000 --- a/src/test_api.sh +++ /dev/null @@ -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 "✅ 所有测试完成!" diff --git a/test_all.sh b/test_all.sh deleted file mode 100755 index 5a89cac..0000000 --- a/test_all.sh +++ /dev/null @@ -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 "" diff --git a/test_data_dir.sh b/test_data_dir.sh deleted file mode 100755 index d282fc3..0000000 --- a/test_data_dir.sh +++ /dev/null @@ -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/" diff --git a/total_start.sh b/total_start.sh deleted file mode 100755 index 1b166ce..0000000 --- a/total_start.sh +++ /dev/null @@ -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 diff --git a/web/README.md b/web/README.md deleted file mode 100644 index 2b0e741..0000000 --- a/web/README.md +++ /dev/null @@ -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是否安装 diff --git a/web/nul b/web/nul new file mode 100644 index 0000000..e69de29 diff --git a/web/pages/main.html b/web/pages/main.html index cba9e83..8c93701 100644 --- a/web/pages/main.html +++ b/web/pages/main.html @@ -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 @@

${dataset.name}

-

${dataset.size || '未知大小'} • ${dataset.records_count || dataset.description || '未知'}

+

${dataset.size_display || dataset.size_mb + ' MB' || '未知大小'} • ${dataset.description || '无描述'}

${statusText} - + +
`; @@ -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 = '
' +
+                            JSON.stringify(data.preview, null, 2) +
+                            '
'; + } else { + // 如果是对象,直接显示 + contentHtml = '
' +
+                            JSON.stringify(data.preview, null, 2) +
+                            '
'; + } + + // 显示模态框 + 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('删除失败: 网络错误'); + } + } diff --git a/web/start-http-server.sh b/web/start-http-server.sh index 78e8788..cd13b3d 100755 --- a/web/start-http-server.sh +++ b/web/start-http-server.sh @@ -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服务器 +# 启动 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 diff --git a/web/start.bat b/web/start.bat new file mode 100644 index 0000000..fef18a3 --- /dev/null +++ b/web/start.bat @@ -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 diff --git a/web/start.sh b/web/start.sh deleted file mode 100755 index c57963e..0000000 --- a/web/start.sh +++ /dev/null @@ -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 -