Chainlit을 알게 된 경위는 이렇다.
멀티턴 대화랑 Tavily를 비롯한 LangChain tools를 결합해서 내 음악 디깅 전용 챗봇을 만들어보자는 취지였다.
Ollama를 비롯해서 많이 쓰던 Open Web UI를 사용해볼까 했는데 백엔드와 프론트엔드까지 생각 하려니 예상보다 복잡한 것 같았다.
때문에 더 쉬운 툴이 없을까 하다가 찾은게 Chainlit이다.
Docs: 링크
Github: 링크
Cookbook: 링크
튜토리얼의 코드를 살짝만 손보아서 채팅 목록을 저장해보았는데 잘 작동하는걸 확인했다.
import json
from datetime import datetime
from pathlib import Path
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser
from langchain.schema.runnable import Runnable
from langchain.schema.runnable.config import RunnableConfig
from typing import cast
import chainlit as cl
@cl.on_chat_start
async def on_chat_start():
model = ChatOpenAI(streaming=True)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You're a mucic recommendation assistant.",
),
("human", "{question}"),
]
)
runnable = prompt | model | StrOutputParser()
cl.user_session.set("chat_history", []) # 채팅 기록을 저장할 리스트 초기화
cl.user_session.set("runnable", runnable)
# 대화 세션의 고유 ID 생성 (timestamp 사용)
session_id = 'sampleUser' + datetime.now().strftime("%Y%m%d_%H%M%S")
cl.user_session.set("session_id", session_id)
# 저장 디렉토리 생성
save_dir = Path("chat_logs")
#save_dir.mkdir(exist_ok=True)
cl.user_session.set("save_path", save_dir / f"chat_session_{session_id}.jsonl")
@cl.on_message
async def on_message(message: cl.Message):
runnable = cast(Runnable, cl.user_session.get("runnable")) # type: Runnable
chat_history = cl.user_session.get("chat_history")
save_path = cl.user_session.get("save_path")
session_id = cl.user_session.get("session_id")
# Save the message to the chat history
chat_history.append({"role": "human",
"content": message.content,
"timestamp": datetime.now().isoformat()})
msg = cl.Message(content="")
full_response = "" # 전체 응답을 저장할 변수
async for chunk in runnable.astream(
{"question": message.content},
config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]),
):
await msg.stream_token(chunk)
full_response += chunk # 응답 청크를 모아서 저장
await msg.send()
# AI 응답을 저장
chat_history.append({"role": "assistant",
"content": full_response,
"timestamp": datetime.now().isoformat()})
# JSONL 파일에 AI 응답 저장
with open(save_path, "a", encoding="utf-8") as f:
f.write(json.dumps(chat_history, ensure_ascii=False) + "\n")
# 세션에 업데이트된 채팅 기록 저장
cl.user_session.set("chat_history", chat_history)
아래는 jsonl 형식으로 저장한 채팅 기록이다.
[{"role": "human", "content": "tripleS와 유사한 음악 추천해줘", "timestamp": "2025-05-14T17:19:23.090359"}, {"role": "assistant", "content": "tripleS(트리플에스)는 트로트 가수들이 모인 그룹으로, 전통적이고 감성적인 음악을 선보입니다. 이와 유사한 음악을 찾는다면 트로트나 발라드 장르의 곡을 추천해 드릴 수 있습니다. 예를 들어, 김연자, 임영웅, 장민호, 임영웅, 조항조 등의 가수들의 음악을 들어보시는 것을 추천드립니다. 또한 박효신, 정승환, 다비치와 같은 발라드 가수들의 곡도 유사한 감성을 느낄 수 있을 것입니다. 더 좋은 추천을 위해서는 어떤 스타일이나 분위기를 선호하시는지 더 자세한 정보를 제공해 주시면 더 정확한 추천을 드릴 수 있을 것입니다.", "timestamp": "2025-05-14T17:19:26.031770"}, {"role": "human", "content": "트로트가 아니라 K-pop 걸그룹이야. 이를 반영해서 추천해줘 ", "timestamp": "2025-05-14T17:19:40.109859"}, {"role": "assistant", "content": "알겠습니다! K-pop 걸그룹 노래를 추천해 드릴게요. 여자친구(GFRIEND)의 \"여름비 (Summer Rain)\"을 추천드립니다. 이 노래는 여자친구의 매력적인 보컬과 멜로디가 인상적인 곡입니다. 즐겁게 감상해보시길 바랍니다!", "timestamp": "2025-05-14T17:19:41.509107"}]
ChatHistory를 만들고 저장하는 과정과 왼쪽 사이드에 채팅 목록을 가져오는 방법, 그리고 Tavily나 RAG 등의 기능을 덧붙여봐야겠다.
아니면 streamlit으로도 챗봇을 만들 수 있으니 이쪽으로 넘어가는 방안도 고려해야겠다.
References:
https://cheatsheet.md/ko/python-cheatsheet/Chainlit
https://github.com/Chainlit/cookbook/tree/main/resume-chat
https://docs.chainlit.io/api-reference/lifecycle-hooks/on-chat-resume
https://docs.chainlit.io/data-persistence/history
https://docs.streamlit.io/develop/tutorials/chat-and-llm-apps/build-conversational-apps
'AI Codes > LangChain & MCP & Agent' 카테고리의 다른 글
Multi Agent와 ReAct 관련 글 모음 (0) | 2025.05.28 |
---|---|
Streamlit으로 음악 추천을 위한 챗봇 구현 (2) | 2025.05.16 |
LLM으로 테이블과 차트 생성 (2) | 2025.05.08 |
금융 PDF에서 Figure와 Table 추출하기 (0) | 2025.05.02 |
부서와 직급을 고려한 RAG 그리고 평가 (2) | 2025.05.02 |