Spaces:
Sleeping
Sleeping
Uploading modified local folder struture
Browse files- .streamlit/config.toml +5 -0
- Dockerfile +17 -5
- README.md +7 -2
- agent_plan_solve/__init__.py +0 -0
- agent_plan_solve/graph/__init__.py +0 -0
- agent_plan_solve/graph/build_graph.py +27 -0
- agent_plan_solve/graph/nodes.py +96 -0
- agent_plan_solve/graph/state.py +15 -0
- agent_plan_solve/tools/__init__.py +0 -0
- agent_plan_solve/tools/calculator.py +42 -0
- agent_plan_solve/utils/__init__.py +0 -0
- agent_plan_solve/utils/llm_config.py +23 -0
- agent_plan_solve_app.py +62 -0
- config.py +30 -0
- requirements.txt +0 -3
- requirements/requirements.txt +52 -0
.streamlit/config.toml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[server]
|
| 2 |
+
enableXsrfProtection = false
|
| 3 |
+
enableCORS = false
|
| 4 |
+
maxUploadSize = 200
|
| 5 |
+
gatherUsageStats = false
|
Dockerfile
CHANGED
|
@@ -1,20 +1,32 @@
|
|
| 1 |
-
FROM python:3.
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
|
|
|
| 5 |
RUN apt-get update && apt-get install -y \
|
| 6 |
build-essential \
|
| 7 |
curl \
|
| 8 |
git \
|
| 9 |
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
|
| 11 |
-
|
|
|
|
| 12 |
COPY src/ ./src/
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
EXPOSE 8501
|
| 17 |
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
-
ENTRYPOINT ["streamlit", "run", "
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
+
# Install system dependencies
|
| 6 |
RUN apt-get update && apt-get install -y \
|
| 7 |
build-essential \
|
| 8 |
curl \
|
| 9 |
git \
|
| 10 |
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
|
| 12 |
+
# Copy project files
|
| 13 |
+
COPY requirements/requirements.txt ./requirements.txt
|
| 14 |
COPY src/ ./src/
|
| 15 |
+
COPY agent_plan_solve_app.py ./
|
| 16 |
+
COPY agent_plan_solve/ ./agent_plan_solve/
|
| 17 |
+
COPY config.py ./config.py
|
| 18 |
+
COPY .streamlit /app/.streamlit
|
| 19 |
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
# Install Python dependencies
|
| 23 |
+
RUN pip3 install --upgrade pip && pip3 install -r requirements.txt
|
| 24 |
|
| 25 |
EXPOSE 8501
|
| 26 |
|
| 27 |
+
ENV STREAMLIT_SERVER_HEADLESS=true
|
| 28 |
+
|
| 29 |
+
# Start the Streamlit app
|
| 30 |
+
#CMD ["streamlit", "run", "agent_plan_solve_app.py", "--server.port=8501", "--server.address=0.0.0.0", "--server.enableXsrfProtection=false"]
|
| 31 |
|
| 32 |
+
ENTRYPOINT ["streamlit", "run", "agent_plan_solve_app.py", "--server.port=8501", "--server.address=0.0.0.0", "--server.enableXsrfProtection=false"]
|
README.md
CHANGED
|
@@ -4,14 +4,19 @@ emoji: π
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: red
|
| 6 |
sdk: docker
|
|
|
|
| 7 |
app_port: 8501
|
| 8 |
tags:
|
| 9 |
-
- streamlit
|
|
|
|
|
|
|
|
|
|
| 10 |
pinned: false
|
| 11 |
short_description: AI planner using Wikipedia, ArXiv, Duck-search & Calculator
|
|
|
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
| 15 |
|
| 16 |
Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
|
| 17 |
|
|
|
|
| 4 |
colorFrom: red
|
| 5 |
colorTo: red
|
| 6 |
sdk: docker
|
| 7 |
+
app_file: agent_plan_solve_app.py
|
| 8 |
app_port: 8501
|
| 9 |
tags:
|
| 10 |
+
- streamlit
|
| 11 |
+
- agentic-ai
|
| 12 |
+
- wikipedia
|
| 13 |
+
- strategic-planning
|
| 14 |
pinned: false
|
| 15 |
short_description: AI planner using Wikipedia, ArXiv, Duck-search & Calculator
|
| 16 |
+
startup_duration_timeout: 1h
|
| 17 |
---
|
| 18 |
|
| 19 |
+
|
| 20 |
|
| 21 |
Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
|
| 22 |
|
agent_plan_solve/__init__.py
ADDED
|
File without changes
|
agent_plan_solve/graph/__init__.py
ADDED
|
File without changes
|
agent_plan_solve/graph/build_graph.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agent_plan_solve/graph/graph.py
|
| 2 |
+
|
| 3 |
+
from langgraph.graph import StateGraph, START, END
|
| 4 |
+
from agent_plan_solve.graph.state import PlanState
|
| 5 |
+
from agent_plan_solve.graph.nodes import (
|
| 6 |
+
_build_initial_plan,
|
| 7 |
+
_run_step,
|
| 8 |
+
_get_final_response,
|
| 9 |
+
_should_continue
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
__all__ = ["graph"]
|
| 13 |
+
print("β
build_graph.py loaded")
|
| 14 |
+
|
| 15 |
+
# Build the LangGraph
|
| 16 |
+
builder = StateGraph(PlanState)
|
| 17 |
+
|
| 18 |
+
builder.add_node("initial_plan", _build_initial_plan)
|
| 19 |
+
builder.add_node("run", _run_step)
|
| 20 |
+
builder.add_node("response", _get_final_response)
|
| 21 |
+
|
| 22 |
+
builder.add_edge(START, "initial_plan")
|
| 23 |
+
builder.add_edge("initial_plan", "run")
|
| 24 |
+
builder.add_conditional_edges("run", _should_continue)
|
| 25 |
+
builder.add_edge("response", END)
|
| 26 |
+
|
| 27 |
+
graph = builder.compile()
|
agent_plan_solve/graph/nodes.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agent_plan_solve/graph/nodes.py
|
| 2 |
+
|
| 3 |
+
from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
|
| 4 |
+
from langgraph.prebuilt import create_react_agent
|
| 5 |
+
from langgraph.prebuilt.chat_agent_executor import AgentState
|
| 6 |
+
from agent_plan_solve.graph.state import Plan, PlanState
|
| 7 |
+
from agent_plan_solve.utils.llm_config import get_openai_llm
|
| 8 |
+
from agent_plan_solve.tools.calculator import calculator_tool
|
| 9 |
+
from langchain.agents import load_tools
|
| 10 |
+
from typing import Literal
|
| 11 |
+
|
| 12 |
+
# Load LLM
|
| 13 |
+
llm = get_openai_llm()
|
| 14 |
+
|
| 15 |
+
# Planner prompt
|
| 16 |
+
planner_prompt = ChatPromptTemplate.from_messages([
|
| 17 |
+
("system",
|
| 18 |
+
"For the given task, come up with a step-by-step plan.\n"
|
| 19 |
+
"Each step should be self-contained and lead to the final answer.\n"
|
| 20 |
+
"Avoid superfluous steps."),
|
| 21 |
+
("user", "Prepare a plan to solve the following task:\n{task}\n")
|
| 22 |
+
])
|
| 23 |
+
|
| 24 |
+
planner = planner_prompt | llm.with_structured_output(Plan)
|
| 25 |
+
|
| 26 |
+
# Toolset
|
| 27 |
+
tools = load_tools(
|
| 28 |
+
tool_names=["ddg-search", "arxiv", "wikipedia"],
|
| 29 |
+
llm=llm
|
| 30 |
+
) + [calculator_tool]
|
| 31 |
+
|
| 32 |
+
# Execution agent prompt
|
| 33 |
+
step_prompt = ChatPromptTemplate.from_messages([
|
| 34 |
+
("system",
|
| 35 |
+
"You're a smart assistant that carefully helps solve complex tasks.\n"
|
| 36 |
+
"Use tools to verify facts, compute results, and avoid assumptions."),
|
| 37 |
+
("user",
|
| 38 |
+
"TASK:\n{task}\n\nPLAN:\n{plan}\n\nSTEP TO EXECUTE:\n{step}\n")
|
| 39 |
+
])
|
| 40 |
+
|
| 41 |
+
class StepState(AgentState):
|
| 42 |
+
task: str
|
| 43 |
+
plan: str
|
| 44 |
+
step: str
|
| 45 |
+
|
| 46 |
+
execution_agent = create_react_agent(
|
| 47 |
+
model=llm,
|
| 48 |
+
tools=tools,
|
| 49 |
+
state_schema=StepState,
|
| 50 |
+
prompt=step_prompt
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
# Final response prompt
|
| 54 |
+
final_prompt = PromptTemplate.from_template(
|
| 55 |
+
"You're a helpful assistant that has executed a plan.\n"
|
| 56 |
+
"Given the results, prepare the final response.\n"
|
| 57 |
+
"TASK:\n{task}\n\nPLAN WITH RESULTS:\n{plan}\nFINAL RESPONSE:\n"
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# Utility functions
|
| 61 |
+
def get_current_step(state: PlanState) -> int:
|
| 62 |
+
return len(state.get("past_steps", []))
|
| 63 |
+
|
| 64 |
+
def get_full_plan(state: PlanState) -> str:
|
| 65 |
+
full_plan = []
|
| 66 |
+
for i, step in enumerate(state["plan"].steps):
|
| 67 |
+
full_step = f"# {i+1}. Planned step: {step}\n"
|
| 68 |
+
if i < get_current_step(state):
|
| 69 |
+
full_step += f"Result: {state['past_steps'][i]}\n"
|
| 70 |
+
full_plan.append(full_step)
|
| 71 |
+
return "\n".join(full_plan)
|
| 72 |
+
|
| 73 |
+
# Node functions
|
| 74 |
+
async def _build_initial_plan(state: PlanState) -> PlanState:
|
| 75 |
+
plan = await planner.ainvoke(state["task"])
|
| 76 |
+
return {"plan": plan}
|
| 77 |
+
|
| 78 |
+
async def _run_step(state: PlanState) -> PlanState:
|
| 79 |
+
plan = state["plan"]
|
| 80 |
+
current_step = get_current_step(state)
|
| 81 |
+
step = await execution_agent.ainvoke({
|
| 82 |
+
"plan": get_full_plan(state),
|
| 83 |
+
"step": plan.steps[current_step],
|
| 84 |
+
"task": state["task"]
|
| 85 |
+
})
|
| 86 |
+
return {"past_steps": [step["messages"][-1].content]}
|
| 87 |
+
|
| 88 |
+
async def _get_final_response(state: PlanState) -> PlanState:
|
| 89 |
+
final_response = await (final_prompt | llm).ainvoke({
|
| 90 |
+
"task": state["task"],
|
| 91 |
+
"plan": get_full_plan(state)
|
| 92 |
+
})
|
| 93 |
+
return {"final_response": final_response}
|
| 94 |
+
|
| 95 |
+
def _should_continue(state: PlanState) -> Literal["run", "response"]:
|
| 96 |
+
return "run" if get_current_step(state) < len(state["plan"].steps) else "response"
|
agent_plan_solve/graph/state.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agent_plan_solve/graph/state.py
|
| 2 |
+
|
| 3 |
+
from typing import Annotated, TypedDict
|
| 4 |
+
import operator
|
| 5 |
+
from pydantic import BaseModel, Field
|
| 6 |
+
|
| 7 |
+
class Plan(BaseModel):
|
| 8 |
+
"""Plan to follow in future"""
|
| 9 |
+
steps: list[str] = Field(..., description="Different steps to follow, in sorted order")
|
| 10 |
+
|
| 11 |
+
class PlanState(TypedDict):
|
| 12 |
+
task: str
|
| 13 |
+
plan: Plan
|
| 14 |
+
past_steps: Annotated[list[str], operator.add]
|
| 15 |
+
final_response: str
|
agent_plan_solve/tools/__init__.py
ADDED
|
File without changes
|
agent_plan_solve/tools/calculator.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agent_plan_solve/tools/calculator.py
|
| 2 |
+
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
from langchain_core.runnables import RunnableLambda, RunnableConfig
|
| 5 |
+
from langchain_core.tools import ToolException
|
| 6 |
+
import numexpr as ne
|
| 7 |
+
|
| 8 |
+
# Custom exception for calculator errors
|
| 9 |
+
class CalculatorToolException(ToolException):
|
| 10 |
+
def __init__(self, message: str, expression: str):
|
| 11 |
+
super().__init__(f"[Calculator Error] {message} | Expression: '{expression}'")
|
| 12 |
+
|
| 13 |
+
# Input schema for the calculator tool
|
| 14 |
+
class CalculatorArgs(BaseModel):
|
| 15 |
+
expression: str = Field(..., description="Mathematical expression to be evaluated")
|
| 16 |
+
|
| 17 |
+
# Core calculator logic
|
| 18 |
+
def calculator(state: CalculatorArgs, config: RunnableConfig) -> str:
|
| 19 |
+
expression = state["expression"]
|
| 20 |
+
math_constants = config["configurable"].get("math_constants", {})
|
| 21 |
+
|
| 22 |
+
try:
|
| 23 |
+
result = ne.evaluate(expression.strip(), local_dict=math_constants)
|
| 24 |
+
return str(result)
|
| 25 |
+
except Exception as e:
|
| 26 |
+
raise CalculatorToolException(str(e), expression)
|
| 27 |
+
|
| 28 |
+
# Wrap with retry logic
|
| 29 |
+
calculator_with_retry = RunnableLambda(calculator).with_retry(
|
| 30 |
+
wait_exponential_jitter=True,
|
| 31 |
+
stop_after_attempt=3,
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
# Convert to LangChain-compatible tool
|
| 35 |
+
calculator_tool = calculator_with_retry.as_tool(
|
| 36 |
+
name="calculator",
|
| 37 |
+
description=(
|
| 38 |
+
"Calculates a single mathematical expression, incl. complex numbers.\n"
|
| 39 |
+
"Always add * to operations, examples:\n73i -> 73*i\n7pi**2 -> 7*pi**2"
|
| 40 |
+
),
|
| 41 |
+
args_schema=CalculatorArgs
|
| 42 |
+
)
|
agent_plan_solve/utils/__init__.py
ADDED
|
File without changes
|
agent_plan_solve/utils/llm_config.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agent_plan_solve/utils/llm_config.py
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
from config import set_environment
|
| 5 |
+
from langchain_openai import ChatOpenAI
|
| 6 |
+
|
| 7 |
+
# Load environment variables from .env
|
| 8 |
+
set_environment()
|
| 9 |
+
|
| 10 |
+
class ChatOpenAIWrapper(ChatOpenAI):
|
| 11 |
+
def __init__(self, model_name="gpt-5-nano", **kwargs):
|
| 12 |
+
super().__init__(
|
| 13 |
+
model=model_name,
|
| 14 |
+
api_key=os.getenv("OPENAI_API_KEY"),
|
| 15 |
+
**kwargs
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
def get_openai_llm(model_name="gpt-5-nano", streaming=True, **kwargs):
|
| 19 |
+
return ChatOpenAIWrapper(
|
| 20 |
+
model_name=model_name,
|
| 21 |
+
streaming=streaming,
|
| 22 |
+
**kwargs
|
| 23 |
+
)
|
agent_plan_solve_app.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import asyncio
|
| 3 |
+
import os
|
| 4 |
+
import sys
|
| 5 |
+
|
| 6 |
+
# β
Must be first Streamlit call
|
| 7 |
+
st.set_page_config(page_title="Strategic Planner", layout="centered")
|
| 8 |
+
|
| 9 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 10 |
+
# π¦ Environment & Path Setup
|
| 11 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 12 |
+
project_root = os.path.join(os.getcwd(), "agent_plan_solve")
|
| 13 |
+
if project_root not in sys.path:
|
| 14 |
+
sys.path.insert(0, project_root)
|
| 15 |
+
|
| 16 |
+
from config import set_environment
|
| 17 |
+
set_environment()
|
| 18 |
+
|
| 19 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 20 |
+
# π§ LangGraph Agent Import
|
| 21 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 22 |
+
from agent_plan_solve.graph.build_graph import graph
|
| 23 |
+
|
| 24 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 25 |
+
# ποΈ Streamlit UI
|
| 26 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 27 |
+
st.title("π§ Planner & Research Analyst with GPT-5 Nano")
|
| 28 |
+
st.markdown("Enter a task below and let the agent plan and execute it step-by-step.")
|
| 29 |
+
task_input = st.text_area("Task:", placeholder="e.g. Write a strategic one-pager for building an AI startup")
|
| 30 |
+
|
| 31 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 32 |
+
# π Async Agent Execution
|
| 33 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 34 |
+
async def run_agent(task: str):
|
| 35 |
+
return await graph.ainvoke({"task": task})
|
| 36 |
+
|
| 37 |
+
def display_response(response):
|
| 38 |
+
st.markdown("### β
Final Output")
|
| 39 |
+
if hasattr(response, "content"):
|
| 40 |
+
st.markdown(response.content)
|
| 41 |
+
elif isinstance(response, str):
|
| 42 |
+
st.markdown(response)
|
| 43 |
+
elif isinstance(response, dict) and "content" in response:
|
| 44 |
+
st.markdown(response["content"])
|
| 45 |
+
else:
|
| 46 |
+
st.error("No response generated.")
|
| 47 |
+
|
| 48 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 49 |
+
# π Trigger Agent
|
| 50 |
+
# βββββββββββββββββββββββββββββββββββββββββββββ
|
| 51 |
+
if st.button("Run Agent"):
|
| 52 |
+
if not task_input.strip():
|
| 53 |
+
st.warning("Please enter a task.")
|
| 54 |
+
else:
|
| 55 |
+
with st.spinner("Running LangGraph agent..."):
|
| 56 |
+
try:
|
| 57 |
+
loop = asyncio.new_event_loop()
|
| 58 |
+
asyncio.set_event_loop(loop)
|
| 59 |
+
result = loop.run_until_complete(run_agent(task_input))
|
| 60 |
+
display_response(result.get("final_response"))
|
| 61 |
+
except Exception as e:
|
| 62 |
+
st.error(f"β Agent execution failed: {e}")
|
config.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
|
| 4 |
+
def set_environment(verbose=True) -> dict:
|
| 5 |
+
env_path = os.path.abspath(".env")
|
| 6 |
+
|
| 7 |
+
# Load .env only if it exists
|
| 8 |
+
if os.path.exists(env_path):
|
| 9 |
+
load_dotenv(dotenv_path=env_path, override=True)
|
| 10 |
+
if verbose:
|
| 11 |
+
print(f"β
Loaded .env from: {env_path}")
|
| 12 |
+
else:
|
| 13 |
+
if verbose:
|
| 14 |
+
print("β οΈ No .env file found. Relying on system environment variables.")
|
| 15 |
+
|
| 16 |
+
required_keys = [
|
| 17 |
+
"OPENAI_API_KEY",
|
| 18 |
+
"OPENROUTER_API_KEY",
|
| 19 |
+
"GEMINI_API_KEY",
|
| 20 |
+
"GROQ_API_KEY"
|
| 21 |
+
]
|
| 22 |
+
missing_keys = [key for key in required_keys if not os.getenv(key)]
|
| 23 |
+
|
| 24 |
+
if verbose:
|
| 25 |
+
if missing_keys:
|
| 26 |
+
print(f"β οΈ Missing environment variables: {missing_keys}")
|
| 27 |
+
else:
|
| 28 |
+
print("β
All required API keys loaded successfully!")
|
| 29 |
+
|
| 30 |
+
return {key: os.getenv(key) for key in required_keys}
|
requirements.txt
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
altair
|
| 2 |
-
pandas
|
| 3 |
-
streamlit
|
|
|
|
|
|
|
|
|
|
|
|
requirements/requirements.txt
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# βββββββββ Core LangChain Stack βββββββββ
|
| 2 |
+
langchain==0.3.17
|
| 3 |
+
langchain-core>=0.3.67,<0.4.0
|
| 4 |
+
langchain-community==0.3.16
|
| 5 |
+
langchain-openai==0.3.19
|
| 6 |
+
langchain-anthropic==0.3.5
|
| 7 |
+
langchain-google-genai==2.0.0
|
| 8 |
+
langchain-google-vertexai==2.0.28
|
| 9 |
+
langchain-huggingface==0.3.1
|
| 10 |
+
langchain-groq==0.2.4
|
| 11 |
+
langchain-ollama==0.2.3
|
| 12 |
+
langchain-mistralai==0.2.6
|
| 13 |
+
langchain-chroma==0.2.2
|
| 14 |
+
langchain-text-splitters==0.3.5
|
| 15 |
+
langchain-experimental==0.3.4
|
| 16 |
+
langgraph==0.3.34
|
| 17 |
+
langsmith>=0.3.45,<0.4.0
|
| 18 |
+
|
| 19 |
+
# βββββββββ Embeddings & Transformers βββββββββ
|
| 20 |
+
sentence-transformers>=2.6.1
|
| 21 |
+
transformers>=4.40.0
|
| 22 |
+
huggingface-hub>=0.33.4,<0.40.0
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
# βββββββββ Retrieval & Search βββββββββ
|
| 26 |
+
duckduckgo_search==8.0.4
|
| 27 |
+
arxiv==2.1.3
|
| 28 |
+
wikipedia==1.4.0
|
| 29 |
+
rank_bm25==0.2.2
|
| 30 |
+
datasets==3.4.0
|
| 31 |
+
|
| 32 |
+
# βββββββββ UI & Dev Tools βββββββββ
|
| 33 |
+
streamlit==1.37.1
|
| 34 |
+
ruff==0.9.4
|
| 35 |
+
altair>=5.4.0
|
| 36 |
+
python-dotenv
|
| 37 |
+
|
| 38 |
+
# βββββββββ Document Loaders and document processors βββββββββ
|
| 39 |
+
docarray==0.41.0
|
| 40 |
+
pypdf
|
| 41 |
+
python-docx
|
| 42 |
+
unstructured
|
| 43 |
+
beautifulsoup4
|
| 44 |
+
html2text
|
| 45 |
+
nltk
|
| 46 |
+
|
| 47 |
+
# βββββββββ Infra & Orchestration βββββββββ
|
| 48 |
+
ray==2.43.0
|
| 49 |
+
|
| 50 |
+
#other libraries
|
| 51 |
+
pydantic
|
| 52 |
+
typing
|