Szuflada / chat_utils.py
jaczad's picture
Aplikacja tworzy bazę po uruchomieniu
0e2081a
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import create_history_aware_retriever, create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
def create_rag_chain(database: Chroma):
"""
Tworzy łańcuch RAG z obsługą historii konwersacji.
"""
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)
retriever = database.as_retriever(search_kwargs={"k": 3})
# Prompt do kontekstualizacji pytania
contextualize_q_system_prompt = (
"Biorąc pod uwagę historię czatu i ostatnie pytanie użytkownika, "
"które może odnosić się do kontekstu w historii czatu, "
"sformułuj samodzielne pytanie, które można zrozumieć bez historii czatu. "
"NIE odpowiadaj na pytanie, po prostu przeformułuj je, jeśli to konieczne, "
"a w przeciwnym razie zwróć je w niezmienionej formie."
)
contextualize_q_prompt = ChatPromptTemplate.from_messages([
("system", contextualize_q_system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
])
history_aware_retriever = create_history_aware_retriever(
llm, retriever, contextualize_q_prompt
)
# Prompt do generowania odpowiedzi
qa_system_prompt = (
"Jesteś asystentem do zadawania pytań i odpowiedzi na temat treści ze strony mojaszuflada.pl. "
"Użyj poniższych fragmentów odzyskanego kontekstu, aby odpowiedzieć na pytanie. "
"Odpowiadaj zawsze w języku polskim. "
"Jeśli nie znasz odpowiedzi, po prostu powiedz, że tego nie wiesz. "
"Zachowaj zwięzłość odpowiedzi, ale bądź pomocny i przyjazny."
"\n\n{context}"
)
qa_prompt = ChatPromptTemplate.from_messages([
("system", qa_system_prompt),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
])
question_answer_chain = create_stuff_documents_chain(llm, qa_prompt)
rag_chain = create_retrieval_chain(history_aware_retriever, question_answer_chain)
return rag_chain
def format_sources(source_docs):
"""
Formatuje listę źródeł do wyświetlenia w odpowiedzi.
"""
if not source_docs:
return "?"
sources = []
for doc in source_docs:
metadata = doc.metadata
title = metadata.get("title", "Brak tytułu")
source_url = metadata.get("source", "Brak URL")
pub_date_raw = metadata.get("published_time")
if pub_date_raw:
pub_date = pub_date_raw.split("T")[0]
sources.append(f"- [{title}]({source_url}) ({pub_date})")
else:
sources.append(f"- [{title}]({source_url})")
return "\n".join(sources)
def create_session_history_manager():
"""
Tworzy menedżer historii sesji.
"""
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
return get_session_history