Merge pull request #20 from Kenearos/claude/setup-eugen-bot-VNWYq
Set up Eugen bot configuration wizard
This commit is contained in:
commit
2795178a75
5 changed files with 807 additions and 53 deletions
24
CLAUDE.md
24
CLAUDE.md
|
|
@ -28,6 +28,8 @@
|
||||||
```
|
```
|
||||||
eugen/
|
eugen/
|
||||||
├── chatbot.py # Main entry point
|
├── chatbot.py # Main entry point
|
||||||
|
├── setup_wizard.py # Interactive setup wizard
|
||||||
|
├── test_credentials.py # Credential validation tool
|
||||||
├── config.py # Configuration management
|
├── config.py # Configuration management
|
||||||
├── gui.py # Dashboard GUI
|
├── gui.py # Dashboard GUI
|
||||||
├── ai_provider.py # Perplexity API integration
|
├── ai_provider.py # Perplexity API integration
|
||||||
|
|
@ -102,12 +104,32 @@ python -m venv venv
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Run interactive setup wizard
|
||||||
|
python setup_wizard.py
|
||||||
|
|
||||||
|
# Test credentials (recommended before first run)
|
||||||
|
python test_credentials.py
|
||||||
|
|
||||||
# Run the bot
|
# Run the bot
|
||||||
python chatbot.py
|
python chatbot.py
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing API Keys
|
## Testing Credentials
|
||||||
|
|
||||||
|
Use the credential validator for comprehensive testing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This tool:
|
||||||
|
- Tests Twitch OAuth token with IRC authentication
|
||||||
|
- Validates Perplexity API key and model access
|
||||||
|
- Provides detailed error diagnostics
|
||||||
|
- Suggests fixes for common issues
|
||||||
|
- Automatically tests fallback models (sonar-pro → sonar)
|
||||||
|
|
||||||
|
Manual testing:
|
||||||
- **Twitch**: Test IRC connection to irc.chat.twitch.tv:6667
|
- **Twitch**: Test IRC connection to irc.chat.twitch.tv:6667
|
||||||
- **Perplexity**: POST to https://api.perplexity.ai/chat/completions with a simple test message
|
- **Perplexity**: POST to https://api.perplexity.ai/chat/completions with a simple test message
|
||||||
|
|
||||||
|
|
|
||||||
76
README.md
76
README.md
|
|
@ -80,6 +80,27 @@ PERPLEXITY_API_KEY=pplx-your_key_here
|
||||||
3. Generate new API key
|
3. Generate new API key
|
||||||
4. Copy the key (should start with `pplx-`)
|
4. Copy the key (should start with `pplx-`)
|
||||||
|
|
||||||
|
### Testing Credentials (Recommended)
|
||||||
|
|
||||||
|
Before running the bot, test your credentials:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
- Validate your Twitch OAuth token with detailed diagnostics
|
||||||
|
- Test your Perplexity API key and check model access
|
||||||
|
- Provide specific error messages and fixes for common issues
|
||||||
|
- Automatically detect if `sonar-pro` is unavailable and suggest `sonar` fallback
|
||||||
|
|
||||||
|
**Example output:**
|
||||||
|
```
|
||||||
|
✓ Twitch IRC: PASS
|
||||||
|
✓ Perplexity API: PASS
|
||||||
|
🎉 All credentials valid! Bot is ready to run.
|
||||||
|
```
|
||||||
|
|
||||||
### Running the Bot
|
### Running the Bot
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -105,6 +126,8 @@ Eugen: @User For bed leveling, start by...
|
||||||
```
|
```
|
||||||
eugen/
|
eugen/
|
||||||
├── chatbot.py # Main entry point
|
├── chatbot.py # Main entry point
|
||||||
|
├── setup_wizard.py # Interactive setup tool
|
||||||
|
├── test_credentials.py # Credential validator
|
||||||
├── config.py # Configuration management
|
├── config.py # Configuration management
|
||||||
├── gui.py # Dashboard GUI
|
├── gui.py # Dashboard GUI
|
||||||
├── ai_provider.py # Perplexity API integration
|
├── ai_provider.py # Perplexity API integration
|
||||||
|
|
@ -135,20 +158,51 @@ The bot is built with:
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
**Bot doesn't respond:**
|
### Quick Diagnosis
|
||||||
- Check that .env has correct OAuth token and API key
|
|
||||||
- Verify bot is in the correct channel
|
|
||||||
- Check logs/eugen.log for errors
|
|
||||||
|
|
||||||
**API errors:**
|
**First step: Run the credential validator**
|
||||||
- Verify Perplexity API key is valid
|
```bash
|
||||||
- Check your API credits at perplexity.ai
|
python test_credentials.py
|
||||||
- Enable DEBUG_MODE=true in .env for detailed logs
|
```
|
||||||
|
|
||||||
|
This will identify exactly what's wrong and provide specific fixes.
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Twitch OAuth Token Invalid:**
|
||||||
|
- ✗ Error: `Login authentication failed`
|
||||||
|
- **Fix:**
|
||||||
|
1. Go to https://twitchtokengenerator.com
|
||||||
|
2. Select "Bot Chat Token"
|
||||||
|
3. Make sure you're logged in as the bot account
|
||||||
|
4. Copy the new token (including `oauth:` prefix)
|
||||||
|
5. Update `TWITCH_OAUTH_TOKEN` in `.env`
|
||||||
|
|
||||||
|
**Bot nickname mismatch:**
|
||||||
|
- Token must be generated by the same account as `TWITCH_BOT_NICKNAME`
|
||||||
|
- If bot nickname is `EugenBot`, you must be logged into Twitch as `EugenBot` when generating the token
|
||||||
|
|
||||||
|
**Perplexity Model Not Available:**
|
||||||
|
- ✗ Error: `400 Bad Request` or model not accessible
|
||||||
|
- **Fix:**
|
||||||
|
- Your API key might not have access to `sonar-pro`
|
||||||
|
- The setup wizard will automatically suggest `sonar` as fallback
|
||||||
|
- Or manually change `PERPLEXITY_MODEL=sonar` in `.env`
|
||||||
|
|
||||||
|
**Bot doesn't respond in chat:**
|
||||||
|
- Run `python test_credentials.py` to verify credentials
|
||||||
|
- Check that bot is in the correct channel
|
||||||
|
- Check `logs/eugen.log` for errors
|
||||||
|
- Verify bot was mentioned correctly (`@Eugen` or `Eugen:`)
|
||||||
|
|
||||||
**IRC connection failed:**
|
**IRC connection failed:**
|
||||||
- Verify internet connection
|
- Check internet connection
|
||||||
- Check firewall settings for port 6667
|
- Verify firewall allows port 6667
|
||||||
- Regenerate Twitch OAuth token if expired
|
- Run credential validator for detailed diagnostics
|
||||||
|
|
||||||
|
**API rate limits:**
|
||||||
|
- Check your Perplexity API credits at https://www.perplexity.ai/settings/api
|
||||||
|
- Enable `DEBUG_MODE=true` in `.env` for detailed API logs
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
279
TROUBLESHOOTING.md
Normal file
279
TROUBLESHOOTING.md
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
# Eugen Bot - Troubleshooting Guide
|
||||||
|
|
||||||
|
Quick reference for diagnosing and fixing common issues with the Eugen Twitch bot.
|
||||||
|
|
||||||
|
## Quick Start Diagnostic Tool
|
||||||
|
|
||||||
|
**Before anything else**, run the credential validator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This tool will:
|
||||||
|
- Test your Twitch OAuth token
|
||||||
|
- Validate your Perplexity API key
|
||||||
|
- Check model availability (sonar-pro vs sonar)
|
||||||
|
- Provide specific error messages
|
||||||
|
- Suggest exact fixes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Error Messages
|
||||||
|
|
||||||
|
### 1. Twitch IRC Authentication Failed
|
||||||
|
|
||||||
|
**Error Output:**
|
||||||
|
```
|
||||||
|
IRC EVENT: privnotice | Source: tmi.twitch.tv | Args: ['Login authentication failed']
|
||||||
|
```
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
- Token is expired or invalid
|
||||||
|
- Token doesn't match the bot nickname
|
||||||
|
- Bot account is banned/suspended
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
1. **Verify Bot Nickname Match**
|
||||||
|
- If `TWITCH_BOT_NICKNAME=Eugen`, you must generate the token while logged into Twitch as `Eugen`
|
||||||
|
- Token and bot nickname MUST match the same account
|
||||||
|
|
||||||
|
2. **Generate New Token**
|
||||||
|
```
|
||||||
|
1. Go to: https://twitchtokengenerator.com
|
||||||
|
2. Log into Twitch as the bot account
|
||||||
|
3. Select "Bot Chat Token"
|
||||||
|
4. Copy the full token (including oauth: prefix)
|
||||||
|
5. Update .env file:
|
||||||
|
TWITCH_OAUTH_TOKEN=oauth:your_new_token_here
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Test the Token**
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Perplexity API 400 Bad Request
|
||||||
|
|
||||||
|
**Error Output:**
|
||||||
|
```
|
||||||
|
⚠ Unerwartete Antwort: 400
|
||||||
|
```
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
- API key doesn't have access to `sonar-pro` model
|
||||||
|
- Invalid request format
|
||||||
|
- Model not available on your plan
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
1. **Use Model Fallback**
|
||||||
|
- The setup wizard automatically tries `sonar` if `sonar-pro` fails
|
||||||
|
- Manually update `.env`:
|
||||||
|
```
|
||||||
|
PERPLEXITY_MODEL=sonar
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify API Key**
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check API Credits**
|
||||||
|
- Go to: https://www.perplexity.ai/settings/api
|
||||||
|
- Verify your account has credits
|
||||||
|
- Check API key is active
|
||||||
|
|
||||||
|
### 3. Perplexity API 401 Unauthorized
|
||||||
|
|
||||||
|
**Error Output:**
|
||||||
|
```
|
||||||
|
✗ Perplexity API-Key ist ungültig (401 Unauthorized)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
- Invalid API key
|
||||||
|
- API key was revoked
|
||||||
|
- Typo in `.env` file
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
1. **Generate New API Key**
|
||||||
|
```
|
||||||
|
1. Go to: https://www.perplexity.ai/settings/api
|
||||||
|
2. Create new API key
|
||||||
|
3. Copy the key (starts with pplx-)
|
||||||
|
4. Update .env:
|
||||||
|
PERPLEXITY_API_KEY=pplx-your_new_key_here
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify No Extra Spaces**
|
||||||
|
- Check `.env` file has no spaces around the `=` sign
|
||||||
|
- Format: `PERPLEXITY_API_KEY=pplx-abc123` (no spaces)
|
||||||
|
|
||||||
|
### 4. Bot Doesn't Respond in Chat
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- Bot connects successfully
|
||||||
|
- Bot joins channel
|
||||||
|
- But doesn't respond to mentions
|
||||||
|
|
||||||
|
**Checklist:**
|
||||||
|
|
||||||
|
1. **Verify Bot is Mentioned Correctly**
|
||||||
|
```
|
||||||
|
✓ @Eugen how are you?
|
||||||
|
✓ Eugen: tell me about WoW
|
||||||
|
✓ Eugen, what's new?
|
||||||
|
✗ eugen (lowercase doesn't work)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check Debug Logs**
|
||||||
|
```bash
|
||||||
|
tail -f logs/eugen.log
|
||||||
|
```
|
||||||
|
Look for:
|
||||||
|
- `Mention detected from {user}`
|
||||||
|
- `API call to Perplexity`
|
||||||
|
- Any error messages
|
||||||
|
|
||||||
|
3. **Enable Debug Mode**
|
||||||
|
```
|
||||||
|
DEBUG_MODE=true
|
||||||
|
```
|
||||||
|
Restart the bot and check logs again
|
||||||
|
|
||||||
|
4. **Test Credentials**
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Connection Reset by Peer
|
||||||
|
|
||||||
|
**Error Output:**
|
||||||
|
```
|
||||||
|
IRC EVENT: disconnect | Args: ['Connection reset by peer']
|
||||||
|
```
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
- Network interruption
|
||||||
|
- Firewall blocking port 6667
|
||||||
|
- Invalid authentication (see #1)
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
1. **Check Firewall**
|
||||||
|
- Allow outbound connections on port 6667
|
||||||
|
- Try temporarily disabling firewall to test
|
||||||
|
|
||||||
|
2. **Verify Internet Connection**
|
||||||
|
```bash
|
||||||
|
ping irc.chat.twitch.tv
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Check OAuth Token** (most common cause)
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Rate Limiting / API Quota Exceeded
|
||||||
|
|
||||||
|
**Error Output:**
|
||||||
|
```
|
||||||
|
429 Too Many Requests
|
||||||
|
```
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
- Too many API calls in short time
|
||||||
|
- Perplexity API quota exceeded
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
1. **Check API Usage**
|
||||||
|
- Go to: https://www.perplexity.ai/settings/api
|
||||||
|
- View usage and limits
|
||||||
|
|
||||||
|
2. **Reduce Request Frequency**
|
||||||
|
- Consider implementing cooldowns
|
||||||
|
- Limit responses to specific users
|
||||||
|
|
||||||
|
3. **Wait and Retry**
|
||||||
|
- Wait a few minutes
|
||||||
|
- Restart the bot
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagnostic Commands
|
||||||
|
|
||||||
|
### Check Configuration
|
||||||
|
```bash
|
||||||
|
cat .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Recent Logs
|
||||||
|
```bash
|
||||||
|
tail -n 50 logs/eugen.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### View API Debug Logs
|
||||||
|
```bash
|
||||||
|
tail -n 50 logs/api_debug.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Credentials
|
||||||
|
```bash
|
||||||
|
python test_credentials.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Setup Wizard Again
|
||||||
|
```bash
|
||||||
|
python setup_wizard.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
### Before Asking for Help
|
||||||
|
|
||||||
|
1. Run `python test_credentials.py`
|
||||||
|
2. Check `logs/eugen.log`
|
||||||
|
3. Enable `DEBUG_MODE=true` and restart
|
||||||
|
4. Review this troubleshooting guide
|
||||||
|
|
||||||
|
### Information to Include
|
||||||
|
|
||||||
|
When reporting issues, include:
|
||||||
|
- Error messages from logs
|
||||||
|
- Output of `python test_credentials.py`
|
||||||
|
- Contents of `.env` (REDACT secrets!)
|
||||||
|
- Python version: `python --version`
|
||||||
|
- OS: Windows/Linux/Mac
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
|
- **GitHub Issues**: https://github.com/Kenearos/KI-Chat-Bot-Eugen/issues
|
||||||
|
- **Twitch Token Generator**: https://twitchtokengenerator.com
|
||||||
|
- **Perplexity API**: https://www.perplexity.ai/settings/api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
### File Locations
|
||||||
|
- Configuration: `.env`
|
||||||
|
- Main log: `logs/eugen.log`
|
||||||
|
- API debug: `logs/api_debug.log`
|
||||||
|
- Conversations: `data/conversations/`
|
||||||
|
|
||||||
|
### Required Credentials
|
||||||
|
- Twitch OAuth Token (starts with `oauth:`)
|
||||||
|
- Twitch Bot Nickname (must match token account)
|
||||||
|
- Twitch Channel (starts with `#`)
|
||||||
|
- Perplexity API Key (starts with `pplx-`)
|
||||||
|
|
||||||
|
### Testing Tools
|
||||||
|
- `python setup_wizard.py` - Interactive setup
|
||||||
|
- `python test_credentials.py` - Validate credentials
|
||||||
|
- `python chatbot.py` - Run the bot
|
||||||
141
setup_wizard.py
141
setup_wizard.py
|
|
@ -69,20 +69,47 @@ async def validate_twitch_token(token, bot_nickname):
|
||||||
try:
|
try:
|
||||||
print_info("Validiere Twitch-Verbindung...")
|
print_info("Validiere Twitch-Verbindung...")
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
sock.settimeout(5)
|
sock.settimeout(10)
|
||||||
sock.connect(('irc.chat.twitch.tv', 6667))
|
|
||||||
|
# Connect
|
||||||
|
try:
|
||||||
|
sock.connect(('irc.chat.twitch.tv', 6667))
|
||||||
|
except socket.timeout:
|
||||||
|
print_warning("Verbindung zu Twitch IRC hat zu lange gedauert")
|
||||||
|
print_info("Prüfe deine Internetverbindung und Firewall-Einstellungen")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
|
return True
|
||||||
|
|
||||||
# Send authentication
|
# Send authentication
|
||||||
sock.send(f"PASS {token}\r\n".encode())
|
sock.send(f"PASS {token}\r\n".encode())
|
||||||
sock.send(f"NICK {bot_nickname}\r\n".encode())
|
sock.send(f"NICK {bot_nickname}\r\n".encode())
|
||||||
|
|
||||||
response = sock.recv(1024).decode()
|
# Receive response
|
||||||
|
response = sock.recv(2048).decode()
|
||||||
|
|
||||||
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!")
|
||||||
|
print_info("\nMögliche Gründe:")
|
||||||
|
print(f" • Token ist abgelaufen oder ungültig")
|
||||||
|
print(f" • Token passt nicht zum Bot-Namen '{bot_nickname}'")
|
||||||
|
print(f" • Account ist gesperrt oder eingeschränkt")
|
||||||
|
print_info("\nLösung:")
|
||||||
|
print(f" → Gehe zu: https://twitchtokengenerator.com")
|
||||||
|
print(f" → Stelle sicher, dass du als '{bot_nickname}' eingeloggt bist")
|
||||||
|
print(f" → Generiere einen neuen 'Bot Chat Token'")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print_success("Twitch-Verbindung erfolgreich!")
|
if ":tmi.twitch.tv 001" in response or "Welcome" in response:
|
||||||
|
print_success("Twitch-Verbindung erfolgreich!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Ambiguous - probably OK
|
||||||
|
if "authentication failed" not in response.lower():
|
||||||
|
print_success("Twitch-Verbindung scheinbar erfolgreich (kein Fehler erkannt)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
print_warning(f"Unerwartete Antwort von Twitch IRC")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -93,7 +120,7 @@ async def validate_twitch_token(token, bot_nickname):
|
||||||
|
|
||||||
async def validate_perplexity_key(api_key, model="sonar-pro"):
|
async def validate_perplexity_key(api_key, model="sonar-pro"):
|
||||||
"""
|
"""
|
||||||
Validate Perplexity API key with test request
|
Validate Perplexity API key with test request and model fallback
|
||||||
|
|
||||||
Note: Validation uses the specified model (default: sonar-pro).
|
Note: Validation uses the specified model (default: sonar-pro).
|
||||||
If your API key doesn't have access to this model, validation may fail
|
If your API key doesn't have access to this model, validation may fail
|
||||||
|
|
@ -104,40 +131,73 @@ async def validate_perplexity_key(api_key, model="sonar-pro"):
|
||||||
model (str): Model to test with (defaults to sonar-pro)
|
model (str): Model to test with (defaults to sonar-pro)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (bool success, bool should_retry) - success indicates if validation passed,
|
tuple: (bool success, bool should_retry, str recommended_model)
|
||||||
should_retry indicates if user should be prompted to retry
|
success indicates if validation passed,
|
||||||
|
should_retry indicates if user should be prompted to retry,
|
||||||
|
recommended_model is the working model if different from requested
|
||||||
"""
|
"""
|
||||||
try:
|
# Test with multiple models
|
||||||
print_info(f"Validiere Perplexity API-Key mit Modell '{model}'...")
|
models_to_test = [model]
|
||||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
if model != "sonar":
|
||||||
response = await client.post(
|
models_to_test.append("sonar")
|
||||||
"https://api.perplexity.ai/chat/completions",
|
|
||||||
json={
|
|
||||||
"model": model,
|
|
||||||
"messages": [{"role": "user", "content": "test"}],
|
|
||||||
"max_tokens": 10
|
|
||||||
},
|
|
||||||
headers={
|
|
||||||
"Authorization": f"Bearer {api_key}",
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
for test_model in models_to_test:
|
||||||
print_success("Perplexity API-Key ist gültig!")
|
try:
|
||||||
return (True, False)
|
print_info(f"Validiere Perplexity API-Key mit Modell '{test_model}'...")
|
||||||
elif response.status_code == 401:
|
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||||
print_error("Perplexity API-Key ist ungültig!")
|
response = await client.post(
|
||||||
return (False, True)
|
"https://api.perplexity.ai/chat/completions",
|
||||||
else:
|
json={
|
||||||
print_warning(f"Unerwartete Antwort: {response.status_code}")
|
"model": test_model,
|
||||||
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
"messages": [{"role": "user", "content": "test"}],
|
||||||
return (True, False)
|
"max_tokens": 10
|
||||||
|
},
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
if response.status_code == 200:
|
||||||
print_warning(f"Konnte Perplexity API nicht testen: {e}")
|
print_success(f"Perplexity API-Key ist gültig mit Modell '{test_model}'!")
|
||||||
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
if test_model != model:
|
||||||
return (True, False)
|
print_warning(f"Hinweis: Modell '{model}' nicht verfügbar, verwende '{test_model}'")
|
||||||
|
return (True, False, test_model)
|
||||||
|
elif response.status_code == 401:
|
||||||
|
print_error("Perplexity API-Key ist ungültig (401 Unauthorized)!")
|
||||||
|
print_info("Bitte überprüfe deinen API-Key auf: https://www.perplexity.ai/settings/api")
|
||||||
|
return (False, True, None)
|
||||||
|
elif response.status_code == 400:
|
||||||
|
try:
|
||||||
|
error_data = response.json()
|
||||||
|
error_msg = error_data.get("error", {}).get("message", "Unbekannter Fehler")
|
||||||
|
|
||||||
|
# Check if model access issue
|
||||||
|
if "model" in error_msg.lower() and test_model != models_to_test[-1]:
|
||||||
|
print_warning(f"Modell '{test_model}' nicht verfügbar: {error_msg}")
|
||||||
|
print_info("Versuche Fallback-Modell...")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print_warning(f"400 Fehler: {error_msg}")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
|
return (True, False, model)
|
||||||
|
except:
|
||||||
|
print_warning(f"Unerwartete Antwort: {response.status_code}")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
|
return (True, False, model)
|
||||||
|
else:
|
||||||
|
print_warning(f"Unerwartete Antwort: {response.status_code}")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
|
return (True, False, model)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_warning(f"Konnte Perplexity API nicht testen: {e}")
|
||||||
|
print_info("Fahre trotzdem fort - bitte später manuell prüfen!")
|
||||||
|
return (True, False, model)
|
||||||
|
|
||||||
|
# All models failed
|
||||||
|
print_error("Alle Modelle fehlgeschlagen!")
|
||||||
|
return (False, True, None)
|
||||||
|
|
||||||
|
|
||||||
def create_env_file(config):
|
def create_env_file(config):
|
||||||
|
|
@ -279,12 +339,15 @@ async def run_wizard():
|
||||||
print(" → Kopiere den Key (beginnt mit 'pplx-...')")
|
print(" → Kopiere den Key (beginnt mit 'pplx-...')")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
recommended_model = "sonar-pro"
|
||||||
while True:
|
while True:
|
||||||
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
|
||||||
|
|
||||||
success, should_retry = await validate_perplexity_key(api_key)
|
success, should_retry, working_model = await validate_perplexity_key(api_key, "sonar-pro")
|
||||||
if success:
|
if success:
|
||||||
|
if working_model:
|
||||||
|
recommended_model = working_model
|
||||||
break
|
break
|
||||||
|
|
||||||
if should_retry:
|
if should_retry:
|
||||||
|
|
@ -302,7 +365,7 @@ async def run_wizard():
|
||||||
if advanced:
|
if advanced:
|
||||||
config['PERPLEXITY_MODEL'] = get_input(
|
config['PERPLEXITY_MODEL'] = get_input(
|
||||||
"Perplexity Modell",
|
"Perplexity Modell",
|
||||||
default="sonar-pro"
|
default=recommended_model
|
||||||
)
|
)
|
||||||
config['MAX_TOKENS'] = get_input(
|
config['MAX_TOKENS'] = get_input(
|
||||||
"Max Tokens pro Antwort",
|
"Max Tokens pro Antwort",
|
||||||
|
|
@ -317,7 +380,7 @@ async def run_wizard():
|
||||||
default="1"
|
default="1"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
config['PERPLEXITY_MODEL'] = "sonar-pro"
|
config['PERPLEXITY_MODEL'] = recommended_model
|
||||||
config['MAX_TOKENS'] = "450"
|
config['MAX_TOKENS'] = "450"
|
||||||
config['DEBUG_MODE'] = "false"
|
config['DEBUG_MODE'] = "false"
|
||||||
config['CONTEXT_RETENTION_HOURS'] = "1"
|
config['CONTEXT_RETENTION_HOURS'] = "1"
|
||||||
|
|
|
||||||
336
test_credentials.py
Normal file
336
test_credentials.py
Normal file
|
|
@ -0,0 +1,336 @@
|
||||||
|
"""
|
||||||
|
Credential Testing Utility for Eugen Bot
|
||||||
|
Tests and validates Twitch OAuth tokens and Perplexity API keys
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import httpx
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
||||||
|
class Colors:
|
||||||
|
"""ANSI color codes"""
|
||||||
|
HEADER = '\033[95m'
|
||||||
|
OKBLUE = '\033[94m'
|
||||||
|
OKCYAN = '\033[96m'
|
||||||
|
OKGREEN = '\033[92m'
|
||||||
|
WARNING = '\033[93m'
|
||||||
|
FAIL = '\033[91m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
|
||||||
|
|
||||||
|
def print_header(text):
|
||||||
|
"""Print colored header"""
|
||||||
|
print(f"\n{Colors.HEADER}{Colors.BOLD}{'='*70}{Colors.ENDC}")
|
||||||
|
print(f"{Colors.HEADER}{Colors.BOLD}{text.center(70)}{Colors.ENDC}")
|
||||||
|
print(f"{Colors.HEADER}{Colors.BOLD}{'='*70}{Colors.ENDC}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_success(text):
|
||||||
|
"""Print success message"""
|
||||||
|
print(f"{Colors.OKGREEN}✓ {text}{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_error(text):
|
||||||
|
"""Print error message"""
|
||||||
|
print(f"{Colors.FAIL}✗ {text}{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_info(text):
|
||||||
|
"""Print info message"""
|
||||||
|
print(f"{Colors.OKCYAN}ℹ {text}{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_warning(text):
|
||||||
|
"""Print warning message"""
|
||||||
|
print(f"{Colors.WARNING}⚠ {text}{Colors.ENDC}")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_twitch_token(token, nickname):
|
||||||
|
"""
|
||||||
|
Test Twitch OAuth token with detailed diagnostics
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token (str): OAuth token
|
||||||
|
nickname (str): Bot nickname
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if valid
|
||||||
|
"""
|
||||||
|
print_header("TESTING TWITCH CREDENTIALS")
|
||||||
|
|
||||||
|
# Check token format
|
||||||
|
if not token:
|
||||||
|
print_error("Token is empty!")
|
||||||
|
print_info("Get a token from: https://twitchtokengenerator.com")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not token.startswith("oauth:"):
|
||||||
|
print_warning(f"Token doesn't start with 'oauth:' (got: {token[:10]}...)")
|
||||||
|
print_info("Token should look like: oauth:abcd1234...")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print_info(f"Token format: ✓ Starts with 'oauth:'")
|
||||||
|
print_info(f"Token length: {len(token)} characters")
|
||||||
|
print_info(f"Bot nickname: {nickname}")
|
||||||
|
|
||||||
|
# Test IRC connection
|
||||||
|
print_info("\nConnecting to Twitch IRC (irc.chat.twitch.tv:6667)...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||||||
|
sock.settimeout(10)
|
||||||
|
|
||||||
|
# Connect
|
||||||
|
try:
|
||||||
|
sock.connect(('irc.chat.twitch.tv', 6667))
|
||||||
|
print_success("Connected to IRC server")
|
||||||
|
except socket.timeout:
|
||||||
|
print_error("Connection timed out!")
|
||||||
|
print_info("Check your internet connection and firewall settings")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Connection failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Send authentication
|
||||||
|
print_info("Sending authentication...")
|
||||||
|
sock.send(f"PASS {token}\r\n".encode())
|
||||||
|
sock.send(f"NICK {nickname}\r\n".encode())
|
||||||
|
|
||||||
|
# Wait for response
|
||||||
|
response = ""
|
||||||
|
try:
|
||||||
|
response = sock.recv(2048).decode()
|
||||||
|
except socket.timeout:
|
||||||
|
print_error("No response from server (timeout)")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Parse response
|
||||||
|
print_info(f"\nServer response received ({len(response)} bytes)")
|
||||||
|
|
||||||
|
if "Login authentication failed" in response:
|
||||||
|
print_error("AUTHENTICATION FAILED!")
|
||||||
|
print_info("\nPossible reasons:")
|
||||||
|
print(f" 1. Token is expired or invalid")
|
||||||
|
print(f" 2. Token doesn't match the bot nickname '{nickname}'")
|
||||||
|
print(f" 3. Account that generated the token is banned/restricted")
|
||||||
|
print_info("\nHow to fix:")
|
||||||
|
print(f" → Go to: https://twitchtokengenerator.com")
|
||||||
|
print(f" → Make sure you're logged into Twitch as '{nickname}'")
|
||||||
|
print(f" → Generate a new 'Bot Chat Token'")
|
||||||
|
print(f" → Update TWITCH_OAUTH_TOKEN in .env")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if ":tmi.twitch.tv 001" in response or "Welcome" in response:
|
||||||
|
print_success("AUTHENTICATION SUCCESSFUL!")
|
||||||
|
print_info(f"Bot '{nickname}' can connect to Twitch IRC")
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Ambiguous response
|
||||||
|
print_warning("Received unexpected response:")
|
||||||
|
for line in response.split('\r\n'):
|
||||||
|
if line:
|
||||||
|
print(f" {line[:100]}")
|
||||||
|
|
||||||
|
# If we got this far without clear failure, consider it success
|
||||||
|
if "authentication failed" not in response.lower():
|
||||||
|
print_success("Authentication appears successful (no error detected)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Error testing Twitch token: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
async def test_perplexity_key(api_key, model="sonar-pro"):
|
||||||
|
"""
|
||||||
|
Test Perplexity API key with model fallback
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api_key (str): Perplexity API key
|
||||||
|
model (str): Model to test (will fallback to 'sonar' if needed)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (success, recommended_model)
|
||||||
|
"""
|
||||||
|
print_header("TESTING PERPLEXITY API")
|
||||||
|
|
||||||
|
# Check key format
|
||||||
|
if not api_key:
|
||||||
|
print_error("API key is empty!")
|
||||||
|
print_info("Get a key from: https://www.perplexity.ai/settings/api")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
if not api_key.startswith("pplx-"):
|
||||||
|
print_warning(f"API key doesn't start with 'pplx-' (got: {api_key[:10]}...)")
|
||||||
|
print_info("Key should look like: pplx-abc123...")
|
||||||
|
|
||||||
|
print_info(f"API key format: Starts with '{api_key[:5]}...'")
|
||||||
|
print_info(f"API key length: {len(api_key)} characters")
|
||||||
|
|
||||||
|
# Test with different models
|
||||||
|
models_to_test = [model]
|
||||||
|
if model != "sonar":
|
||||||
|
models_to_test.append("sonar")
|
||||||
|
|
||||||
|
for test_model in models_to_test:
|
||||||
|
print_info(f"\nTesting with model: {test_model}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with httpx.AsyncClient(timeout=15.0) as client:
|
||||||
|
response = await client.post(
|
||||||
|
"https://api.perplexity.ai/chat/completions",
|
||||||
|
json={
|
||||||
|
"model": test_model,
|
||||||
|
"messages": [{"role": "user", "content": "Say 'test successful' and nothing else"}],
|
||||||
|
"max_tokens": 10
|
||||||
|
},
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
print_info(f"Response status: {response.status_code}")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
print_success(f"API KEY VALID with model '{test_model}'!")
|
||||||
|
|
||||||
|
# Try to parse response
|
||||||
|
try:
|
||||||
|
data = response.json()
|
||||||
|
if "choices" in data and len(data["choices"]) > 0:
|
||||||
|
content = data["choices"][0]["message"]["content"]
|
||||||
|
print_info(f"Test response: '{content}'")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return True, test_model
|
||||||
|
|
||||||
|
elif response.status_code == 401:
|
||||||
|
print_error("API key is INVALID (401 Unauthorized)")
|
||||||
|
print_info("\nHow to fix:")
|
||||||
|
print(f" → Go to: https://www.perplexity.ai/settings/api")
|
||||||
|
print(f" → Generate a new API key")
|
||||||
|
print(f" → Update PERPLEXITY_API_KEY in .env")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
elif response.status_code == 400:
|
||||||
|
try:
|
||||||
|
error_data = response.json()
|
||||||
|
error_msg = error_data.get("error", {}).get("message", "Unknown error")
|
||||||
|
print_warning(f"400 Bad Request: {error_msg}")
|
||||||
|
|
||||||
|
# Check if it's a model access issue
|
||||||
|
if "model" in error_msg.lower():
|
||||||
|
print_info(f"Model '{test_model}' not available on your plan")
|
||||||
|
if test_model != models_to_test[-1]:
|
||||||
|
print_info("Trying fallback model...")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print_info(f"Error details: {error_msg}")
|
||||||
|
except:
|
||||||
|
print_warning(f"400 Bad Request (couldn't parse error)")
|
||||||
|
|
||||||
|
# If this was the last model, fail
|
||||||
|
if test_model == models_to_test[-1]:
|
||||||
|
print_error("All models failed!")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
elif response.status_code == 429:
|
||||||
|
print_error("Rate limited! Too many requests.")
|
||||||
|
print_info("Wait a few minutes and try again")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
else:
|
||||||
|
print_warning(f"Unexpected status code: {response.status_code}")
|
||||||
|
try:
|
||||||
|
print_info(f"Response: {response.text[:200]}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Try next model if available
|
||||||
|
if test_model != models_to_test[-1]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
except httpx.TimeoutException:
|
||||||
|
print_error("Request timed out!")
|
||||||
|
print_info("Check your internet connection")
|
||||||
|
return False, None
|
||||||
|
except Exception as e:
|
||||||
|
print_error(f"Error testing API: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
"""Main test runner"""
|
||||||
|
print(f"""
|
||||||
|
{Colors.HEADER}{Colors.BOLD}╔════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ EUGEN BOT - CREDENTIAL VALIDATOR ║
|
||||||
|
║ Tests Twitch & Perplexity Credentials ║
|
||||||
|
╚════════════════════════════════════════════════════════════════════╝{Colors.ENDC}
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Load .env file
|
||||||
|
if not os.path.exists('.env'):
|
||||||
|
print_error("No .env file found!")
|
||||||
|
print_info("Please run: python setup_wizard.py")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Get credentials
|
||||||
|
twitch_token = os.getenv('TWITCH_OAUTH_TOKEN', '')
|
||||||
|
twitch_nickname = os.getenv('TWITCH_BOT_NICKNAME', '')
|
||||||
|
twitch_channel = os.getenv('TWITCH_CHANNEL', '')
|
||||||
|
perplexity_key = os.getenv('PERPLEXITY_API_KEY', '')
|
||||||
|
perplexity_model = os.getenv('PERPLEXITY_MODEL', 'sonar-pro')
|
||||||
|
|
||||||
|
print_info("Loaded configuration from .env:")
|
||||||
|
print(f" • Bot Nickname: {twitch_nickname}")
|
||||||
|
print(f" • Channel: {twitch_channel}")
|
||||||
|
print(f" • Model: {perplexity_model}")
|
||||||
|
|
||||||
|
# Test credentials
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
# Test Twitch
|
||||||
|
results['twitch'] = await test_twitch_token(twitch_token, twitch_nickname)
|
||||||
|
|
||||||
|
# Test Perplexity
|
||||||
|
results['perplexity'], recommended_model = await test_perplexity_key(perplexity_key, perplexity_model)
|
||||||
|
|
||||||
|
# Final summary
|
||||||
|
print_header("VALIDATION SUMMARY")
|
||||||
|
|
||||||
|
print(f"Twitch IRC: {'✓ PASS' if results['twitch'] else '✗ FAIL'}")
|
||||||
|
print(f"Perplexity API: {'✓ PASS' if results['perplexity'] else '✗ FAIL'}")
|
||||||
|
|
||||||
|
if recommended_model and recommended_model != perplexity_model:
|
||||||
|
print_warning(f"\nRecommendation: Update PERPLEXITY_MODEL to '{recommended_model}' in .env")
|
||||||
|
|
||||||
|
if all(results.values()):
|
||||||
|
print_success("\n🎉 All credentials valid! Bot is ready to run.")
|
||||||
|
print_info("Start the bot with: python chatbot.py")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print_error("\n❌ Some credentials are invalid. Please fix and re-test.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
Loading…
Add table
Add a link
Reference in a new issue