graphics-llm / app.py
Tom
Update to Jina-CLIP-v2 embeddings and rebrand to Viz LLM
2d671a2
raw
history blame
5.1 kB
"""
Viz LLM - Gradio App
A RAG-powered assistant for data visualization guidance, powered by Jina-CLIP-v2
embeddings and research from the field of information graphics.
"""
import os
import gradio as gr
from dotenv import load_dotenv
from src.rag_pipeline import create_pipeline
from datetime import datetime, timedelta
from collections import defaultdict
# Load environment variables
load_dotenv()
# Rate limiting: Track requests per user (IP-based)
# Format: {ip: [(timestamp1, timestamp2, ...)]}
rate_limit_tracker = defaultdict(list)
DAILY_LIMIT = 20
# Initialize the RAG pipeline
print("Initializing Graphics Design Pipeline...")
try:
pipeline = create_pipeline(
retrieval_k=5,
model=os.getenv("LLM_MODEL", "meta-llama/Llama-3.1-8B-Instruct"),
temperature=float(os.getenv("LLM_TEMPERATURE", "0.2"))
)
print("✓ Pipeline initialized successfully")
except Exception as e:
print(f"✗ Error initializing pipeline: {e}")
raise
def check_rate_limit(request: gr.Request) -> tuple[bool, int]:
"""Check if user has exceeded rate limit"""
if request is None:
return True, DAILY_LIMIT # Allow if no request object
user_id = request.client.host
now = datetime.now()
cutoff = now - timedelta(days=1)
# Remove old requests (older than 24 hours)
rate_limit_tracker[user_id] = [
ts for ts in rate_limit_tracker[user_id] if ts > cutoff
]
remaining = DAILY_LIMIT - len(rate_limit_tracker[user_id])
if remaining <= 0:
return False, 0
# Add current request
rate_limit_tracker[user_id].append(now)
return True, remaining - 1
def recommend_stream(message: str, history: list, request: gr.Request):
"""
Streaming version of design recommendation function
Args:
message: User's design query
history: Chat history
request: Gradio request object for rate limiting
Yields:
Response chunks
"""
# Check rate limit
allowed, remaining = check_rate_limit(request)
if not allowed:
yield "⚠️ **Rate limit exceeded.** You've reached the maximum of 20 queries per day. Please try again in 24 hours."
return
try:
response_stream = pipeline.generate_recommendations(message, stream=True)
full_response = ""
for chunk in response_stream:
full_response += chunk
yield full_response
# Add rate limit info at the end
if remaining <= 5:
yield full_response + f"\n\n---\n*You have {remaining} queries remaining today.*"
except Exception as e:
yield f"Error generating response: {str(e)}\n\nPlease check your environment variables (HF_TOKEN, SUPABASE_URL, SUPABASE_KEY) and try again."
# Minimal CSS to fix UI artifacts
custom_css = """
/* Hide retry/undo buttons that appear as artifacts */
.chatbot button[aria-label="Retry"],
.chatbot button[aria-label="Undo"] {
display: none !important;
}
"""
# Create Gradio interface
with gr.Blocks(
title="Viz LLM",
css=custom_css
) as demo:
gr.Markdown("""
# 📊 Viz LLM
Get design recommendations for creating effective data visualizations based on research and best practices.
""")
# Main chat interface
chatbot = gr.ChatInterface(
fn=recommend_stream,
type="messages",
examples=[
"What's the best chart type for showing trends over time?",
"How do I create an effective infographic for complex data?",
"What are best practices for data visualization accessibility?",
"How should I design a dashboard for storytelling?",
"What visualization works best for comparing categories?"
],
cache_examples=False,
api_name="recommend"
)
# Knowledge base section (below chat interface)
gr.Markdown("""
### Knowledge Base
This assistant draws on research papers, design principles, and examples from the field of information graphics and data visualization.
**Credits:** Special thanks to the researchers whose work informed this model: Robert Kosara, Edward Segel, Jeffrey Heer, Matthew Conlen, John Maeda, Kennedy Elliott, Scott McCloud, and many others.
---
**Usage Limits:** This service is limited to 20 queries per day per user to manage costs. Responses are optimized for English.
<div style="text-align: center; margin-top: 20px; opacity: 0.6; font-size: 0.9em;">
Embeddings: Jina-CLIP-v2
</div>
""")
# Launch configuration
if __name__ == "__main__":
# Check for required environment variables
required_vars = ["SUPABASE_URL", "SUPABASE_KEY", "HF_TOKEN"]
missing_vars = [var for var in required_vars if not os.getenv(var)]
if missing_vars:
print(f"⚠️ Warning: Missing environment variables: {', '.join(missing_vars)}")
print("Please set these in your .env file or as environment variables")
# Launch the app
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_api=True
)