方案尚未生成完成。
") return HttpResponse(task.html_content) def pdf_view(self, request: HttpRequest, task_id: int) -> HttpResponse: task = SolutionTask.objects.get(id=task_id) if not task.html_content: messages.error(request, "方案尚未生成,无法导出 PDF") return HttpResponseRedirect(reverse("admin:legal_solution_solutiontask_change", args=[task_id])) # 使用缓存 if task.pdf_file: try: with task.pdf_file.open("rb") as f: pdf_bytes = f.read() response = HttpResponse(pdf_bytes, content_type="application/pdf") response["Content-Disposition"] = f'inline; filename="法律服务方案-{task.id}.pdf"' return response except Exception: pass exporter = PdfExporter() pdf_bytes = exporter.export(task.html_content) # 缓存 PDF from django.core.files.base import ContentFile task.pdf_file.save(f"solution_{task.id}.pdf", ContentFile(pdf_bytes), save=True) response = HttpResponse(pdf_bytes, content_type="application/pdf") response["Content-Disposition"] = f'inline; filename="法律服务方案-{task.id}.pdf"' return response def adjust_section_view(self, request: HttpRequest, task_id: int, section_id: int) -> HttpResponse: section = SolutionSection.objects.get(id=section_id, task_id=task_id) if request.method == "POST": feedback = request.POST.get("feedback", "").strip() if not feedback: messages.error(request, "请填写调整意见") else: try: service = SolutionTaskService() service.regenerate_section(section_id=section_id, feedback=feedback) messages.success(request, f"「{section.title}」已重新生成") except Exception as exc: messages.error(request, f"重新生成失败:{exc}") return HttpResponseRedirect(reverse("admin:legal_solution_solutiontask_change", args=[task_id])) # GET: 显示调整表单 html = f"""当前版本:v{section.version}。请描述你希望如何调整这个段落。
""" from django.middleware.csrf import get_token get_token(request) return HttpResponse( html.replace( request.META.get("CSRF_COOKIE", ""), get_token(request), ) ) def save_model(self, request: HttpRequest, obj: SolutionTask, form: Any, change: bool) -> None: if change: super().save_model(request, obj, form, change) return # 新建:设置创建人 is_lawyer = getattr(getattr(request.user, "_meta", None), "label_lower", "") == "organization.lawyer" if is_lawyer and getattr(request.user, "id", None): obj.created_by_id = int(request.user.id) super().save_model(request, obj, form, change) # 提交到队列 service = SolutionTaskService() service._dispatch(obj) if obj.status == SolutionTaskStatus.FAILED: messages.error(request, f"任务创建但提交失败:{obj.error}") else: messages.success(request, "法律服务方案任务已提交,请稍后刷新查看进度。") @admin.display(description="案情简述", ordering="case_summary") def case_summary_short(self, obj: SolutionTask) -> str: return obj.case_summary[:40] + "..." if len(obj.case_summary) > 40 else obj.case_summary @admin.display(description="HTML 预览") def preview_html_field(self, obj: SolutionTask) -> str: if not obj.html_content: return "—" preview_url = reverse("admin:legal_solution_solutiontask_preview", args=[obj.pk]) return format_html( '🔍 在新标签页预览 ' '', preview_url, preview_url, ) @admin.display(description="PDF 导出") def download_pdf_button(self, obj: SolutionTask) -> str: if not obj.html_content: return "—" pdf_url = reverse("admin:legal_solution_solutiontask_pdf", args=[obj.pk]) return format_html('⬇️ 导出 PDF', pdf_url) @staticmethod def _build_model_choices() -> tuple[list[tuple[str, str]], bool, str]: """构建模型选项列表,同时返回连接状态信息。 Returns: (choices, is_fallback, error_message) """ choices: list[tuple[str, str]] = [] seen: set[str] = set() default = LLMConfig.get_default_model().strip() if default: choices.append((default, f"{default}(默认)")) seen.add(default) try: result = ModelListService().get_result() for item in result.models: mid = str(item.get("id", "")).strip() mname = str(item.get("name", "")).strip() if mid and mid not in seen: choices.append((mid, f"{mname} ({mid})" if mname and mname != mid else mid)) seen.add(mid) if result.is_fallback: return choices or [(default or "Qwen/Qwen2.5-7B-Instruct", "默认模型")], True, result.error_message except Exception: return choices or [(default or "Qwen/Qwen2.5-7B-Instruct", "默认模型")], True, "加载模型列表异常" return choices or [(default or "Qwen/Qwen2.5-7B-Instruct", "默认模型")], False, ""