from __future__ import annotations from __future__ import annotations import asyncio import json import re from datetime import datetime, timedelta, timezone from io import BytesIO from pathlib import Path from typing import Any, Optional from uuid import uuid4 from fastapi import APIRouter, BackgroundTasks, Body, Depends, File, HTTPException, Query, UploadFile from fastapi.responses import JSONResponse, StreamingResponse from pydantic import BaseModel from sqlalchemy import and_, delete, select from sqlalchemy.ext.asyncio import AsyncSession from ...core.response import error_response, success_response from ...core.database import get_db from ...models import ( AICallLog, AlignmentRecord, Integration, ModelRequirementBinding, ModelVersion, ProjectSignalLink, Signal, Task, TruthNode, User, UserProject, ) from ...schemas.sstc import ( AlignmentConfirmRequest, AlignmentStartRequest, CharterUpdateRequest, ReleaseVerificationItemPatchRequest, ReleaseCreateRequest, ReleaseStatusPatchRequest, ReviewArchiveRequest, ReviewContentPatchRequest, ReviewCreateRequest, ReviewImprovementToTaskRequest, WorkloadOptimizeRequest, TaskStatusPatchRequest, ) from ...services.llm_service import llm_service from ...services.ai_service_core import AIService from ...services.ai_pmo_kernel import AIPMOKernelService from ...services.operation_log_service import log_operation from ...services.auth import has_any_role from ...services.skill import recommend_personnel from ...services.skill import skill_score_service from ...services.sstc_service_core import ( ALIGNED_STATUSES, DONE_STATUSES, RELEASE_VERIFIED_STATUSES, SSTCService, ) from ...services import workload as workload_service from ...services.budget_enforcement import BudgetEnforcementService from ...services.feishu_integration_service import get_feishu_service from ...services.adaptive_rag_service import AdaptiveRAGService from ...services.context_cache_service import context_cache_service from ...services.task_persistence_core import build_task_create_draft, persist_task from ...dependencies import get_current_user, require_project_member_or_manager from ...utils.title import compact_title from ...utils.timezone import CN_TZ, now_cn_aware, now_cn_naive _FEISHU_PLACEHOLDER_RE = re.compile(r"^飞书用户\(([^)]+)\)$") _SIGNAL_PREFIX_RE = re.compile(r"^\[(.*?)\]\s*:\s*") _GENERIC_SIGNAL_SOURCE_TITLE_RE = re.compile( r"(加入到信号源|加入信号源|新增(?:一个)?信号源|创建(?:一个)?信号源|添加(?:一个)?信号源)" ) DEFAULT_SIGNAL_AUTO_ENTER_THRESHOLD = 0.80 DEFAULT_PROJECT_AUTO_CREATE_THRESHOLD = 0.85 DEFAULT_PROJECT_UNCERTAIN_THRESHOLD = 0.60 _SIGNAL_STATUS_CODE_PENDING = "pending" _SIGNAL_STATUS_CODE_LINKED = "linked" _SIGNAL_STATUS_CODE_CLOSED = "closed" _SIGNAL_STATUS_LABEL_BY_CODE = { _SIGNAL_STATUS_CODE_PENDING: "待处理", _SIGNAL_STATUS_CODE_LINKED: "已关联宪章", _SIGNAL_STATUS_CODE_CLOSED: "已关闭", } _SIGNAL_STATUS_FILTER_ALIAS = { "pending": _SIGNAL_STATUS_CODE_PENDING, "待处理": _SIGNAL_STATUS_CODE_PENDING, "linked": _SIGNAL_STATUS_CODE_LINKED, "已关联宪章": _SIGNAL_STATUS_CODE_LINKED, "closed": _SIGNAL_STATUS_CODE_CLOSED, "archived": _SIGNAL_STATUS_CODE_CLOSED, "已关闭": _SIGNAL_STATUS_CODE_CLOSED, "已归档": _SIGNAL_STATUS_CODE_CLOSED, } _SIGNAL_LOCK_REASON = "信号已关联宪章,禁止重复新建" _BEIJING_UTC_OFFSET = timedelta(hours=8) _ALLOWED_ATTACHMENT_TYPES = {"image", "file", "media", "document"} _SIGNAL_ATTACHMENT_MAX_BYTES = 20 * 1024 * 1024 _SIGNAL_ATTACHMENT_ALLOWED_EXTENSIONS = { ".jpg": "image", ".jpeg": "image", ".png": "image", ".gif": "image", ".pdf": "document", ".doc": "document", ".docx": "document", ".zip": "file", } _SIGNAL_ATTACHMENT_ALLOWED_MIME_TYPES = { "image/jpeg", "image/png", "image/gif", "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/zip", "application/x-zip-compressed", "multipart/x-zip", "application/octet-stream", } _CHARTER_REQUIRED_FIELDS: dict[str, tuple[str, ...]] = { "module_1": ("problem_statement", "goal_statement", "kpis"), "module_2": ("in_scope", "out_of_scope", "alignment_qa"), "module_3": ("primary_model", "fallback_model", "capability_table", "dependency_map"), "module_4": ("milestones", "role_effort_estimates", "capability_owner_assignment"), "module_5": ("risk_register", "trigger_rules", "execution_rule"), "module_6": ("attachment_metadata", "attachment_summary", "search_tags"), } RELEASE_STATUS_TRANSITIONS: dict[str, set[str]] = { "pending": {"releasing", "online"}, "releasing": {"online", "rolled_back"}, "online": {"rolled_back"}, "rolled_back": {"releasing"}, "verified": set(), }