146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
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 ...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 import llm_service
|
|
from ...services.ai_service import AIService
|
|
from ...services.ai_pmo_kernel_service import AIPMOKernelService
|
|
from ...services.operation_log_service import log_operation
|
|
from ...services.auth import has_any_role
|
|
from ...services.skill_service import recommend_personnel
|
|
from ...services import skill_score_service
|
|
from ...services.sstc_service import (
|
|
ALIGNED_STATUSES,
|
|
DONE_STATUSES,
|
|
RELEASE_VERIFIED_STATUSES,
|
|
SSTCService,
|
|
)
|
|
from ...services import workload_service
|
|
from ...services.budget_enforcement_service import BudgetEnforcementService
|
|
from ...services.feishu_integration import get_feishu_service
|
|
from ...services.adaptive_rag_service import AdaptiveRAGService
|
|
from ...services.context_cache import context_cache_service
|
|
from ...services.task_persistence 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(),
|
|
}
|
|
|
|
|