File size: 7,092 Bytes
9b867b0 b1d0f85 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 49fea4f 9b867b0 |
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 |
# app.py (on Hugging Face Spaces)
import gradio as gr
import httpx
import asyncio
import json
# Replace with your Modal API endpoint URL
MODAL_API_ENDPOINT = "https://blastingneurons--collective-hive-backend-orchestrate-hive-api.modal.run"
# Helper function to format chat history for Gradio's 'messages' type
def format_chat_history_for_gradio(log_entries: list[dict]) -> list[dict]:
formatted_messages = []
for entry in log_entries:
# Default to 'System' if agent name is not found
role = entry.get("agent", "System")
content = entry.get("text", "")
formatted_messages.append({"role": role, "content": content})
return formatted_messages
async def call_modal_backend(problem_input: str, complexity: int):
full_chat_history = []
# Initialize all outputs with default values for the first yield
current_status = "Connecting to Hive..."
current_solution = ""
current_confidence = ""
current_minority_opinions = ""
# First yield to clear previous state and show connecting message
yield (
current_status,
format_chat_history_for_gradio([]),
current_solution,
current_confidence,
current_minority_opinions
)
try:
async with httpx.AsyncClient(timeout=600.0) as client: # Longer timeout for the full process
# Make sure to send complexity if your Modal backend expects it
async with client.stream("POST", MODAL_API_ENDPOINT, json={"problem": problem_input, "complexity": complexity}) as response:
response.raise_for_status() # Raise an exception for HTTP errors (4xx or 5xx)
buffer = ""
async for chunk in response.aiter_bytes():
buffer += chunk.decode('utf-8')
while "\n" in buffer:
line, buffer = buffer.split("\n", 1)
if not line.strip(): continue # Skip empty lines
try:
data = json.loads(line)
event_type = data.get("event")
if event_type == "status_update":
current_status = data["data"]
elif event_type == "chat_update":
full_chat_history.append(data["data"])
current_status = "In Progress..." # Update status to reflect ongoing discussion
elif event_type == "final_solution":
current_status = "Solution Complete!"
current_solution = data["solution"]
current_confidence = data["confidence"]
current_minority_opinions = data["minority_opinions"]
# Yield final state and then return to end the generator
yield (
current_status,
format_chat_history_for_gradio(full_chat_history + [{"agent": "System", "content": "Final solution synthesized."}]),
current_solution,
current_confidence,
current_minority_opinions
)
return # Done processing
# Yield the current state of all outputs after processing each event
yield (
current_status,
format_chat_history_for_gradio(full_chat_history),
current_solution,
current_confidence,
current_minority_opinions
)
except json.JSONDecodeError as e:
print(f"JSON Decode Error: {e} in line: {line}")
# Handle incomplete JSON chunks, perhaps buffer and process when a full line is received
# For robustness, you might yield an error status here too
current_status = f"Error decoding: {e}"
yield (current_status, format_chat_history_for_gradio(full_chat_history), current_solution, current_confidence, current_minority_opinions)
except Exception as e:
print(f"Error processing event: {e}, Data: {data}")
current_status = f"Error: {e}"
yield (current_status, format_chat_history_for_gradio(full_chat_history), current_solution, current_confidence, current_minority_opinions)
return # Exit on critical error
except httpx.HTTPStatusError as e:
current_status = f"HTTP Error: {e.response.status_code} - {e.response.text}"
print(current_status)
except httpx.RequestError as e:
current_status = f"Request Error: Could not connect to Modal backend: {e}"
print(current_status)
except Exception as e:
current_status = f"An unexpected error occurred: {e}"
print(current_status)
# Final yield in case of errors or unexpected termination
yield (current_status, format_chat_history_for_gradio(full_chat_history), current_solution, current_confidence, current_minority_opinions)
with gr.Blocks() as demo:
gr.Markdown("# Collective Intelligence Hive")
gr.Markdown("Enter a problem and watch a hive of AI agents collaborate to solve it! Powered by Modal and Nebius.")
with gr.Row():
problem_input = gr.Textbox(label="Problem to Solve", lines=3, placeholder="e.g., 'Develop a marketing strategy for a new eco-friendly smart home device targeting millennials.'", scale=3)
complexity_slider = gr.Slider(minimum=1, maximum=5, value=3, step=1, label="Problem Complexity", scale=1)
initiate_btn = gr.Button("Initiate Hive", variant="primary")
status_output = gr.Textbox(label="Hive Status", interactive=False)
with gr.Row():
with gr.Column(scale=2):
chat_display = gr.Chatbot(
label="Agent Discussion Log",
height=500,
type='messages',
autoscroll=True
)
with gr.Column(scale=1):
solution_output = gr.Textbox(label="Synthesized Solution", lines=10, interactive=False)
confidence_output = gr.Textbox(label="Solution Confidence", interactive=False)
minority_output = gr.Textbox(label="Minority Opinions", lines=3, interactive=False)
initiate_btn.click(
call_modal_backend,
inputs=[problem_input, complexity_slider],
outputs=[
status_output,
chat_display,
solution_output,
confidence_output,
minority_output
],
queue=True
)
demo.launch() |