채팅 API 사용
보안
로그인
채팅 API에 사용할 JWT (access token) 을 얻기 위해 로그인 합니다.
import requests
genos_url = 'GenOS 주소'
url = f"{genos_url}/app/api/chat"
body = {
"user_id": "genos_user_01",
"password": "<PASSWD>"
}
res = requests.post(f"{url}/auth/login",json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"access_token": "<JWT 1>",
"refresh_token": "<JWT 2>",
"user": {
"id": 1,
"user_id": "genos_user_01",
"name": "GenOS 사용자 01",
"email": "genos_user_01@mnc.ai",
"image": "string",
"group": null,
"reset_required": null,
"consent_date": null,
"consent_required": false,
"last_login_time": "2025-02-18T14:25:00",
"is_active": true,
"reg_date": "2025-01-03T14:24:58",
"mod_date": "2025-02-18T14:25:00",
"group_id": null,
"group_name": null
},
"current_login_ip": "123.123.123.123",
"last_login_ip": "192.168.74.172",
"last_login_date": "2025-02-18 14:25:00"
}
}
access_token, refresh token의 값을 저장합니다.
(Opt.) Access 토큰 재발급
Access 토큰 만료 시, 모든 요청에서 405 Unauthorized 에러가 발생합니다.
refresh token을 갖고 있다면, access token의 재발급을 요청할 수 있습니다.
import requests
genos_url = 'GenOS 주소'
url = f"{genos_url}/app/api/chat"
body = {
"refresh_token": refresh_token
}
res = requests.post(f"{url}/auth/refresh",json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"access_token": "<JWT 3>"
}
}
채팅
사용할 채팅 어플리케이션의 endpoint (
jlig_i3hi_i743
형식) 가 필요합니다.
정보 조회
해당 채팅의 주요 정보를 조회합니다.
import requests
genos_url = 'GenOS 주소'
endpoint = 'jlig_i3hi_i743'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
res = requests.get(f"{url}/chat/info?chat_endpoint={endpoint}", headers=headers)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"chat_id": 112, // 채팅 서비스 ID
"chat_rev_id": 187, // 채팅 서비스 리비전ID
"chat_pub_id": 172, // 채팅 서비스 배포ID
"approval_result": "AP0001",
"memo": null,
"service_rev_id": 187,
"icon": null, // 지정되었을 경우 base64
"reg_user": {
"id": 1,
"user_id": "administrator",
"name": "관리자",
"email": "admin@mnc.ai",
"image": "string",
"group": null,
"reset_required": null,
"consent_date": null,
"is_active": true,
"reg_date": "2025-01-03T14:24:58",
"mod_date": "2025-02-18T14:25:00",
"group_id": null,
"group_name": null
},
"service_status": "CS0003",
"title": "검색 UI", // 채팅 서비스 이름
"chat_name": "검색 UI",
"description": "마크다운테스트",
"workflow_id": 226, // 연결된 워크플로우 ID
"ui_template_id": 3, // UI 타입 (1: 채팅, 2: PDF Viewer, 3: 검색)
"session_id": "fecaa1a2-bedd-4558-a3eb-8f69035fe059", // deprecated
"greeting": "안녕하세요. 무엇을 도와드릴까요?", // 인사말
"chat_samples": [], // 샘플 질문
"feedback_type": "FILL_IN", // 피드백 설정
"feedback_questions": [],
"allow_other_feedback": true,
"workflow_plugins": [] // 파일 기반 대화 등 플러그인 정보
}
}
chat_id, workflow_id의 값을 저장합니다.
기본 채팅요청
채팅 응답을 요청합니다.
import requests
genos_url = 'GenOS 주소'
endpoint = 'jlig_i3hi_i743'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
body = {
"question": "Hi, How are you?"
}
res = requests.post(f"{url}/chat/v2/query/{endpoint}", headers=headers, json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"text": "Im fine thank you, and you?",
"question": "Hi, How are you?,
"chatId": "b3429b0c-de84-4740-acbf-ce53a257c5f4",
"chatMessageId": "83812818-fc9e-40cc-ade9-8666a3e3f81d",
"sessionId": "b3429b0c-de84-4740-acbf-ce53a257c5f4"
}
}
멀티 턴 대화
대화 이력을 기반으로 대화하기 위해서는, 같은 세션에 있다는 정보를 알려주어야 합니다.
따라서 새로고침 시나 세션 재시작 등 하나로 묶어줄 대화에서 유지할 무작위 uuid4 값을 생성하고 이를 이용하면 히스토리 기반 대화가 가능합니다.
import requests
from uuid import uuid4
genos_url = 'GenOS 주소'
endpoint = 'jlig_i3hi_i743'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
session_id = str(uuid4()) # ex) f7a30d14-f9ae-4055-904f-594c0573e7a1
첫번째 턴
body의 chatId는 Flowise에 전달하기 위해서 사용되며, headers의 x-genos-session-id 는 GenOS의로깅을 위해 사용합니다.
원활한 로깅 및 피드백 기능을 위해 매 채팅 요청마다 uuid4를 생성하여 x-genos-trace-id 헤더에 전달합니다.
headers['x-genos-session-id'] = session_id
headers['x-genos-trace-id'] = str(uuid4())
body = {
"question": "My Name is GenOS",
"chatId": session_id
}
res = requests.post(f"{url}/chat/v2/query/{endpoint}", headers=headers, json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"text": "Hi GenOS, How can I help you?",
"question": "My Name is GenOS,
"chatId": "f7a30d14-f9ae-4055-904f-594c0573e7a1",
"chatMessageId": "83812818-fc9e-40cc-ade9-8666a3e3f81d",
"sessionId": "f7a30d14-f9ae-4055-904f-594c0573e7a1"
}
}
두번째 턴
이전 대화 기록을 바탕으로 질의합니다.
session_id는 유지하며, trace id는 새로 생성합니다.
headers['x-genos-session-id'] = session_id
headers['x-genos-trace-id'] = str(uuid4())
body = {
"question": "What is my name?",
"chatId": session_id
}
res = requests.post(f"{url}/chat/v2/query/{endpoint}", headers=headers, json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{
"code": 0,
"errMsg": "success",
"data": {
"text": "Your name is GenOS.", // 이전 대화 이력을 바탕으로 대답
"question": "What is my name?,
"chatId": "f7a30d14-f9ae-4055-904f-594c0573e7a1",
"chatMessageId": "1c052c1e-52f2-49b3-ad75-b4532251899f",
"sessionId": "f7a30d14-f9ae-4055-904f-594c0573e7a1"
}
}
(Advanced) 토큰 별 출력
LLM 추론은 시간이 많이 걸리기 때문에, 한번에 응답을 받지 않고 토큰 별 응답을 받을 수 있습니다.
websocket 통신을 기반으로 하는 socket.io를 이용합니다.
워크플로우에 socket.io 연결
python-socketio 라이브러리가 필요합니다.
sid를 body에 포함하면, workflow에서 해당 sid를 가진 room에만 socket.io "token" 메시지를 emit하여 동시 요청에도 별개의 응답을 받을 수 있습니다.
비동기를 지원하는 예시 코드로 작성되었습니다.
from socketio import AsyncClient
import aiohttp
genos_url = 'GenOS 주소'
endpoint = 'kbps_xddq_wer3'
workflow_id = 226 # 채팅 정보 조회 시 얻은 workflow ID
url = f"{genos_url}/app/api/chat/chat/v2/query/{endpoint}"
headers = 생략
async def genos_chat_query_v2(body):
sio = AsyncClient()
@sio.event
async def connect():
pass
@sio.event
async def disconnect():
pass
@sio.on('start') # 첫번째 토큰 응답 전에 발생
async def start(data):
pass
@sio.on('end') # 마지막 토큰 응답 후에 발생
async def end():
pass
@sio.on('token')
async def token(data): # 토큰 별 응답
print(data)
@sio.on('sourceDocuments') # flowise vectordb의 참조 문서 정보
async def sourceDocuments(data):
print(data)
await sio.connect(genos_url, socketio_path=f'/workflow/{workflow_id}/socket.io')
sid = sio.get_sid() # 연결된 socketio.id 클라이언트의 sid를 body에 포함
body['socketIOClientId'] = sid # Flowise에 요청을 위해 사용
headers['x-genos-workflow-sid'] = sid # GenOS 로깅을 위해 사용
async with aiohttp.ClientSession() as session:
async with session.post(url, json=body, headers=headers) as response:
data = await response.json()
await sio.disconnect()
return data
정상 출력은 위와 동일합니다.
피드백
채팅 요청 시 사용한 trace_id를 이용하여 피드백을 추가할 수 있습니다.
부정 피드백의 경우, 채팅 정보 조회 시 얻은 피드백 타입에 따라 사양이 달라집니다.
긍정 피드백 · 삭제
import requests
genos_url = 'GenOS 주소'
chat_id = 177 # 채팅 정보 조회 시 얻은 채팅 서비스 ID
# 아래는 피드백을 추가할 응답을 특정하기 위해 채팅 전송 요청 헤더의 "x-genos-trace-id"와 "x-genos-session-id"로 각각 지정
trace_id = '4844f357-52e6-483c-8a00-b90f1156d9c4'
session_id = 'a404552c-d6ac-434b-aad7-4ad65ebeeb57'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
body = {
"chat_id": chat_id,
"session_id": session_id,
"trace_id": trace_id,
"thumbs": "up" # 긍정 피드백, "none" 이면 피드백 삭제
}
res = requests.post(f"{url}/chat/feedback/v2", headers=headers, json=body)
print(res.json())
정상 출력은 아래와 같습니다.
{"code":0,"errMsg":"success","data":null}
부정 피드백
주관식
채팅 정보 조회 시 feedback_type이
FILL_IN
이면 주관식 피드백으로 지정된 채팅입니다.
import requests
genos_url = 'GenOS 주소'
chat_id = 177 # 채팅 정보 조회 시 얻은 채팅 서비스 ID
# 아래는 피드백을 추가할 응답을 특정하기 위해 채팅 전송 요청 헤더의 "x-genos-trace-id"와 "x-genos-session-id"로 각각 지정
trace_id = '4844f357-52e6-483c-8a00-b90f1156d9c4'
session_id = 'a404552c-d6ac-434b-aad7-4ad65ebeeb57'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
body = {
"chat_id": chat_id,
"session_id": session_id,
"trace_id": trace_id,
"thumbs": "down" # 부정피드백, "none" 이면 피드백 삭제
"messages": [{ "comment": "The answer is unnecessarily long." }]
}
res = requests.post(f"{url}/chat/feedback/v2", headers=headers, json=body)
print(res.json())
정상 출력은 위와 동일합니다.
객관식
채팅 정보 조회 시 feedback_type이
CHOICE
이면 객관식 피드백으로 지정된 채팅입니다.채팅 정보 조회 시 얻을 수 있는 기타 피드백 관련 정보는 아래와 같습니다.
feedback_questions:
list[str]
, 객관식 피드백 종류allow_other_feedback:
bool
, 정해진 객관식 피드백 외에 다른 의견으로 피드백을 추가할 수 있는지 여부
"feedback_type": "CHOICE",
"feedback_questions": [
"길어요",
"틀렸어요"
],
"allow_other_feedback": true,
...
요청 API
messages에서 question에는 얻은 채팅 정보 조회 시 얻은 feedback_questions의 값을 그대로 넣고, allow_other_feedback이 true이면 "기타" 를 추가합니다.
is_checked가 실제로 사용자가 해당 피드백을 체크했는지에 대한 여부입니다.
comment는 is_checked가 true일 때만 값이 유효하며, 사용자가 부가적으로 추가한 의견입니다.
import requests
genos_url = 'GenOS 주소'
chat_id = 177 # 채팅 정보 조회 시 얻은 채팅 서비스 ID
# 아래는 피드백을 추가할 응답을 특정하기 위해 채팅 전송 요청 헤더의 "x-genos-trace-id"와 "x-genos-session-id"로 각각 지정
trace_id = '4844f357-52e6-483c-8a00-b90f1156d9c4'
session_id = 'a404552c-d6ac-434b-aad7-4ad65ebeeb57'
url = f"{genos_url}/app/api/chat"
headers = {
"Authorization": "Bearer <JWT 1>"
}
body = {
"chat_id": chat_id,
"session_id": session_id,
"trace_id": trace_id,
"thumbs": "down" # 부정피드백, "none" 이면 피드백 삭제
"messages": [
{ "question": "길어요", "comment": "불필요해요", "is_checked": True },
{ "question": "틀렸어요", "comment": "", "is_checked": False },
{ "question": "기타", "comment": "", "is_checked": False }
]
}
res = requests.post(f"{url}/chat/feedback/v2", headers=headers, json=body)
print(res.json())
정상 출력은 위와 동일합니다.
Last updated
Was this helpful?