File size: 5,593 Bytes
b4f2238 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | """
外部模板模型
本模块定义外部模板 (ExternalTemplate) 数据模型,
用于存储法院、破产管理人等机构提供的 Word 模板文件及其元数据.
"""
from __future__ import annotations
import logging
from typing import ClassVar
from django.db import models
from django.utils.translation import gettext_lazy as _
from .choices import FillType, TemplateStatus
logger: logging.Logger = logging.getLogger(__name__)
class ExternalTemplate(models.Model):
"""
外部模板
存储法院、破产管理人、仲裁委员会等机构提供的 Word 模板文件.
通过结构指纹 (SHA-256) 去重, 支持 LLM 字段映射分析.
数据隔离基于 law_firm (律所级别共享).
Requirements: 1.1, 1.3, 1.4, 1.5, 1.6, 3.1, 3.4, 8.1, 8.2,
9.1, 9.2, 11.4, 11.5, 12.1, 13.1, 13.2, 13.3
"""
id: int
name = models.CharField(
max_length=255,
verbose_name=_("模板名称"),
)
source_name = models.CharField(
max_length=255,
blank=True,
default="",
verbose_name=_("来源机构"),
help_text=_("法院名称或其他机构名称"),
)
file_path = models.CharField(
max_length=500,
verbose_name=_("文件路径"),
help_text=_("相对于 MEDIA_ROOT 的存储路径"),
)
original_filename = models.CharField(
max_length=255,
verbose_name=_("原始文件名"),
)
file_size = models.PositiveIntegerField(
verbose_name=_("文件大小(字节)"),
)
structure_fingerprint = models.CharField(
max_length=64,
blank=True,
default="",
db_index=True,
verbose_name=_("结构指纹"),
help_text=_("基于模板 XML 结构计算的 SHA-256 哈希值"),
)
structure_json = models.JSONField(
default=dict,
blank=True,
verbose_name=_("提取的结构JSON"),
)
status = models.CharField(
max_length=20,
choices=TemplateStatus.choices,
default=TemplateStatus.UPLOADED,
verbose_name=_("状态"),
)
mapping_source = models.ForeignKey(
"self",
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=_("映射来源模板"),
help_text=_("结构指纹匹配时复用映射的原始模板"),
)
version = models.PositiveIntegerField(
default=1,
verbose_name=_("版本号"),
)
is_active = models.BooleanField(
default=True,
verbose_name=_("是否活跃"),
)
uploaded_by = models.ForeignKey(
"organization.Lawyer",
on_delete=models.SET_NULL,
null=True,
verbose_name=_("上传者"),
related_name="uploaded_external_templates",
)
law_firm = models.ForeignKey(
"organization.LawFirm",
on_delete=models.CASCADE,
verbose_name=_("所属律所"),
related_name="external_templates",
)
status_changed_at = models.DateTimeField(
auto_now=True,
verbose_name=_("状态变更时间"),
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name=_("创建时间"),
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name=_("更新时间"),
)
class Meta:
app_label = "documents"
verbose_name = _("外部模板")
verbose_name_plural = _("外部模板")
ordering: ClassVar = ["-updated_at"]
indexes: ClassVar = [
models.Index(fields=["law_firm", "source_name"]),
models.Index(fields=["law_firm", "is_active"]),
models.Index(fields=["structure_fingerprint"]),
models.Index(fields=["status"]),
]
def __str__(self) -> str:
return self.name
class ExternalTemplateFieldMapping(models.Model):
"""
外部模板字段映射
存储 LLM 分析生成的字段映射关系, 将模板中的可填充位置
通过语义标签(semantic_label)标识, 填充时由 LLM 根据案件数据自动取值。
Requirements: 4.3, 4.4, 4.5, 5.1, 5.2, 5.3, 5.5, 12.1
"""
id: int
template = models.ForeignKey(
ExternalTemplate,
on_delete=models.CASCADE,
related_name="field_mappings",
verbose_name=_("关联模板"),
)
position_locator = models.JSONField(
verbose_name=_("位置定位器"),
)
position_description = models.CharField(
max_length=500,
blank=True,
default="",
verbose_name=_("位置描述"),
)
semantic_label = models.CharField(
max_length=255,
verbose_name=_("语义标签"),
)
fill_type = models.CharField(
max_length=30,
choices=FillType.choices,
default=FillType.TEXT,
verbose_name=_("填充类型"),
)
sort_order = models.PositiveIntegerField(
default=0,
verbose_name=_("排序"),
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name=_("创建时间"),
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name=_("更新时间"),
)
class Meta:
app_label = "documents"
verbose_name = _("字段映射")
verbose_name_plural = _("字段映射")
ordering: ClassVar = ["sort_order", "id"]
indexes: ClassVar = [
models.Index(fields=["template", "sort_order"]),
]
def __str__(self) -> str:
return f"{self.template.name} - {self.semantic_label}"
|