PuruAI commited on
Commit
4c18251
·
verified ·
1 Parent(s): eb720d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +4 -213
app.py CHANGED
@@ -9,228 +9,19 @@ from fastapi import FastAPI, Depends, HTTPException
9
  from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
10
  import uvicorn
11
 
12
- # Note: The 'transformers' pipeline is required for the LLM loader
13
  from transformers import pipeline
14
 
15
- # ===== LangChain imports (fixed for 0.3.x + community modules) =====
16
  from langchain_community.llms import HuggingFacePipeline
17
  from langchain_community.utilities import SerpAPIWrapper
18
  from langchain_community.vectorstores import Chroma
19
  from langchain_community.embeddings import HuggingFaceEmbeddings
 
20
 
 
21
  from langchain.memory import ConversationBufferMemory
22
  from langchain.agents import initialize_agent, Tool
23
  from langchain.chains import LLMChain
24
  from langchain.prompts import PromptTemplate
25
  from langchain.docstore.document import Document
26
-
27
- # Correct import for Python REPL tool
28
- from langchain.tools import PythonREPL
29
-
30
- # ===========================================
31
- # ENVIRONMENT VARIABLES
32
- # ===========================================
33
- HF_TOKEN = os.getenv("HF_TOKEN")
34
- SERPAPI_KEY = os.getenv("SERPAPI_API_KEY")
35
- JWT_SECRET = os.getenv("JWT_SECRET", "changeme123")
36
-
37
- # ===========================================
38
- # AUTH
39
- # ===========================================
40
- security = HTTPBearer()
41
-
42
- def verify_jwt(credentials: HTTPAuthorizationCredentials = Depends(security)):
43
- token = credentials.credentials
44
- if token != JWT_SECRET:
45
- raise HTTPException(status_code=403, detail="Invalid token")
46
- return True
47
-
48
- # ===========================================
49
- # MODEL LOADER
50
- # ===========================================
51
- MODEL_ID = "PuruAI/Medini_Intelligence"
52
- FALLBACK_MODEL = "gpt2"
53
-
54
- def load_llm():
55
- pipeline_kwargs = {"max_new_tokens": 512, "temperature": 0.7}
56
- try:
57
- model_pipeline = pipeline("text-generation", model=MODEL_ID, use_auth_token=HF_TOKEN, **pipeline_kwargs)
58
- except Exception:
59
- print(f"Warning: Failed to load {MODEL_ID}. Falling back to {FALLBACK_MODEL}.")
60
- model_pipeline = pipeline("text-generation", model=FALLBACK_MODEL, **pipeline_kwargs)
61
- return HuggingFacePipeline(pipeline=model_pipeline)
62
-
63
- llm = load_llm()
64
-
65
- # ===========================================
66
- # VECTOR MEMORY
67
- # ===========================================
68
- embeddings = HuggingFaceEmbeddings()
69
- chroma_db = Chroma(persist_directory="./medini_memory", embedding_function=embeddings)
70
- retriever = chroma_db.as_retriever()
71
-
72
- qa_prompt_template = """
73
- You are a question-answering system. Use the following context, which contains information retrieved from memory, to answer the user's question.
74
- If the context is empty or does not contain the answer, state clearly that the information is not in memory.
75
- Context:
76
- {context}
77
- Question: {question}
78
- Answer:
79
- """
80
- QA_PROMPT = PromptTemplate(template=qa_prompt_template, input_variables=["context", "question"])
81
- qa_chain = LLMChain(llm=llm, prompt=QA_PROMPT)
82
-
83
- def retrieve_and_answer(question: str) -> str:
84
- docs = retriever.get_relevant_documents(question)
85
- context = "\n---\n".join([d.page_content for d in docs])
86
- return qa_chain.run(context=context, question=question)
87
-
88
- # ===========================================
89
- # TOOLS
90
- # ===========================================
91
- search = SerpAPIWrapper(serpapi_api_key=SERPAPI_KEY)
92
- python_tool = PythonREPL()
93
-
94
- tools = [
95
- Tool(name="Knowledge Recall", func=retrieve_and_answer, description="Retrieve info from Medini memory."),
96
- Tool(name="Web Search", func=search.run, description="Search the web for up-to-date information."),
97
- Tool(name="Python REPL", func=python_tool.run, description="Execute Python code, useful for math and data manipulation."),
98
- ]
99
-
100
- TOOL_MAP = {tool.name.lower().replace(" ", ""): tool.func for tool in tools}
101
-
102
- # ===========================================
103
- # AGENT
104
- # ===========================================
105
- memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
106
- agent = initialize_agent(
107
- tools=tools,
108
- llm=llm,
109
- agent="conversational-react-description",
110
- memory=memory,
111
- verbose=True
112
- )
113
-
114
- # ===========================================
115
- # PLANNER (Autonomous Goal)
116
- # ===========================================
117
- plan_prompt = PromptTemplate(
118
- input_variables=["goal"],
119
- template="""
120
- You are Medini Planner. Decompose the high-level goal into a JSON object containing a 'steps' array (max 6 steps). Each step must have: id (integer), name (short string), description (detailed instruction), and tool_hint (either 'recall', 'search', 'python', or 'agent').
121
- Return JSON only.
122
- Goal: {goal}
123
- """
124
- )
125
- planner_chain = LLMChain(llm=llm, prompt=plan_prompt)
126
-
127
- def create_plan(goal: str) -> Dict[str, Any]:
128
- raw = planner_chain.run(goal=goal)
129
- m = re.search(r"\{.*\}", raw, flags=re.DOTALL)
130
- json_str = m.group(0) if m else raw
131
- json_str = json_str.replace("```json", "").replace("```", "").strip()
132
- plan = json.loads(json_str)
133
- if 'steps' not in plan:
134
- raise ValueError("Parsed JSON is missing the 'steps' array.")
135
- return plan
136
-
137
- def execute_step(step: Dict[str, Any]) -> Dict[str, Any]:
138
- hint = (step.get("tool_hint") or "").lower()
139
- input_text = step.get("description")
140
- output = "Execution skipped."
141
- status = "error"
142
-
143
- try:
144
- tool_func = None
145
- if "recall" in hint:
146
- tool_func = TOOL_MAP.get("knowledgerecall")
147
- elif "search" in hint:
148
- tool_func = TOOL_MAP.get("websearch")
149
- elif "python" in hint:
150
- tool_func = TOOL_MAP.get("pythonrepl")
151
-
152
- if tool_func:
153
- output = tool_func(input_text)
154
- else:
155
- output = agent.run(input_text)
156
- status = "ok"
157
- except Exception as e:
158
- output = f"Execution Error: {str(e)}"
159
- status = "error"
160
-
161
- chroma_db.add_documents([Document(page_content=f"Step {step['id']} - {step['name']} Result: {output}")])
162
- return {"id": step['id'], "name": step['name'], "status": status, "output": output}
163
-
164
- def execute_plan(goal: str) -> Dict[str, Any]:
165
- try:
166
- plan = create_plan(goal)
167
- except ValueError as e:
168
- return {"goal": goal, "error": str(e)}
169
- results = [execute_step(step) for step in plan.get("steps", [])]
170
- return {"goal": goal, "plan": plan, "results": results}
171
-
172
- # ===========================================
173
- # FASTAPI BACKEND
174
- # ===========================================
175
- app = FastAPI(title="Medini Agent API")
176
-
177
- @app.post("/chat")
178
- def chat_endpoint(message: str, auth: bool = Depends(verify_jwt)):
179
- response = agent.run(message)
180
- return {"response": response}
181
-
182
- @app.post("/goal")
183
- def goal_endpoint(goal: str, auth: bool = Depends(verify_jwt)):
184
- report = execute_plan(goal)
185
- return report
186
-
187
- # ===========================================
188
- # GRADIO FRONTEND
189
- # ===========================================
190
- def gradio_chat(message, history):
191
- try:
192
- response = agent.run(message)
193
- history.append((message, response))
194
- except Exception as e:
195
- history.append((message, f"An error occurred: {str(e)}"))
196
- return history, ""
197
-
198
- def gradio_execute_plan(goal):
199
- try:
200
- return execute_plan(goal)
201
- except Exception as e:
202
- return {"error": f"Failed to execute plan: {str(e)}"}
203
-
204
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
205
- gr.Markdown("# 🤖 Medini Autonomous Agent")
206
- gr.Markdown("Chat or submit high-level goals. Agentic AI handles reasoning, memory, and tool use.")
207
-
208
- with gr.Row():
209
- with gr.Column(scale=2):
210
- gr.Markdown("## Conversational Chat")
211
- chatbot = gr.Chatbot(height=400)
212
- msg = gr.Textbox(placeholder="Type your message...", label="Chat Input")
213
- clear_btn = gr.Button("Clear Chat")
214
-
215
- msg.submit(gradio_chat, [msg, chatbot], [chatbot, msg])
216
- clear_btn.click(lambda: [], None, chatbot, queue=False)
217
-
218
- with gr.Column(scale=1):
219
- gr.Markdown("## Autonomous Goal Planner")
220
- goal_input = gr.Textbox(placeholder="Enter high-level goal.", label="Goal")
221
- run_goal_btn = gr.Button("Run Goal", variant="primary")
222
- gr.Markdown("---")
223
- gr.Markdown("### Execution Report")
224
- goal_output = gr.JSON(label="Plan and Results")
225
-
226
- run_goal_btn.click(gradio_execute_plan, [goal_input], goal_output)
227
-
228
- # ===========================================
229
- # LAUNCH
230
- # ===========================================
231
- if __name__ == "__main__":
232
- def start_api():
233
- uvicorn.run(app, host="0.0.0.0", port=8000, log_level="critical")
234
-
235
- threading.Thread(target=start_api, daemon=True).start()
236
- demo.launch(share=False)
 
9
  from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
10
  import uvicorn
11
 
12
+ # Transformers pipeline for LLM
13
  from transformers import pipeline
14
 
15
+ # ===== LangChain Community Imports (v0.3+) =====
16
  from langchain_community.llms import HuggingFacePipeline
17
  from langchain_community.utilities import SerpAPIWrapper
18
  from langchain_community.vectorstores import Chroma
19
  from langchain_community.embeddings import HuggingFaceEmbeddings
20
+ from langchain_community.tools import PythonREPL
21
 
22
+ # ===== LangChain Core Imports =====
23
  from langchain.memory import ConversationBufferMemory
24
  from langchain.agents import initialize_agent, Tool
25
  from langchain.chains import LLMChain
26
  from langchain.prompts import PromptTemplate
27
  from langchain.docstore.document import Document