New project with gemini thinking3
This commit is contained in:
parent
38911478ce
commit
7aa9a761ff
1 changed files with 146 additions and 105 deletions
|
|
@ -1,171 +1,212 @@
|
||||||
import os
|
import os
|
||||||
import streamlit as st
|
import streamlit as st
|
||||||
|
import google.generativeai as genai
|
||||||
|
import tempfile
|
||||||
|
import bs4
|
||||||
|
from typing import List
|
||||||
from agno.agent import Agent
|
from agno.agent import Agent
|
||||||
from agno.models.google import Gemini
|
from agno.models.google import Gemini
|
||||||
from agno.tools.duckduckgo import DuckDuckGoTools
|
|
||||||
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
|
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader
|
||||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
from langchain_qdrant import QdrantVectorStore
|
from langchain_qdrant import QdrantVectorStore
|
||||||
from qdrant_client import QdrantClient
|
from qdrant_client import QdrantClient
|
||||||
from qdrant_client.models import Distance, VectorParams
|
from qdrant_client.models import Distance, VectorParams
|
||||||
from agno.vectordb.pgvector import PgVector
|
from langchain_core.embeddings import Embeddings
|
||||||
from agno.embedder.google import GeminiEmbedder
|
|
||||||
import tempfile
|
|
||||||
import bs4
|
|
||||||
|
|
||||||
# Streamlit App Title
|
|
||||||
st.title("AI Agent with Agno and Gemini Thinking")
|
|
||||||
|
|
||||||
# Sidebar for API Key Input
|
# Custom Gemini Embedder Class
|
||||||
st.sidebar.header("Configuration")
|
class GeminiEmbedder(Embeddings):
|
||||||
google_api_key = st.sidebar.text_input("Enter your Google API Key", type="password")
|
def __init__(self, model_name="models/embedding-004"):
|
||||||
qdrant_api_key = st.sidebar.text_input("Enter your Qdrant API Key", type="password")
|
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
|
||||||
qdrant_url = st.sidebar.text_input("Enter your Qdrant URL", placeholder="https://your-qdrant-url.com")
|
self.model = model_name
|
||||||
|
|
||||||
if google_api_key:
|
def embed_documents(self, texts: List[str]) -> List[List[float]]:
|
||||||
os.environ["GOOGLE_API_KEY"] = google_api_key
|
return [self.embed_query(text) for text in texts]
|
||||||
|
|
||||||
|
def embed_query(self, text: str) -> List[float]:
|
||||||
|
response = genai.embed_content(
|
||||||
|
model=self.model,
|
||||||
|
content=text,
|
||||||
|
task_type="retrieval_document"
|
||||||
|
)
|
||||||
|
return response['embedding']
|
||||||
|
|
||||||
|
# Initialize Streamlit App
|
||||||
|
st.title("🤖 AI Agent with Gemini & Qdrant RAG")
|
||||||
|
|
||||||
|
# Sidebar Configuration
|
||||||
|
st.sidebar.header("🔑 API Configuration")
|
||||||
|
google_api_key = st.sidebar.text_input("Google API Key", type="password")
|
||||||
|
qdrant_api_key = st.sidebar.text_input("Qdrant API Key", type="password")
|
||||||
|
qdrant_url = st.sidebar.text_input("Qdrant URL",
|
||||||
|
placeholder="https://your-cluster.cloud.qdrant.io:6333")
|
||||||
|
|
||||||
# Initialize Qdrant Client
|
# Initialize Qdrant Client
|
||||||
def init_qdrant():
|
def init_qdrant():
|
||||||
if not qdrant_api_key or not qdrant_url:
|
if not all([qdrant_api_key, qdrant_url]):
|
||||||
st.warning("Please provide Qdrant API Key and URL in the sidebar.")
|
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
client = QdrantClient(url=qdrant_url, api_key=qdrant_api_key, timeout=60)
|
return QdrantClient(
|
||||||
client.get_collections() # Test connection
|
url=qdrant_url,
|
||||||
return client
|
api_key=qdrant_api_key,
|
||||||
|
timeout=60
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Failed to initialize Qdrant: {e}")
|
st.error(f"🔴 Qdrant connection failed: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
qdrant_client = init_qdrant()
|
# Document Processing Functions
|
||||||
|
def process_pdf(file):
|
||||||
# File/URL Upload Section
|
|
||||||
st.sidebar.header("Upload Data")
|
|
||||||
uploaded_file = st.sidebar.file_uploader("Upload a document", type=["txt", "pdf", "jpg", "png"])
|
|
||||||
web_url = st.sidebar.text_input("Enter a web URL")
|
|
||||||
|
|
||||||
# Document and Web URL Processing
|
|
||||||
def process_document(file):
|
|
||||||
try:
|
try:
|
||||||
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
|
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
|
||||||
tmp_file.write(file.getvalue())
|
tmp_file.write(file.getvalue())
|
||||||
tmp_path = tmp_file.name
|
loader = PyPDFLoader(tmp_file.name)
|
||||||
|
|
||||||
loader = PyPDFLoader(tmp_path)
|
|
||||||
documents = loader.load()
|
documents = loader.load()
|
||||||
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
|
text_splitter = RecursiveCharacterTextSplitter(
|
||||||
texts = text_splitter.split_documents(documents)
|
chunk_size=1000,
|
||||||
|
chunk_overlap=200
|
||||||
os.unlink(tmp_path)
|
)
|
||||||
return texts
|
return text_splitter.split_documents(documents)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Error processing document: {e}")
|
st.error(f"📄 PDF processing error: {str(e)}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def process_web_url(url):
|
def process_web(url):
|
||||||
try:
|
try:
|
||||||
loader = WebBaseLoader(
|
loader = WebBaseLoader(
|
||||||
web_paths=(url,),
|
web_paths=(url,),
|
||||||
bs_kwargs=dict(
|
bs_kwargs=dict(
|
||||||
parse_only=bs4.SoupStrainer(
|
parse_only=bs4.SoupStrainer(
|
||||||
class_=("post-content", "post-title", "post-header")
|
class_=("post-content", "post-title", "post-header", "content", "main")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
),
|
|
||||||
)
|
)
|
||||||
documents = loader.load()
|
documents = loader.load()
|
||||||
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
|
text_splitter = RecursiveCharacterTextSplitter(
|
||||||
texts = text_splitter.split_documents(documents)
|
chunk_size=1000,
|
||||||
return texts
|
chunk_overlap=200
|
||||||
|
)
|
||||||
|
return text_splitter.split_documents(documents)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Error processing web URL: {e}")
|
st.error(f"🌐 Web processing error: {str(e)}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Create and Populate Qdrant Vector Store
|
# Vector Store Management
|
||||||
COLLECTION_NAME = "agno_rag"
|
COLLECTION_NAME = "agno_rag"
|
||||||
|
|
||||||
def create_vector_store(texts):
|
def create_vector_store(client, texts):
|
||||||
if not qdrant_client:
|
|
||||||
return None
|
|
||||||
try:
|
try:
|
||||||
# Create collection if it doesn't exist
|
# Create collection if needed
|
||||||
try:
|
try:
|
||||||
qdrant_client.create_collection(
|
client.create_collection(
|
||||||
collection_name=COLLECTION_NAME,
|
collection_name=COLLECTION_NAME,
|
||||||
vectors_config=VectorParams(size=1024, distance=Distance.COSINE)
|
vectors_config=VectorParams(
|
||||||
|
size=768, # Gemini embedding-004 dimension
|
||||||
|
distance=Distance.COSINE
|
||||||
)
|
)
|
||||||
st.success(f"Created new collection: {COLLECTION_NAME}")
|
)
|
||||||
|
st.success(f"📚 Created new collection: {COLLECTION_NAME}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if "already exists" not in str(e).lower():
|
if "already exists" not in str(e).lower():
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
# Initialize QdrantVectorStore
|
# Initialize vector store
|
||||||
vector_store = QdrantVectorStore(
|
vector_store = QdrantVectorStore(
|
||||||
client=qdrant_client,
|
client=client,
|
||||||
collection_name=COLLECTION_NAME,
|
collection_name=COLLECTION_NAME,
|
||||||
embedding=GeminiEmbedder(dimensions=1024) # Add embedding model if needed
|
embedding=GeminiEmbedder()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add documents to the vector store
|
# Add documents
|
||||||
with st.spinner('Storing documents in Qdrant...'):
|
with st.spinner('📤 Uploading documents to Qdrant...'):
|
||||||
vector_store.add_documents(texts)
|
vector_store.add_documents(texts)
|
||||||
st.success("Documents successfully stored in Qdrant!")
|
st.success("✅ Documents stored successfully!")
|
||||||
|
|
||||||
return vector_store
|
return vector_store
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
st.error(f"Error creating vector store: {e}")
|
st.error(f"🔴 Vector store error: {str(e)}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Process Uploaded File or Web URL
|
# Main Application Flow
|
||||||
if uploaded_file:
|
if google_api_key:
|
||||||
texts = process_document(uploaded_file)
|
os.environ["GOOGLE_API_KEY"] = google_api_key
|
||||||
if texts:
|
genai.configure(api_key=google_api_key)
|
||||||
vector_store = create_vector_store(texts)
|
|
||||||
elif web_url:
|
|
||||||
texts = process_web_url(web_url)
|
|
||||||
if texts:
|
|
||||||
vector_store = create_vector_store(texts)
|
|
||||||
|
|
||||||
# Initialize the Agent
|
qdrant_client = init_qdrant()
|
||||||
if google_api_key and qdrant_client:
|
|
||||||
thinking_agent = Agent(
|
# File/URL Upload Section
|
||||||
name="Thinking Agent",
|
st.sidebar.header("📁 Data Upload")
|
||||||
role="Think about the problem",
|
uploaded_file = st.sidebar.file_uploader("Upload PDF", type=["pdf"])
|
||||||
model=Gemini(id="gemini-2.0-flash-exp", api_key=google_api_key),
|
web_url = st.sidebar.text_input("Or enter URL")
|
||||||
instructions="Given the problem, think about it and provide a detailed explanation",
|
|
||||||
|
# Process documents
|
||||||
|
vector_store = None
|
||||||
|
if uploaded_file:
|
||||||
|
texts = process_pdf(uploaded_file)
|
||||||
|
if texts and qdrant_client:
|
||||||
|
vector_store = create_vector_store(qdrant_client, texts)
|
||||||
|
elif web_url:
|
||||||
|
texts = process_web(web_url)
|
||||||
|
if texts and qdrant_client:
|
||||||
|
vector_store = create_vector_store(qdrant_client, texts)
|
||||||
|
|
||||||
|
# Initialize Agent
|
||||||
|
agent = Agent(
|
||||||
|
name="Gemini RAG Agent",
|
||||||
|
model=Gemini(id="gemini-2.0-flash-exp"),
|
||||||
|
instructions="You are AGI. You are elite speicialist in all fields and an expert in all fields. Answer user's questions clearly, if any document is added, Use retrieved documents to answer questions accurately",
|
||||||
show_tool_calls=True,
|
show_tool_calls=True,
|
||||||
markdown=True,
|
markdown=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Initialize chat history
|
||||||
|
if 'history' not in st.session_state:
|
||||||
|
st.session_state.history = []
|
||||||
|
|
||||||
# Display chat history if it exists
|
# Display chat messages
|
||||||
if 'chat_history' not in st.session_state:
|
for msg in st.session_state.history:
|
||||||
st.session_state.chat_history = []
|
with st.chat_message(msg["role"]):
|
||||||
|
st.write(msg["content"])
|
||||||
|
|
||||||
for message in st.session_state.chat_history:
|
# User input
|
||||||
with st.chat_message(message["role"]):
|
if prompt := st.chat_input("Ask about your documents..."):
|
||||||
st.write(message["content"])
|
# Add user message to history
|
||||||
|
st.session_state.history.append({"role": "user", "content": prompt})
|
||||||
|
with st.chat_message("user"):
|
||||||
|
st.write(prompt)
|
||||||
|
|
||||||
# Chat input using Streamlit's chat_input for better UX
|
# Retrieve relevant documents
|
||||||
user_input = st.chat_input("Ask a question or describe a problem you'd like me to think about...")
|
context = ""
|
||||||
|
if vector_store:
|
||||||
if user_input:
|
|
||||||
# Query the Qdrant vector store for relevant documents
|
|
||||||
if 'vector_store' in locals():
|
|
||||||
retriever = vector_store.as_retriever(
|
retriever = vector_store.as_retriever(
|
||||||
search_type="similarity_score_threshold",
|
search_type="similarity_score_threshold",
|
||||||
search_kwargs={"k": 5, "score_threshold": 0.7}
|
search_kwargs={"k": 5, "score_threshold": 0.7}
|
||||||
)
|
)
|
||||||
relevant_docs = retriever.get_relevant_documents(user_input)
|
docs = retriever.invoke(prompt)
|
||||||
|
context = "\n\n".join([d.page_content for d in docs])
|
||||||
|
|
||||||
if relevant_docs:
|
# Generate response
|
||||||
st.write("Relevant Documents:")
|
with st.spinner("🤖 Thinking..."):
|
||||||
for doc in relevant_docs:
|
try:
|
||||||
st.write(doc.page_content[:200] + "...")
|
full_prompt = f"Context: {context}\n\nQuestion: {prompt}"
|
||||||
|
response = agent.run(full_prompt)
|
||||||
|
|
||||||
# Process the user's input with the agent
|
# Add assistant response to history
|
||||||
response = thinking_agent.run(user_input)
|
st.session_state.history.append({
|
||||||
st.write("Agent's Response:")
|
"role": "assistant",
|
||||||
|
"content": response.content
|
||||||
|
})
|
||||||
|
|
||||||
|
with st.chat_message("assistant"):
|
||||||
st.write(response.content)
|
st.write(response.content)
|
||||||
|
|
||||||
|
if vector_store and docs:
|
||||||
|
with st.expander("🔍 See sources"):
|
||||||
|
for i, doc in enumerate(docs, 1):
|
||||||
|
st.write(f"Source {i}: {doc.page_content[:200]}...")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"❌ Error generating response: {str(e)}")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
st.warning("Please enter your Google API Key and Qdrant credentials in the sidebar to proceed.")
|
st.warning("⚠️ Please enter your Google API Key to continue")
|
||||||
Loading…
Reference in a new issue