Download apps/document_recognition/usecases/court_document_recognition/recognize_document.py from jun2024/fc: direct link, hf CLI and curl.
- Browser
- Download file 7.17 kB
-
https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/document_recognition/usecases/court_document_recognition/recognize_document.py
- Command line
-
hf download hf://spaces/jun2024/fc/apps/document_recognition/usecases/court_document_recognition/recognize_document.py
-
curl -L -o recognize_document.py https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/document_recognition/usecases/court_document_recognition/recognize_document.py
7.17 kB
| """Module for recognize document.""" | |
| from __future__ import annotations | |
| import logging | |
| from dataclasses import dataclass | |
| from datetime import date | |
| from typing import Any | |
| from apps.core.exceptions import RecognitionTimeoutError, ServiceUnavailableError, ValidationException | |
| from apps.document_recognition.services.data_classes import ( | |
| BindingResult, | |
| DocumentType, | |
| RecognitionResponse, | |
| RecognitionResult, | |
| ) | |
| logger = logging.getLogger("apps.document_recognition") | |
| class RecognizeCourtDocumentUsecase: | |
| text_extraction: Any | |
| classifier: Any | |
| extractor: Any | |
| binding_service: Any | |
| document_renamer: Any | |
| def execute(self, *, file_path: str, user: Any | None = None) -> RecognitionResponse: | |
| logger.info("开始识别文书", extra={"action": "recognize_document", "file_path": file_path}) | |
| try: | |
| extraction_result = self.text_extraction.extract_text(file_path) | |
| if not extraction_result.success or not extraction_result.text.strip(): | |
| return self._empty_response(file_path, extraction_result) | |
| doc_type, confidence = self.classifier.classify(extraction_result.text) | |
| case_number, key_time = self._extract_key_info(doc_type, extraction_result.text) | |
| recognition = RecognitionResult( | |
| document_type=doc_type, | |
| case_number=case_number, | |
| key_time=key_time, | |
| raw_text=extraction_result.text, | |
| confidence=confidence, | |
| extraction_method=extraction_result.extraction_method, | |
| ) | |
| binding, renamed_file_path = self._bind_document( | |
| doc_type, case_number, key_time, extraction_result.text, file_path, user | |
| ) | |
| logger.info( | |
| "文书识别完成", | |
| extra={"action": "recognize_document", "document_type": doc_type.value, "case_number": case_number}, | |
| ) | |
| return RecognitionResponse(recognition=recognition, binding=binding, file_path=renamed_file_path) | |
| except (ValidationException, ServiceUnavailableError, RecognitionTimeoutError): | |
| raise | |
| except Exception: | |
| logger.error("文书识别失败", extra={"action": "recognize_document", "file_path": file_path}, exc_info=True) | |
| raise | |
| def _empty_response(self, file_path: Any, extraction_result: Any) -> RecognitionResponse: | |
| """文本提取失败时返回空结果""" | |
| return RecognitionResponse( | |
| recognition=RecognitionResult( | |
| document_type=DocumentType.OTHER, | |
| case_number=None, | |
| key_time=None, | |
| raw_text="", | |
| confidence=0.0, | |
| extraction_method=extraction_result.extraction_method, | |
| ), | |
| binding=BindingResult.failure_result(message="无法从文书中提取文字", error_code="TEXT_EXTRACTION_FAILED"), | |
| file_path=file_path, | |
| ) | |
| def _extract_key_info(self, doc_type: Any, text: Any) -> tuple[Any, Any]: | |
| """根据文书类型提取案号和关键时间""" | |
| if doc_type == DocumentType.SUMMONS: | |
| info = self.extractor.extract_summons_info(text) | |
| return (info.get("case_number"), info.get("court_time")) | |
| if doc_type == DocumentType.EXECUTION_RULING: | |
| info = self.extractor.extract_execution_info(text) | |
| return (info.get("case_number"), info.get("preservation_deadline")) | |
| return (None, None) | |
| def _bind_document( | |
| self, doc_type: Any, case_number: Any, key_time: Any, raw_text: Any, file_path: Any, user: Any | |
| ) -> tuple[Any, Any]: | |
| """绑定文书到案件,返回 (binding, renamed_file_path)""" | |
| _UNSUPPORTED = { | |
| DocumentType.OTHER: ("暂时只支持传票识别,其他文书类型敬请期待", "UNSUPPORTED_DOCUMENT_TYPE"), | |
| DocumentType.EXECUTION_RULING: ("执行裁定书绑定功能开发中,敬请期待", "FEATURE_NOT_IMPLEMENTED"), | |
| } | |
| if doc_type != DocumentType.SUMMONS or not case_number: | |
| if not case_number and doc_type == DocumentType.SUMMONS: | |
| return ( | |
| BindingResult.failure_result( | |
| message="未识别到案号,无法绑定案件", error_code="CASE_NUMBER_NOT_FOUND" | |
| ), | |
| file_path, | |
| ) | |
| msg, code = _UNSUPPORTED.get(doc_type, ("不支持的文书类型", "UNSUPPORTED")) | |
| return (BindingResult.failure_result(message=msg, error_code=code), file_path) | |
| case_id = self.binding_service.find_case_by_number(case_number) | |
| case_name = None | |
| renamed_file_path = file_path | |
| if case_id: | |
| case_dto = self.binding_service.case_service.get_case_by_id_internal(case_id) | |
| if case_dto: | |
| case_name = case_dto.name | |
| if case_name: | |
| renamed_file_path = self._rename_document(file_path=file_path, document_type=doc_type, case_name=case_name) | |
| log_content = self.binding_service.format_log_content( | |
| document_type=doc_type, case_number=case_number, key_time=key_time, raw_text=raw_text | |
| ) | |
| binding = self.binding_service.bind_document_to_case( | |
| case_number=case_number, | |
| document_type=doc_type, | |
| content=log_content, | |
| key_time=key_time, | |
| file_path=renamed_file_path, | |
| user=user, | |
| ) | |
| return (binding, renamed_file_path) | |
| def _rename_document(self, *, file_path: str, document_type: DocumentType, case_name: str) -> str: | |
| try: | |
| title_map = { | |
| DocumentType.SUMMONS: "传票", | |
| DocumentType.EXECUTION_RULING: "执行裁定书", | |
| DocumentType.OTHER: "司法文书", | |
| } | |
| title = title_map.get(document_type, "司法文书") | |
| new_filename = self.document_renamer.generate_filename( | |
| title=title, case_name=case_name, received_date=date.today() | |
| ) | |
| from apps.core.utils.path import Path | |
| original_path = Path(file_path) | |
| new_path = original_path.parent / new_filename | |
| counter = 1 | |
| while new_path.exists(): | |
| base_filename = new_filename.replace("收.pdf", f"收{counter}.pdf") | |
| new_path = original_path.parent / base_filename | |
| counter += 1 | |
| if counter > 100: | |
| break | |
| original_path.rename(new_path) | |
| logger.info( | |
| "文书重命名成功", | |
| extra={ | |
| "action": "rename_document", | |
| "original_path": file_path, | |
| "new_path": str(new_path), | |
| "document_type": document_type.value, | |
| "case_name": case_name, | |
| }, | |
| ) | |
| return str(new_path) | |
| except Exception: | |
| logger.warning("文书重命名失败,保留原文件名", extra={}) | |
| return file_path | |