# /// script
# requires-python = ">=3.12"
# dependencies = [
# "gradio>=4.25.0",
# "requests>=2.32.2",
# "groq>=0.5.0",
# "python-dotenv>=1.0.0",
# ]
# ///
import gradio as gr
import requests
import json
import os
from groq import Groq
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Initialize global variables
reasoning_history = []
ENV_DEEPSEEK_KEY = os.getenv("DEEPSEEK_API_KEY", "")
ENV_GROQ_KEY = os.getenv("GROQ_API_KEY", "")
def validate_keys(deepseek_key, groq_key):
"""Validate API keys and return appropriate message"""
if not deepseek_key or not groq_key:
missing = []
if not deepseek_key:
missing.append("DeepSeek")
if not groq_key:
missing.append("Groq")
return False, f"Missing API key(s) for: {', '.join(missing)}. Please configure keys."
return True, "Keys configured successfully!"
def process_deepseek(message, api_key):
if not api_key:
raise ValueError("DeepSeek API key not configured")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
data = {
"model": "deepseek-reasoner",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": message}
],
"stream": True,
"max_tokens": 1
}
response = requests.post(
"https://api.deepseek.com/chat/completions",
headers=headers,
json=data,
stream=True
)
reasoning = []
for line in response.iter_lines():
if line:
try:
cleaned_line = line.decode('utf-8').replace('data: ', '').strip()
if cleaned_line == '[DONE]':
continue
chunk = json.loads(cleaned_line)
if chunk.get('choices'):
content = chunk['choices'][0]['delta'].get('reasoning_content', '')
if content:
reasoning.append(content)
except Exception as e:
continue
return ' '.join(reasoning)
def chat_fn(message, history, deepseek_key, groq_key):
# Use environment variables if available, otherwise use UI inputs
active_deepseek_key = ENV_DEEPSEEK_KEY or deepseek_key
active_groq_key = ENV_GROQ_KEY or groq_key
# Validate keys before processing
is_valid, validation_message = validate_keys(active_deepseek_key, active_groq_key)
if not is_valid:
yield {"role": "assistant", "content": validation_message}
return
try:
reasoning = process_deepseek(message, active_deepseek_key)
except Exception as e:
yield {"role": "assistant", "content": f"DeepSeek API Error: {str(e)}"}
return
reasoning_history.append(reasoning)
groq_prompt = f"""You will be given a query and reasoning steps.
Review the reasoning, thinking through each of the steps and provide a concise answer to the user.
{message}
{reasoning}"""
try:
client = Groq(api_key=active_groq_key)
groq_response = client.chat.completions.create(
model="llama-3.3-70b-specdec",
messages=[{"role": "user", "content": groq_prompt}],
temperature=0.7,
max_tokens=1024,
top_p=1,
stream=True,
)
accumulated_response = ""
for chunk in groq_response:
part = chunk.choices[0].delta.content or ""
accumulated_response += part
yield {"role": "assistant", "content": accumulated_response}
except Exception as e:
yield {"role": "assistant", "content": f"Groq API Error: {str(e)}"}
def show_reasoning():
return reasoning_history[-1] if reasoning_history else "No reasoning available"
def toggle_reasoning_visibility(visible):
return gr.update(visible=visible)
def show_settings():
return gr.update(visible=True)
def hide_settings():
return gr.update(visible=False)
# Create the Gradio interface
with gr.Blocks(theme=gr.themes.Soft(), title="Thoughtful Lightning") as demo:
# Initialize error banner
error_banner = gr.Markdown(visible=False)
# Main Interface
gr.Markdown("## ⚡ Thoughtful Lightning")
gr.Markdown("*Powered by DeepSeek R1 reasoning and Groq's lightning-fast inference*")
# Settings Group (Initially Hidden)
with gr.Group(visible=False) as settings_group:
gr.Markdown("### ⚙️ Settings")
gr.Markdown("*Note: Environment variables will be used if available*")
with gr.Row():
with gr.Column(scale=1):
deepseek_key = gr.Textbox(
label="DeepSeek API Key",
type="password",
value="",
placeholder="Enter DeepSeek API key" if not ENV_DEEPSEEK_KEY else "Using key from environment",
info="DeepSeek R1 API key for reasoning"
)
groq_key = gr.Textbox(
label="Groq API Key",
type="password",
value="",
placeholder="Enter Groq API key" if not ENV_GROQ_KEY else "Using key from environment",
info="Groq API key for fast inference"
)
with gr.Row():
close_btn = gr.Button("Close")
settings_status = gr.Markdown()
with gr.Row():
with gr.Column(scale=1):
settings_btn = gr.Button("⚙️ Settings")
reasoning_btn = gr.Button("🧐 Show Reasoning")
with gr.Row():
chat_interface = gr.ChatInterface(
chat_fn,
additional_inputs=[deepseek_key, groq_key],
examples=[
["How many r's are in strawberry"],
["Which is greater 9.11 or 9.9"],
["Best way to learn Rust in 2024?"]
]
)
reasoning_output = gr.Textbox(
label="Reasoning Steps",
interactive=False,
visible=False,
lines=8,
max_lines=12
)
# Event handlers
settings_btn.click(
fn=show_settings,
outputs=[settings_group]
)
close_btn.click(
fn=hide_settings,
outputs=[settings_group]
)
reasoning_btn.click(
fn=show_reasoning,
outputs=reasoning_output
).then(
fn=toggle_reasoning_visibility,
inputs=[gr.State(True)],
outputs=[reasoning_output]
)
if __name__ == "__main__":
# Create .env file if it doesn't exist
if not os.path.exists(".env"):
with open(".env", "w") as f:
f.write("DEEPSEEK_API_KEY=\nGROQ_API_KEY=\n")
# Show error if no keys are configured
if not (ENV_DEEPSEEK_KEY or ENV_GROQ_KEY):
print("\n⚠️ No API keys found in environment variables.")
print("You can either:")
print("1. Add them to your .env file")
print("2. Configure them in the UI settings\n")
demo.queue().launch()