Catalyst / admin/Apex 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Apex

public

Bid Management and Orchestration Tool with AI Capability

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Apex / Synapse-Apexv2 / backend / app / routers / capabilities.py 4111 B · main
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from fastapi import APIRouter, Depends, Form, HTTPException, UploadFile
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.deps import audit, require_roles
from app.models import (
    ROLE_ADMIN,
    ROLE_BID_MANAGER,
    ROLE_CONTRIBUTOR,
    Capability,
    CapabilityResponse,
    Document,
    User,
)
from app.schemas import CapabilityOut, CapabilityUpdate
from app.services import storage
from app.workers.tasks import extract_capabilities, regenerate_capability_response

router = APIRouter(prefix="/api/capabilities", tags=["capabilities"])
editor = require_roles(ROLE_ADMIN, ROLE_BID_MANAGER, ROLE_CONTRIBUTOR)


@router.post("/upload")
async def upload_docs(
    kind: str = Form("service"),
    framework_ids: str = Form(""),
    files: list[UploadFile] = None,
    db: Session = Depends(get_db),
    actor: User = Depends(editor),
):
    if not files:
        raise HTTPException(400, "No files")
    doc_ids = []
    for f in files:
        data = await f.read()
        path, sha = storage.save_file(data, f.filename)
        text = storage.extract_text(data, f.filename, f.content_type or "")
        doc = Document(
            kind=kind, filename=f.filename, path=path, mime=f.content_type or "",
            size=len(data), sha256=sha, text_content=text, uploaded_by=actor.id,
        )
        db.add(doc)
        db.flush()
        doc_ids.append(doc.id)
    db.commit()
    fw_ids = [int(x) for x in framework_ids.split(",") if x.strip().isdigit()]
    task = extract_capabilities.delay(doc_ids, fw_ids)
    audit(db, actor, "capability_extraction_started", "document", None, {"docs": doc_ids})
    return {"document_ids": doc_ids, "task_id": task.id}


@router.get("", response_model=list[CapabilityOut])
def list_capabilities(status: str | None = None, db: Session = Depends(get_db), _: User = Depends(editor)):
    q = select(Capability).order_by(Capability.category, Capability.name)
    if status:
        q = q.where(Capability.status == status)
    return db.execute(q).scalars().unique().all()


@router.patch("/{cap_id}", response_model=CapabilityOut)
def update_capability(cap_id: int, body: CapabilityUpdate, db: Session = Depends(get_db), actor: User = Depends(editor)):
    cap = db.get(Capability, cap_id)
    if not cap:
        raise HTTPException(404, "Not found")
    for k, v in body.model_dump(exclude_none=True).items():
        setattr(cap, k, v)
    db.commit()
    db.refresh(cap)
    audit(db, actor, "capability_updated", "capability", cap.id, {"status": cap.status})
    return cap


@router.post("/{cap_id}/approve", response_model=CapabilityOut)
def approve_capability(cap_id: int, db: Session = Depends(get_db), actor: User = Depends(editor)):
    cap = db.get(Capability, cap_id)
    if not cap:
        raise HTTPException(404, "Not found")
    cap.status = "approved"
    for r in cap.responses:
        r.approved = True
    db.commit()
    db.refresh(cap)
    audit(db, actor, "capability_approved", "capability", cap.id)
    return cap


@router.delete("/{cap_id}")
def delete_capability(cap_id: int, db: Session = Depends(get_db), _: User = Depends(editor)):
    cap = db.get(Capability, cap_id)
    if cap:
        db.delete(cap)
        db.commit()
    return {"ok": True}


@router.post("/responses/{resp_id}/regenerate")
def regenerate_response(resp_id: int, db: Session = Depends(get_db), _: User = Depends(editor)):
    resp = db.get(CapabilityResponse, resp_id)
    if not resp:
        raise HTTPException(404, "Not found")
    task = regenerate_capability_response.delay(resp_id)
    return {"task_id": task.id}


@router.patch("/responses/{resp_id}")
def edit_response(resp_id: int, payload: dict, db: Session = Depends(get_db), _: User = Depends(editor)):
    resp = db.get(CapabilityResponse, resp_id)
    if not resp:
        raise HTTPException(404, "Not found")
    if "response_text" in payload:
        resp.response_text = payload["response_text"]
    if "approved" in payload:
        resp.approved = bool(payload["approved"])
    db.commit()
    return {"ok": True}