You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
3.8 KiB
Python
137 lines
3.8 KiB
Python
# backend/app/routers/research.py
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlmodel import Session, select
|
|
|
|
from ..agents.research_agent import answer_question, run_research
|
|
from ..auth.deps import current_user
|
|
from ..auth.scope import scoped
|
|
from ..db import get_session
|
|
from ..models import (
|
|
Person,
|
|
ResearchChart,
|
|
ResearchCollection,
|
|
ResearchQA,
|
|
ResearchReport,
|
|
ResearchSource,
|
|
)
|
|
from ..schemas import (
|
|
AskOut,
|
|
AskRequest,
|
|
ChartOut,
|
|
CollectionOut,
|
|
QAOut,
|
|
ReportOut,
|
|
ResearchHomeOut,
|
|
SourceOut,
|
|
StartResearchOut,
|
|
StartResearchRequest,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
RS_PROMPTS = [
|
|
"최신 AI 반도체 시장 동향 — 보고서·논문·뉴스 종합해줘",
|
|
"신생아 유모차 구매 관련해서 정보 모아줘",
|
|
"경쟁사 A 매출 5년 추이 차트 그리고 내년 예측해줘",
|
|
]
|
|
ENTRIES = [
|
|
{
|
|
"id": "report",
|
|
"icon": "globe",
|
|
"tone": "blue",
|
|
"title": "멀티소스 종합 리포트",
|
|
"desc": "논문·뉴스·보고서를 모아 교차 분석",
|
|
},
|
|
{
|
|
"id": "qa",
|
|
"icon": "brain",
|
|
"tone": "green",
|
|
"title": "지식 베이스 Q&A",
|
|
"desc": "저장한 자료에 근거와 함께 답변",
|
|
},
|
|
{
|
|
"id": "chart",
|
|
"icon": "chart",
|
|
"tone": "coral",
|
|
"title": "시각화 & 추세 예측",
|
|
"desc": "데이터를 그리고 한계까지 짚어 예측",
|
|
},
|
|
]
|
|
|
|
|
|
@router.get("/research/home", response_model=ResearchHomeOut)
|
|
def research_home(s: Session = Depends(get_session), user: Person = Depends(current_user)):
|
|
cols = s.exec(
|
|
scoped(select(ResearchCollection), ResearchCollection, user.id).order_by(
|
|
ResearchCollection.sort_order
|
|
)
|
|
).all()
|
|
srcs = s.exec(select(ResearchSource).order_by(ResearchSource.sort_order)).all()
|
|
return ResearchHomeOut(
|
|
collections=[CollectionOut(id=c.id, name=c.name, tone=c.tone, n=c.n) for c in cols],
|
|
sources=[
|
|
SourceOut(
|
|
id=x.id,
|
|
kind=x.kind.value if hasattr(x.kind, "value") else x.kind,
|
|
title=x.title,
|
|
from_=x.from_label,
|
|
col=x.col,
|
|
learned=x.learned,
|
|
)
|
|
for x in srcs
|
|
],
|
|
prompts=RS_PROMPTS,
|
|
entries=ENTRIES,
|
|
)
|
|
|
|
|
|
@router.get("/research/report", response_model=ReportOut)
|
|
def get_report(s: Session = Depends(get_session)):
|
|
rp = s.exec(select(ResearchReport)).first()
|
|
if not rp:
|
|
raise HTTPException(404, "no report")
|
|
return ReportOut(
|
|
id=rp.id,
|
|
title=rp.title,
|
|
asked=rp.asked,
|
|
meta=rp.meta,
|
|
counts=rp.counts,
|
|
synthesis=rp.synthesis,
|
|
cross=rp.cross,
|
|
note=rp.note,
|
|
)
|
|
|
|
|
|
@router.get("/research/qa", response_model=QAOut)
|
|
def get_qa(s: Session = Depends(get_session)):
|
|
qa = s.exec(select(ResearchQA)).first()
|
|
if not qa:
|
|
return QAOut()
|
|
return QAOut(id=qa.id, q=qa.q, a=qa.a, refs=qa.refs)
|
|
|
|
|
|
@router.get("/research/chart", response_model=ChartOut)
|
|
def get_chart(s: Session = Depends(get_session)):
|
|
c = s.exec(select(ResearchChart)).first()
|
|
if not c:
|
|
raise HTTPException(404, "no chart")
|
|
return ChartOut(
|
|
id=c.id,
|
|
title=c.title,
|
|
asked=c.asked,
|
|
unit=c.unit,
|
|
bars=c.bars,
|
|
insight=c.insight,
|
|
caution=c.caution,
|
|
)
|
|
|
|
|
|
@router.post("/research/start", response_model=StartResearchOut)
|
|
def start_research(req: StartResearchRequest, s: Session = Depends(get_session)):
|
|
return run_research(s, req.query)
|
|
|
|
|
|
@router.post("/research/ask", response_model=AskOut)
|
|
def ask(req: AskRequest, s: Session = Depends(get_session)):
|
|
return answer_question(s, req.q, collection_id=req.collection_id)
|