219 lines
7.8 KiB
Python
219 lines
7.8 KiB
Python
from __future__ import annotations
|
|
|
|
from http import HTTPStatus
|
|
from typing import Any
|
|
|
|
from repositories.history_repository import (
|
|
append_generated_history,
|
|
clear_history_and_suppressions,
|
|
load_history_for_config,
|
|
)
|
|
|
|
|
|
def run_mark_issue(payload: dict[str, Any], ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
upsert_issue_mark = ctx["upsert_issue_mark"]
|
|
append_review_log = ctx["append_review_log"]
|
|
try:
|
|
mark_type = str(payload.get("mark_type", "")).strip()
|
|
if mark_type not in {"recognition_error", "generation_error"}:
|
|
raise ValueError("mark_type must be recognition_error or generation_error")
|
|
|
|
source_line = str(payload.get("source_line", "")).strip()
|
|
if not source_line:
|
|
raise ValueError("source_line is required")
|
|
|
|
note = str(payload.get("note", "")).strip()
|
|
record = payload.get("record")
|
|
if not isinstance(record, dict):
|
|
record = {}
|
|
issue, issue_created = upsert_issue_mark(
|
|
mark_type=mark_type,
|
|
source_line=source_line,
|
|
note=note,
|
|
record=record,
|
|
)
|
|
|
|
log_path = append_review_log(
|
|
"manual_mark",
|
|
{
|
|
"mark_type": mark_type,
|
|
"source_line": source_line,
|
|
"note": note,
|
|
"record": record,
|
|
"issue_id": str(issue.get("id", "")),
|
|
"issue_action": "create" if issue_created else "update",
|
|
},
|
|
)
|
|
except ValueError as exc:
|
|
return HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)}
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return (
|
|
HTTPStatus.OK,
|
|
{
|
|
"ok": True,
|
|
"message": "已记录到复盘日志",
|
|
"log_file": str(log_path),
|
|
"issue": issue,
|
|
"issue_created": issue_created,
|
|
},
|
|
)
|
|
|
|
|
|
def run_suppress_skipped(payload: dict[str, Any], ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
suppress_skip_item = ctx["suppress_skip_item"]
|
|
append_review_log = ctx["append_review_log"]
|
|
try:
|
|
line = str(payload.get("line", "")).strip()
|
|
reason = str(payload.get("reason", "")).strip()
|
|
item, created = suppress_skip_item(line, reason)
|
|
append_review_log(
|
|
"skip_suppress",
|
|
{
|
|
"line": line,
|
|
"reason": reason or "*",
|
|
"created": created,
|
|
"suppress_id": str(item.get("id", "")),
|
|
},
|
|
)
|
|
except ValueError as exc:
|
|
return HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)}
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return HTTPStatus.OK, {"ok": True, "created": created, "item": item}
|
|
|
|
|
|
def run_update_issue(payload: dict[str, Any], ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
update_issue_mark = ctx["update_issue_mark"]
|
|
append_review_log = ctx["append_review_log"]
|
|
try:
|
|
issue_id = str(payload.get("id", "")).strip()
|
|
if not issue_id:
|
|
raise ValueError("id is required")
|
|
|
|
has_mark_type = "mark_type" in payload
|
|
has_source_line = "source_line" in payload
|
|
has_note = "note" in payload
|
|
has_record = "record" in payload
|
|
if not (has_mark_type or has_source_line or has_note or has_record):
|
|
raise ValueError("nothing to update")
|
|
|
|
issue = update_issue_mark(
|
|
issue_id=issue_id,
|
|
mark_type=payload.get("mark_type") if has_mark_type else None,
|
|
source_line=payload.get("source_line") if has_source_line else None,
|
|
note=payload.get("note") if has_note else None,
|
|
record=payload.get("record") if has_record and isinstance(payload.get("record"), dict) else None,
|
|
)
|
|
if issue is None:
|
|
return HTTPStatus.NOT_FOUND, {"ok": False, "error": "issue not found"}
|
|
append_review_log(
|
|
"issue_update",
|
|
{
|
|
"issue_id": issue_id,
|
|
"mark_type": issue.get("mark_type", ""),
|
|
"source_line": issue.get("source_line", ""),
|
|
"note": issue.get("note", ""),
|
|
},
|
|
)
|
|
except ValueError as exc:
|
|
return HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)}
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return HTTPStatus.OK, {"ok": True, "issue": issue}
|
|
|
|
|
|
def run_delete_issue(payload: dict[str, Any], ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
delete_issue_mark = ctx["delete_issue_mark"]
|
|
append_review_log = ctx["append_review_log"]
|
|
try:
|
|
issue_id = str(payload.get("id", "")).strip()
|
|
if not issue_id:
|
|
raise ValueError("id is required")
|
|
deleted = delete_issue_mark(issue_id)
|
|
if not deleted:
|
|
return HTTPStatus.NOT_FOUND, {"ok": False, "error": "issue not found"}
|
|
append_review_log(
|
|
"issue_delete",
|
|
{
|
|
"issue_id": issue_id,
|
|
},
|
|
)
|
|
except ValueError as exc:
|
|
return HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)}
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return HTTPStatus.OK, {"ok": True, "id": issue_id}
|
|
|
|
|
|
def run_output_clear(ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
load_config = ctx["load_config"]
|
|
resolve_output_dir = ctx["resolve_output_dir"]
|
|
cleanup_output_artifacts = ctx["cleanup_output_artifacts"]
|
|
append_review_log = ctx["append_review_log"]
|
|
try:
|
|
config = load_config()
|
|
output_dir = resolve_output_dir(config)
|
|
stat = cleanup_output_artifacts(output_dir)
|
|
append_review_log(
|
|
"manual_cleanup",
|
|
{
|
|
"output_dir": str(output_dir),
|
|
**stat,
|
|
},
|
|
)
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return (
|
|
HTTPStatus.OK,
|
|
{
|
|
"ok": True,
|
|
"message": "输出目录已清理",
|
|
"output_dir": str(output_dir),
|
|
**stat,
|
|
},
|
|
)
|
|
|
|
|
|
def run_history_append(payload: dict[str, Any], ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
load_config = ctx["load_config"]
|
|
try:
|
|
records = payload.get("records", [])
|
|
key_fields = payload.get("key_fields", ["branch", "amount", "type"])
|
|
if not isinstance(records, list):
|
|
raise ValueError("records must be a list")
|
|
if not isinstance(key_fields, list) or not key_fields:
|
|
key_fields = ["branch", "amount", "type"]
|
|
key_fields = [str(k) for k in key_fields]
|
|
|
|
config = load_config()
|
|
history_path, _ = load_history_for_config(config, ctx)
|
|
stat = append_generated_history(
|
|
history_path=history_path,
|
|
generated_items=records,
|
|
key_fields=key_fields,
|
|
ctx=ctx,
|
|
)
|
|
except ValueError as exc:
|
|
return HTTPStatus.BAD_REQUEST, {"ok": False, "error": str(exc)}
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return HTTPStatus.OK, {"ok": True, **stat}
|
|
|
|
|
|
def run_history_clear(ctx: dict[str, Any]) -> tuple[HTTPStatus, dict[str, Any]]:
|
|
load_config = ctx["load_config"]
|
|
try:
|
|
config = load_config()
|
|
suppressed_cleared = clear_history_and_suppressions(config, ctx)
|
|
except Exception as exc:
|
|
return HTTPStatus.INTERNAL_SERVER_ERROR, {"ok": False, "error": str(exc)}
|
|
|
|
return HTTPStatus.OK, {"ok": True, "count": 0, "skipped_suppressed_cleared": suppressed_cleared}
|