studentchatbot / app.py
aak007's picture
Initial commit for Hugging Face
45b17a5
Raw
History Blame Contribute Delete
4.38 kB
from flask import Flask, render_template, jsonify, request
from src.helper import download_hugging_face_embeddings
from langchain_pinecone import PineconeVectorStore
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from dotenv import load_dotenv
from src.prompt import *
import os
import traceback
app = Flask(__name__)
load_dotenv(override=True)
PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
os.environ["PINECONE_API_KEY"] = PINECONE_API_KEY
if GOOGLE_API_KEY:
os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY
embeddings = download_hugging_face_embeddings()
index_name = os.environ.get("PINECONE_INDEX_NAME", "student-chatbot")
# Embed each chunk and upsert the embeddings into your Pinecone index.
docsearch = PineconeVectorStore.from_existing_index(
index_name=index_name, embedding=embeddings
)
retriever = docsearch.as_retriever(search_type="similarity", search_kwargs={"k": 3})
chatModel = ChatGoogleGenerativeAI(
model="gemini-2.5-flash",
temperature=0,
max_retries=2,
)
prompt = ChatPromptTemplate.from_messages(
[
("system", system_prompt),
("human", "{input}"),
]
)
question_answer_chain = create_stuff_documents_chain(chatModel, prompt)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)
def build_context_fallback_answer(user_query: str) -> str:
"""Return a best-effort answer using retrieved context only (no LLM call)."""
try:
docs = retriever.invoke(user_query)
except Exception:
return "Gemini quota is reached, and I could not fetch context right now. Please try again shortly."
if not docs:
return "Gemini quota is reached, and I could not find relevant context for this question right now."
top_doc_text = (docs[0].page_content or "").strip()
if not top_doc_text:
return "Gemini quota is reached, but retrieved context is empty. Please try again later."
answer_line = None
for line in top_doc_text.splitlines():
if line.lower().startswith("answer:"):
answer_line = line.split(":", 1)[1].strip()
break
if answer_line:
return f"Gemini quota reached, so I am answering from stored context: {answer_line}"
snippet = " ".join(
part.strip() for part in top_doc_text.splitlines() if part.strip()
)
snippet = snippet[:450]
return "Gemini quota reached, so I am answering from stored context: " f"{snippet}"
@app.route("/")
def index():
return render_template("chat.html")
@app.route("/get", methods=["GET", "POST"])
def chat():
msg = request.values.get("msg", "").strip()
if not msg:
return "Please enter a question.", 200
print(msg)
if not GOOGLE_API_KEY:
return (
"GOOGLE_API_KEY is missing. Add it to your .env file and restart the app.",
200,
)
try:
response = rag_chain.invoke({"input": msg})
answer = response.get("answer") if isinstance(response, dict) else None
if not answer:
return (
"I could not generate a response right now. Please try rephrasing your question.",
200,
)
print("Response : ", answer)
return str(answer), 200
except Exception as e:
print("Error: ", str(e))
traceback.print_exc()
error_text = str(e).lower()
if (
"api key" in error_text
or "permission" in error_text
or "unauthorized" in error_text
):
return (
"Your Gemini API key is invalid or missing permissions. Please verify GOOGLE_API_KEY.",
200,
)
if "quota" in error_text or "rate" in error_text or "429" in error_text:
fallback_answer = build_context_fallback_answer(msg)
return fallback_answer, 200
return (
"I am having trouble reaching the AI service right now. Please try again in a few seconds.",
200,
)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
app.run(host="0.0.0.0", port=port, debug=False)