228 lines
6.6 KiB
Python
228 lines
6.6 KiB
Python
# 问题配置路由 - 完整CRUD
|
|
|
|
import os
|
|
import shutil
|
|
from datetime import datetime
|
|
from flask import request, jsonify, render_template, current_app, session, redirect
|
|
from app.routes import main_bp
|
|
from app.models import db, Problem, StudentProblem
|
|
from app.config import load_api_config, save_api_config
|
|
from app.routes.auth import login_required_json, admin_required
|
|
|
|
|
|
@main_bp.route("/problems")
|
|
@login_required_json
|
|
def settings():
|
|
"""问题配置页面 - 所有登录用户可访问"""
|
|
return render_template("problems.html", active_nav="problems")
|
|
|
|
|
|
@main_bp.route("/api-settings")
|
|
@admin_required
|
|
def api_settings_page():
|
|
"""API设置页面 - 仅管理员"""
|
|
return render_template("api_settings.html", active_nav="api-settings")
|
|
|
|
|
|
# ==================== API配置接口 ====================
|
|
|
|
|
|
@main_bp.route("/api/config", methods=["GET"])
|
|
@admin_required
|
|
def get_api_config():
|
|
"""获取API配置"""
|
|
config = load_api_config(current_app.config)
|
|
# 不返回完整的api_key,只返回前5位和后5位
|
|
if config.get("api_key"):
|
|
api_key = config["api_key"]
|
|
if len(api_key) > 10:
|
|
config["api_key_preview"] = api_key[:5] + "..." + api_key[-5:]
|
|
else:
|
|
config["api_key_preview"] = "****"
|
|
return jsonify(config)
|
|
|
|
|
|
|
|
|
|
|
|
@main_bp.route("/api/config", methods=["POST"])
|
|
@admin_required
|
|
def update_api_config():
|
|
"""更新API配置"""
|
|
data = request.get_json()
|
|
|
|
# 验证必填字段
|
|
if not data.get("api_key"):
|
|
return jsonify({"error": "API Key不能为空"}), 400
|
|
|
|
# 根据provider设置默认endpoint
|
|
provider = data.get("provider", "volcengine")
|
|
default_endpoints = {
|
|
"minimax": "https://api.minimaxi.com/anthropic/v1",
|
|
"volcengine": "https://ark.cn-beijing.volces.com/api/coding/v3",
|
|
"deepseek": "https://api.deepseek.com/v1",
|
|
"openrouter": "https://openrouter.ai/api/v1",
|
|
}
|
|
default_endpoint = default_endpoints.get(provider, "https://ark.cn-beijing.volces.com/api/coding/v3")
|
|
|
|
# 保存配置
|
|
config = {
|
|
"provider": provider,
|
|
"api_key": data.get("api_key", ""),
|
|
"base_url": data.get("base_url", default_endpoint),
|
|
"model": data.get("model", "doubao-seed-2.0-pro"),
|
|
"temperature": float(data.get("temperature", 0.7)),
|
|
"prompt_template": data.get("prompt_template", ""),
|
|
}
|
|
|
|
save_api_config(config, current_app.config)
|
|
return jsonify({"message": "配置保存成功"})
|
|
|
|
|
|
@main_bp.route("/api/problems", methods=["GET"])
|
|
@login_required_json
|
|
def get_problems():
|
|
"""获取问题列表(从数据库读取)"""
|
|
from app.models import Problem
|
|
|
|
problems = Problem.query.order_by(Problem.no).all()
|
|
return jsonify([p.to_dict() for p in problems])
|
|
|
|
|
|
@main_bp.route("/api/problems/<int:problem_id>", methods=["GET"])
|
|
@login_required_json
|
|
def get_problem_detail(problem_id):
|
|
"""获取单个问题的详细信息"""
|
|
from app.models import Problem
|
|
|
|
problem = Problem.query.get(problem_id)
|
|
if not problem:
|
|
return jsonify({"error": "问题不存在"}), 404
|
|
|
|
return jsonify({
|
|
"id": problem.id,
|
|
"no": problem.no,
|
|
"name": problem.name,
|
|
"category": problem.category,
|
|
"content": problem.content,
|
|
})
|
|
|
|
|
|
@main_bp.route("/api/problems", methods=["POST"])
|
|
@admin_required
|
|
def create_problem():
|
|
"""创建新问题 - 仅管理员"""
|
|
from app.models import Problem
|
|
|
|
data = request.get_json()
|
|
no = data.get("no", "").strip()
|
|
name = data.get("name", "").strip()
|
|
category = data.get("category", "技术类")
|
|
content = data.get("content", "")
|
|
|
|
if not no or not name:
|
|
return jsonify({"error": "编号和名称不能为空"}), 400
|
|
|
|
# 检查编号是否已存在
|
|
existing = Problem.query.filter_by(no=no).first()
|
|
if existing:
|
|
return jsonify({"error": "该编号已存在"}), 400
|
|
|
|
# 创建问题
|
|
problem = Problem(no=no, name=name, category=category, content=content)
|
|
db.session.add(problem)
|
|
db.session.commit()
|
|
|
|
return jsonify({"message": "创建成功", "id": problem.id, "no": problem.no, "name": problem.name})
|
|
|
|
|
|
@main_bp.route("/api/problems/<int:problem_id>", methods=["PUT"])
|
|
@login_required_json
|
|
def update_problem(problem_id):
|
|
"""更新问题"""
|
|
from app.models import Problem
|
|
|
|
problem = Problem.query.get(problem_id)
|
|
if not problem:
|
|
return jsonify({"error": "问题不存在"}), 404
|
|
|
|
data = request.get_json()
|
|
if "name" in data:
|
|
problem.name = data["name"].strip()
|
|
if "category" in data:
|
|
problem.category = data["category"]
|
|
if "content" in data:
|
|
problem.content = data["content"]
|
|
|
|
db.session.commit()
|
|
return jsonify({"message": "更新成功"})
|
|
|
|
|
|
@main_bp.route("/api/problems/<int:problem_id>", methods=["DELETE"])
|
|
@admin_required
|
|
def delete_problem(problem_id):
|
|
"""删除问题"""
|
|
from app.models import Problem
|
|
|
|
problem = Problem.query.get(problem_id)
|
|
if not problem:
|
|
return jsonify({"error": "问题不存在"}), 404
|
|
|
|
# 检查是否有关联数据
|
|
from app.models import StudentProblem
|
|
if StudentProblem.query.filter_by(problem_db_id=problem_id).first():
|
|
return jsonify({"error": "该问题已被学员使用,无法删除"}), 400
|
|
|
|
db.session.delete(problem)
|
|
db.session.commit()
|
|
|
|
return jsonify({"message": "删除成功"})
|
|
|
|
|
|
# ==================== AI测试接口 ====================
|
|
|
|
|
|
@main_bp.route("/api/config/test", methods=["POST"])
|
|
@admin_required
|
|
def test_api_connection():
|
|
"""测试API连接"""
|
|
import requests
|
|
|
|
config = load_api_config(current_app.config)
|
|
provider = config.get("provider", "volcengine")
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {config.get('api_key', '')}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
|
|
payload = {
|
|
"model": config.get("model", "doubao-seed-2.0-pro"),
|
|
"messages": [{"role": "user", "content": "你好"}],
|
|
"max_tokens": 50,
|
|
}
|
|
|
|
try:
|
|
# MiniMax 使用 Anthropic 格式的 API
|
|
if provider == "minimax":
|
|
endpoint = f"{config.get('base_url')}/messages"
|
|
payload["max_tokens"] = 50
|
|
else:
|
|
endpoint = f"{config.get('base_url')}/chat/completions"
|
|
|
|
response = requests.post(
|
|
endpoint,
|
|
headers=headers,
|
|
json=payload,
|
|
timeout=30,
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
return jsonify({"success": True, "message": "连接成功"})
|
|
else:
|
|
return jsonify(
|
|
{"success": False, "error": f"API返回错误: {response.status_code}"}
|
|
)
|
|
except Exception as e:
|
|
return jsonify({"success": False, "error": str(e)})
|