This commit is contained in:
@@ -19,7 +19,8 @@
|
||||
| `edm_routes.py` | EDM 與節慶儀表板 | `/edm`, `/festival` |
|
||||
| `monthly_routes.py` | 月結分析 | `/monthly_summary_analysis`, `/api/monthly_summary_data` |
|
||||
| `daily_sales_routes.py` | 當日業績 | `/daily_sales`, `/daily_sales/export*` |
|
||||
| `market_intel_routes.py` | 市場情報 Phase 64 candidate queue review handoff | `/market_intel`, `/market_intel/*`, `/api/market_intel/status`, `/api/market_intel/schema`, `/api/market_intel/schema_smoke`, `/api/market_intel/schema_db_probe`, `/api/market_intel/platform_seed_db_diff`, `/api/market_intel/legacy_source_bridge`, `/api/market_intel/mcp_readiness`, `/api/market_intel/mcp_tool_contract`, `/api/market_intel/mcp_deploy_preflight`, `/api/market_intel/mcp_activation_runbook`, `/api/market_intel/mcp_fetch_gate`, `/api/market_intel/scheduler_plan`, `/api/market_intel/manual_sample_plan`, `/api/market_intel/manual_sample_acceptance`, `/api/market_intel/manual_sample_review`, `/api/market_intel/manual_sample_review/evaluate`, `/api/market_intel/manual_sample_review/candidate_handoff`, `/api/market_intel/manual_sample_review/candidate_queue_draft`, `/api/market_intel/manual_sample_review/candidate_queue_approval`, `/api/market_intel/manual_sample_review/candidate_queue_transaction`, `/api/market_intel/manual_sample_review/candidate_queue_writer_status`, `/api/market_intel/manual_sample_review/candidate_queue_writer_preflight`, `/api/market_intel/manual_sample_review/candidate_queue_writer_postwrite_smoke`, `/api/market_intel/manual_sample_review/candidate_queue_writer_operator_drill`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_package`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_readiness`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_receipt`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_closeout`, `/api/market_intel/manual_sample_review/candidate_queue_review_handoff`, `/api/market_intel/match_review_plan`, `/api/market_intel/opportunity_plan`, `/api/market_intel/opportunity_scoring_plan`, `/api/market_intel/opportunity_evidence_plan`, `/api/market_intel/opportunity_alert_plan`, `/api/market_intel/adapters`, `/api/market_intel/dry_run_plan`, `/api/market_intel/discovery_plan`, `/api/market_intel/manual_discovery`, `/api/market_intel/candidate_preview`, `/api/market_intel/platform_seed_plan`, `/api/market_intel/platform_seed_write_guard`, `/api/market_intel/platform_seed_writer_plan`, `/api/market_intel/migration_blueprint`, `/api/market_intel/migration_apply_drill`, `/api/market_intel/migration_catalog_review`, `/api/market_intel/migration_live_smoke`, `/api/market_intel/live_db_inventory`, `/api/market_intel/seed_writer_cli_status`, `/api/market_intel/write_approval_runbook`, `/api/market_intel/deployment_readiness` |
|
||||
| `market_intel_routes.py` | 市場情報 Phase 65 candidate queue review inventory 主路由 | `/market_intel`, `/market_intel/*`, `/api/market_intel/status`, `/api/market_intel/schema`, `/api/market_intel/schema_smoke`, `/api/market_intel/schema_db_probe`, `/api/market_intel/platform_seed_db_diff`, `/api/market_intel/legacy_source_bridge`, `/api/market_intel/mcp_readiness`, `/api/market_intel/mcp_tool_contract`, `/api/market_intel/mcp_deploy_preflight`, `/api/market_intel/mcp_activation_runbook`, `/api/market_intel/mcp_fetch_gate`, `/api/market_intel/scheduler_plan`, `/api/market_intel/manual_sample_plan`, `/api/market_intel/manual_sample_acceptance`, `/api/market_intel/manual_sample_review`, `/api/market_intel/manual_sample_review/evaluate`, `/api/market_intel/manual_sample_review/candidate_handoff`, `/api/market_intel/manual_sample_review/candidate_queue_draft`, `/api/market_intel/manual_sample_review/candidate_queue_approval`, `/api/market_intel/manual_sample_review/candidate_queue_transaction`, `/api/market_intel/manual_sample_review/candidate_queue_writer_status`, `/api/market_intel/manual_sample_review/candidate_queue_writer_preflight`, `/api/market_intel/manual_sample_review/candidate_queue_writer_postwrite_smoke`, `/api/market_intel/manual_sample_review/candidate_queue_writer_operator_drill`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_package`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_readiness`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_receipt`, `/api/market_intel/manual_sample_review/candidate_queue_writer_run_closeout`, `/api/market_intel/manual_sample_review/candidate_queue_review_handoff`, `/api/market_intel/match_review_plan`, `/api/market_intel/opportunity_plan`, `/api/market_intel/opportunity_scoring_plan`, `/api/market_intel/opportunity_evidence_plan`, `/api/market_intel/opportunity_alert_plan`, `/api/market_intel/adapters`, `/api/market_intel/dry_run_plan`, `/api/market_intel/discovery_plan`, `/api/market_intel/manual_discovery`, `/api/market_intel/candidate_preview`, `/api/market_intel/platform_seed_plan`, `/api/market_intel/platform_seed_write_guard`, `/api/market_intel/platform_seed_writer_plan`, `/api/market_intel/migration_blueprint`, `/api/market_intel/migration_apply_drill`, `/api/market_intel/migration_catalog_review`, `/api/market_intel/migration_live_smoke`, `/api/market_intel/live_db_inventory`, `/api/market_intel/seed_writer_cli_status`, `/api/market_intel/write_approval_runbook`, `/api/market_intel/deployment_readiness` |
|
||||
| `market_intel_review_routes.py` | 市場情報人工 queue review 只讀延伸 API | `/api/market_intel/manual_sample_review/candidate_queue_review_inventory` |
|
||||
| `api_routes.py` | 通用任務與查詢 API | `/api/run_task`, `/api/history/*` |
|
||||
| `export_routes.py` | 匯出功能 | `/api/export/*` |
|
||||
| `import_routes.py` | 匯入功能 | `/api/import_excel`, `/api/import/monthly_summary` |
|
||||
|
||||
166
routes/market_intel_review_routes.py
Normal file
166
routes/market_intel_review_routes.py
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/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_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
|
||||
|
||||
|
||||
@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
|
||||
Reference in New Issue
Block a user