|
|
|
import os |
|
from getpass import getpass |
|
from openai import OpenAI |
|
import gradio as gr |
|
import requests |
|
import json |
|
from datetime import datetime |
|
|
|
|
|
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") |
|
BSEARCH_API = os.getenv("BSEARCH_API") |
|
|
|
|
|
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, |
|
) |
|
|
|
|
|
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 |
|
} |
|
|
|
|
|
url = "https://api.search.brave.com/res/v1/web/search" |
|
params = { |
|
"q": query, |
|
"count": 5 |
|
} |
|
|
|
response = requests.get(url, headers=headers, params=params) |
|
response.raise_for_status() |
|
|
|
data = response.json() |
|
|
|
|
|
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 [] |
|
|
|
|
|
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" |
|
|
|
history.append(("π Web Search Query", user_message)) |
|
history.append(("π Search Results", search_results)) |
|
|
|
|
|
messages_for_api = [] |
|
|
|
|
|
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: |
|
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}) |
|
|
|
|
|
current_message = search_context + user_message if search_context else user_message |
|
messages_for_api.append({"role": "user", "content": current_message}) |
|
|
|
try: |
|
|
|
resp = client.chat.completions.create( |
|
model="deepseek/deepseek-r1-0528-qwen3-8b", |
|
messages=messages_for_api, |
|
|
|
) |
|
bot_reply = resp.choices[0].message.content |
|
|
|
history.append((user_message, bot_reply)) |
|
except Exception as e: |
|
|
|
history.append((user_message, f"Error: {e}")) |
|
|
|
return history, "" |
|
|
|
|
|
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 : deepseek-r1-0528-qwen3-8b</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) |
|
|
|
|
|
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]) |
|
|
|
|
|
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() |