feat(agent): 增加 LLM 路由与诊断日志
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import logging
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
@@ -15,6 +16,9 @@ MAX_PREVIEW_CHARS = 3000
|
||||
MAX_ROWS_PER_SHEET = 20
|
||||
|
||||
|
||||
logger = logging.getLogger("review_agent.file_summary.attachment_reader")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AttachmentReadResult:
|
||||
status: str
|
||||
@@ -32,10 +36,29 @@ class AttachmentReadResult:
|
||||
def read_attachment_details(attachment: FileAttachment) -> AttachmentReadResult:
|
||||
file_path = _attachment_absolute_path(attachment)
|
||||
file_type = Path(attachment.original_name).suffix.lower().lstrip(".")
|
||||
logger.info(
|
||||
"Attachment read started",
|
||||
extra={
|
||||
"attachment_id": attachment.pk,
|
||||
"conversation_id": attachment.conversation_id,
|
||||
"original_name": attachment.original_name,
|
||||
"file_type": file_type,
|
||||
"storage_path": attachment.storage_path,
|
||||
"resolved_path": str(file_path),
|
||||
},
|
||||
)
|
||||
|
||||
if not file_path.exists():
|
||||
logger.warning(
|
||||
"Attachment read missing file",
|
||||
extra={"attachment_id": attachment.pk, "resolved_path": str(file_path)},
|
||||
)
|
||||
return _failed(attachment, file_type, "附件文件不存在。")
|
||||
if file_type not in SUPPORTED_EXTENSIONS:
|
||||
logger.warning(
|
||||
"Attachment read unsupported type",
|
||||
extra={"attachment_id": attachment.pk, "file_type": file_type},
|
||||
)
|
||||
return _failed(attachment, file_type, f"暂不支持解析 .{file_type or 'unknown'} 文件。", "unsupported")
|
||||
|
||||
try:
|
||||
@@ -52,9 +75,21 @@ def read_attachment_details(attachment: FileAttachment) -> AttachmentReadResult:
|
||||
else:
|
||||
sections = _read_text(file_path)
|
||||
except Exception as exc:
|
||||
logger.exception(
|
||||
"Attachment read failed",
|
||||
extra={"attachment_id": attachment.pk, "file_type": file_type, "error": str(exc)},
|
||||
)
|
||||
return _failed(attachment, file_type, str(exc))
|
||||
|
||||
preview = _build_preview(sections)
|
||||
logger.info(
|
||||
"Attachment read finished",
|
||||
extra={
|
||||
"attachment_id": attachment.pk,
|
||||
"section_count": len(sections),
|
||||
"preview_length": len(preview),
|
||||
},
|
||||
)
|
||||
return AttachmentReadResult(
|
||||
status="success",
|
||||
filename=attachment.original_name,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
@@ -8,6 +9,9 @@ from openpyxl import Workbook
|
||||
from review_agent.models import ExportedSummaryFile, FileSummaryBatch
|
||||
|
||||
|
||||
logger = logging.getLogger("review_agent.file_summary.export_excel")
|
||||
|
||||
|
||||
def _exports_dir(batch: FileSummaryBatch) -> Path:
|
||||
root = Path(batch.work_dir) if batch.work_dir else Path(settings.MEDIA_ROOT) / "file_summary" / batch.batch_no
|
||||
export_dir = root / "exports"
|
||||
@@ -16,6 +20,7 @@ def _exports_dir(batch: FileSummaryBatch) -> Path:
|
||||
|
||||
|
||||
def generate_excel_export(batch: FileSummaryBatch) -> ExportedSummaryFile:
|
||||
logger.info("Excel export generation started", extra={"batch_id": batch.pk})
|
||||
workbook = Workbook()
|
||||
summary = workbook.active
|
||||
summary.title = "汇总信息"
|
||||
@@ -47,9 +52,14 @@ def generate_excel_export(batch: FileSummaryBatch) -> ExportedSummaryFile:
|
||||
|
||||
path = _exports_dir(batch) / f"{batch.batch_no}-summary.xlsx"
|
||||
workbook.save(path)
|
||||
return ExportedSummaryFile.objects.create(
|
||||
exported = ExportedSummaryFile.objects.create(
|
||||
batch=batch,
|
||||
export_type=ExportedSummaryFile.ExportType.EXCEL,
|
||||
file_name=path.name,
|
||||
storage_path=str(path),
|
||||
)
|
||||
logger.info(
|
||||
"Excel export generation finished",
|
||||
extra={"batch_id": batch.pk, "export_id": exported.pk, "path": str(path)},
|
||||
)
|
||||
return exported
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
@@ -7,6 +8,9 @@ from django.conf import settings
|
||||
from review_agent.models import ExportedSummaryFile, FileSummaryBatch
|
||||
|
||||
|
||||
logger = logging.getLogger("review_agent.file_summary.report")
|
||||
|
||||
|
||||
def _exports_dir(batch: FileSummaryBatch) -> Path:
|
||||
root = Path(batch.work_dir) if batch.work_dir else Path(settings.MEDIA_ROOT) / "file_summary" / batch.batch_no
|
||||
export_dir = root / "exports"
|
||||
@@ -55,6 +59,7 @@ def build_markdown_report(batch: FileSummaryBatch) -> str:
|
||||
|
||||
|
||||
def generate_markdown_report(batch: FileSummaryBatch) -> tuple[ExportedSummaryFile, str]:
|
||||
logger.info("Markdown report generation started", extra={"batch_id": batch.pk})
|
||||
content = build_markdown_report(batch)
|
||||
path = _exports_dir(batch) / f"{batch.batch_no}-summary.md"
|
||||
path.write_text(content, encoding="utf-8")
|
||||
@@ -64,4 +69,8 @@ def generate_markdown_report(batch: FileSummaryBatch) -> tuple[ExportedSummaryFi
|
||||
file_name=path.name,
|
||||
storage_path=str(path),
|
||||
)
|
||||
logger.info(
|
||||
"Markdown report generation finished",
|
||||
extra={"batch_id": batch.pk, "export_id": exported.pk, "path": str(path)},
|
||||
)
|
||||
return exported, build_summary_table(batch)
|
||||
|
||||
Reference in New Issue
Block a user