Spaces:
Configuration error
Configuration error
File size: 12,034 Bytes
d4ea4e5 |
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 |
# app.py
import gradio as gr
import os
import traceback
import asyncio
from dotenv import load_dotenv
from models.task_prompt import TaskPrompt
import time
from llama_index.core import Settings as LlamaSettings # Import at top level
from llama_index.llms.anthropic import Anthropic # Import at top level
from manager_agent2 import ManagerAgent # Ensure this path is correct
import concurrent.futures # For running blocking code in a separate thread
# Load environment variables from .env file
load_dotenv()
# --- Configuration ---
LLM_MODEL = "claude-sonnet-4-20250514"
# --- Global variables ---
current_status = "Ready"
llm_global = None
manager_agent_global = None
# Settings_global is not strictly needed as a global if LlamaSettings is imported directly
# Thread pool executor for running blocking agent tasks
thread_pool_executor = concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count() or 1)
# --- LlamaIndex LLM Initialization ---
def initialize_components():
global llm_global, manager_agent_global
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
print("\n" + "="*60)
print("⚠️ ERROR: ANTHROPIC_API_KEY not found in environment variables!")
print("Please set your API key (e.g., in a .env file).")
print("="*60 + "\n")
return
try:
llm_global = Anthropic(
model=LLM_MODEL,
temperature=0.2,
max_tokens=4096
)
LlamaSettings.llm = llm_global # Use the imported LlamaSettings directly
print(f"Successfully initialized LlamaIndex with Anthropic model: {LLM_MODEL} (temperature=0.2)")
manager_agent_global = ManagerAgent(
llm_global,
max_iterations=30, # Keep this reasonable for testing
update_callback=update_status_callback
)
print("✅ ManagerAgent initialized successfully")
except Exception as e:
print(f"Error initializing Anthropic LLM or ManagerAgent: {e}")
traceback.print_exc()
# --- Update callback function (called by ManagerAgent) ---
def update_status_callback(message):
global current_status
# This function is called from the ManagerAgent's thread (potentially)
# or the ReAct agent's execution context.
# It needs to update the global variable, which the Gradio polling thread will pick up.
current_status = message
print(f"✅ UI_STATUS_UPDATE (via callback): {message}") # Differentiate console log
# --- Status retrieval function for Gradio polling ---
def get_current_status_for_ui():
global current_status
timestamp = time.time()
return f"{current_status}<span style='display:none;'>{timestamp}</span>"
# --- Gradio Interface Setup ---
def create_gradio_interface():
if "ANTHROPIC_API_KEY" not in os.environ:
gr.Warning("ANTHROPIC_API_KEY not found in environment variables! ALITA may not function correctly.")
with gr.Blocks(theme="soft") as demo:
gr.Markdown("# GALITA")
gr.Markdown("GALITA is a self-learning AI agent that can search for information, analyze data, create tools, and orchestrate complex tasks.")
chatbot_component = gr.Chatbot(
label="Chat",
height=500,
show_label=False,
# type='messages' # For Gradio 4.x+
)
gr.Markdown("Gradio version: " + gr.__version__ + " (Chatbot type defaults to 'tuples' for older versions. Consider `type='messages'` for newer Gradio if issues persist with chat display).")
with gr.Row():
message_textbox = gr.Textbox(
placeholder="Tapez votre message ici...",
scale=7,
show_label=False,
container=False
)
gr.Examples(
examples=[
"🔍 Recherche des informations sur l'intelligence artificielle",
"📊 Analyse les tendances du marché technologique",
"⚡ Crée un script pour automatiser une tâche répétitive",
"🌐 Trouve des ressources open source pour machine learning",
"what is the temperature in paris now"
],
inputs=message_textbox,
)
status_box_component = gr.Textbox(
label="Agent Status",
value=get_current_status_for_ui(),
interactive=False,
# elem_id="status_box_alita" # For potential direct JS manipulation if desperate (avoid)
)
def add_user_msg(user_input_text, chat_history_list):
if not user_input_text.strip():
return gr.update(), chat_history_list
# For older Gradio, history is list of [user_msg, bot_msg] tuples
chat_history_list.append((user_input_text, None))
return gr.update(value=""), chat_history_list
async def generate_bot_reply(chat_history_list):
if not chat_history_list or chat_history_list[-1][0] is None:
# This case should ideally not be reached if add_user_msg works correctly
yield chat_history_list
return
user_message = chat_history_list[-1][0]
if manager_agent_global is None or LlamaSettings.llm is None:
# This update_status_callback will set current_status
# The polling mechanism (continuous_status_updater) should pick it up.
update_status_callback("⚠️ Error: Agent or LLM not initialized. Check API key and logs.")
# For older Gradio, update the last tuple's second element
chat_history_list[-1] = (chat_history_list[-1][0], "❌ Critical Error: ALITA is not properly initialized. Please check server logs and API key.")
yield chat_history_list
return
try:
print(f"\n🤖 GRADIOLOG: Processing user message: '{user_message[:100]}{'...' if len(user_message) > 100 else ''}'")
update_status_callback(f"💬 Processing: '{user_message[:50]}{'...' if len(user_message) > 50 else ''}'")
await asyncio.sleep(0.01) # Allow UI to briefly update with "Processing..."
task_prompt = TaskPrompt(text=user_message)
update_status_callback("🔄 Analyzing request and determining optimal workflow...")
await asyncio.sleep(0.01) # Allow UI to briefly update
# Run the blocking manager_agent_global.run_task in a separate thread
loop = asyncio.get_event_loop()
response_text_from_agent = await loop.run_in_executor(
thread_pool_executor,
manager_agent_global.run_task, # The function to run
task_prompt # Arguments to the function
)
# By this point, run_task has completed, and all its internal
# calls to update_status_callback (via send_update) should have occurred.
# The polling mechanism should have picked up these changes.
update_status_callback("✨ Generating final response stream...")
await asyncio.sleep(0.01)
final_bot_response = response_text_from_agent
words = final_bot_response.split()
accumulated_response_stream = ""
total_words = len(words)
# Initialize bot's part of the message in history for older Gradio
current_user_message = chat_history_list[-1][0]
chat_history_list[-1] = (current_user_message, "")
if not words:
chat_history_list[-1] = (current_user_message, final_bot_response.strip())
yield chat_history_list
else:
for i, word in enumerate(words):
accumulated_response_stream += word + " "
# These status updates are for the streaming part,
# agent's internal updates should have already happened.
if total_words > 0: # Avoid division by zero
if i == total_words // 4: update_status_callback("🔄 Streaming response (25%)...")
elif i == total_words // 2: update_status_callback("🔄 Streaming response (50%)...")
elif i == (total_words * 3) // 4: update_status_callback("🔄 Streaming response (75%)...")
if i % 3 == 0 or i == len(words) - 1:
chat_history_list[-1] = (current_user_message, accumulated_response_stream.strip())
yield chat_history_list
await asyncio.sleep(0.01) # For streaming effect
# Ensure final complete response is set
if chat_history_list[-1][1] != final_bot_response.strip():
chat_history_list[-1] = (current_user_message, final_bot_response.strip())
yield chat_history_list
print("✅ GRADIOLOG: Task processing and streaming completed.")
update_status_callback("✅ Ready for your next request")
except Exception as e:
error_message_for_ui = f"❌ Gradio/Agent Error: {str(e)}"
print(f"\n🚨 GRADIOLOG: Error in generate_bot_reply: {e}")
traceback.print_exc()
update_status_callback(f"❌ Error: {str(e)[:100]}...")
chat_history_list[-1] = (chat_history_list[-1][0], error_message_for_ui)
yield chat_history_list
message_textbox.submit(
add_user_msg,
inputs=[message_textbox, chatbot_component],
outputs=[message_textbox, chatbot_component],
show_progress="hidden", # Gradio 3.x might not have this, can be ignored
).then(
generate_bot_reply,
inputs=[chatbot_component],
outputs=[chatbot_component],
api_name=False, # Good practice
# show_progress="hidden", # Gradio 3.x might not have this
)
async def continuous_status_updater(update_interval_seconds=0.3): # Slightly faster poll
"""Continuously yields status updates for the status_box_component."""
print("GRADIOLOG: Starting continuous_status_updater loop.")
while True:
# print(f"POLL: Fetching status: {current_status}") # DEBUG: very verbose
yield get_current_status_for_ui()
await asyncio.sleep(update_interval_seconds)
demo.load(continuous_status_updater, inputs=None, outputs=status_box_component)
print("GRADIOLOG: Continuous status updater loaded.")
return demo
# Initialize LLM and Agent components
initialize_components()
# --- Launch the Application ---
if __name__ == "__main__":
print(f"Gradio version: {gr.__version__}")
print("🚀 Starting Gradio ALITA Chat Application...")
alita_interface = create_gradio_interface()
try:
alita_interface.launch(
share=False,
server_name="127.0.0.1",
server_port=5126,
show_error=True,
# debug=True # Can be helpful
)
except KeyboardInterrupt:
print("\n👋 Application stopped by user")
except Exception as e:
print(f"\n❌ Error launching application: {e}")
traceback.print_exc()
finally:
print("Shutting down thread pool executor...")
thread_pool_executor.shutdown(wait=True) # Clean up threads
print("✅ Gradio application stopped.") |