""" 自动命名工具Admin 独立的Admin模块 """ from __future__ import annotations from pathlib import Path from typing import Any, ClassVar from django import forms from django.contrib import admin from django.http import HttpRequest, HttpResponse, HttpResponseRedirect from django.middleware.csrf import get_token from django.urls import path, reverse from apps.automation.models import NamerTool from apps.automation.services.ai.prompts import DEFAULT_FILENAME_PROMPT from apps.automation.services.document.document_processing import process_uploaded_document from apps.core.interfaces import ServiceLocator class AutoNamerToolForm(forms.Form): """自动命名工具表单""" upload = forms.FileField(required=True, help_text="支持PDF、DOCX和图片文件(JPG、PNG、BMP、TIFF等)") prompt = forms.CharField( required=True, widget=forms.Textarea(attrs={"rows": 8}), initial=DEFAULT_FILENAME_PROMPT, help_text="AI提示词,用于指导模型生成合适的文件名", ) model = forms.CharField(required=True, initial="qwen3:0.6b", help_text="使用的AI模型名称") limit = forms.IntegerField(required=False, help_text="文字提取限制(留空使用默认值1500字)") preview_page = forms.IntegerField(required=False, min_value=1, help_text="PDF预览页码(留空使用默认值第1页)") @admin.register(NamerTool) class AutoNamerToolAdmin(admin.ModelAdmin[NamerTool]): """自动命名工具管理类""" change_list_template = None def get_urls(self) -> list[Any]: urls = super().get_urls() info = self.model._meta.app_label, self.model._meta.model_name custom: list[Any] = [ path("process/", self.admin_site.admin_view(self.process_view), name="{}_{}_process".format(*info)), path("", self.admin_site.admin_view(self.redirect_to_process)), ] return custom + urls def redirect_to_process(self, request: HttpRequest) -> HttpResponseRedirect: info = self.model._meta.app_label, self.model._meta.model_name return HttpResponseRedirect(reverse("admin:{}_{}_process".format(*info))) def _process_view_post(self, request: Any, form: AutoNamerToolForm) -> HttpResponse: """处理 POST 请求""" fp = form.cleaned_data["upload"] prompt = form.cleaned_data["prompt"] model = form.cleaned_data["model"] limit = form.cleaned_data.get("limit") preview_page = form.cleaned_data.get("preview_page") info = self.model._meta.app_label, self.model._meta.model_name return_url = reverse("admin:{}_{}_process".format(*info)) try: extraction = process_uploaded_document(fp, limit=limit, preview_page=preview_page) except ValueError as e: return HttpResponse(str(e)) text = extraction.text or "" if extraction.kind not in {"pdf", "docx", "image"}: return HttpResponse("不支持的文件类型,支持PDF、DOCX和图片文件(JPG、PNG等)") if not text.strip(): return self._render_no_text_error(extraction, return_url) return self._render_ai_result(model, prompt, text, extraction, return_url) def _render_no_text_error(self, extraction: Any, return_url: str) -> HttpResponse: """渲染无文字内容错误页""" error_msg = "文档中没有提取到文字内容,无法生成命名。" if extraction.kind == "image": error_msg += "
提示:图片文件可能包含手写文字、复杂排版或图片质量较差,建议尝试更清晰的扫描件。" elif extraction.kind == "pdf": error_msg += "
提示:PDF可能是扫描版或图片格式,系统已尝试OCR识别但未成功。" html = f"""

自动命名工具(上传文档 + 提示词 → 模型生成)

❌ 处理失败

{error_msg}

文件信息:

← 返回重新上传

""" return HttpResponse(html) def _render_ai_result(self, model: str, prompt: str, text: str, extraction: Any, return_url: str) -> HttpResponse: """调用 AI 并渲染结果""" try: msg_list = [{"role": "system", "content": prompt}, {"role": "user", "content": text}] llm_service = ServiceLocator.get_llm_service() llm_response = llm_service.chat(messages=msg_list, backend="ollama", model=model, fallback=False) response_text = llm_response.content or "无返回内容" html = f"""

自动命名工具(上传文档 + 提示词 → 模型生成)

📄 文件信息:

📝 提取的文字内容

{text}

🤖 Ollama 返回结果

{response_text}
← 返回
""" return HttpResponse(html) except Exception as e: import traceback error_detail = str(e) error_traceback = traceback.format_exc() html = f"""

自动命名工具(上传文档 + 提示词 → 模型生成)

处理失败

错误信息:

{error_detail}
查看详细错误堆栈
{error_traceback}

返回

""" return HttpResponse(html) def process_view(self, request: HttpRequest) -> HttpResponse: """自动命名工具主视图""" if request.method == "POST": form = AutoNamerToolForm(request.POST, request.FILES) if form.is_valid(): return self._process_view_post(request, form) else: form = AutoNamerToolForm() csrf_token = get_token(request) html = f"""

自动命名工具(上传文档 + 提示词 → 模型生成)






""" return HttpResponse(html) def has_add_permission(self, request: HttpRequest) -> bool: return False def has_change_permission(self, request: HttpRequest, obj: NamerTool | None = None) -> bool: return True def has_view_permission(self, request: HttpRequest, obj: NamerTool | None = None) -> bool: return True def has_delete_permission(self, request: HttpRequest, obj: NamerTool | None = None) -> bool: return False