101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
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)
|