-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstreamlit_rag_frontend.py
More file actions
171 lines (134 loc) · 5.54 KB
/
Copy pathstreamlit_rag_frontend.py
File metadata and controls
171 lines (134 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import uuid
import streamlit as st
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langraph_rag_backend import (
chatbot,
ingest_pdf,
retrieve_all_threads,
thread_document_metadata,
)
# =========================== Utilities ===========================
def generate_thread_id():
return uuid.uuid4()
def reset_chat():
thread_id = generate_thread_id()
st.session_state["thread_id"] = thread_id
add_thread(thread_id)
st.session_state["message_history"] = []
def add_thread(thread_id):
if thread_id not in st.session_state["chat_threads"]:
st.session_state["chat_threads"].append(thread_id)
def load_conversation(thread_id):
state = chatbot.get_state(config={"configurable": {"thread_id": thread_id}})
return state.values.get("messages", [])
# ======================= Session Initialization ===================
if "message_history" not in st.session_state:
st.session_state["message_history"] = []
if "thread_id" not in st.session_state:
st.session_state["thread_id"] = generate_thread_id()
if "chat_threads" not in st.session_state:
st.session_state["chat_threads"] = retrieve_all_threads()
if "ingested_docs" not in st.session_state:
st.session_state["ingested_docs"] = {}
add_thread(st.session_state["thread_id"])
thread_key = str(st.session_state["thread_id"])
thread_docs = st.session_state["ingested_docs"].setdefault(thread_key, {})
threads = st.session_state["chat_threads"][::-1]
selected_thread = None
# ============================ Sidebar ============================
st.sidebar.title("LangGraph PDF Chatbot")
st.sidebar.markdown(f"**Thread ID:** `{thread_key}`")
if st.sidebar.button("New Chat", use_container_width=True):
reset_chat()
st.rerun()
if thread_docs:
latest_doc = list(thread_docs.values())[-1]
st.sidebar.success(
f"Using `{latest_doc.get('filename')}` "
f"({latest_doc.get('chunks')} chunks from {latest_doc.get('documents')} pages)"
)
else:
st.sidebar.info("No PDF indexed yet.")
uploaded_pdf = st.sidebar.file_uploader("Upload a PDF for this chat", type=["pdf"])
if uploaded_pdf:
if uploaded_pdf.name in thread_docs:
st.sidebar.info(f"`{uploaded_pdf.name}` already processed for this chat.")
else:
with st.sidebar.status("Indexing PDF…", expanded=True) as status_box:
summary = ingest_pdf(
uploaded_pdf.getvalue(),
thread_id=thread_key,
filename=uploaded_pdf.name,
)
thread_docs[uploaded_pdf.name] = summary
status_box.update(label="✅ PDF indexed", state="complete", expanded=False)
st.sidebar.subheader("Past conversations")
if not threads:
st.sidebar.write("No past conversations yet.")
else:
for thread_id in threads:
if st.sidebar.button(str(thread_id), key=f"side-thread-{thread_id}"):
selected_thread = thread_id
# ============================ Main Layout ========================
st.title("Multi Utility Chatbot")
# Chat area
for message in st.session_state["message_history"]:
with st.chat_message(message["role"]):
st.text(message["content"])
user_input = st.chat_input("Ask about your document or use tools")
if user_input:
st.session_state["message_history"].append({"role": "user", "content": user_input})
with st.chat_message("user"):
st.text(user_input)
CONFIG = {
"configurable": {"thread_id": thread_key},
"metadata": {"thread_id": thread_key},
"run_name": "chat_turn",
}
with st.chat_message("assistant"):
status_holder = {"box": None}
def ai_only_stream():
for message_chunk, _ in chatbot.stream(
{"messages": [HumanMessage(content=user_input)]},
config=CONFIG,
stream_mode="messages",
):
if isinstance(message_chunk, ToolMessage):
tool_name = getattr(message_chunk, "name", "tool")
if status_holder["box"] is None:
status_holder["box"] = st.status(
f"🔧 Using `{tool_name}` …", expanded=True
)
else:
status_holder["box"].update(
label=f"🔧 Using `{tool_name}` …",
state="running",
expanded=True,
)
if isinstance(message_chunk, AIMessage):
yield message_chunk.content
ai_message = st.write_stream(ai_only_stream())
if status_holder["box"] is not None:
status_holder["box"].update(
label="✅ Tool finished", state="complete", expanded=False
)
st.session_state["message_history"].append(
{"role": "assistant", "content": ai_message}
)
doc_meta = thread_document_metadata(thread_key)
if doc_meta:
st.caption(
f"Document indexed: {doc_meta.get('filename')} "
f"(chunks: {doc_meta.get('chunks')}, pages: {doc_meta.get('documents')})"
)
st.divider()
if selected_thread:
st.session_state["thread_id"] = selected_thread
messages = load_conversation(selected_thread)
temp_messages = []
for msg in messages:
role = "user" if isinstance(msg, HumanMessage) else "assistant"
temp_messages.append({"role": role, "content": msg.content})
st.session_state["message_history"] = temp_messages
st.session_state["ingested_docs"].setdefault(str(selected_thread), {})
st.rerun()