152 lines
5.2 KiB
Python
152 lines
5.2 KiB
Python
import json
|
|
import logging
|
|
|
|
from django.db import transaction
|
|
from rest_framework import status
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
|
|
from .llm import analyze_requirements
|
|
from .models import Requirement, Submission
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _parse_llm_override(request) -> dict:
|
|
raw = request.data.get("llm")
|
|
if not raw:
|
|
return {}
|
|
if isinstance(raw, str):
|
|
try:
|
|
raw = json.loads(raw)
|
|
except json.JSONDecodeError:
|
|
return {}
|
|
return raw if isinstance(raw, dict) else {}
|
|
|
|
|
|
def _validate_llm_override(override: dict) -> str | None:
|
|
if override.get("mode") != "custom":
|
|
return None
|
|
if not (override.get("base_url") or "").strip() or not (override.get("model") or "").strip():
|
|
return "custom 模式必须提供 llm.base_url 和 llm.model"
|
|
return None
|
|
|
|
|
|
@api_view(["POST"])
|
|
@permission_classes([IsAuthenticated])
|
|
@transaction.atomic
|
|
def create_requirement(request):
|
|
title = (request.data.get("title") or "").strip()
|
|
content = (request.data.get("content") or "").strip()
|
|
if not title or not content:
|
|
return Response({"detail": "title 和 content 不能为空"}, status=status.HTTP_400_BAD_REQUEST)
|
|
override = _parse_llm_override(request)
|
|
err = _validate_llm_override(override)
|
|
if err:
|
|
return Response({"detail": err}, status=status.HTTP_400_BAD_REQUEST)
|
|
try:
|
|
spec = analyze_requirements(content, override)
|
|
except Exception:
|
|
logger.exception("AI 分析作业要求失败, 使用默认检测计划")
|
|
from .llm import _default_spec
|
|
spec = _default_spec()
|
|
requirement = Requirement.objects.create(
|
|
title=title, content=content, spec=spec, llm_config=override,
|
|
)
|
|
from .serializers import RequirementSerializer
|
|
return Response(RequirementSerializer(requirement).data, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def list_requirements(request):
|
|
qs = Requirement.objects.all()
|
|
q = request.query_params.get("q")
|
|
if q:
|
|
qs = qs.filter(title__icontains=q) | qs.filter(content__icontains=q)
|
|
from .serializers import RequirementSerializer
|
|
page = int(request.query_params.get("page", 1))
|
|
size = int(request.query_params.get("size", 20))
|
|
items = qs[(page - 1) * size: page * size]
|
|
return Response({
|
|
"count": qs.count(),
|
|
"page": page,
|
|
"items": RequirementSerializer(items, many=True).data,
|
|
})
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def get_requirement(request, pk):
|
|
try:
|
|
requirement = Requirement.objects.get(pk=pk)
|
|
except Requirement.DoesNotExist:
|
|
return Response({"detail": "不存在"}, status=status.HTTP_404_NOT_FOUND)
|
|
from .serializers import RequirementSerializer
|
|
return Response(RequirementSerializer(requirement).data)
|
|
|
|
|
|
@api_view(["POST"])
|
|
@permission_classes([IsAuthenticated])
|
|
@transaction.atomic
|
|
def create_submission(request, pk):
|
|
try:
|
|
requirement = Requirement.objects.get(pk=pk)
|
|
except Requirement.DoesNotExist:
|
|
return Response({"detail": "作业要求不存在"}, status=status.HTTP_404_NOT_FOUND)
|
|
name = (request.data.get("name") or "").strip()
|
|
file = request.FILES.get("file")
|
|
if not file:
|
|
return Response({"detail": "缺少上传文件 file"}, status=status.HTTP_400_BAD_REQUEST)
|
|
submission = Submission.objects.create(
|
|
requirement=requirement,
|
|
name=name or file.name,
|
|
file=file,
|
|
submitted_by=request.user,
|
|
)
|
|
from .tasks import run_submission
|
|
try:
|
|
run_submission(submission.id)
|
|
except Exception:
|
|
logger.exception("检测任务启动失败")
|
|
submission.status = "failed"
|
|
submission.save(update_fields=["status"])
|
|
from .serializers import SubmissionSerializer
|
|
return Response(SubmissionSerializer(submission).data, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def list_submissions(request):
|
|
qs = Submission.objects.all()
|
|
req_id = request.query_params.get("requirement")
|
|
if req_id:
|
|
qs = qs.filter(requirement_id=req_id)
|
|
from .serializers import SubmissionSerializer
|
|
return Response({"items": SubmissionSerializer(qs, many=True).data})
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def get_submission(request, pk):
|
|
try:
|
|
submission = Submission.objects.get(pk=pk)
|
|
except Submission.DoesNotExist:
|
|
return Response({"detail": "不存在"}, status=status.HTTP_404_NOT_FOUND)
|
|
from .serializers import SubmissionSerializer
|
|
return Response(SubmissionSerializer(submission).data)
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def get_report(request, pk):
|
|
try:
|
|
submission = Submission.objects.get(pk=pk)
|
|
except Submission.DoesNotExist:
|
|
return Response({"detail": "不存在"}, status=status.HTTP_404_NOT_FOUND)
|
|
if not submission.report:
|
|
return Response({"detail": "报告尚未生成", "status": submission.status},
|
|
status=status.HTTP_202_ACCEPTED)
|
|
return Response(submission.report)
|