- /v1/negotiation/sessions/{id}/chat/{init,messages,send} 추가
- agent(9500) 위임 어댑터(IAgentClient) + mock(use_mock) 격리 → agent 미연동 시 1402 graceful degrade
- negotiation.chats 메시지 영속화(meta JSONB) + 종료 시 세션 입찰/거부 확정(단일 트랜잭션)
- 동시전송 가드(유저 메시지 pre-claim/CHAT_IN_PROGRESS) + 실패 시 롤백, 마감/만료 분기, init 만료 정리
- ChatSender enum, chat 에러코드(1400~1403), chats ORM 모델, AgentConfig
- 테스트 10건(test_chat.py), AGENT_INTEGRATION.md 연동 규약 문서
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
58 lines
2.3 KiB
Python
58 lines
2.3 KiB
Python
from fastapi import APIRouter, Depends
|
|
from fastapi.security import HTTPAuthorizationCredentials
|
|
|
|
from common.models.gmodel import UserInfo
|
|
from router.v1.validator.dependencies import IsValidAccessToken, RemoveNoneResponse, security
|
|
from services.chat_service import ChatService
|
|
from .chat_protocol import Req_ChatSend, Res_ChatInit, Res_ChatMessages, Res_ChatSend
|
|
|
|
router = APIRouter(prefix="/v1/negotiation", tags=["Negotiation Chat"], responses={404: {"description": "Not found"}})
|
|
|
|
|
|
@router.get(
|
|
path="/sessions/{session_id}/chat/init",
|
|
response_model=Res_ChatInit,
|
|
summary="채팅 진입(상품·견적 메타)",
|
|
description="채팅 화면 진입용. 상품/견적 정보 + 현재 세션 상태 + 마감 시각(타이머)을 반환한다. 소유(공급사) 검증.",
|
|
)
|
|
async def chat_init(
|
|
session_id: str,
|
|
user_info: UserInfo = Depends(IsValidAccessToken),
|
|
credentials: HTTPAuthorizationCredentials = Depends(security),
|
|
service: ChatService = Depends(),
|
|
):
|
|
return RemoveNoneResponse(await service.init(user_info, credentials.credentials, session_id))
|
|
|
|
|
|
@router.get(
|
|
path="/sessions/{session_id}/chat/messages",
|
|
response_model=Res_ChatMessages,
|
|
summary="대화 히스토리",
|
|
description="세션의 대화 말풍선 목록(seq 오름차순). 비어 있고 협상중이면 오프닝 메시지를 생성해 포함한다.",
|
|
)
|
|
async def chat_messages(
|
|
session_id: str,
|
|
user_info: UserInfo = Depends(IsValidAccessToken),
|
|
credentials: HTTPAuthorizationCredentials = Depends(security),
|
|
service: ChatService = Depends(),
|
|
):
|
|
return RemoveNoneResponse(await service.messages(user_info, credentials.credentials, session_id))
|
|
|
|
|
|
@router.post(
|
|
path="/sessions/{session_id}/chat/send",
|
|
response_model=Res_ChatSend,
|
|
summary="협상 한 턴 전송",
|
|
description="유저 입력을 보내고 agent 가 만든 봇 응답 1건을 반환한다(append-only). 종료 시 세션 입찰을 확정한다.",
|
|
)
|
|
async def chat_send(
|
|
session_id: str,
|
|
req: Req_ChatSend,
|
|
user_info: UserInfo = Depends(IsValidAccessToken),
|
|
credentials: HTTPAuthorizationCredentials = Depends(security),
|
|
service: ChatService = Depends(),
|
|
):
|
|
return RemoveNoneResponse(
|
|
await service.send(user_info, credentials.credentials, session_id, req.user_input_type, req.user_input)
|
|
)
|