Spaces:
Build error
Build error
| """ | |
| Mock extraction engine for testing without external dependencies. | |
| """ | |
| import os | |
| import datetime | |
| from typing import Dict, Any, Optional | |
| from lxml import etree | |
| from fastapi_app.lib.extraction import BaseExtractor | |
| from fastapi_app.lib.utils.tei_utils import ( | |
| create_tei_document, | |
| create_tei_header, | |
| create_revision_desc_with_status, | |
| serialize_tei_with_formatted_header, | |
| get_file_id_from_options, | |
| create_encoding_desc_with_extractor, | |
| ) | |
| from fastapi_app.lib.utils.doi_utils import encode_for_xml_id | |
| class MockExtractor(BaseExtractor): | |
| """Mock extractor for testing without external dependencies.""" | |
| SUPPORTED_VARIANTS = [ | |
| "mock-default", | |
| "mock-variant-a", | |
| "mock-variant-b", | |
| ] | |
| def get_info(cls) -> Dict[str, Any]: | |
| """Return information about the mock extractor.""" | |
| return { | |
| "id": "mock-extractor", | |
| "name": "Mock Extractor", | |
| "description": "Mock extractor for testing without external dependencies (available in testing mode only)", | |
| "input": ["pdf", "xml"], | |
| "output": ["tei-document"], | |
| "variants": list(cls.SUPPORTED_VARIANTS), | |
| "options": { | |
| "doi": { | |
| "type": "string", | |
| "label": "DOI", | |
| "description": "DOI of the document for metadata enrichment", | |
| "required": False | |
| }, | |
| "variant_id": { | |
| "type": "string", | |
| "label": "Variant identifier", | |
| "description": "Variant identifier for the mock extraction", | |
| "required": False, | |
| "options": list(cls.SUPPORTED_VARIANTS) | |
| } | |
| }, | |
| "navigation_xpath": { | |
| "mock-default": [ | |
| { | |
| "value": "//tei:biblStruct", | |
| "label": "<biblStruct>" | |
| } | |
| ] | |
| } | |
| } | |
| def is_available(cls) -> bool: | |
| """Mock extractor available only in testing mode.""" | |
| app_mode = os.environ.get("FASTAPI_APPLICATION_MODE", "development") | |
| return app_mode == "testing" | |
| async def extract(self, pdf_path: Optional[str] = None, xml_content: Optional[str] = None, | |
| options: Optional[Dict[str, Any]] = None) -> str: | |
| """ | |
| Mock extraction that returns a simple TEI document. | |
| Args: | |
| pdf_path: Path to the PDF file (for PDF input) | |
| xml_content: XML content string (for XML input) | |
| options: Extraction options | |
| Returns: | |
| Complete TEI document as XML string | |
| """ | |
| if not pdf_path and not xml_content: | |
| raise ValueError("Either PDF path or XML content is required for mock extraction") | |
| if options is None: | |
| options = {} | |
| # Create TEI document | |
| tei_doc = create_tei_document() | |
| # Create basic TEI header | |
| doi = options.get("doi", "") | |
| tei_header = create_tei_header(doi, {}) | |
| assert tei_header is not None | |
| timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat().replace("+00:00", "Z") | |
| file_id = get_file_id_from_options(options, pdf_path) | |
| if not file_id: | |
| file_id = f"mock-extracted-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}" | |
| fileDesc = tei_header.find("fileDesc") | |
| assert fileDesc is not None | |
| # Set xml:id on fileDesc for document identity (NCName-safe encoding) | |
| fileDesc.set("{http://www.w3.org/XML/1998/namespace}id", encode_for_xml_id(file_id)) | |
| # Create encodingDesc with applications | |
| existing_encodingDesc = tei_header.find("encodingDesc") | |
| if existing_encodingDesc is not None: | |
| tei_header.remove(existing_encodingDesc) | |
| # Get variant_id from options | |
| info = self.get_info() | |
| default_variant_id = info["options"]["variant_id"]["options"][0] # "mock-default" | |
| variant_id = options.get("variant_id", default_variant_id) | |
| encodingDesc = create_encoding_desc_with_extractor( | |
| timestamp=timestamp, | |
| extractor_name="Mock Extractor", | |
| extractor_ident="mock-extractor", | |
| extractor_version="1.0", | |
| variant_id=variant_id, | |
| ) | |
| tei_header.append(encodingDesc) | |
| # Replace revisionDesc with mock-specific version | |
| existing_revisionDesc = tei_header.find("revisionDesc") | |
| if existing_revisionDesc is not None: | |
| tei_header.remove(existing_revisionDesc) | |
| revision_desc = create_revision_desc_with_status(timestamp, "extraction", "Generated with mock extractor for testing") | |
| tei_header.append(revision_desc) | |
| tei_doc.append(tei_header) | |
| # Create mock content with sample references | |
| standOff = etree.SubElement(tei_doc, "standOff") | |
| listBibl = etree.SubElement(standOff, "listBibl") | |
| # Add a few mock bibliography entries | |
| for i in range(3): | |
| biblStruct = etree.SubElement(listBibl, "biblStruct", status="verified") | |
| analytic = etree.SubElement(biblStruct, "analytic") | |
| title = etree.SubElement(analytic, "title", level="a", type="main") | |
| title.text = f"Mock Reference Title {i+1}" | |
| author = etree.SubElement(analytic, "author") | |
| persName = etree.SubElement(author, "persName") | |
| forename = etree.SubElement(persName, "forename", type="first") | |
| forename.text = f"John{i+1}" | |
| surname = etree.SubElement(persName, "surname") | |
| surname.text = f"Doe{i+1}" | |
| monogr = etree.SubElement(biblStruct, "monogr") | |
| title_monogr = etree.SubElement(monogr, "title", level="j") | |
| title_monogr.text = f"Mock Journal {i+1}" | |
| imprint = etree.SubElement(monogr, "imprint") | |
| date_imprint = etree.SubElement(imprint, "date", type="published", when=f"202{i}") | |
| date_imprint.text = f"202{i}" | |
| # Serialize to XML with formatted header (no schema validation for mock extractor) | |
| return serialize_tei_with_formatted_header(tei_doc, []) | |