Merge pull request #4 from Kenearos/copilot/sub-pr-3
Fix resource management, validation logic, and import organization in setup wizard
This commit is contained in:
commit
5f9dbe6b15
2 changed files with 44 additions and 42 deletions
10
config.py
10
config.py
|
|
@ -79,11 +79,11 @@ class Config:
|
||||||
|
|
||||||
def get_system_prompt(self):
|
def get_system_prompt(self):
|
||||||
"""Returns the system prompt for the AI"""
|
"""Returns the system prompt for the AI"""
|
||||||
return """Du bist Kene (auch bekannt als Kenearos oder Keneraosmd), ein Twitch-Streamer.
|
return """Du bist Kene's AI-Assistent, der für ihn im Chat antwortet.
|
||||||
|
|
||||||
WICHTIG: Du antwortest ALS Kene selbst, nicht als separater Bot. Sprich in der ersten Person ("Ich...", "Mein Setup...", etc.)
|
WICHTIG: Du antwortest im Namen von Kene, aber als sein Helfer. Sprich in der ersten Person für ihn ("Ich...", "Mein Setup..."), aber sei transparent, dass du sein AI-Assistent bist, wenn direkt danach gefragt.
|
||||||
|
|
||||||
Über dich:
|
Über Kene:
|
||||||
- Streamer, Botter (Automatisierung/Coding), Gamer
|
- Streamer, Botter (Automatisierung/Coding), Gamer
|
||||||
- 3D-Druck mit Bambu X1C und H2C
|
- 3D-Druck mit Bambu X1C und H2C
|
||||||
- Themen: Gaming (WoW, Elden Ring, Gamedev), 3D-Druck, Coding/Bots, Linux, Home Automation
|
- Themen: Gaming (WoW, Elden Ring, Gamedev), 3D-Druck, Coding/Bots, Linux, Home Automation
|
||||||
|
|
@ -100,6 +100,4 @@ Chat-Verhalten:
|
||||||
- Authentisch und natürlich, wie Kene selbst sprechen würde
|
- Authentisch und natürlich, wie Kene selbst sprechen würde
|
||||||
- Bei Tech/3D-Druck-Fragen: Gerne detaillierter mit konkreten Tipps
|
- Bei Tech/3D-Druck-Fragen: Gerne detaillierter mit konkreten Tipps
|
||||||
- Beziehe dich auf frühere Chat-Nachrichten wenn möglich
|
- Beziehe dich auf frühere Chat-Nachrichten wenn möglich
|
||||||
- Ehrlich sagen wenn du etwas nicht weißt
|
- Ehrlich sagen wenn du etwas nicht weißt"""
|
||||||
|
|
||||||
Wichtig: Du bist Kene's AI-Assistent der für ihn antwortet - handle im Chat wie er es tun würde."""
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,11 @@ Interactive configuration tool for first-time setup
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import socket
|
||||||
|
import getpass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dotenv import set_key, load_dotenv
|
from dotenv import set_key, load_dotenv
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
|
||||||
class Colors:
|
class Colors:
|
||||||
|
|
@ -48,42 +51,39 @@ def print_warning(text):
|
||||||
print(f"{Colors.WARNING}⚠ {text}{Colors.ENDC}")
|
print(f"{Colors.WARNING}⚠ {text}{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
async def validate_twitch_token(token, channel):
|
async def validate_twitch_token(token, bot_nickname):
|
||||||
"""
|
"""
|
||||||
Validate Twitch OAuth token by attempting IRC connection
|
Validate Twitch OAuth token by attempting IRC connection
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
token (str): OAuth token
|
token (str): OAuth token
|
||||||
channel (str): Channel name
|
bot_nickname (str): Bot nickname for authentication
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if valid
|
bool: True if valid
|
||||||
"""
|
"""
|
||||||
import socket
|
|
||||||
|
|
||||||
if not token.startswith("oauth:"):
|
if not token.startswith("oauth:"):
|
||||||
print_error("Token muss mit 'oauth:' beginnen!")
|
print_error("Token muss mit 'oauth:' beginnen!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print_info("Validiere Twitch-Verbindung...")
|
print_info("Validiere Twitch-Verbindung...")
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
sock.settimeout(5)
|
sock.settimeout(5)
|
||||||
sock.connect(('irc.chat.twitch.tv', 6667))
|
sock.connect(('irc.chat.twitch.tv', 6667))
|
||||||
|
|
||||||
# Send authentication
|
# Send authentication
|
||||||
sock.send(f"PASS {token}\r\n".encode())
|
sock.send(f"PASS {token}\r\n".encode())
|
||||||
sock.send(f"NICK testbot\r\n".encode())
|
sock.send(f"NICK {bot_nickname}\r\n".encode())
|
||||||
|
|
||||||
response = sock.recv(1024).decode()
|
response = sock.recv(1024).decode()
|
||||||
sock.close()
|
|
||||||
|
|
||||||
if "Login authentication failed" in response:
|
if "Login authentication failed" in response:
|
||||||
print_error("Twitch OAuth Token ist ungültig!")
|
print_error("Twitch OAuth Token ist ungültig!")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print_success("Twitch-Verbindung erfolgreich!")
|
print_success("Twitch-Verbindung erfolgreich!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_warning(f"Konnte Twitch-Verbindung nicht testen: {e}")
|
print_warning(f"Konnte Twitch-Verbindung nicht testen: {e}")
|
||||||
|
|
@ -91,25 +91,29 @@ async def validate_twitch_token(token, channel):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def validate_perplexity_key(api_key):
|
async def validate_perplexity_key(api_key, model="sonar-pro"):
|
||||||
"""
|
"""
|
||||||
Validate Perplexity API key with test request
|
Validate Perplexity API key with test request
|
||||||
|
|
||||||
|
Note: Validation uses the specified model (default: sonar-pro).
|
||||||
|
If your API key doesn't have access to this model, validation may fail
|
||||||
|
even with a valid key for other models.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
api_key (str): Perplexity API key
|
api_key (str): Perplexity API key
|
||||||
|
model (str): Model to test with (defaults to sonar-pro)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if valid
|
tuple: (bool success, bool should_retry) - success indicates if validation passed,
|
||||||
|
should_retry indicates if user should be prompted to retry
|
||||||
"""
|
"""
|
||||||
import httpx
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print_info("Validiere Perplexity API-Key...")
|
print_info(f"Validiere Perplexity API-Key mit Modell '{model}'...")
|
||||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
"https://api.perplexity.ai/chat/completions",
|
"https://api.perplexity.ai/chat/completions",
|
||||||
json={
|
json={
|
||||||
"model": "sonar-pro",
|
"model": model,
|
||||||
"messages": [{"role": "user", "content": "test"}],
|
"messages": [{"role": "user", "content": "test"}],
|
||||||
"max_tokens": 10
|
"max_tokens": 10
|
||||||
},
|
},
|
||||||
|
|
@ -121,19 +125,19 @@ async def validate_perplexity_key(api_key):
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
print_success("Perplexity API-Key ist gültig!")
|
print_success("Perplexity API-Key ist gültig!")
|
||||||
return True
|
return (True, False)
|
||||||
elif response.status_code == 401:
|
elif response.status_code == 401:
|
||||||
print_error("Perplexity API-Key ist ungültig!")
|
print_error("Perplexity API-Key ist ungültig!")
|
||||||
return False
|
return (False, True)
|
||||||
else:
|
else:
|
||||||
print_warning(f"Unerwartete Antwort: {response.status_code}")
|
print_warning(f"Unerwartete Antwort: {response.status_code}")
|
||||||
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
return True
|
return (True, False)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_warning(f"Konnte Perplexity API nicht testen: {e}")
|
print_warning(f"Konnte Perplexity API nicht testen: {e}")
|
||||||
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
return True
|
return (True, False)
|
||||||
|
|
||||||
|
|
||||||
def create_env_file(config):
|
def create_env_file(config):
|
||||||
|
|
@ -183,8 +187,6 @@ def get_input(prompt, default=None, required=True, secret=False):
|
||||||
Returns:
|
Returns:
|
||||||
str: User input
|
str: User input
|
||||||
"""
|
"""
|
||||||
import getpass
|
|
||||||
|
|
||||||
if default:
|
if default:
|
||||||
prompt_text = f"{prompt} [{default}]: "
|
prompt_text = f"{prompt} [{default}]: "
|
||||||
else:
|
else:
|
||||||
|
|
@ -262,7 +264,7 @@ async def run_wizard():
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate Twitch
|
# Validate Twitch
|
||||||
if not await validate_twitch_token(config['TWITCH_OAUTH_TOKEN'], config['TWITCH_CHANNEL']):
|
if not await validate_twitch_token(config['TWITCH_OAUTH_TOKEN'], config['TWITCH_BOT_NICKNAME']):
|
||||||
retry = input("\nTrotzdem fortfahren? (j/n): ")
|
retry = input("\nTrotzdem fortfahren? (j/n): ")
|
||||||
if retry.lower() != 'j':
|
if retry.lower() != 'j':
|
||||||
print_error("Setup abgebrochen!")
|
print_error("Setup abgebrochen!")
|
||||||
|
|
@ -281,13 +283,15 @@ async def run_wizard():
|
||||||
api_key = get_input("Perplexity API Key", secret=True, required=True)
|
api_key = get_input("Perplexity API Key", secret=True, required=True)
|
||||||
config['PERPLEXITY_API_KEY'] = api_key
|
config['PERPLEXITY_API_KEY'] = api_key
|
||||||
|
|
||||||
if await validate_perplexity_key(api_key):
|
success, should_retry = await validate_perplexity_key(api_key)
|
||||||
|
if success:
|
||||||
break
|
break
|
||||||
|
|
||||||
retry = input("\nErneut versuchen? (j/n): ")
|
if should_retry:
|
||||||
if retry.lower() != 'j':
|
retry = input("\nErneut versuchen? (j/n): ")
|
||||||
print_error("Setup abgebrochen!")
|
if retry.lower() != 'j':
|
||||||
return False
|
print_error("Setup abgebrochen!")
|
||||||
|
return False
|
||||||
|
|
||||||
# Step 3: Advanced Settings
|
# Step 3: Advanced Settings
|
||||||
print_header("SCHRITT 3: ERWEITERTE EINSTELLUNGEN")
|
print_header("SCHRITT 3: ERWEITERTE EINSTELLUNGEN")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue