AGENT / app.py
Anshini's picture
Create app.py
dbf4b06 verified
import streamlit as st
import uuid
from langgraph.graph import StateGraph, END, START
from langgraph.checkpoint.memory import MemorySaver
from typing_extensions import TypedDict
from typing import Annotated, Dict, Any, List
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.runnables import Runnable
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_groq import ChatGroq
from langchain_together import Together
import os
from dotenv import load_dotenv
from langgraph.checkpoint.memory import MemorySaver
load_dotenv()
groq_api_key = os.getenv("GROQ_API_KEY")
together_api_key = os.getenv("TOGETHER_API_KEY")
google_api_key = os.getenv("GOOGLE_API_KEY")
# -------------------
# Define State
# -------------------
class State(TypedDict):
messages: List[str]
answers: List[str]
retry_count: int
questions: List[str]
code: str
explanation: str
task_plan: str
user_input: str
# -------------------
# Initialize LLM
# -------------------
# llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) # Replace with ChatGroq or Together if needed
question_model = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0.7, google_api_key=google_api_key)
llm_agent_model = Together(model="mistralai/Mistral-7B-Instruct-v0.1")
code_model = Together(model="deepseek-ai/deepseek-coder-6.7b-instruct",api_key=together_api_key)
confirm_model = ChatGroq(model="qwen/qwen3-32b",api_key=groq_api_key)
explain_model = ChatGroq(model="meta-llama/llama-guard-4-12b",api_key=groq_api_key)
# -------------------
# Define Node Functions
# -------------------
def llm_agent(state: State) -> State:
messages = [
SystemMessage(content="You are an AI task planner. Break down user instructions."),
HumanMessage(content=state["user_input"])
]
response = llm_agent_model.invoke(messages)
state["task_plan"] = response.content
return state
def generate_questions(state: State) -> State:
messages = [
SystemMessage(content="You generate follow-up questions to clarify vague instructions."),
HumanMessage(content=state["answers"][0])
]
response = question_model.invoke(messages)
state["questions"] = response.content
return state
def generate_code(state: State) -> State:
messages = [
SystemMessage(content="You are a coding expert. Generate clean, well-documented Python code."),
HumanMessage(content=state["answers"][0])
]
response = code_model.invoke(messages)
state["code"] = response.content
return state
def handle_answers(state: State) -> State:
print("Handling answers...")
answer = state["answers"][0]
system_prompt = "You are a helpful assistant that confirms the received idea."
user_msg = f"The user said: '{answer}'. Confirm and move ahead."
response = confirm_model.invoke([
SystemMessage(content=system_prompt),
HumanMessage(content=user_msg)
])
if 'messages' not in state:
state['messages'] =[]
state["messages"].append(response.content.strip())
return state
def explain_code(state: State) -> State:
print("Explaining code...")
code = state["code"]
system_prompt = "You are a Python tutor. Explain what the following code does in simple terms."
user_msg = f"Code:\n{code}"
response = explain_model.invoke([
SystemMessage(content=system_prompt),
HumanMessage(content=user_msg)
])
state["explanation"] = response.content.strip()
return state
def wait_for_answers(state: State) -> State:
print("Waiting for answers...")
state["retry_count"] = state.get("retry_count", 0) + 1
# Simulate receiving an answer after 2 retries
if state["retry_count"] >= 2:
state["answers"] = ["Build a calculator app"]
return state
# -------------------
# Define Condition Function
# -------------------
MAX_RETRIES = 3
def check_if_answered(state: State) -> str:
if "answers" in state and state["answers"]:
return "answered"
elif state.get("retry_count", 0) >= MAX_RETRIES:
print("Max retries reached. Proceeding anyway.")
return "answered"
else:
return "not_answered"
# -------------------
# Build the Graph
# -------------------
builder = StateGraph(State)
builder.add_node("LLM_Agent", llm_agent)
builder.add_node("Generate_Questions", generate_questions)
builder.add_node("Wait_For_Answers", wait_for_answers)
builder.add_node("Handle_Answers", handle_answers)
builder.add_node("Generate_Code", generate_code)
builder.add_node("Code_Explainer", explain_code)
builder.set_entry_point("LLM_Agent")
builder.add_edge("LLM_Agent", "Generate_Questions")
builder.add_conditional_edges(
"Generate_Questions",
check_if_answered,
{
"answered": "Handle_Answers",
"not_answered": "Wait_For_Answers"
}
)
builder.add_edge("Wait_For_Answers", "Generate_Questions")
builder.add_edge("Handle_Answers", "Generate_Code")
builder.add_edge("Generate_Code", "Code_Explainer")
builder.add_edge("Code_Explainer", END)
# graph = builder.compile(checkpointer = MemorySaver())
# graph = StateGraph(State)
# -------------------
# Compile and Run
# -------------------
# memory = MemorySaver()
# graph = builder.compile(checkpointer=memory)
# inputs = {"messages": [], "answers": [], "retry_count": 0, "code": "", "explanation": "", "questions": [], "task_plan" :"","user_input": "I want to create an agent"}
# for step in graph.stream(inputs, configurable={"thread_id": st.session_state.thread_id}):
# for key, val in step.items():
# print(f"\n--- {key} ---\n{val}")
st.set_page_config(page_title="MitraVerse", layout="wide")
if "thread_id" not in st.session_state:
st.session_state.thread_id = str(uuid.uuid4())
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
memory = MemorySaver()
graph = builder.compile(checkpointer=memory)
st.markdown("""
<style>
.stChatMessage {
padding: 12px;
margin-bottom: 12px;
border-radius: 12px;
max-width: 90%;
}
.user {
background-color: #dcf8c6;
align-self: flex-end;
}
.bot {
background-color: #f1f0f0;
align-self: flex-start;
}
.input-box {
display: flex;
align-items: center;
gap: 0.5rem;
}
#floating-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.25rem 0.75rem;
background-color: #f9f9f9;
border-radius: 0.75rem;
margin-top: 1rem;
border: 1px solid #ccc;
}
.floating-popup {
margin-top: 0.5rem;
padding: 0.5rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
background-color: white;
}
</style>
""", unsafe_allow_html=True)
st.title("🧠MitraVerse")
# Columns for button layout
col1, col2, col3 = st.columns(3)
# Initialize session
# if "thread_id" not in st.session_state:
# st.session_state.thread_id = "1"
# if "chat_history" not in st.session_state:
# st.session_state.chat_history = []
# Show chat
for msg in st.session_state.chat_history:
role = "user" if isinstance(msg, HumanMessage) else "bot"
st.markdown(f"<div class='stChatMessage {role}'>{msg.content}</div>",unsafe_allow_html=True)
user_input = st.chat_input("What would you like to build?")
if user_input:
st.session_state.chat_history.append(HumanMessage(content=user_input))
state_input = {
"messages": [],
"answers": [user_input],
"retry_count": 0,
"code": "",
"explanation": "",
"questions": [],
"task_plan": "",
"user_input": user_input,
}
for step in graph.stream(state_input, configurable={"thread_id": st.session_state.thread_id}):
for _, state in step.items():
# Display messages from different stages
if "task_plan" in state and state["task_plan"]:
st.session_state.chat_history.append(SystemMessage(content=f"🔧 Task Plan:\n{state['task_plan']}"))
if "questions" in state and state["questions"]:
st.session_state.chat_history.append(SystemMessage(content=f"❓ Questions:\n{state['questions']}"))
if "code" in state and state["code"]:
st.session_state.chat_history.append(SystemMessage(content=f"💻 Code:\n```python\n{state['code']}\n```"))
if "explanation" in state and state["explanation"]:
st.session_state.chat_history.append(SystemMessage(content=f"📘 Explanation:\n{state['explanation']}"))