aiqcamp's picture
Update app.py
cf76e4a verified
# 2) The actual app
import os
from getpass import getpass
from openai import OpenAI
import gradio as gr
import requests
import json
from datetime import datetime
# β€”β€”β€” Configure your OpenRouter key β€”β€”β€”
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
BSEARCH_API = os.getenv("BSEARCH_API")
# Check if the API key was retrieved
if not OPENROUTER_API_KEY:
print("Error: OPENROUTER_API_KEY not found in environment.")
print("Please set your API key in the environment as 'OPENROUTER_API_KEY'.")
else:
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=OPENROUTER_API_KEY,
)
# Brave Search function
def brave_search(query):
"""Perform a web search using Brave Search API."""
if not BSEARCH_API:
return "Error: BSEARCH_API not found in environment. Please set your Brave Search API key."
try:
headers = {
"Accept": "application/json",
"X-Subscription-Token": BSEARCH_API
}
# Brave Search API endpoint
url = "https://api.search.brave.com/res/v1/web/search"
params = {
"q": query,
"count": 5 # Number of results to return
}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
# Format the search results
results = []
if "web" in data and "results" in data["web"]:
for idx, result in enumerate(data["web"]["results"][:5], 1):
title = result.get("title", "No title")
url = result.get("url", "")
description = result.get("description", "No description")
results.append(f"{idx}. **{title}**\n URL: {url}\n {description}\n")
if results:
return "πŸ” **Web Search Results:**\n\n" + "\n".join(results)
else:
return "No search results found."
except Exception as e:
return f"Search error: {str(e)}"
def openrouter_chat(user_message, history, use_web_search):
"""Send user_message and history to mistralai/devstral-small:free and append to history."""
history = history or []
# If web search is enabled, perform search first
search_context = ""
if use_web_search and user_message.strip():
search_results = brave_search(user_message)
search_context = f"\n\n{search_results}\n\nBased on the above search results, please answer the following question:\n"
# Add search results to history as a system message
history.append(("πŸ” Web Search Query", user_message))
history.append(("🌐 Search Results", search_results))
# Build the messages list from the history and the current user message
messages_for_api = []
# Add system message if web search was used
if search_context:
messages_for_api.append({
"role": "system",
"content": "You are a helpful assistant. When web search results are provided, incorporate them into your response to give accurate and up-to-date information."
})
for human_message, ai_message in history[:-2] if use_web_search else history: # Exclude search entries from API messages
if not human_message.startswith("πŸ”") and not human_message.startswith("🌐"):
messages_for_api.append({"role": "user", "content": human_message})
if ai_message is not None:
messages_for_api.append({"role": "assistant", "content": ai_message})
# Add the current user message with search context if applicable
current_message = search_context + user_message if search_context else user_message
messages_for_api.append({"role": "user", "content": current_message})
try:
# Call the model with the mistralai/Devstral-Small-2505 for full conversation history
resp = client.chat.completions.create(
model="mistralai/devstral-small:free",
messages=messages_for_api,
# you can tweak max_tokens, temperature, etc. here
)
bot_reply = resp.choices[0].message.content
# Append the user message and bot reply to the history for Gradio display
history.append((user_message, bot_reply))
except Exception as e:
# Handle potential errors and append an error message to the history
history.append((user_message, f"Error: {e}"))
return history, ""
# Clean and professional CSS
custom_css = """
/* Clean gradient background */
.gradio-container {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
padding: 20px;
}
/* Main container styling */
.container {
max-width: 1200px;
margin: 0 auto;
}
/* Chat container with subtle glassmorphism */
#component-0 {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.1);
padding: 20px;
}
/* Chatbot styling */
.chatbot {
background: rgba(255, 255, 255, 0.95) !important;
border-radius: 12px !important;
border: 1px solid #e0e0e0 !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
}
/* Message bubbles */
.message {
border-radius: 10px !important;
padding: 12px 16px !important;
margin: 8px 0 !important;
}
.user {
background-color: #4a5568 !important;
color: white !important;
margin-left: 20% !important;
}
.bot {
background-color: #f7fafc !important;
color: #2d3748 !important;
margin-right: 20% !important;
border: 1px solid #e2e8f0 !important;
}
/* Input styling */
.textbox {
border-radius: 8px !important;
border: 2px solid #e2e8f0 !important;
background: white !important;
font-size: 16px !important;
}
.textbox:focus {
border-color: #4a5568 !important;
box-shadow: 0 0 0 3px rgba(74, 85, 104, 0.1) !important;
}
/* Checkbox styling */
.checkbox-group {
background: rgba(255, 255, 255, 0.8) !important;
border-radius: 8px !important;
padding: 10px !important;
margin: 10px 0 !important;
}
/* Button styling */
button {
background: #4a5568 !important;
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 10px 20px !important;
font-weight: 600 !important;
transition: all 0.2s ease !important;
}
button:hover {
background: #2d3748 !important;
transform: translateY(-1px) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
}
/* Title styling */
h1, h2 {
color: #2d3748 !important;
}
/* Remove excessive shadows and effects */
* {
text-shadow: none !important;
}
/* Responsive design */
@media (max-width: 768px) {
.user {
margin-left: 10% !important;
}
.bot {
margin-right: 10% !important;
}
}
"""
with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
gr.HTML(
"""
<div style="text-align: center; padding: 20px;">
<h1 style="font-size: 2.5em; margin-bottom: 10px;">πŸ€– AI Chat Assistant : Mistral-Devstral</h1>
<p style="font-size: 1.1em; color: #718096;">with Web Search</p>
<!-- λ°°μ§€ μ„Ήμ…˜ -->
<div style="margin-top: 20px; display: flex; justify-content: center; align-items: center; gap: 15px;">
<a href="https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528" target="_blank">
<img src="https://img.shields.io/static/v1?label=Commercial%20API&message=deepseek-r1-0528&color=%230000ff&labelColor=%23800080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="badge">
</a>
<a href="https://huggingface.co/spaces/aiqcamp/deepseek-r1-0528-qwen3-8b" target="_blank">
<img src="https://img.shields.io/static/v1?label=Commercial%20API&message=deepseek-r1-0528-qwen3-8b&color=%230000ff&labelColor=%23800080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="badge">
</a>
<a href="https://huggingface.co/spaces/aiqcamp/Mistral-Devstral-API" target="_blank">
<img src="https://img.shields.io/static/v1?label=Free%20API&message=Mistral-Devstral&color=%230000ff&labelColor=%23800080&logo=huggingface&logoColor=%23ffa500&style=for-the-badge" alt="badge">
</a>
</div>
</div>
"""
)
chatbot = gr.Chatbot(
label="Chat History",
height=500,
elem_classes=["chatbot"],
bubble_full_width=False
)
with gr.Row():
msg_in = gr.Textbox(
placeholder="Type your message here...",
label="Message",
scale=4,
lines=1
)
submit_btn = gr.Button("Send", scale=1, variant="primary")
with gr.Row():
use_web_search = gr.Checkbox(
label="πŸ” Enable Web Search",
value=True,
scale=2
)
clear_btn = gr.Button("Clear Chat", scale=1)
# Event handlers
def submit_message(msg, history, search):
return openrouter_chat(msg, history, search)
msg_in.submit(
submit_message,
inputs=[msg_in, chatbot, use_web_search],
outputs=[chatbot, msg_in]
)
submit_btn.click(
submit_message,
inputs=[msg_in, chatbot, use_web_search],
outputs=[chatbot, msg_in]
)
clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg_in])
# Add example queries
gr.Examples(
examples=[
["What's the latest news about AI?", True],
["Explain quantum computing in simple terms", False],
["What's the weather like today?", True],
["Write a Python function to sort a list", False],
["What are the current stock market trends?", True]
],
inputs=[msg_in, use_web_search],
label="Example Queries"
)
demo.launch()