feat: improve resume optimization and import reliability

This commit is contained in:
hyp
2026-08-10 11:26:47 +08:00
parent 1c762fd092
commit d8db0d8792
35 changed files with 1861 additions and 661 deletions
+29
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import hashlib
import time
from collections import OrderedDict
from pathlib import Path
from typing import Protocol
@@ -10,6 +11,7 @@ from uuid import uuid4
from .document_extractors import extract_text, normalize_upload_name, validate_upload
from .import_parser_fast import slim_parser
from .llm_services import log_ai_event
from .resume_import_models import ParsedResumeDraft
from .resume_import_rules import parse_resume_text
@@ -38,16 +40,29 @@ class ResumeImportService:
self._parse_cache: OrderedDict[str, ParsedResumeDraft] = OrderedDict()
def prepare(self, *, file_name: str, declared_mime: str | None, content: bytes) -> dict:
total_started = time.perf_counter()
if len(content) > MAX_IMPORT_BYTES:
raise ValueError("import_file_too_large")
safe_name, extension = normalize_upload_name(file_name)
mime_type = validate_upload(extension=extension, declared_mime=declared_mime, content=content)
sha256 = hashlib.sha256(content).hexdigest()
draft = self._parse_cache.get(sha256)
cache_hit = draft is not None
extract_ms = 0
parse_ms = 0
validate_ms = 0
text_characters: int | None = None
if draft is None:
extract_started = time.perf_counter()
text = extract_text(extension=extension, content=content)
extract_ms = round((time.perf_counter() - extract_started) * 1000)
text_characters = len(text)
parse_started = time.perf_counter()
draft = self.parser.parse(text=text, source_name=safe_name)
parse_ms = round((time.perf_counter() - parse_started) * 1000)
validate_started = time.perf_counter()
self._validate_document(draft.document)
validate_ms = round((time.perf_counter() - validate_started) * 1000)
self._parse_cache[sha256] = draft
self._parse_cache.move_to_end(sha256)
while len(self._parse_cache) > _PARSE_CACHE_SIZE:
@@ -57,8 +72,22 @@ class ResumeImportService:
draft = draft.model_copy(deep=True)
object_key = f"{sha256[:2]}/{uuid4().hex}{extension}"
target = self.storage_root / object_key
storage_started = time.perf_counter()
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(content)
storage_ms = round((time.perf_counter() - storage_started) * 1000)
log_ai_event(
"resume_import_prepared",
extract_ms=extract_ms,
parse_ms=parse_ms,
validate_ms=validate_ms,
storage_ms=storage_ms,
total_ms=round((time.perf_counter() - total_started) * 1000),
cache_hit=cache_hit,
file_extension=extension,
size_bytes=len(content),
text_characters=text_characters,
)
return {
"file_name": safe_name,
"mime_type": mime_type,