KI-Chat-Bot-Eugen/gui.py
Claude 03df6035c5
Add comprehensive Perplexity model selection in setup wizard
Setup wizard improvements:
- Expanded model dropdown with 6 Perplexity models:
  * sonar-pro (recommended default)
  * sonar
  * sonar-reasoning
  * llama-3.1-sonar-small-128k-online
  * llama-3.1-sonar-large-128k-online
  * llama-3.1-sonar-huge-128k-online

- Added info button (?) next to model selector
- Info popup explains each model's characteristics:
  * Performance
  * Use cases
  * Speed/quality tradeoffs
  * Cost considerations

Created MODEL_CHANGE.md documentation:
- How to change model in .env file
- How to re-run setup wizard
- Detailed model descriptions
- Example configuration

Users can now easily choose the right model for their needs
and change it anytime without reconfiguring everything.
2026-01-02 21:47:10 +00:00

319 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Dashboard GUI for Eugen Bot
Live monitoring interface using FreeSimpleGUI
"""
import FreeSimpleGUI as sg
import threading
from datetime import datetime
from queue import Queue
class Dashboard:
"""Live monitoring dashboard for bot activity"""
def __init__(self, bot=None):
"""
Initialize dashboard
Args:
bot: Reference to the main bot instance
"""
self.bot = bot
sg.theme('DarkBlue3')
# Event queue for thread-safe updates
self.event_queue = Queue()
self.window = None
self.is_running = False
# Statistics
self.stats = {
"messages": 0,
"api_calls": 0,
"errors": 0,
"start_time": datetime.now()
}
def log_event(self, event_type, data):
"""
Add event to queue for display
Args:
event_type (str): Type of event (chat_message, api_call, etc.)
data (dict): Event data
"""
timestamp = datetime.now().strftime("%H:%M:%S")
if event_type == "chat_message":
msg = f"{timestamp} | {data['username']}: {data['content']}"
self.stats["messages"] += 1
elif event_type == "mention_detected":
msg = f"{timestamp} | [MENTION] Bot addressed by {data['username']}"
elif event_type == "api_call":
msg = f"{timestamp} | [API] → Perplexity ({data.get('model', 'sonar-pro')})"
self.stats["api_calls"] += 1
elif event_type == "api_response":
preview = data['content'][:60] + "..." if len(data['content']) > 60 else data['content']
msg = f"{timestamp} | [RESPONSE] {preview}"
elif event_type == "bot_response":
preview = data['content'][:60] + "..." if len(data['content']) > 60 else data['content']
msg = f"{timestamp} | Eugen: @{data['username']} {preview}"
elif event_type == "error":
msg = f"{timestamp} | ❌ ERROR: {data['error']}"
self.stats["errors"] += 1
elif event_type == "info":
msg = f"{timestamp} | {data['message']}"
elif event_type == "warning":
msg = f"{timestamp} | ⚠ {data['message']}"
elif event_type == "context_loaded":
msg = f"{timestamp} | [CONTEXT] Loaded {data['count']} messages for {data['username']}"
else:
msg = f"{timestamp} | {event_type}: {data}"
self.event_queue.put(msg)
def create_layout(self):
"""Create the GUI layout"""
# Header
header = [
[sg.Text("EUGEN BOT - LIVE DASHBOARD", font=("Arial", 16, "bold"))],
[sg.Text("Status: 🟢 RUNNING", key="-STATUS-", font=("Arial", 10))],
[sg.Text("Uptime: 00:00:00", key="-UPTIME-", size=(20, 1)),
sg.Text("Messages: 0", key="-MSG-COUNT-", size=(20, 1)),
sg.Text("API Calls: 0", key="-API-COUNT-", size=(20, 1)),
sg.Text("Errors: 0", key="-ERROR-COUNT-", size=(20, 1))],
[sg.HorizontalSeparator()]
]
# Live feed
feed = [
[sg.Text("LIVE ACTIVITY FEED", font=("Arial", 12, "bold"))],
[sg.Multiline(
size=(140, 25),
key="-LOG-",
disabled=True,
autoscroll=True,
font=("Courier New", 9)
)]
]
# Control buttons
controls = [
[sg.HorizontalSeparator()],
[
sg.Button("Clear Log", key="-CLEAR-"),
sg.Button("Reset Stats", key="-RESET-"),
sg.Button("Stop Bot", key="-STOP-", button_color=("white", "red"))
]
]
# Combine all sections
layout = header + feed + controls
return layout
def run(self):
"""Run the dashboard GUI in main thread"""
layout = self.create_layout()
self.window = sg.Window(
"Eugen Bot Dashboard",
layout,
finalize=True,
size=(1000, 650)
)
self.is_running = True
# Main event loop
while self.is_running:
event, values = self.window.read(timeout=100)
# Handle window close
if event == sg.WINDOW_CLOSED or event == "-STOP-":
self.is_running = False
if self.bot:
self.bot.stop()
break
# Handle clear log
if event == "-CLEAR-":
self.window["-LOG-"].update("")
# Handle reset stats
if event == "-RESET-":
self.stats = {
"messages": 0,
"api_calls": 0,
"errors": 0,
"start_time": datetime.now()
}
# Update log with queued events
while not self.event_queue.empty():
try:
msg = self.event_queue.get_nowait()
self.window["-LOG-"].print(msg)
except:
break
# Update statistics
self._update_stats()
self.window.close()
def _update_stats(self):
"""Update statistics display"""
if not self.window:
return
# Calculate uptime
uptime = datetime.now() - self.stats["start_time"]
hours, remainder = divmod(int(uptime.total_seconds()), 3600)
minutes, seconds = divmod(remainder, 60)
uptime_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
# Update displays
self.window["-UPTIME-"].update(f"Uptime: {uptime_str}")
self.window["-MSG-COUNT-"].update(f"Messages: {self.stats['messages']}")
self.window["-API-COUNT-"].update(f"API Calls: {self.stats['api_calls']}")
self.window["-ERROR-COUNT-"].update(f"Errors: {self.stats['errors']}")
def show_error(self, title, message):
"""Show error popup"""
sg.popup_error(message, title=title)
def show_info(self, title, message):
"""Show info popup"""
sg.popup(message, title=title)
def stop(self):
"""Stop the dashboard"""
self.is_running = False
if self.window:
self.window.close()
class SetupWizard:
"""Configuration wizard for first-time setup"""
def __init__(self):
sg.theme('DarkBlue3')
def run(self):
"""
Run the setup wizard
Returns:
dict: Configuration values or None if cancelled
"""
layout = [
[sg.Text("EUGEN CONFIGURATION WIZARD", font=("Arial", 16, "bold"))],
[sg.HorizontalSeparator()],
[sg.Text("TWITCH CONFIGURATION", font=("Arial", 12, "bold"))],
[sg.Text("Bot Nickname:", size=(20, 1)), sg.Input("Eugen", key="-BOT-NAME-")],
[sg.Text("OAuth Token:", size=(20, 1)), sg.Input("oauth:", key="-OAUTH-", password_char="*")],
[sg.Text("Channel:", size=(20, 1)), sg.Input("#", key="-CHANNEL-")],
[sg.HorizontalSeparator()],
[sg.Text("PERPLEXITY CONFIGURATION", font=("Arial", 12, "bold"))],
[sg.Text("API Key:", size=(20, 1)), sg.Input("pplx-", key="-API-KEY-", password_char="*")],
[sg.Text("Model:", size=(20, 1)),
sg.Combo([
"sonar-pro",
"sonar",
"sonar-reasoning",
"llama-3.1-sonar-small-128k-online",
"llama-3.1-sonar-large-128k-online",
"llama-3.1-sonar-huge-128k-online"
], default_value="sonar-pro", key="-MODEL-", size=(35, 1)),
sg.Button("?", key="-MODEL-INFO-", size=(2, 1))],
[sg.Text("", size=(20, 1)),
sg.Text("Recommended: sonar-pro (best quality)", font=("Arial", 8), text_color="gray")],
[sg.Text("Max Tokens:", size=(20, 1)), sg.Input("450", key="-TOKENS-")],
[sg.HorizontalSeparator()],
[sg.Checkbox("Enable Debug Mode", default=True, key="-DEBUG-")],
[sg.Checkbox("Auto Reconnect", default=True, key="-RECONNECT-")],
[sg.HorizontalSeparator()],
[sg.Button("Save & Start", key="-SAVE-"), sg.Button("Cancel", key="-CANCEL-")]
]
window = sg.Window("Eugen Setup", layout)
config = None
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED or event == "-CANCEL-":
break
# Show model info
if event == "-MODEL-INFO-":
model_info = """PERPLEXITY MODEL OVERVIEW:
🔵 sonar-pro (RECOMMENDED)
- Best quality and reasoning capabilities
- Ideal for chat bots and complex queries
- Good balance of speed and intelligence
🟢 sonar
- Faster, lower cost
- Good for simple queries
- Less complex reasoning
🧠 sonar-reasoning
- Enhanced reasoning for complex problems
- Slower but more thoughtful responses
📚 llama-3.1-sonar-small-128k-online
- Smallest, fastest Llama model
- 128k context window
- Best for simple, quick responses
📚 llama-3.1-sonar-large-128k-online
- Larger Llama model
- Better quality than small
- Good balance
📚 llama-3.1-sonar-huge-128k-online
- Largest Llama model
- Best quality but slower
- Higher cost
For most chat bots: Use sonar-pro"""
sg.popup_scrolled(model_info, title="Model Information", size=(60, 25))
continue
if event == "-SAVE-":
# Validate inputs
if not values["-OAUTH-"].startswith("oauth:"):
sg.popup_error("Twitch OAuth token must start with 'oauth:'")
continue
if not values["-CHANNEL-"].startswith("#"):
sg.popup_error("Channel must start with '#'")
continue
if not values["-API-KEY-"].startswith("pplx-"):
sg.popup_error("Perplexity API key must start with 'pplx-'")
continue
# Build config
config = {
"TWITCH_BOT_NICKNAME": values["-BOT-NAME-"],
"TWITCH_OAUTH_TOKEN": values["-OAUTH-"],
"TWITCH_CHANNEL": values["-CHANNEL-"],
"PERPLEXITY_API_KEY": values["-API-KEY-"],
"PERPLEXITY_MODEL": values["-MODEL-"],
"MAX_TOKENS": values["-TOKENS-"],
"DEBUG_MODE": "true" if values["-DEBUG-"] else "false",
"AUTO_RECONNECT": "true" if values["-RECONNECT-"] else "false"
}
break
window.close()
return config