Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,13 +1,6 @@
|
|
1 |
# app.py
|
2 |
-
#
|
3 |
-
#
|
4 |
-
# This app leverages LangGraph, DeepSeek-R1 via text-based function calling, and Agentic RAG.
|
5 |
-
# API keys are securely loaded via environment variables.
|
6 |
-
#
|
7 |
-
# To deploy:
|
8 |
-
# 1. Add your API key to Hugging Face Space secrets with the key DEEP_SEEK_API.
|
9 |
-
# 2. Ensure your requirements.txt includes langchain-community.
|
10 |
-
# 3. Run the app with Streamlit.
|
11 |
|
12 |
import os
|
13 |
import re
|
@@ -17,14 +10,17 @@ import requests
|
|
17 |
from typing import Sequence
|
18 |
from typing_extensions import TypedDict, Annotated
|
19 |
|
20 |
-
#
|
21 |
from langchain.embeddings.openai import OpenAIEmbeddings
|
22 |
from langchain.vectorstores import Chroma
|
23 |
from langchain.schema import HumanMessage, AIMessage
|
24 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
25 |
from langchain.tools.retriever import create_retriever_tool
|
26 |
|
27 |
-
#
|
|
|
|
|
|
|
28 |
from langgraph.graph import END, StateGraph, START
|
29 |
from langgraph.prebuilt import ToolNode
|
30 |
from langgraph.graph.message import add_messages
|
@@ -46,22 +42,34 @@ development_texts = [
|
|
46 |
"Product Y: In the Performance Optimization Stage Before Release"
|
47 |
]
|
48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
# --- Preprocessing & Embeddings ---
|
50 |
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=10)
|
51 |
research_docs = splitter.create_documents(research_texts)
|
52 |
development_docs = splitter.create_documents(development_texts)
|
53 |
|
54 |
-
embeddings = OpenAIEmbeddings(
|
|
|
|
|
|
|
55 |
|
|
|
56 |
research_vectorstore = Chroma.from_documents(
|
57 |
documents=research_docs,
|
58 |
embedding=embeddings,
|
59 |
-
collection_name="research_collection"
|
|
|
60 |
)
|
61 |
development_vectorstore = Chroma.from_documents(
|
62 |
documents=development_docs,
|
63 |
embedding=embeddings,
|
64 |
-
collection_name="development_collection"
|
|
|
65 |
)
|
66 |
|
67 |
research_retriever = research_vectorstore.as_retriever()
|
@@ -77,11 +85,12 @@ development_tool = create_retriever_tool(
|
|
77 |
"development_db_tool",
|
78 |
"Search information from the development database."
|
79 |
)
|
|
|
80 |
tools = [research_tool, development_tool]
|
81 |
|
82 |
# --- Agent and Workflow Functions ---
|
83 |
-
# Note: We are using only AIMessage and HumanMessage for our message types.
|
84 |
class AgentState(TypedDict):
|
|
|
85 |
messages: Annotated[Sequence[AIMessage | HumanMessage], add_messages]
|
86 |
|
87 |
def agent(state: AgentState):
|
@@ -118,6 +127,8 @@ Otherwise, just answer directly.
|
|
118 |
if response.status_code == 200:
|
119 |
response_text = response.json()['choices'][0]['message']['content']
|
120 |
logger.info(f"DeepSeek response: {response_text}")
|
|
|
|
|
121 |
if "SEARCH_RESEARCH:" in response_text:
|
122 |
query = response_text.split("SEARCH_RESEARCH:")[1].strip()
|
123 |
results = research_retriever.invoke(query)
|
@@ -235,33 +246,87 @@ def process_question(user_question, app, config):
|
|
235 |
return events
|
236 |
|
237 |
# --- Streamlit UI ---
|
238 |
-
import streamlit as st
|
239 |
-
|
240 |
def main():
|
241 |
st.set_page_config(
|
242 |
-
page_title="
|
243 |
layout="wide",
|
244 |
initial_sidebar_state="expanded"
|
245 |
)
|
246 |
|
247 |
-
#
|
248 |
st.markdown("""
|
249 |
<style>
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
}
|
256 |
</style>
|
257 |
""", unsafe_allow_html=True)
|
258 |
|
259 |
-
|
260 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
261 |
|
262 |
-
|
263 |
-
|
264 |
-
|
|
|
|
|
265 |
|
266 |
if __name__ == "__main__":
|
267 |
main()
|
|
|
1 |
# app.py
|
2 |
+
# Multi-Agent Chatbot with LangGraph, DeepSeek-R1, Function Calls, and Agentic RAG
|
3 |
+
# Using local (in-memory) Chroma to avoid tenant errors.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
import os
|
6 |
import re
|
|
|
10 |
from typing import Sequence
|
11 |
from typing_extensions import TypedDict, Annotated
|
12 |
|
13 |
+
# LangChain imports
|
14 |
from langchain.embeddings.openai import OpenAIEmbeddings
|
15 |
from langchain.vectorstores import Chroma
|
16 |
from langchain.schema import HumanMessage, AIMessage
|
17 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
18 |
from langchain.tools.retriever import create_retriever_tool
|
19 |
|
20 |
+
# Chroma in-memory settings
|
21 |
+
from chromadb.config import Settings
|
22 |
+
|
23 |
+
# LangGraph imports
|
24 |
from langgraph.graph import END, StateGraph, START
|
25 |
from langgraph.prebuilt import ToolNode
|
26 |
from langgraph.graph.message import add_messages
|
|
|
42 |
"Product Y: In the Performance Optimization Stage Before Release"
|
43 |
]
|
44 |
|
45 |
+
# --- Chroma Client Settings (in-memory) ---
|
46 |
+
client_settings = Settings(
|
47 |
+
chroma_api_impl="local",
|
48 |
+
persist_directory=None # Set to None for ephemeral in-memory DB
|
49 |
+
)
|
50 |
+
|
51 |
# --- Preprocessing & Embeddings ---
|
52 |
splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=10)
|
53 |
research_docs = splitter.create_documents(research_texts)
|
54 |
development_docs = splitter.create_documents(development_texts)
|
55 |
|
56 |
+
embeddings = OpenAIEmbeddings(
|
57 |
+
model="text-embedding-3-large",
|
58 |
+
openai_api_key=os.environ.get("OPENAI_API_KEY") # Make sure your HF Space secret is set
|
59 |
+
)
|
60 |
|
61 |
+
# Create vector stores using local in-memory Chroma
|
62 |
research_vectorstore = Chroma.from_documents(
|
63 |
documents=research_docs,
|
64 |
embedding=embeddings,
|
65 |
+
collection_name="research_collection",
|
66 |
+
client_settings=client_settings
|
67 |
)
|
68 |
development_vectorstore = Chroma.from_documents(
|
69 |
documents=development_docs,
|
70 |
embedding=embeddings,
|
71 |
+
collection_name="development_collection",
|
72 |
+
client_settings=client_settings
|
73 |
)
|
74 |
|
75 |
research_retriever = research_vectorstore.as_retriever()
|
|
|
85 |
"development_db_tool",
|
86 |
"Search information from the development database."
|
87 |
)
|
88 |
+
|
89 |
tools = [research_tool, development_tool]
|
90 |
|
91 |
# --- Agent and Workflow Functions ---
|
|
|
92 |
class AgentState(TypedDict):
|
93 |
+
# Using only AIMessage | HumanMessage
|
94 |
messages: Annotated[Sequence[AIMessage | HumanMessage], add_messages]
|
95 |
|
96 |
def agent(state: AgentState):
|
|
|
127 |
if response.status_code == 200:
|
128 |
response_text = response.json()['choices'][0]['message']['content']
|
129 |
logger.info(f"DeepSeek response: {response_text}")
|
130 |
+
|
131 |
+
# Format the response to call the right tool
|
132 |
if "SEARCH_RESEARCH:" in response_text:
|
133 |
query = response_text.split("SEARCH_RESEARCH:")[1].strip()
|
134 |
results = research_retriever.invoke(query)
|
|
|
246 |
return events
|
247 |
|
248 |
# --- Streamlit UI ---
|
|
|
|
|
249 |
def main():
|
250 |
st.set_page_config(
|
251 |
+
page_title="Multi-Agent Chatbot",
|
252 |
layout="wide",
|
253 |
initial_sidebar_state="expanded"
|
254 |
)
|
255 |
|
256 |
+
# Simple CSS for improved visibility
|
257 |
st.markdown("""
|
258 |
<style>
|
259 |
+
.stApp {
|
260 |
+
background-color: #ffffff;
|
261 |
+
}
|
262 |
+
.stButton > button {
|
263 |
+
width: 100%;
|
264 |
+
margin-top: 20px;
|
265 |
+
}
|
266 |
+
.data-box {
|
267 |
+
padding: 20px;
|
268 |
+
border-radius: 10px;
|
269 |
+
margin: 10px 0;
|
270 |
+
background-color: #f0f0f0;
|
271 |
+
}
|
272 |
+
.research-box {
|
273 |
+
border-left: 5px solid #1976d2;
|
274 |
+
color: #111 !important;
|
275 |
+
}
|
276 |
+
.dev-box {
|
277 |
+
border-left: 5px solid #43a047;
|
278 |
+
color: #111 !important;
|
279 |
}
|
280 |
</style>
|
281 |
""", unsafe_allow_html=True)
|
282 |
|
283 |
+
# Sidebar with data
|
284 |
+
with st.sidebar:
|
285 |
+
st.header("π Available Data")
|
286 |
+
st.subheader("Research Database")
|
287 |
+
for text in research_texts:
|
288 |
+
st.markdown(f'<div class="data-box research-box">{text}</div>', unsafe_allow_html=True)
|
289 |
+
st.subheader("Development Database")
|
290 |
+
for text in development_texts:
|
291 |
+
st.markdown(f'<div class="data-box dev-box">{text}</div>', unsafe_allow_html=True)
|
292 |
+
|
293 |
+
st.title("π€ Multi-Agent Chatbot")
|
294 |
+
st.markdown("---")
|
295 |
+
|
296 |
+
query = st.text_area("Enter your question:", height=100, placeholder="e.g., What is the latest advancement in AI research?")
|
297 |
+
|
298 |
+
col1, col2 = st.columns([1, 2])
|
299 |
+
with col1:
|
300 |
+
if st.button("π Get Answer", use_container_width=True):
|
301 |
+
if query:
|
302 |
+
with st.spinner("Processing your question..."):
|
303 |
+
events = process_question(query, app_workflow, {"configurable": {"thread_id": "1"}})
|
304 |
+
for event in events:
|
305 |
+
# Step logs
|
306 |
+
if 'agent' in event:
|
307 |
+
with st.expander("π Processing Step", expanded=True):
|
308 |
+
content = event['agent']['messages'][0].content
|
309 |
+
if "Results:" in content:
|
310 |
+
st.markdown("### π Retrieved Documents:")
|
311 |
+
docs = content[content.find("Results:"):]
|
312 |
+
st.info(docs)
|
313 |
+
elif 'generate' in event:
|
314 |
+
st.markdown("### β¨ Final Answer:")
|
315 |
+
st.success(event['generate']['messages'][0].content)
|
316 |
+
else:
|
317 |
+
st.warning("β οΈ Please enter a question first!")
|
318 |
+
with col2:
|
319 |
+
st.markdown("""
|
320 |
+
### π― How to Use
|
321 |
+
1. Type your question in the text box.
|
322 |
+
2. Click "Get Answer" to process.
|
323 |
+
3. View retrieved documents and the final answer.
|
324 |
|
325 |
+
### π‘ Example Questions
|
326 |
+
- What are the latest advancements in AI research?
|
327 |
+
- What is the status of Project A?
|
328 |
+
- What are the current trends in machine learning?
|
329 |
+
""")
|
330 |
|
331 |
if __name__ == "__main__":
|
332 |
main()
|