Spaces:
Running
Running
import json | |
import requests | |
from rich.console import Console | |
from rich.live import Live | |
from rich.markdown import Markdown | |
from rich.panel import Panel | |
from rich.text import Text | |
class StreamResponseHandler: | |
""" | |
A utility class for handling streaming responses from API endpoints. | |
Provides rich formatting and real-time updates of the response content. | |
""" | |
def __init__(self, console=None): | |
""" | |
Initialize the stream response handler. | |
Args: | |
console (Console, optional): A Rich console instance. If not provided, a new one will be created. | |
""" | |
self.console = console or Console() | |
def check_server_health(self, health_url="http://localhost:8000/health"): | |
""" | |
Check if the server is running and accessible. | |
Args: | |
health_url (str, optional): The URL to check server health. Defaults to "http://localhost:8000/health". | |
Returns: | |
bool: True if the server is running and accessible, False otherwise. | |
""" | |
try: | |
self.console.print("Checking server health...", style="bold yellow") | |
response = requests.get(health_url) | |
if response.status_code == 200: | |
self.console.print("[bold green]β Server is running and accessible.[/]") | |
return True | |
else: | |
self.console.print(f"[bold red]β Server health check failed[/] with status code: {response.status_code}") | |
return False | |
except requests.exceptions.ConnectionError: | |
self.console.print("[bold red]β Error:[/] Could not connect to the server. Make sure it's running.") | |
return False | |
except Exception as e: | |
self.console.print(f"[bold red]β Error checking server health:[/] {e}") | |
return False | |
def stream_response(self, url, payload=None, params=None, method="POST", title="AI Response"): | |
""" | |
Send a request to an endpoint and stream the output to the terminal. | |
Args: | |
url (str): The URL of the endpoint to send the request to. | |
payload (dict, optional): The JSON payload to send in the request body. Defaults to None. | |
params (dict, optional): The query parameters to send in the request. Defaults to None. | |
method (str, optional): The HTTP method to use. Defaults to "POST". | |
title (str, optional): The title to display in the panel. Defaults to "AI Response". | |
Returns: | |
bool: True if the streaming was successful, False otherwise. | |
""" | |
# Display request information | |
self.console.print(f"Sending request to [bold cyan]{url}[/]") | |
if payload: | |
self.console.print("Payload:", style="bold") | |
self.console.print(json.dumps(payload, indent=2)) | |
if params: | |
self.console.print("Parameters:", style="bold") | |
self.console.print(json.dumps(params, indent=2)) | |
try: | |
# Prepare the request | |
request_kwargs = { | |
"stream": True | |
} | |
if payload: | |
request_kwargs["json"] = payload | |
if params: | |
request_kwargs["params"] = params | |
# Make the request | |
with getattr(requests, method.lower())(url, **request_kwargs) as response: | |
# Check if the request was successful | |
if response.status_code != 200: | |
self.console.print(f"[bold red]Error:[/] Received status code {response.status_code}") | |
self.console.print(f"Response: {response.text}") | |
return False | |
# Initialize an empty response text | |
full_response = "" | |
# Use Rich's Live display to update the content in place | |
with Live(Panel("Waiting for response...", title=title, border_style="blue"), refresh_per_second=10) as live: | |
# Process the streaming response | |
for line in response.iter_lines(): | |
if line: | |
# Decode the line and parse it as JSON | |
decoded_line = line.decode('utf-8') | |
try: | |
# Parse the JSON | |
data = json.loads(decoded_line) | |
# Extract and display the content | |
if isinstance(data, dict): | |
if "content" in data: | |
for content in data["content"]: | |
if content.get("type") == "text": | |
text_content = content.get("text", "") | |
# Append to the full response | |
full_response += text_content | |
# Update the live display with the current full response | |
live.update(Panel(Markdown(full_response), title=title, border_style="green")) | |
elif content.get("type") == "image_url": | |
image_url = content.get("image_url", {}).get("url", "") | |
# Add a note about the image URL | |
image_note = f"\n\n[Image URL: {image_url}]" | |
full_response += image_note | |
live.update(Panel(Markdown(full_response), title=title, border_style="green")) | |
elif "edited_image_url" in data: | |
# Handle edited image URL from edit endpoint | |
image_url = data.get("edited_image_url", "") | |
image_note = f"\n\n[Edited Image URL: {image_url}]" | |
full_response += image_note | |
live.update(Panel(Markdown(full_response), title=title, border_style="green")) | |
else: | |
# For other types of data, just show the JSON | |
live.update(Panel(Text(json.dumps(data, indent=2)), title="Raw JSON Response", border_style="yellow")) | |
else: | |
live.update(Panel(Text(decoded_line), title="Raw Response", border_style="yellow")) | |
except json.JSONDecodeError: | |
# If it's not valid JSON, just show the raw line | |
live.update(Panel(Text(f"Raw response: {decoded_line}"), title="Invalid JSON", border_style="red")) | |
self.console.print("[bold green]Stream completed.[/]") | |
return True | |
except requests.exceptions.ConnectionError: | |
self.console.print(f"[bold red]Error:[/] Could not connect to the server at {url}", style="red") | |
self.console.print("Make sure the server is running and accessible.", style="red") | |
return False | |
except requests.exceptions.RequestException as e: | |
self.console.print(f"[bold red]Error:[/] {e}", style="red") | |
return False |