Files
ewoooc/routes/market_intel_review_routes.py
OoO ca27f2e4eb
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
新增市場情報 Telegram dispatch report input gate
2026-05-20 12:16:22 +08:00

796 lines
28 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""市場情報人工審核延伸 API。"""
from flask import Blueprint, jsonify, request
from auth import login_required
from services.market_intel import MarketIntelService
from services.market_intel.candidate_queue_review_handoff import (
build_candidate_queue_review_handoff,
)
from services.market_intel.candidate_queue_review_inventory import (
build_candidate_queue_review_inventory,
)
from services.market_intel.candidate_queue_review_decision import (
build_candidate_queue_review_decision,
)
from services.market_intel.candidate_queue_review_decision_approval import (
build_candidate_queue_review_decision_approval,
)
from services.market_intel.candidate_queue_review_decision_transaction import (
build_candidate_queue_review_decision_transaction,
)
from services.market_intel.candidate_queue_review_decision_writer_cli import (
build_candidate_queue_review_decision_writer_cli_plan,
)
from services.market_intel.candidate_queue_review_decision_writer_preflight import (
build_candidate_queue_review_decision_writer_preflight,
)
from services.market_intel.candidate_queue_review_decision_writer_postwrite_smoke import (
build_candidate_queue_review_decision_writer_postwrite_smoke,
)
from services.market_intel.candidate_queue_review_decision_writer_operator_drill import (
build_candidate_queue_review_decision_writer_operator_drill,
)
from services.market_intel.candidate_queue_review_decision_writer_run_package import (
build_candidate_queue_review_decision_writer_run_package,
)
from services.market_intel.candidate_queue_review_decision_writer_run_readiness import (
build_candidate_queue_review_decision_writer_run_readiness,
)
from services.market_intel.candidate_queue_review_decision_writer_run_receipt import (
build_candidate_queue_review_decision_writer_run_receipt,
)
from services.market_intel.candidate_queue_review_decision_writer_run_closeout import (
build_candidate_queue_review_decision_writer_run_closeout,
)
from services.market_intel.candidate_queue_writer_cli import (
build_candidate_queue_writer_cli_plan,
)
from services.market_intel.candidate_queue_writer_operator_drill import (
build_candidate_queue_writer_operator_drill,
)
from services.market_intel.candidate_queue_writer_postwrite_smoke import (
build_candidate_queue_writer_postwrite_smoke,
)
from services.market_intel.candidate_queue_writer_preflight import (
build_candidate_queue_writer_preflight,
)
from services.market_intel.candidate_queue_writer_run_closeout import (
build_candidate_queue_writer_run_closeout,
)
from services.market_intel.candidate_queue_writer_run_package import (
build_candidate_queue_writer_run_package,
)
from services.market_intel.candidate_queue_writer_run_readiness import (
build_candidate_queue_writer_run_readiness,
)
from services.market_intel.candidate_queue_writer_run_receipt import (
build_candidate_queue_writer_run_receipt,
)
market_intel_review_bp = Blueprint("market_intel_review", __name__)
def _extract_run_payload():
payload = request.get_json(silent=True)
limit = request.args.get("limit", default=20, type=int)
if not isinstance(payload, dict):
return None, {}, {}, {}, "invalid_json_object", limit
return (
payload.get("sample_result", payload),
payload.get("operator_evidence", {}),
payload.get("writer_output", {}),
payload.get("postwrite_smoke_result", {}),
None,
limit,
)
def _build_closeout_stack(
*,
service,
sample_result,
payload_error,
operator_evidence,
writer_output,
postwrite_smoke_result,
limit,
):
transaction_preview = service.build_manual_sample_candidate_queue_transaction(
sample_result=sample_result,
payload_error=payload_error,
limit=limit,
)
writer_preflight = build_candidate_queue_writer_preflight(
transaction_preview=transaction_preview,
execute_requested=False,
)
writer_status = build_candidate_queue_writer_cli_plan(
transaction_preview=transaction_preview,
writer_preflight=writer_preflight,
approval_token=None,
approval_token_secret=None,
)
planned_smoke = build_candidate_queue_writer_postwrite_smoke(
transaction_preview=transaction_preview,
execute_requested=False,
)
operator_drill = build_candidate_queue_writer_operator_drill(
transaction_preview=transaction_preview,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=planned_smoke,
)
run_package = build_candidate_queue_writer_run_package(
transaction_preview=transaction_preview,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=planned_smoke,
operator_drill=operator_drill,
)
run_readiness = build_candidate_queue_writer_run_readiness(
transaction_preview=transaction_preview,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=planned_smoke,
operator_drill=operator_drill,
run_package=run_package,
operator_evidence=operator_evidence,
)
receipt = build_candidate_queue_writer_run_receipt(
transaction_preview=transaction_preview,
run_readiness=run_readiness,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
operator_evidence=operator_evidence,
)
closeout = build_candidate_queue_writer_run_closeout(
transaction_preview=transaction_preview,
run_receipt=receipt,
operator_evidence=operator_evidence,
)
handoff = build_candidate_queue_review_handoff(
transaction_preview=transaction_preview,
run_closeout=closeout,
operator_evidence=operator_evidence,
)
return transaction_preview, handoff
def _build_review_decision_stack(
*,
service,
sample_result,
payload_error,
operator_evidence,
writer_output,
postwrite_smoke_result,
limit,
execute_requested,
):
transaction_preview, handoff = _build_closeout_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
limit=limit,
)
read_only_allowed = bool(execute_requested and handoff.get("handoff_ready"))
inventory = build_candidate_queue_review_inventory(
review_handoff=handoff,
postwrite_smoke=build_candidate_queue_writer_postwrite_smoke(
transaction_preview=transaction_preview,
execute_requested=read_only_allowed,
),
live_db_inventory=service.build_live_db_inventory(
execute_requested=read_only_allowed,
),
operator_evidence=operator_evidence,
execute_requested=execute_requested,
)
return build_candidate_queue_review_decision(
review_inventory=inventory,
operator_evidence=operator_evidence,
)
def _build_review_decision_approval_stack(
*,
service,
sample_result,
payload_error,
operator_evidence,
writer_output,
postwrite_smoke_result,
limit,
execute_requested,
):
decision = _build_review_decision_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
limit=limit,
execute_requested=execute_requested,
)
return build_candidate_queue_review_decision_approval(
review_decision=decision,
operator_evidence=operator_evidence,
)
def _build_review_decision_transaction_stack(
*,
service,
sample_result,
payload_error,
operator_evidence,
writer_output,
postwrite_smoke_result,
limit,
execute_requested,
):
approval = _build_review_decision_approval_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
limit=limit,
execute_requested=execute_requested,
)
return build_candidate_queue_review_decision_transaction(
decision_approval=approval,
operator_evidence=operator_evidence,
)
def _build_review_decision_writer_receipt_stack(
*,
service,
sample_result,
payload_error,
operator_evidence,
writer_output,
postwrite_smoke_result,
limit,
):
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
limit=limit,
execute_requested=False,
)
writer_status = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
writer_preflight = build_candidate_queue_review_decision_writer_preflight(
writer_status=writer_status,
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
)
postwrite_smoke = build_candidate_queue_review_decision_writer_postwrite_smoke(
transaction_preview=transaction,
execute_requested=False,
)
operator_drill = build_candidate_queue_review_decision_writer_operator_drill(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_evidence=operator_evidence,
)
run_package = build_candidate_queue_review_decision_writer_run_package(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_drill=operator_drill,
)
run_readiness = build_candidate_queue_review_decision_writer_run_readiness(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_drill=operator_drill,
run_package=run_package,
operator_evidence=operator_evidence,
)
receipt = build_candidate_queue_review_decision_writer_run_receipt(
transaction_preview=transaction,
run_readiness=run_readiness,
writer_output=writer_output,
postwrite_smoke_result=postwrite_smoke_result,
operator_evidence=operator_evidence,
)
return transaction, receipt
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/candidate_queue_review_inventory",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_inventory():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction_preview, handoff = _build_closeout_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
)
read_only_allowed = bool(execute_requested and handoff.get("handoff_ready"))
postwrite_smoke = build_candidate_queue_writer_postwrite_smoke(
transaction_preview=transaction_preview,
execute_requested=read_only_allowed,
)
live_db_inventory = service.build_live_db_inventory(
execute_requested=read_only_allowed,
)
data = build_candidate_queue_review_inventory(
review_handoff=handoff,
postwrite_smoke=postwrite_smoke,
live_db_inventory=live_db_inventory,
operator_evidence=operator_evidence,
execute_requested=execute_requested,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/candidate_queue_review_decision",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
data = _build_review_decision_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=execute_requested,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/candidate_queue_review_decision_approval",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_approval():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
data = _build_review_decision_approval_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=execute_requested,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_transaction",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_transaction():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
data = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=execute_requested,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_status",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_status():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
apply_real_write = (
request.args.get("apply_real_write", "false").lower() == "true"
)
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
data = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
execute_requested=execute_requested,
apply_real_write=apply_real_write,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_preflight",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_preflight():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
apply_real_write = (
request.args.get("apply_real_write", "false").lower() == "true"
)
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
writer_status = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
execute_requested=False,
apply_real_write=False,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
data = build_candidate_queue_review_decision_writer_preflight(
writer_status=writer_status,
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=execute_requested,
apply_real_write=apply_real_write,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_postwrite_smoke",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_postwrite_smoke():
service = MarketIntelService()
execute_requested = request.args.get("execute", "false").lower() == "true"
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
data = build_candidate_queue_review_decision_writer_postwrite_smoke(
transaction_preview=transaction,
execute_requested=execute_requested,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_operator_drill",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_operator_drill():
service = MarketIntelService()
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
writer_status = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
writer_preflight = build_candidate_queue_review_decision_writer_preflight(
writer_status=writer_status,
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
)
postwrite_smoke = build_candidate_queue_review_decision_writer_postwrite_smoke(
transaction_preview=transaction,
execute_requested=False,
)
data = build_candidate_queue_review_decision_writer_operator_drill(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_evidence=operator_evidence,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_run_package",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_run_package():
service = MarketIntelService()
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
writer_status = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
writer_preflight = build_candidate_queue_review_decision_writer_preflight(
writer_status=writer_status,
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
)
postwrite_smoke = build_candidate_queue_review_decision_writer_postwrite_smoke(
transaction_preview=transaction,
execute_requested=False,
)
operator_drill = build_candidate_queue_review_decision_writer_operator_drill(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_evidence=operator_evidence,
)
data = build_candidate_queue_review_decision_writer_run_package(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_drill=operator_drill,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_run_readiness",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_run_readiness():
service = MarketIntelService()
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction = _build_review_decision_transaction_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
execute_requested=False,
)
writer_status = build_candidate_queue_review_decision_writer_cli_plan(
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
approval_token=None,
approval_token_secret=None,
backup_verified=False,
review_inventory_smoke_passed=False,
)
writer_preflight = build_candidate_queue_review_decision_writer_preflight(
writer_status=writer_status,
transaction_preview=transaction,
operator_evidence=operator_evidence,
execute_requested=False,
apply_real_write=False,
)
postwrite_smoke = build_candidate_queue_review_decision_writer_postwrite_smoke(
transaction_preview=transaction,
execute_requested=False,
)
operator_drill = build_candidate_queue_review_decision_writer_operator_drill(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_evidence=operator_evidence,
)
run_package = build_candidate_queue_review_decision_writer_run_package(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_drill=operator_drill,
)
data = build_candidate_queue_review_decision_writer_run_readiness(
transaction_preview=transaction,
writer_preflight=writer_preflight,
writer_status=writer_status,
postwrite_smoke=postwrite_smoke,
operator_drill=operator_drill,
run_package=run_package,
operator_evidence=operator_evidence,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_run_receipt",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_run_receipt():
service = MarketIntelService()
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction, data = _build_review_decision_writer_receipt_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
@market_intel_review_bp.route(
"/api/market_intel/manual_sample_review/"
"candidate_queue_review_decision_writer_run_closeout",
methods=["POST"],
)
@login_required
def market_intel_manual_sample_candidate_queue_review_decision_writer_run_closeout():
service = MarketIntelService()
sample_result, operator_evidence, writer_output, smoke_result, payload_error, limit = (
_extract_run_payload()
)
transaction, receipt = _build_review_decision_writer_receipt_stack(
service=service,
sample_result=sample_result,
payload_error=payload_error,
operator_evidence=operator_evidence,
writer_output=writer_output,
postwrite_smoke_result=smoke_result,
limit=limit,
)
data = build_candidate_queue_review_decision_writer_run_closeout(
transaction_preview=transaction,
run_receipt=receipt,
operator_evidence=operator_evidence,
)
data["phase"] = service.phase
return jsonify(data), 400 if payload_error else 200
from routes import market_intel_review_post_routes # noqa: E402,F401
from routes import market_intel_review_post_ai_routes # noqa: E402,F401
from routes import market_intel_review_report_routes # noqa: E402,F401