| from langgraph.graph import StateGraph, START, END |
| from typing import TypedDict, Annotated |
| from langchain_groq import ChatGroq |
| from langchain_openai import OpenAIEmbeddings, ChatOpenAI |
| from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage |
| from langgraph.graph.message import add_messages |
| from langchain_core.tools import tool |
| from dotenv import load_dotenv |
| from langgraph.checkpoint.memory import MemorySaver |
| import os |
| from langchain_community.vectorstores import FAISS |
| from langchain_community.tools.tavily_search import TavilySearchResults |
|
|
| load_dotenv() |
|
|
|
|
| |
| |
| |
|
|
| FAISS_DB_PATH = "vectorstore/db_faiss" |
| embeddings = OpenAIEmbeddings(model='text-embedding-3-small') |
|
|
| |
| db = None |
|
|
| def reload_vector_store(): |
| """ |
| Reloads the FAISS index from disk. |
| Call this function after a new file is ingested. |
| """ |
| global db |
| if os.path.exists(FAISS_DB_PATH): |
| print(f"Loading FAISS from {FAISS_DB_PATH}...") |
| try: |
| db = FAISS.load_local( |
| FAISS_DB_PATH, |
| embeddings, |
| allow_dangerous_deserialization=True |
| ) |
| print("Vector store loaded successfully.") |
| except Exception as e: |
| print(f"Error loading vector store: {e}") |
| db = None |
| else: |
| print("Warning: No Vector DB found. Please run ingestion first.") |
| db = None |
|
|
| |
| reload_vector_store() |
|
|
|
|
| |
| |
| |
|
|
| class Ragbot_State(TypedDict): |
| query : str |
| context : list[str] |
| metadata : list[dict] |
| RAG : bool |
| web_search : bool |
| model_name : str |
| web_context : str |
| response : Annotated[list[BaseMessage], add_messages] |
|
|
| |
| |
| |
|
|
|
|
| llm_kimi2 = ChatGroq(model='moonshotai/kimi-k2-instruct-0905', streaming=True, temperature=0.4) |
| llm_gpt = ChatOpenAI(model='gpt-4.1-nano', streaming=True, temperature=0.2) |
| llm_gpt_oss = ChatGroq(model='openai/gpt-oss-120b', streaming=True, temperature=0.3) |
| llm_lamma4 = ChatGroq(model='meta-llama/llama-4-scout-17b-16e-instruct', streaming=True, temperature=0.5) |
| llm_qwen3 = ChatGroq(model='qwen/qwen3-32b', streaming=True, temperature=0.5) |
|
|
| def get_llm(model_name: str): |
| if model_name == "kimi2": |
| return llm_kimi2 |
| elif model_name == "gpt": |
| return llm_gpt |
| elif model_name == "gpt_oss": |
| return llm_gpt_oss |
| elif model_name == "lamma4": |
| return llm_lamma4 |
| elif model_name == "qwen3": |
| return llm_qwen3 |
| else: |
| return llm_gpt |
|
|
| |
| |
| |
|
|
| @tool |
| def tavily_search(query: str) -> dict: |
| """ |
| Perform a real-time web search using Tavily. |
| """ |
| try: |
| search = TavilySearchResults(max_results=2) |
| results = search.run(query) |
| return {"query": query, "results": results} |
| except Exception as e: |
| return {"error": str(e)} |
| |
| |
| |
| |
|
|
| def fetch_web_context(state: Ragbot_State): |
| user_query = state["query"] |
|
|
| enriched_query = f""" |
| Fetch the latest, accurate, and up-to-date information about: |
| {user_query} |
| |
| Focus on: |
| - recent news |
| - official announcements |
| - verified sources |
| - factual data |
| """ |
|
|
| web_result = tavily_search.run(enriched_query) |
|
|
| return { |
| "web_context": str(web_result) |
| } |
|
|
| |
| |
| |
|
|
| @tool |
| def faiss_search(query: str) -> str: |
| """Search the FAISS vectorstore and return relevant documents.""" |
| |
| if db is None: |
| return "No documents have been uploaded yet.", [] |
|
|
| try: |
| results = db.similarity_search(query, k=3) |
| context = "\n\n".join([doc.page_content for doc in results]) |
| metadata = [doc.metadata for doc in results] |
| return context, metadata |
| except Exception as e: |
| return f"Error searching vector store: {str(e)}", [] |
|
|
| |
| |
| |
|
|
|
|
| def router(state: Ragbot_State): |
| if state["RAG"]: |
| return "fetch_context" |
|
|
| if state["web_search"]: |
| return "fetch_web_context" |
|
|
| return "chat" |
|
|
| |
| |
| |
|
|
| def fetch_context(state: Ragbot_State): |
| query = state["query"] |
| context, metadata = faiss_search.invoke({"query": query}) |
| return {"context": [context], "metadata": [metadata]} |
|
|
|
|
| |
| |
| |
|
|
|
|
| SYSTEM_PROMPT = SystemMessage( |
| content=""" |
| You are **Cortex AI**, an advanced multi-capability conversational and reasoning assistant created by Junaid. |
| |
| Cortex AI is designed to be: |
| - Highly intelligent, reliable, and context-aware |
| - Capable of natural human-like conversation as well as deep technical reasoning |
| - Adaptive across multiple domains including AI, Machine Learning, Data Science, Software Engineering, and general knowledge |
| |
| You represent a next-generation AI system with the ability to: |
| - Engage in friendly, natural, and professional conversations |
| - Answer questions using your own knowledge when no external context is required |
| - Leverage provided context accurately when available |
| - Dynamically utilize web search when real-time or up-to-date information is needed |
| - Utilize retrieval-based knowledge (RAG) when document or database context is provided |
| - Seamlessly switch between casual chat, technical explanation, and problem-solving modes |
| |
| About your creator: |
| You were built by **Junaid**, an AI & Machine Learning engineer and student specializing in Data Science, Machine Learning, Deep Learning, NLP, Computer Vision, and AI-driven systems. You reflect his focus on practical, production-ready AI solutions and high engineering standards. |
| |
| Core Behavioral Guidelines: |
| |
| 1. **Accuracy First** |
| - Always prioritize correctness over speed or verbosity. |
| - If information is uncertain, incomplete, or unavailable, clearly state that. |
| - Never hallucinate or fabricate facts. |
| |
| 2. **Context-Aware Intelligence** |
| - If relevant context is provided, treat it as the primary source of truth. |
| - If context is not relevant or not provided, rely on your general knowledge. |
| - Do not mix unrelated context into answers. |
| |
| 3. **Adaptive Intelligence** |
| - If web search is enabled, use it for real-time, current, or dynamic information. |
| - If retrieval (RAG) is enabled, use it for document-based or knowledge-base questions. |
| - If neither is enabled or required, respond directly using your internal knowledge. |
| |
| 4. **Natural & Professional Communication** |
| - Maintain a clear, human-like, and engaging conversational tone. |
| - Be concise where possible, detailed where necessary. |
| - Avoid robotic, overly verbose, or overly casual language. |
| |
| 5. **Multi-Tasking Excellence** |
| - Handle technical explanations, coding help, architectural guidance, reasoning tasks, and casual conversation equally well. |
| - Break down complex concepts into simple, understandable explanations when needed. |
| |
| 6. **No Internal Exposure** |
| - Never mention internal implementation details such as embeddings, vector stores, pipelines, system architecture, or model orchestration. |
| - Focus only on delivering the best possible user-facing response. |
| |
| 7. **User-Centric Approach** |
| - Be helpful, supportive, and solution-oriented. |
| - Proactively guide the user when appropriate. |
| - Align responses with the user’s skill level and intent. |
| |
| You are not just a chatbot. |
| You are **Cortex AI** — a powerful, intelligent, and reliable AI assistant built to deliver high-quality, real-world value. |
| """ |
| ) |
|
|
| |
| |
| |
|
|
| def chat(state:Ragbot_State): |
| query = state['query'] |
| context = state['context'] |
| metadata = state['metadata'] |
| web_context = state['web_context'] |
| model_name = state.get('model_name', 'gpt') |
|
|
| history = state.get("response", []) |
|
|
| |
| prompt = f""" |
| You are an expert assistant designed to answer user questions using multiple information sources. |
| |
| Source Priority Rules (STRICT): |
| 1. **Conversation History**: Check if the answer was provided in previous messages (e.g., user's name, previous topics). |
| 2. If the provided Context contains the answer, use ONLY the Context. |
| 3. If the Context does not contain the answer and Web Context is available, use the Web Context. |
| 4. If neither Context nor Web Context contains the answer, use your general knowledge. |
| 5. Do NOT invent or hallucinate facts. |
| 6. If the answer cannot be determined, clearly say so. |
| |
| User Question: |
| {query} |
| |
| Retrieved Context (Vector Database): |
| {context} |
| |
| Metadata: |
| {metadata} |
| |
| Web Context (Real-time Search): |
| {web_context} |
| |
| Final Answer: |
| """ |
|
|
| selected_llm = get_llm(model_name) |
| messages = [SYSTEM_PROMPT] + history + [HumanMessage(content=prompt)] |
| response = selected_llm.invoke(messages) |
| return { |
| 'response': [ |
| HumanMessage(content=query), |
| response |
| ] |
| } |
|
|
| |
| |
| |
|
|
| |
| memory = MemorySaver() |
| graph = StateGraph(Ragbot_State) |
|
|
| graph.add_node("fetch_context", fetch_context) |
| graph.add_node("fetch_web_context", fetch_web_context) |
| graph.add_node("chat", chat) |
|
|
| graph.add_conditional_edges( |
| START, |
| router, |
| { |
| "fetch_context": "fetch_context", |
| "fetch_web_context": "fetch_web_context", |
| "chat": "chat" |
| } |
| ) |
|
|
| graph.add_edge("fetch_context", "chat") |
| graph.add_edge("fetch_web_context", "chat") |
| graph.add_edge("chat", END) |
|
|
| app = graph.compile(checkpointer=memory) |
|
|
|
|
| |
| |
| |
|
|
| def ask_bot(query: str, use_rag: bool = False, use_web: bool = False, thread_id: str = "1"): |
| config = {"configurable": {"thread_id": thread_id}} |
| inputs = { |
| "query": query, |
| "RAG": use_rag, |
| "web_search": use_web, |
| "context": [], |
| "metadata": [], |
| "web_context": "", |
| } |
| |
| result = app.invoke(inputs, config=config) |
| last_message = result['response'][-1] |
| |
| return last_message.content |
|
|
|
|
| """print("--- Conversation 1 ---") |
| # User says hello and gives name |
| response = ask_bot("Hi, my name is Junaid", thread_id="session_A") |
| print(f"Bot: {response}") |
| |
| # User asks for name (RAG and Web are OFF) |
| response = ask_bot("What is my name?", thread_id="session_A") |
| print(f"Bot: {response}")""" |