Ali-Developments commited on
Commit
88a0c11
ยท
verified ยท
1 Parent(s): 81917a3

Upload 2 files

Browse files
Files changed (2) hide show
  1. .env +8 -0
  2. Agent.py +148 -0
.env ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ GROQ_API_KEY="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"
2
+ LANGFUSE_PUBLIC_KEY="pk-lf-2d11058c-faea-457d-8187-50adb4adf9df"
3
+ LANGFUSE_PRIVATE_KEY="sk-lf-6238da13-7995-49f6-be87-7a6b0063abf3"
4
+ HUGGINGFACE_API_TOKEN="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"
5
+ SERPAPI_API_KEY="46b4f7315c732276e79ac17d4f5881594703fc2b8f9ae267c4763ec5c1d39d0a"
6
+ TELEGRAM_BOT_TOKEN= "7836025598:AAHIY1azhByyvTnojr3gLC1wmL0TgA-OO7w"
7
+
8
+
Agent.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import os
3
+ import streamlit as st
4
+ from dotenv import load_dotenv
5
+ from langchain.docstore.document import Document
6
+ from langchain_community.retrievers import BM25Retriever
7
+ from langchain.tools import Tool
8
+ from langchain.utilities import SerpAPIWrapper
9
+ from langgraph.graph.message import add_messages
10
+ from langgraph.graph import START, StateGraph
11
+ from langgraph.prebuilt import ToolNode, tools_condition
12
+ from langchain_core.messages import AnyMessage, HumanMessage
13
+ from langchain_groq import ChatGroq
14
+ from typing import TypedDict, Annotated
15
+ import fitz # PyMuPDF
16
+
17
+ # Load environment variables
18
+ load_dotenv()
19
+ os.environ["GROQ_API_KEY"] = os.getenv("GROQ_API_KEY")
20
+ groq_api_key = os.getenv("GROQ_API_KEY")
21
+ serpapi_api_key = os.getenv("SERPAPI_API_KEY")
22
+
23
+ # --- PDF uploader and parser ---
24
+ def parse_pdfs(uploaded_files):
25
+ pdf_docs = []
26
+ for uploaded_file in uploaded_files:
27
+ with fitz.open(stream=uploaded_file.read(), filetype="pdf") as doc:
28
+ text = ""
29
+ for page in doc:
30
+ text += page.get_text()
31
+ pdf_docs.append(Document(page_content=text, metadata={"source": uploaded_file.name}))
32
+ return pdf_docs
33
+
34
+ # --- Guest info retrieval ---
35
+ def build_retriever(all_docs):
36
+ return BM25Retriever.from_documents(all_docs)
37
+
38
+ def extract_text(query: str, retriever):
39
+ results = retriever.invoke(query)
40
+ if results:
41
+ return "\n\n".join([doc.page_content for doc in results[:3]])
42
+ else:
43
+ return "ู„ู… ูŠุชู… ุงู„ุนุซูˆุฑ ุนู„ู‰ ู…ุนู„ูˆู…ุงุช ู…ุทุงุจู‚ุฉ ููŠ ุงู„ู…ู„ูุงุช."
44
+
45
+ # --- Streamlit UI ---
46
+ st.set_page_config(page_title="NINU Agent", page_icon="๐Ÿ›๏ธ")
47
+ st.title("๐Ÿ›๏ธ NINU - Guest & PDF & Web Assistant")
48
+
49
+ st.markdown("** Hint:** NINU can help summarize lectures, answer questions from PDFs, and search the web interactively.")
50
+
51
+ if "conversation_history" not in st.session_state:
52
+ st.session_state.conversation_history = []
53
+
54
+ query = st.text_area("๐Ÿ“ ุงูƒุชุจ ุณุคุงู„ูƒ ุฃูˆ ูƒู…ู„ ู…ุฐุงูƒุฑุชูƒ ู‡ู†ุง:")
55
+
56
+ uploaded_files = st.file_uploader("๐Ÿ“„ ุงุฑูุน ู…ู„ูุงุช PDF ู„ู„ู…ุญุงุถุฑุงุช", type=["pdf"], accept_multiple_files=True)
57
+
58
+ if st.button("Ask NINU") and query:
59
+ # Parse PDFs if uploaded
60
+ user_docs = parse_pdfs(uploaded_files) if uploaded_files else []
61
+ bm25_retriever = build_retriever(user_docs) if user_docs else None
62
+
63
+ # Tool for PDF retrieval (if PDFs uploaded)
64
+ def pdf_tool_func(q):
65
+ if bm25_retriever:
66
+ return extract_text(q, bm25_retriever)
67
+ else:
68
+ return "ู„ุง ุชูˆุฌุฏ ู…ู„ูุงุช PDF ู…ุฑููˆุนุฉ ู„ู„ุจุญุซ."
69
+
70
+ NINU_tool = Tool(
71
+ name="NINU_Lec_retriever",
72
+ func=pdf_tool_func,
73
+ description="Retrieves content from uploaded PDFs based on a query."
74
+ )
75
+
76
+ # Tool for Web search using SerpAPI
77
+ serpapi = SerpAPIWrapper(serpapi_api_key=serpapi_api_key)
78
+ SerpAPI_tool = Tool(
79
+ name="WebSearch",
80
+ func=serpapi.run,
81
+ description="Searches the web for recent information."
82
+ )
83
+
84
+ # Combine tools
85
+ tools = [NINU_tool, SerpAPI_tool]
86
+
87
+ # Create LLM and bind tools
88
+ llm = ChatGroq(model="deepseek-r1-distill-llama-70b", groq_api_key=groq_api_key)
89
+ llm_with_tools = llm.bind_tools(tools)
90
+
91
+ # Define Agent state and assistant function
92
+ class AgentState(TypedDict):
93
+ messages: Annotated[list[AnyMessage], add_messages]
94
+
95
+ def assistant(state: AgentState):
96
+ return {
97
+ "messages": [llm_with_tools.invoke(state["messages"])]
98
+ }
99
+
100
+ # Build the StateGraph agent
101
+ builder = StateGraph(AgentState)
102
+ builder.add_node("assistant", assistant)
103
+ builder.add_node("tools", ToolNode(tools))
104
+ builder.add_edge(START, "assistant")
105
+ builder.add_conditional_edges("assistant", tools_condition)
106
+ builder.add_edge("tools", "assistant")
107
+ NINU = builder.compile()
108
+
109
+ # Add intro prompt if first message
110
+ if len(st.session_state.conversation_history) == 0:
111
+ intro_prompt = """
112
+ You are a general AI assistant with access to two tools:
113
+
114
+ 1. NINU_Lec_retriever: retrieves content from uploaded PDFs based on a query.
115
+ 2. WebSearch: performs web searches to answer questions about current events or general knowledge.
116
+
117
+ Based on the user's query, decide whether to use NINU_Lec_retriever, WebSearch, or both.
118
+
119
+ When answering, report your thoughts and finish your answer with the following template:
120
+ FINAL ANSWER: [YOUR FINAL ANSWER].
121
+
122
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
123
+
124
+ If you are asked for a number, don't use commas or units (like $, %, etc.) unless specified.
125
+
126
+ If you are asked for a string, avoid articles, abbreviations, and write digits in plain text unless specified.
127
+ """
128
+ st.session_state.conversation_history.append(HumanMessage(content=intro_prompt))
129
+
130
+ # Add user query
131
+ st.session_state.conversation_history.append(HumanMessage(content=query))
132
+
133
+ # Invoke the agent
134
+ response = NINU.invoke({"messages": st.session_state.conversation_history})
135
+
136
+ # Append assistant reply to conversation history
137
+ assistant_reply = response["messages"][-1]
138
+ st.session_state.conversation_history.append(assistant_reply)
139
+
140
+ # Show assistant reply
141
+ st.markdown("### NINU's Response:")
142
+ st.write(assistant_reply.content)
143
+
144
+ # Show full conversation history (optional)
145
+ with st.expander("๐Ÿงพ Show full conversation history"):
146
+ for msg in st.session_state.conversation_history:
147
+ role = "You" if msg.type == "human" else "NINU"
148
+ st.markdown(f"**{role}:** {msg.content}")