feat: add pcf analysis web app and api
This commit is contained in:
+115
@@ -0,0 +1,115 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class PcfBlock:
|
||||
"""PCF 中的一个顶层段。"""
|
||||
|
||||
block_type: str
|
||||
value: str = ""
|
||||
fields: dict[str, list[str]] = field(default_factory=dict)
|
||||
line_no: int = 0
|
||||
|
||||
def first(self, key: str, default: str = "") -> str:
|
||||
values = self.fields.get(key, [])
|
||||
return values[0] if values else default
|
||||
|
||||
|
||||
@dataclass
|
||||
class WeldRecord:
|
||||
"""内部标准焊口记录。"""
|
||||
|
||||
source_file: str
|
||||
pipeline_reference: str = ""
|
||||
piping_spec: str = ""
|
||||
line_no: str = ""
|
||||
weld_no: str = ""
|
||||
diameter: str = ""
|
||||
outside_diameter: str = ""
|
||||
wall_thickness: str = ""
|
||||
spec: str = ""
|
||||
weld_area_raw: str = ""
|
||||
weld_area: str = ""
|
||||
contractor_raw: str = ""
|
||||
component_identifier: str = ""
|
||||
master_component_identifier: str = ""
|
||||
skey: str = ""
|
||||
uci: str = ""
|
||||
material_1: str = ""
|
||||
material_2: str = ""
|
||||
issues: list[str] = field(default_factory=list)
|
||||
raw_fields: dict[str, list[str]] = field(default_factory=dict)
|
||||
|
||||
def set_if_empty(self, field_name: str, value: str) -> None:
|
||||
if hasattr(self, field_name) and not getattr(self, field_name) and value:
|
||||
setattr(self, field_name, value)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UnknownFieldCandidate:
|
||||
"""等待 DeepSeek 识别的非标准字段候选。"""
|
||||
|
||||
source_field: str
|
||||
section: str
|
||||
sample_values: list[str]
|
||||
context: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class MappingDecision:
|
||||
"""DeepSeek 字段映射结果。"""
|
||||
|
||||
source_field: str
|
||||
target_field: str
|
||||
confidence: float
|
||||
reason: str = ""
|
||||
sample_values: list[str] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def is_usable(self) -> bool:
|
||||
return bool(self.source_field and self.target_field and self.confidence >= 0)
|
||||
|
||||
|
||||
@dataclass
|
||||
class JobResult:
|
||||
job_id: str
|
||||
input_files: int
|
||||
weld_count: int
|
||||
warning_count: int
|
||||
error_count: int
|
||||
output_xls: Path
|
||||
issues_csv: Path
|
||||
report_json: Path
|
||||
messages: list[str] = field(default_factory=list)
|
||||
llm_enabled: bool = False
|
||||
llm_mappings: list[MappingDecision] = field(default_factory=list)
|
||||
import_headers: list[str] = field(default_factory=list)
|
||||
import_columns: list[dict[str, str]] = field(default_factory=list)
|
||||
import_rows: list[dict[str, str]] = field(default_factory=list)
|
||||
issue_rows: list[dict[str, str]] = field(default_factory=list)
|
||||
|
||||
def to_public_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"job_id": self.job_id,
|
||||
"input_files": self.input_files,
|
||||
"weld_count": self.weld_count,
|
||||
"warning_count": self.warning_count,
|
||||
"error_count": self.error_count,
|
||||
"messages": self.messages,
|
||||
"llm_enabled": self.llm_enabled,
|
||||
"tables": {
|
||||
"import_headers": self.import_headers,
|
||||
"import_columns": self.import_columns,
|
||||
"import_rows": self.import_rows,
|
||||
"issue_rows": self.issue_rows,
|
||||
},
|
||||
"downloads": {
|
||||
"xls": f"/api/jobs/{self.job_id}/download/xls",
|
||||
"issues": f"/api/jobs/{self.job_id}/download/issues",
|
||||
"report": f"/api/jobs/{self.job_id}/download/report",
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user