import json from django.contrib import messages from django.contrib.auth.decorators import login_required from django.db import transaction from django.db.models import Count from django.shortcuts import get_object_or_404, redirect, render from requirements.llm import analyze_requirements, _default_spec from requirements.models import Requirement, Submission from requirements.tasks import run_submission @login_required def dashboard(request): requirements = Requirement.objects.annotate(sub_count=Count("submissions")).order_by("-created_at") recent_submissions = Submission.objects.select_related("requirement").order_by("-created_at")[:15] return render(request, "web/dashboard.html", { "requirements": requirements, "recent_submissions": recent_submissions, }) @login_required def requirement_detail(request, pk): requirement = get_object_or_404(Requirement, pk=pk) submissions = requirement.submissions.all() return render(request, "web/requirement.html", { "requirement": requirement, "submissions": submissions, }) @login_required def submission_detail(request, pk): submission = get_object_or_404(Submission, pk=pk) return render(request, "web/submission.html", { "submission": submission, "report_json": json.dumps(submission.report or {}, ensure_ascii=False, indent=2), }) @login_required def create_requirement(request): from django.conf import settings if request.method != "POST": return render(request, "web/create_requirement.html", { "llm_base_url": settings.LLM_BASE_URL, "llm_model": settings.LLM_MODEL, }) title = (request.POST.get("title") or "").strip() content = (request.POST.get("content") or "").strip() if not title or not content: messages.error(request, "标题和内容不能为空") return redirect("create-requirement") llm_mode = request.POST.get("llm_mode", "default") override = {} if llm_mode == "custom": override = { "mode": "custom", "base_url": (request.POST.get("llm_base_url") or "").strip(), "api_key": (request.POST.get("llm_api_key") or "").strip(), "model": (request.POST.get("llm_model") or "").strip(), } if not override["base_url"] or not override["model"]: messages.error(request, "custom 模式必须填写 LLM 地址和模型名") return redirect("create-requirement") try: spec = analyze_requirements(content, override) except Exception: spec = _default_spec() with transaction.atomic(): requirement = Requirement.objects.create( title=title, content=content, spec=spec, llm_config=override, ) messages.success(request, f"已创建作业要求「{title}」,AI 分析完成") return redirect("requirement-detail", pk=requirement.pk) @login_required def upload_submission(request, pk): requirement = get_object_or_404(Requirement, pk=pk) if request.method != "POST": return redirect("requirement-detail", pk=pk) file = request.FILES.get("file") if not file: messages.error(request, "请选择要上传的项目包(tar/tar.gz/zip)") return redirect("requirement-detail", pk=pk) name = (request.POST.get("name") or "").strip() or file.name with transaction.atomic(): submission = Submission.objects.create( requirement=requirement, name=name, file=file, submitted_by=request.user, ) try: run_submission(submission.pk) except Exception: submission.status = "failed" submission.save(update_fields=["status"]) messages.success(request, f"已提交「{name}」,检测完成") return redirect("submission-detail", pk=submission.pk)