micposso commited on
Commit
05e1eb9
Β·
1 Parent(s): fa2dc5b

update file

Browse files
Files changed (3) hide show
  1. .env.example +17 -0
  2. app.py +178 -16
  3. requirements.txt +3 -1
.env.example ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copy this file to .env and fill in your API keys
2
+
3
+ # Google AI API Key (for Gemini)
4
+ GOOGLE_API_KEY=your_google_api_key_here
5
+
6
+ # Groq API Key
7
+ GROQ_API_KEY=your_groq_api_key_here
8
+
9
+ # Tavily API Key (for web search)
10
+ TAVILY_API_KEY=your_tavily_api_key_here
11
+
12
+ # Supabase Configuration (optional - for vector store)
13
+ SUPABASE_URL=your_supabase_url_here
14
+ SUPABASE_SERVICE_KEY=your_supabase_service_key_here
15
+
16
+ # Hugging Face API Token (optional - for HuggingFace models)
17
+ HUGGINGFACEHUB_API_TOKEN=your_huggingface_token_here
app.py CHANGED
@@ -14,6 +14,9 @@ from langchain_community.vectorstores import SupabaseVectorStore
14
  from langchain_core.messages import SystemMessage, HumanMessage
15
  from langchain_core.tools import tool
16
  from supabase.client import Client, create_client
 
 
 
17
 
18
  load_dotenv()
19
 
@@ -120,16 +123,20 @@ with open("system_prompt.txt", "r", encoding="utf-8") as f:
120
  sys_msg = SystemMessage(content=system_prompt)
121
 
122
  # build a retriever
123
- embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2") # dim=768
124
- supabase: Client = create_client(
125
- os.environ.get("SUPABASE_URL"),
126
- os.environ.get("SUPABASE_SERVICE_KEY"))
127
- vector_store = SupabaseVectorStore(
128
- client=supabase,
129
- embedding= embeddings,
130
- table_name="documents",
131
- query_name="match_documents_langchain",
132
- )
 
 
 
 
133
 
134
 
135
 
@@ -188,11 +195,15 @@ def build_graph(provider: str = "google"):
188
  def retriever(state: MessagesState):
189
  """Retriever node that searches for similar questions"""
190
  try:
 
 
 
 
191
  query = state["messages"][-1].content
192
  similar_docs = vector_store.similarity_search(query, k=1)
193
 
194
  if not similar_docs:
195
- return {"messages": [AIMessage(content="No similar questions found. Let me help you with a new response.")]}
196
 
197
  content = similar_docs[0].page_content
198
  if "Final answer :" in content:
@@ -203,13 +214,13 @@ def build_graph(provider: str = "google"):
203
  return {"messages": [AIMessage(content=answer)]}
204
  except Exception as e:
205
  # If retrieval fails, pass to assistant for a fresh response
206
- return {"messages": [sys_msg] + state["messages"]}
207
 
208
  def should_continue(state: MessagesState):
209
  """Determine whether to continue with assistant or end"""
210
  last_message = state["messages"][-1]
211
- # If retriever found a good answer, end here
212
- if isinstance(last_message, AIMessage) and len(last_message.content) > 50:
213
  return "end"
214
  # Otherwise, continue to assistant
215
  return "assistant"
@@ -240,5 +251,156 @@ def build_graph(provider: str = "google"):
240
  graph = builder.compile()
241
  return graph
242
 
243
- # Compile graph
244
- return builder.compile()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  from langchain_core.messages import SystemMessage, HumanMessage
15
  from langchain_core.tools import tool
16
  from supabase.client import Client, create_client
17
+ import gradio as gr
18
+ import pandas as pd
19
+ import json
20
 
21
  load_dotenv()
22
 
 
123
  sys_msg = SystemMessage(content=system_prompt)
124
 
125
  # build a retriever
126
+ try:
127
+ embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2") # dim=768
128
+ supabase: Client = create_client(
129
+ os.environ.get("SUPABASE_URL"),
130
+ os.environ.get("SUPABASE_SERVICE_KEY"))
131
+ vector_store = SupabaseVectorStore(
132
+ client=supabase,
133
+ embedding= embeddings,
134
+ table_name="documents",
135
+ query_name="match_documents_langchain",
136
+ )
137
+ except Exception as e:
138
+ print(f"Warning: Could not initialize vector store: {e}")
139
+ vector_store = None
140
 
141
 
142
 
 
195
  def retriever(state: MessagesState):
196
  """Retriever node that searches for similar questions"""
197
  try:
198
+ if vector_store is None:
199
+ # If vector store is not available, pass to assistant
200
+ return {"messages": state["messages"]}
201
+
202
  query = state["messages"][-1].content
203
  similar_docs = vector_store.similarity_search(query, k=1)
204
 
205
  if not similar_docs:
206
+ return {"messages": state["messages"]}
207
 
208
  content = similar_docs[0].page_content
209
  if "Final answer :" in content:
 
214
  return {"messages": [AIMessage(content=answer)]}
215
  except Exception as e:
216
  # If retrieval fails, pass to assistant for a fresh response
217
+ return {"messages": state["messages"]}
218
 
219
  def should_continue(state: MessagesState):
220
  """Determine whether to continue with assistant or end"""
221
  last_message = state["messages"][-1]
222
+ # If retriever found a good answer (AIMessage from retriever), end here
223
+ if isinstance(last_message, AIMessage) and len(last_message.content) > 50 and not last_message.tool_calls:
224
  return "end"
225
  # Otherwise, continue to assistant
226
  return "assistant"
 
251
  graph = builder.compile()
252
  return graph
253
 
254
+ # Initialize the graph
255
+ try:
256
+ graph = build_graph("google") # You can change this to "groq" or "huggingface"
257
+ except Exception as e:
258
+ print(f"Warning: Could not initialize graph with Google provider: {e}")
259
+ try:
260
+ graph = build_graph("groq")
261
+ print("Successfully initialized with Groq provider")
262
+ except Exception as e2:
263
+ print(f"Warning: Could not initialize graph with Groq provider: {e2}")
264
+ graph = None
265
+
266
+ def run_and_submit_all():
267
+ """Run evaluation on all questions and submit answers"""
268
+ try:
269
+ if graph is None:
270
+ return "❌ Error: Agent is not properly initialized. Please check environment variables and API keys.", pd.DataFrame()
271
+
272
+ # Load questions from questions.json
273
+ try:
274
+ with open("questions.json", "r", encoding="utf-8") as f:
275
+ questions_data = json.load(f)
276
+ except FileNotFoundError:
277
+ return "❌ Error: questions.json file not found.", pd.DataFrame()
278
+ except json.JSONDecodeError as e:
279
+ return f"❌ Error: Invalid JSON in questions.json: {e}", pd.DataFrame()
280
+
281
+ if not isinstance(questions_data, list):
282
+ return "❌ Error: questions.json should contain a list of questions.", pd.DataFrame()
283
+
284
+ results = []
285
+ status_messages = []
286
+
287
+ status_messages.append(f"πŸš€ Starting evaluation with {len(questions_data)} questions...")
288
+
289
+ for i, question_item in enumerate(questions_data, 1):
290
+ try:
291
+ # Handle different question formats
292
+ if isinstance(question_item, dict):
293
+ question = question_item.get("question", str(question_item))
294
+ question_id = question_item.get("task_id", question_item.get("id", i))
295
+ level = question_item.get("Level", "N/A")
296
+ file_name = question_item.get("file_name", "")
297
+ else:
298
+ question = str(question_item)
299
+ question_id = i
300
+ level = "N/A"
301
+ file_name = ""
302
+
303
+ status_messages.append(f"πŸ“ Processing question {i}/{len(questions_data)}: {question[:50]}...")
304
+
305
+ # Convert question to HumanMessage and invoke graph
306
+ human_msg = HumanMessage(content=question)
307
+ result = graph.invoke({"messages": [human_msg]})
308
+
309
+ # Extract answer from result
310
+ if result and "messages" in result and result["messages"]:
311
+ answer = result["messages"][-1].content
312
+ else:
313
+ answer = "No response generated"
314
+
315
+ results.append({
316
+ "Task ID": question_id,
317
+ "Question": question,
318
+ "Level": level,
319
+ "File Name": file_name,
320
+ "Agent Answer": answer
321
+ })
322
+
323
+ status_messages.append(f"βœ… Question {i} completed")
324
+
325
+ except Exception as e:
326
+ error_msg = f"❌ Error processing question {i}: {str(e)}"
327
+ status_messages.append(error_msg)
328
+ results.append({
329
+ "Task ID": question_id if 'question_id' in locals() else i,
330
+ "Question": question if 'question' in locals() else "Error loading question",
331
+ "Level": level if 'level' in locals() else "N/A",
332
+ "File Name": file_name if 'file_name' in locals() else "",
333
+ "Agent Answer": f"Error: {str(e)}"
334
+ })
335
+
336
+ # Create DataFrame for results
337
+ results_df = pd.DataFrame(results)
338
+
339
+ # Prepare final status message
340
+ successful_answers = len([r for r in results if not r["Agent Answer"].startswith("Error:")])
341
+ final_status = f"""
342
+ 🎯 Evaluation Complete!
343
+ βœ… Successfully processed: {successful_answers}/{len(questions_data)} questions
344
+ πŸ“Š Results are displayed in the table below.
345
+
346
+ πŸ“ Detailed Log:
347
+ """ + "\n".join(status_messages)
348
+
349
+ return final_status, results_df
350
+
351
+ except Exception as e:
352
+ error_msg = f"❌ Critical error during evaluation: {str(e)}"
353
+ return error_msg, pd.DataFrame()
354
+
355
+ # --- Build Gradio Interface using Blocks ---
356
+ with gr.Blocks() as demo:
357
+ gr.Markdown("# Basic Agent Evaluation Runner")
358
+ gr.Markdown(
359
+ """
360
+ **Instructions:**
361
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
362
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
363
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
364
+ ---
365
+ **Disclaimers:**
366
+ Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
367
+ This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
368
+ """
369
+ )
370
+
371
+ gr.LoginButton()
372
+
373
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
374
+
375
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
376
+ # Removed max_rows=10 from DataFrame constructor
377
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
378
+
379
+ run_button.click(
380
+ fn=run_and_submit_all,
381
+ outputs=[status_output, results_table]
382
+ )
383
+
384
+ if __name__ == "__main__":
385
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
386
+ # Check for SPACE_HOST and SPACE_ID at startup for information
387
+ space_host_startup = os.getenv("SPACE_HOST")
388
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
389
+
390
+ if space_host_startup:
391
+ print(f"βœ… SPACE_HOST found: {space_host_startup}")
392
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
393
+ else:
394
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
395
+
396
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
397
+ print(f"βœ… SPACE_ID found: {space_id_startup}")
398
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
399
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
400
+ else:
401
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
402
+
403
+ print("-"*(60 + len(" App Starting ")) + "\n")
404
+
405
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
406
+ demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -9,4 +9,6 @@ langchain-huggingface
9
  supabase
10
  sentence-transformers
11
  tavily-python
12
- wikipedia
 
 
 
9
  supabase
10
  sentence-transformers
11
  tavily-python
12
+ wikipedia
13
+ gradio
14
+ pandas