from django import forms from pathlib import Path from apps.documents.forms import MultipleFileField, SUPPORTED_EXTENSIONS class ChatForm(forms.Form): # 该表单只负责收集用户问题和可选文档范围, # 不承载任何 Agent 业务逻辑,便于在 View 层保持轻量。 message = forms.CharField( label="问题", max_length=4000, error_messages={ "required": "请输入要咨询的问题。", "max_length": "问题过长,请控制在 4000 字以内。", }, widget=forms.Textarea( attrs={ "rows": 8, "placeholder": "例如:请结合已上传 SOP,分析当前异常的原因、风险等级和建议动作。", } ), ) document_ids = forms.MultipleChoiceField( label="文档范围", required=False, choices=(), widget=forms.CheckboxSelectMultiple, error_messages={"invalid_choice": "请选择当前场景下已入库的文档。"}, ) def __init__(self, *args, documents=None, **kwargs): super().__init__(*args, **kwargs) documents = documents or [] # 仅允许选择当前场景且已完成入库的文档, # 避免前端把无效文件范围传入 Agent Core。 self.fields["document_ids"].choices = [ (str(document.id), document.original_name) for document in documents ] def clean_document_ids(self): # View 与 Agent Core 都使用整型文档 ID,统一在表单层完成转换。 return [int(document_id) for document_id in self.cleaned_data.get("document_ids", [])] class ConversationUploadForm(forms.Form): # 会话右侧上传区只负责继续补传资料,不修改会话绑定关系。 files = MultipleFileField(label="补充文件或资料包", required=False) file = forms.FileField(label="兼容单文件上传", required=False) def clean(self): cleaned_data = super().clean() files = list(cleaned_data.get("files") or []) file = cleaned_data.get("file") if file: files.append(file) if not files: raise forms.ValidationError("请至少上传一个文件或资料包。") for uploaded_file in files: if Path(uploaded_file.name).suffix.lower() not in SUPPORTED_EXTENSIONS: raise forms.ValidationError("仅支持 .txt、.md、.pdf、.docx、.zip 和 .7z 文件") cleaned_data["uploaded_files"] = files return cleaned_data