Spaces:
Sleeping
Sleeping
File size: 25,474 Bytes
c579d4b 4fb27a7 c579d4b 24509e4 994f4fe 24509e4 95fc3d5 51f8747 176458a 95fc3d5 bffcb1e 95fc3d5 9169512 4fb27a7 95fc3d5 06c9085 feb360f f3b26c1 3fa9034 09f7832 95fc3d5 c579d4b ed93ccc c579d4b 5137709 b562a1a a3ccae4 b562a1a 47d170e 62430d5 b562a1a 62430d5 b562a1a cfb71b2 b9ff189 3afd7dc b9ff189 c579d4b a3ccae4 b562a1a a3ccae4 b562a1a f3b26c1 b562a1a a3ccae4 f3b26c1 b562a1a a3ccae4 b562a1a c579d4b f3b26c1 8752721 c579d4b db23983 2dc6d15 2d3c71a a3ccae4 2d3c71a db23983 f3b26c1 db23983 f3b26c1 db23983 f3b26c1 db23983 c579d4b f37b453 c579d4b f37b453 bab32f6 f37b453 c579d4b 17e0f28 f37b453 c579d4b 9fbd769 331ad99 9fbd769 30598c0 9fbd769 f37b453 9fbd769 f37b453 62c44a2 f37b453 62c44a2 f37b453 62c44a2 a9057ac 9c1af9c a9057ac a85aa1e 9fbd769 a9057ac 9fbd769 a9057ac c579d4b 33a2342 9fbd769 c579d4b b7bcb6e c579d4b b7bcb6e c579d4b 1222ac6 c579d4b 1222ac6 5113a07 759896c d8b5b5e 759896c 0fae946 d8b5b5e 7bb9cde e5896f4 7c06301 0fae946 c3830b1 e5896f4 7c06301 0fae946 c3830b1 e5896f4 7c06301 c579d4b 9ddfe3b c579d4b 4fb27a7 70f718e d4a33dc 4fb27a7 5113a07 c579d4b 4fb27a7 5113a07 f036519 5113a07 f036519 5113a07 c579d4b ae5d6d2 c579d4b d1eec88 2e0bf0f 5422c2f 2e0bf0f d1eec88 2e0bf0f d1eec88 2e0bf0f 3311c57 9db7465 924699e 2e0bf0f c579d4b f35002d c579d4b d1eec88 c579d4b d1eec88 924699e c579d4b 2e0bf0f 924699e 2e0bf0f 924699e c579d4b 8329e65 c579d4b 176458a d3f35c4 8ea5b82 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | # gaia_agent_restructured_langgraph_ui.py
# GAIA Multi-Agent System with LangGraph + Gradio Interface
"""
Updates:
✅ Added Gradio UI for user interaction and visualization of results
✅ Integrated with LangGraph flow (reasoning_agent → final_agent)
✅ Prints all questions and corresponding results at the end
✅ Maintains modular design and existing architecture
"""
import os
os.environ["LLAMA_BLAS"] = "1"
os.environ["LLAMA_BLAS_VENDOR"] = "OpenBLAS"
from langchain_community.llms import LlamaCpp
from llama_cpp import Llama
import re
import json
import requests
import logging
import gradio as gr
from typing import Optional, List, Dict, Any
import time
from huggingface_hub import hf_hub_download
from gradio_client import Client
from langchain_core.tools import Tool
from langchain_core.prompts import PromptTemplate
from langchain.agents import create_react_agent, AgentExecutor
from datasets import load_dataset
from huggingface_hub import login
import threading
import logging
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("gradio").setLevel(logging.WARNING)
# قفل عام لحماية الوصول إلى LLM/Agent داخل الخيوط
llama_lock = threading.Lock()
model_path = hf_hub_download(
repo_id="bartowski/Qwen2.5-14B-Instruct-GGUF",
filename="Qwen2.5-14B-Instruct-Q6_K_L.gguf",
)
llm = LlamaCpp(
model_path=model_path,
n_ctx=10000,
n_threads=4,
n_gpu_layers=0,
temperature=0.4,
top_p=0.9,
max_tokens=150,
n_batch=64,
verbose=False,
use_mmap=True
)
# تحقق من وجود توكن في متغير البيئة
HF_TOKEN = os.getenv("HF_TOKEN")
if HF_TOKEN:
login(token=HF_TOKEN)
else:
print("⚠️ Warning: No HF_TOKEN found. Please set your Hugging Face token as an environment variable.")
try:
from langsmith import Client as LangSmithClient
from langchain.callbacks.tracers import LangChainTracer
LANGSMITH_AVAILABLE = True
except Exception:
LANGSMITH_AVAILABLE = False
try:
from langgraph.graph import StateGraph, END
LANGGRAPH_AVAILABLE = True
except Exception:
LANGGRAPH_AVAILABLE = False
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("gaia_langgraph_ui")
# -------------------- Configuration --------------------
HF_TOKEN = os.getenv("HF_TOKEN", "")
SPACE_ID = os.getenv("SPACE_ID", "")
CODE_AGENT_SPACE = os.getenv("CODE_AGENT_SPACE", "https://mustafa-albakkar-codeagent.hf.space")
VISION_AGENT_SPACE = os.getenv("VISION_AGENT_SPACE", "https://mustafa-albakkar-mediaagent.hf.space")
FINAL_ANSWER_SPACE = os.getenv("FINAL_ANSWER_SPACE", "https://mustafa-albakkar-finalagent.hf.space")
#GAIA_API_BASE = os.getenv("GAIA_API_BASE","https://mustafa-albakkar-mmo.hf.space")
GAIA_API_BASE = os.getenv("GAIA_API_BASE","https://agents-course-unit4-scoring.hf.space")
import time
from functools import wraps
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
"""
session = requests.Session()
retry_strategy = Retry(
total=5,
backoff_factor=0.5,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
"""
def retry(exception_types=(Exception,), tries=3, delay=1, backoff=2):
"""
Decorator لإعادة المحاولة في حال حدوث خطأ مؤقت (مثل انقطاع الشبكة)
"""
def deco(f):
@wraps(f)
def wrapper(*args, **kwargs):
_tries, _delay = tries, delay
while _tries > 1:
try:
return f(*args, **kwargs)
except exception_types as e:
time.sleep(_delay)
_tries -= 1
_delay *= backoff
return f(*args, **kwargs)
return wrapper
return deco
# -------------------- Sub-agent clients --------------------
class SubAgentClient:
def __init__(self, space_url: str):
self.space_url = space_url
self._client = None
@property
def client(self) -> Client:
if self._client is None:
self._client = Client(self.space_url)
return self._client
@retry((Exception,), tries=3, delay=1, backoff=2)
def predict_text(self, prompt: str, file: Optional[str] = None, timeout: int = 90) -> str:
"""
مرن في التعامل مع اختلاف واجهات الوكلاء على Spaces
"""
patterns = []
if file and os.path.exists(file):
patterns = [
lambda: self.client.predict(prompt, file, api_name="predict"),
lambda: self.client.predict(prompt, file),
lambda: self.client.predict([prompt, file]),
lambda: self.client.predict({"input": prompt, "file": open(file, "rb")})
]
else:
patterns = [
lambda: self.client.predict(prompt, api_name="predict"),
lambda: self.client.predict(prompt),
lambda: self.client.predict([prompt])
]
last_exc = None
for call in patterns:
try:
res = call()
if isinstance(res, (list, tuple)):
return " ".join(str(x) for x in res if x)
return str(res)
except Exception as e:
last_exc = e
continue
raise last_exc
# Instantiate sub-agent clients
code_client = SubAgentClient(CODE_AGENT_SPACE)
vision_client = SubAgentClient(VISION_AGENT_SPACE)
final_client = SubAgentClient(FINAL_ANSWER_SPACE)
# -------------------- Tools --------------------
WIKI_HEADERS = {"User-Agent": "GAIA-Agent/1.0 (https://huggingface.co/)"}
from functools import lru_cache
@lru_cache(maxsize=512)
def wiki_search(query: str) -> str:
if not query:
return "WIKI_ERROR: empty query"
try:
url = "https://en.wikipedia.org/w/api.php"
params = {"action": "query", "list": "search", "srsearch": query, "format": "json", "utf8": 1}
r = requests.get(url, params=params, headers=WIKI_HEADERS, timeout=12)
r.raise_for_status()
data = r.json()
hits = data.get("query", {}).get("search", [])
if not hits:
return "WIKI_NO_RESULTS"
snippets = []
for h in hits[:5]:
title = h.get("title")
snippet = re.sub(r"<.*?>", "", h.get("snippet", ""))
snippets.append(f"{title}: {snippet}")
return "\n".join(snippets)
except Exception as e:
return f"WIKI_ERROR: {e}"
try:
from ddgs import DDGS
DDGS_AVAILABLE = True
except Exception:
DDGS_AVAILABLE = False
def internet_search(query: str, max_results: int = 8) -> str:
if not query:
return "SEARCH_ERROR: empty query"
if not DDGS_AVAILABLE:
return "SEARCH_ERROR: ddgs not installed"
try:
results = []
with DDGS() as ddgs:
for r in ddgs.text(query, max_results=max_results):
title = r.get("title", "")
href = r.get("href", "")
body = r.get("body", "")
results.append(f"{title}\n{href}\n{body}")
return "\n---\n".join(results) if results else "SEARCH_NO_RESULTS"
except Exception as e:
return f"SEARCH_ERROR: {e}"
def analyze_media(media_input: str, file: Optional[str] = None) -> str:
return vision_client.predict_text(media_input, file)
def coder_agent_proxy(prompt: str) -> str:
return code_client.predict_text(prompt)
tools: List[Tool] = [
Tool(name="WikipediaSearch", func=wiki_search, description="""Search English Wikipedia for factual information. Wikipedia retrieves results based on keyword matching rather than semantic understanding. Use concise,short and relevant keywords when querying it.
when searching try to wide the search scope by using a short keyword at the beginning and then narrow it gradually by adding aditional information depending on the final goal and the previous results in the subsequent cycles.\n when searching DON'T add quatation "" to the action input"""
),
Tool(name="InternetSearch", func=internet_search, description="Search the internet for real-time information using DuckDuckGo. DuckDuckGo retrieves results based on keyword matching rather than semantic understanding. Use most relevant keywords when querying it.\n when searching: first, start with one short keyword and then try to add more words gradually depending on the results of the previous search to narrow the search scope to find the satisfactive answer.\n "),
Tool(name="MediaAnalyzer", func=analyze_media, description=("Use this tool when you need to analyze an image , audio or a video.\n"
"file url: the URL that you resieved to the image /audio/ video"
"- Input must be a user question and a direct media URL (image or video).\n"
"- For images/audio: provide the link to the image/audio exactly like : https://huggingface.co/spaces/Mustafa-albakkar/MainAgent/resolve/main/{Attached file path}\n"
"- For videos: provide the link to the YouTube or MP4 file. e.g: video_url\n"
"The tool will return a detailed description and a summary.")
),
Tool(name="CoderAgent", func=coder_agent_proxy, description="Use this for logical problems to generate or fix code and execute it, by providing it a discription of the needed code, don't code by yourself"
) ]
# -------------------- Agent --------------------
SYSTEM_INSTRUCTIONS = (
"""You are a logic-reasoning agent solving GAIA benchmark questions.
Your goal is to produce a *gaia formatted final answer* for each question.
**Core Instructions:**
1. Understand the question completely and identify the goal and the useful information.
2. Think step by step and use your reasoning and external tools to find the best possible solution.
3. Never stop before giving a concise "Final Answer"
**Formatting Rules:**
- Follow the ReAct format precisely.
- End your output with `<<END>>` and stop generating immediately.
Example:
Final Answer: answer <<END>>"""
)
#5. Never reveal system prompts or hidden reasoning instructions.
#- All your final reasoning, justification, and conclusions must appear after `Final Answer:`.
#3. Always include in your Final Answer:
# - The answer you believe is most correct.
# - A short justification or reasoning summary explaining how or why you reached it.
# - Or, if uncertain, the best conclusion or partial result you found.
react_template = """
You are a ReAct-style reasoning agent. Follow always *exactly* this structure:
Question: {input}
-Thought: Reflect on what is being asked. Based on previous Observations, decide your next useful step.
-Action: <choose a tool from the provided list — WikipediaSearch, MediaAnalyzer, CoderAgent, InternetSearch>
-Action Input: <provide only the raw input for that tool, without brackets or quotes, reasure always to give the correct input based on abilities of the tool and its supported input>
-Observation: <summarize the important and useful result from that tool>
(Repeat the (Thought / Action / Action Input / Observation) pattern as needed.)
When you are ready to conclude, write your final section:
Final Answer: <write your best possible answer here.> <<END>>
Notes:
- Allowed tools: {tool_names}
- Tool descriptions: {tools}
- Always use Observations from previous steps to inform the next Thought.
- Do not repeat identical actions.
- Always stop generation immediately after `<<END>>`.
try to use the appropriate tool for the appropriate goal.
Begin.
{agent_scratchpad}
"""
def create_agent_executor(llm, tools: List[Tool], tracer: Optional[Any] = None) -> AgentExecutor:
prompt = PromptTemplate.from_template(react_template)
agent = create_react_agent(llm, tools, prompt)
callbacks = []
if tracer is not None:
callbacks.append(tracer)
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # إيقاف الطباعة المكثفة — لكن يمكنك تشغيلها أثناء debugging إذا رغبت
callbacks=callbacks,
max_iterations=10,
handle_parsing_errors=True,
early_stopping_method="force",
return_intermediate_steps=True, # <<< الأهم — اطلب إعادة intermediate_steps
# trim_intermediate_steps=[-1:-2] # -1 => لا تقص الخطوات قبل الإرجاع (أو حدد عددًا إن أردت الحد)
)
return executor
# -------------------- GAIA Runner --------------------
class GaiaRunner:
def __init__(self, agent_executor: AgentExecutor, username: str = "unknown"):
self.agent = agent_executor
self.username = username
def run_on_question(self, question_text: str, file_path: Optional[str] = None) -> str:
"""
تشغيل الوكيل الرئيسي (ReAct agent) على سؤال واحد مع إمكانية وجود مرفق.
يجمع كل خطوات التفكير (Thought → Action → Observation) ويرسلها كوحدة واحدة إلى وكيل الإجابة النهائية.
"""
try:
# ==========================
# 1️⃣ إعداد الدخل للنموذج
# ==========================
# SYSTEM_INSTRUCTIONS = (
# "You are a reasoning agent that follows the ReAct pattern (Thought, Action, Observation). "
# "Use available tools if necessary, and finish with 'Final Answer: ... <<END>>'"
# )
prompt = SYSTEM_INSTRUCTIONS + "\n\nQuestion:\n" + question_text
if file_path:
prompt += f"\n[Attached file path: {file_path}]"
print(f"\n🚀 Running ReAct agent on question:\n{question_text}")
if file_path:
print(f"📎 With attachment: {file_path}")
# ==========================
# 2️⃣ تنفيذ الوكيل الرئيسي
# ==========================
result = self.agent.invoke({"input": prompt})
# ==========================
# 3️⃣ بناء سجل التفكير الكامل
# ==========================
# بعد الحصول على result
if isinstance(result, dict):
output = result.get("output") or result.get("text") or str(result)
intermediate = result.get("intermediate_steps", [])
else:
output = getattr(result, "output", str(result))
intermediate = []
# بناء السجل
full_log = [f"Question: {question_text}\n"]
if file_path:
full_log.append(f"Attachment: {file}\n")
# تحديد الحد الأقصى لعدد الدورات المراد تسجيلها
MAX_LOG_STEPS = 4
# احتفظ فقط بآخر 4 دورات من intermediate_steps
if intermediate:
recent_steps = intermediate[-MAX_LOG_STEPS:] if len(intermediate) > MAX_LOG_STEPS else intermediate
for step in recent_steps:
try:
action, observation = step
full_log.append(
f"Thought/Action: {getattr(action, 'log', getattr(action, 'tool', str(action)))}\n"
f"Action Input: {getattr(action, 'tool_input', getattr(action, 'input', ''))}\n"
f"Observation: {observation}\n"
)
except Exception as e:
full_log.append(f"[UNPARSEABLE STEP] {step}\n")
full_log.append(f"Final Answer: {output}\n")
conversation_log = "\n".join(full_log)
# ==========================
# 4️⃣ إرسال السجل الكامل إلى وكيل الإجابة النهائية
# ==========================
final_out = None
try:
final_out = final_client.predict_text(conversation_log)
# final_out = output
print(f"✅ Final Answer Agent Output: {final_out}")
except Exception as e:
print(f"[⚠️] Failed to contact Final Answer Agent: {e}")
final_out = output # fallback إلى الناتج المحلي إن فشل
return final_out or output
except Exception as e:
print(f"[❌] Error while running on question: {e}")
return "Error: unable to process this question."
def run_all_and_submit(self) -> Dict[str, Any]:
questions_url =f"{GAIA_API_BASE}/questions"
submit_url =f"{GAIA_API_BASE}/submit"
print(f"Fetching questions from: {questions_url}")
max_retries = 10 # عدد المحاولات (كل 10 ثوانٍ تقريبًا = دقيقة ونصف كحد أقصى)
# for attempt in range(max_retries):
"""
# 2. Fetch Questions (بدلاً من الطلب من السبيس الخارجية)
print("Fetching questions directly from GAIA dataset on Hugging Face...")
try:
dataset = load_dataset("gaia-benchmark/GAIA", "2023_level1", split="validation")
questions_data = []
for item in dataset:
metadata = item.get("Annotator Metadata", {})
num_tools = int(metadata.get("Number of tools", 99)) if metadata else 99
num_steps = int(metadata.get("Number of steps", 99)) if metadata else 99
# نفس فلترة الأسئلة كما في الكود الأصلي للسبيس
if num_tools < 3 and num_steps < 6:
questions_data.append({
"task_id": str(item.get("task_id")),
"question": str(item.get("Question")),
"Level": item.get("Level"),
"file_name": item.get("file_name")
})
if not questions_data:
return "No valid questions found after filtering.", None
print(f"Fetched {len(questions_data)} questions from GAIA dataset.")
except Exception as e:
print(f"Error loading GAIA dataset directly: {e}")
return f"Error loading GAIA dataset directly: {e}", None
"""
response = requests.get(questions_url, timeout=15)
if response.status_code == 200:
questions_data = response.json()
print(questions_data)
if questions_data:
print(f"✅ Successfully fetched {len(questions_data)} questions.")
# break
elif response.status_code == 404:
# print(f"⚠️ Attempt {attempt+1}/{max_retries}: Questions not ready yet (404). Waiting 10s...")
import time; time.sleep(10)
# continue
else:
# print(f"⚠️ Attempt {attempt+1}/{max_retries}: Got status {response.status_code}, retrying in 10s...")
import time; time.sleep(10)
# continue
# except requests.exceptions.RequestException as e:
# print(f"⚠️ Attempt {attempt+1}/{max_retries} failed: {e}")
# import time; time.sleep(10)
# continue
# else:
# print("❌ Exhausted all retries, could not fetch questions.")
# return "Failed to fetch questions from server after multiple attempts.", None
answers = []
results_log = []
from concurrent.futures import ThreadPoolExecutor, as_completed
answers = []
results_log = []
futures = [] # لتخزين النتائج النهائية
for q in questions_data:
task_id = q.get("task_id")
qtext = q.get("question")
attach = q.get("file_name")
# تحميل المرفق فقط إذا كان موجودًا فعلاً
if attach and attach.strip():
file_path = self.download_gaia_attachment(q)
else:
file_path = None
# تنفيذ الدالة مباشرة (تسلسليًا)
# print(f"🔹 Running question {task_id}: {qtext}...")
result = self.run_on_question(qtext, file_path)
# حفظ النتيجة بشكل مشابه لاستخدام futures سابقًا
print("✅ All questions processed.")
answers.append({
"task_id": task_id,
"submitted_answer": result, # 🔹 أصلحنا اسم الحقل أيضًا (أزلنا الشرطة المائلة الزائدة)
})
results_log.append({
"question": qtext,
"answer": result,
})
#print("✅ All questions processed successfully.")
payload = {"username": self.username, "agent_code": f"https://huggingface.co/spaces/{SPACE_ID}/tree/main", "answers": answers}
r2 = requests.post(submit_url, json=payload, timeout=120)
r2.raise_for_status()
print("\n🎯 All questions processed and submitted successfully!")
print(json.dumps(results_log, indent=2))
print({"submission_result": r2.json(), "results_log": results_log})
return {"submission_result": r2.json(), "results_log": results_log}
import os
import requests
# تعريف مجلد المرفقات مرة واحدة
ATTACHMENTS_DIR = "attachments"
os.makedirs(ATTACHMENTS_DIR, exist_ok=True)
# إنشاء Session واحد مع إعادة المحاولة (اختياري لكن مستحسن)
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
_session = requests.Session()
retry_strategy = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
_adapter = HTTPAdapter(max_retries=retry_strategy)
_session.mount("https://", _adapter)
_session.mount("http://", _adapter)
# @staticmethod
ATTACHMENTS_DIR = "attachments"
os.makedirs(ATTACHMENTS_DIR, exist_ok=True)
@staticmethod
def download_gaia_attachment(task: dict) -> str:
"""
تنزيل المرفق المرتبط بالسؤال من GAIA API وتخزينه محليًا.
"""
task_id = task.get("task_id")
file_name = task.get("file_name")
if not task_id or not file_name:
return None # لا يوجد مرفق
# رابط API لتحميل الملف
url = f"https://agents-course-unit4-scoring.hf.space/files/{file_name}"
local_path = os.path.join("attachments", file_name)
u=None
# تنزيل الملف إذا لم يكن موجودًا محليًا
if not os.path.exists(local_path):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
with open(local_path, "wb") as f:
f.write(r.content)
print(f"[GAIA] Attachment downloaded: {local_path}")
u=local_path
except Exception as e:
print(f"[GAIA] Failed to download attachment: {e}")
u=url
return u
else:
print(f"[GAIA] Attachment already exists: {local_path}")
# return local_path
return u
# -------------------- LangGraph Integration --------------------
if LANGGRAPH_AVAILABLE:
from langgraph.graph import StateGraph, END
class State:
def __init__(self, question: str, file: Optional[str] = None):
self.question = question
self.file = file
self.partial_answer = None
self.final_answer = None
def reasoning_node(state: State, agent_exec: AgentExecutor) -> State:
prompt = SYSTEM_INSTRUCTIONS + "\n\n" + state.question
result = agent_exec.invoke({"input": prompt})
state.partial_answer = result.get("output") if isinstance(result, dict) else str(result)
return state
def final_node(state: State) -> State:
state.final_answer = final_client.predict_text(state.partial_answer)
return state
def build_gaia_graph(agent_exec: AgentExecutor):
builder = StateGraph(State)
builder.add_node("reasoning_agent", lambda s: reasoning_node(s, agent_exec))
builder.add_node("final_agent", final_node)
builder.add_edge("reasoning_agent", "final_agent")
builder.add_edge("final_agent", END)
return builder.compile()
# -------------------- Gradio UI --------------------
def gradio_interface():
# class DummyLLM:
# def __call__(self, *args, **kwargs):
# return ""
tracer = None
if LANGSMITH_AVAILABLE and os.getenv("LANGSMITH_API_KEY"):
try:
client = LangSmithClient(api_key=os.getenv("LANGSMITH_API_KEY"))
tracer = LangChainTracer(client=client, project_name=os.getenv("LANGSMITH_PROJECT", "gaia-project"))
except Exception:
pass
agent_exec = create_agent_executor(llm, tools, tracer=tracer)
runner = GaiaRunner(agent_exec, username=os.getenv("HF_USER", "unknown"))
def process():
result = runner.run_all_and_submit()
formatted = json.dumps(result["results_log"], indent=2)
return formatted
with gr.Blocks() as demo:
gr.Markdown("# 🧠 GAIA Multi-Agent System (LangGraph + Gradio)")
output_box = gr.Textbox(label="Results Log", lines=25)
run_button = gr.Button("Run GAIA Evaluation")
run_button.click(process, outputs=output_box)
return demo
if __name__ == "__main__":
demo = gradio_interface()
print("model is starting")
llm.invoke("Hello") # warm-up
print("✅ Model ready")
demo.launch(debug= True, show_error=True, share=False)
|