Add chat-weather-overlay as weather_overlay sub-project
This commit is contained in:
82
weather_overlay/DEVELOPMENT_PLAN.md
Normal file
82
weather_overlay/DEVELOPMENT_PLAN.md
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# Development Plan: Chat-Interactive Weather Overlay
|
||||||
|
|
||||||
|
This document outlines the development plan for creating a chat-interactive weather overlay for Twitch and YouTube.
|
||||||
|
|
||||||
|
## Phase 1: Project Setup
|
||||||
|
|
||||||
|
* [x] Create a new project directory: `chat-weather-overlay`
|
||||||
|
* [ ] Set up a Python virtual environment.
|
||||||
|
* [ ] Initialize a new Git repository.
|
||||||
|
|
||||||
|
## Phase 2: Backend - The Core
|
||||||
|
|
||||||
|
* **Technology:** Python with the FastAPI framework.
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Create a basic FastAPI server.
|
||||||
|
* [ ] Implement a WebSocket endpoint for the overlay to connect to.
|
||||||
|
|
||||||
|
## Phase 3: Frontend - The Connection
|
||||||
|
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Modify the existing `weather.html` to connect to the new backend server's WebSocket.
|
||||||
|
* [ ] Implement logic to handle simple messages from the server to confirm the connection.
|
||||||
|
|
||||||
|
## Phase 4: Backend - Twitch Integration
|
||||||
|
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Add the `twitchio` library to the project.
|
||||||
|
* [ ] Build a bot that can join a Twitch channel and listen for chat messages.
|
||||||
|
* [ ] Implement the `!weather <location>` command parsing.
|
||||||
|
* [ ] When the command is received, send the weather information to the overlay via the WebSocket.
|
||||||
|
|
||||||
|
## Phase 5: Frontend - Command Handling
|
||||||
|
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Update the overlay to handle the weather data sent from the backend.
|
||||||
|
* [ ] Implement the logic for the temporary display (e.g., show the requested location for 10 seconds, then revert).
|
||||||
|
* [ ] Implement the `!weather on|off` functionality.
|
||||||
|
|
||||||
|
## Phase 6: Backend - YouTube Integration
|
||||||
|
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Add a suitable library for reading YouTube chat (e.g., `pytchat`).
|
||||||
|
* [ ] Create a YouTube chat listener.
|
||||||
|
* [ ] Integrate the YouTube chat listener with the command parsing logic.
|
||||||
|
|
||||||
|
## Phase 7: Deployment
|
||||||
|
|
||||||
|
* **Tasks:**
|
||||||
|
* [ ] Guide the user on how to deploy the backend server on their Proxmox server.
|
||||||
|
* [ ] This will likely involve using a process manager like `systemd` and a web server like `Nginx` as a reverse proxy.
|
||||||
|
|
||||||
|
## Future Vision: Monetization and New Projects
|
||||||
|
|
||||||
|
This section serves as a reminder and a place to brainstorm future possibilities for this project and related ideas.
|
||||||
|
|
||||||
|
### Monetization Strategies
|
||||||
|
|
||||||
|
If this service or similar tools become popular, we will need to consider monetization to support the infrastructure costs. Here are some potential models:
|
||||||
|
|
||||||
|
* **Tiered Subscription Model:**
|
||||||
|
* **Free Tier:** Basic functionality (e.g., the weather overlay).
|
||||||
|
* **Premium Tier:** Advanced features, such as:
|
||||||
|
* More complex overlays (e.g., real-time social media feeds, interactive polls).
|
||||||
|
* Custom branding and styling options.
|
||||||
|
* Higher rate limits or faster response times.
|
||||||
|
* Access to a library of pre-made overlay themes.
|
||||||
|
* **Pay-per-Feature:** Allow users to purchase specific features or overlays a la carte.
|
||||||
|
* **Donation/Sponsorship Model:** Rely on the community to support the project through donations or sponsorships.
|
||||||
|
|
||||||
|
### Sidelying Project Ideas
|
||||||
|
|
||||||
|
This project can serve as a foundation for a suite of tools for live streamers and content creators. Here are some ideas for related projects:
|
||||||
|
|
||||||
|
* **Unified Chat Bot:** A bot that can connect to multiple platforms (Twitch, YouTube, Discord) and provide a unified interface for moderation, commands, and alerts.
|
||||||
|
* Unified Chat Bot with simple LLM functions. Something like the Frostytools.com, where the LLM sometimes chimes in and comments on chat, summarizes the past 30 minutes. This could utilize the off-site LLM I have on ai.ramforth.net (openwebui, running ollama and models that can have personalities)
|
||||||
|
* **Interactive Stream Widgets:** A collection of interactive widgets that can be controlled by chat commands, such as:
|
||||||
|
* **Soundboard:** Let viewers trigger sound effects with chat commands.
|
||||||
|
* **On-Screen Alerts:** Display custom alerts for new followers, subscribers, donations, etc.
|
||||||
|
* **Voting/Polling System:** Create real-time polls that viewers can vote on in chat.
|
||||||
|
* **Content Creation Dashboard:** A web-based dashboard that provides streamers with a centralized view of their stream health, chat activity, and audience engagement across all platforms.
|
||||||
|
* This is a huge one. If we can build a suite that uses youtube and twitch login, we can have various tools. I want to tie this one in with the community webpage on thecafeterium.com
|
||||||
|
* **Automated Content Repurposing:** A tool that can automatically clip highlights from a stream and post them to social media platforms like Twitter or TikTok.
|
||||||
74
weather_overlay/main.py
Normal file
74
weather_overlay/main.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
||||||
|
import httpx
|
||||||
|
import json
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
# OpenWeatherMap API Configuration
|
||||||
|
OPENWEATHERMAP_API_KEY = "88764d3fd0fec25358ebce447f9f8d0b"
|
||||||
|
OPENWEATHERMAP_URL = "http://api.openweathermap.org/data/2.5/weather"
|
||||||
|
|
||||||
|
async def get_weather_data(location: str):
|
||||||
|
params = {
|
||||||
|
"q": location,
|
||||||
|
"appid": OPENWEATHERMAP_API_KEY,
|
||||||
|
"units": "metric" # or "imperial" for Fahrenheit
|
||||||
|
}
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
response = await client.get(OPENWEATHERMAP_URL, params=params)
|
||||||
|
response.raise_for_status() # Raise an exception for bad status codes
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
# Extract relevant information
|
||||||
|
weather_description = data["weather"][0]["description"]
|
||||||
|
temperature = data["main"]["temp"]
|
||||||
|
humidity = data["main"]["humidity"]
|
||||||
|
wind_speed = data["wind"]["speed"]
|
||||||
|
wind_deg = data["wind"]["deg"]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"location": data["name"],
|
||||||
|
"description": weather_description,
|
||||||
|
"temperature": temperature,
|
||||||
|
"humidity": humidity,
|
||||||
|
"wind_speed": wind_speed,
|
||||||
|
"wind_direction_deg": wind_deg
|
||||||
|
}
|
||||||
|
except httpx.HTTPStatusError as e:
|
||||||
|
print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}")
|
||||||
|
return {"error": f"Could not fetch weather data for {location}. HTTP Error: {e.response.status_code}"}
|
||||||
|
except httpx.RequestError as e:
|
||||||
|
print(f"An error occurred while requesting {e.request.url!r}: {e}")
|
||||||
|
return {"error": f"Network error while fetching weather data for {location}."}
|
||||||
|
except KeyError as e:
|
||||||
|
print(f"Key error in weather data parsing: {e}. Full response: {data}")
|
||||||
|
return {"error": f"Error parsing weather data for {location}. Missing key: {e}"}
|
||||||
|
except Exception as e:
|
||||||
|
print(f"An unexpected error occurred: {e}")
|
||||||
|
return {"error": f"An unexpected error occurred while fetching weather for {location}."}
|
||||||
|
|
||||||
|
@app.websocket("/ws")
|
||||||
|
async def websocket_endpoint(websocket: WebSocket):
|
||||||
|
await websocket.accept()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data = await websocket.receive_text()
|
||||||
|
try:
|
||||||
|
message = json.loads(data)
|
||||||
|
location = message.get("location")
|
||||||
|
|
||||||
|
if location:
|
||||||
|
weather_data = await get_weather_data(location)
|
||||||
|
await websocket.send_json(weather_data)
|
||||||
|
else:
|
||||||
|
await websocket.send_json({"error": "No location provided in message."})
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
await websocket.send_json({"error": "Invalid JSON format received."})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in websocket processing: {e}")
|
||||||
|
await websocket.send_json({"error": f"Server error: {e}"})
|
||||||
|
except WebSocketDisconnect:
|
||||||
|
print("Client disconnected")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unexpected WebSocket error: {e}")
|
||||||
27
weather_overlay/test_websocket.html
Normal file
27
weather_overlay/test_websocket.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>WebSocket Test</h1>
|
||||||
|
<input type="text" id="message" placeholder="Enter message">
|
||||||
|
<button onclick="sendMessage()">Send</button>
|
||||||
|
<ul id="messages"></ul>
|
||||||
|
<script>
|
||||||
|
const ws = new WebSocket("ws://localhost:8000/ws");
|
||||||
|
ws.onmessage = function(event) {
|
||||||
|
const messages = document.getElementById('messages');
|
||||||
|
const message = document.createElement('li');
|
||||||
|
const content = document.createTextNode(event.data);
|
||||||
|
message.appendChild(content);
|
||||||
|
messages.appendChild(message);
|
||||||
|
};
|
||||||
|
function sendMessage() {
|
||||||
|
const input = document.getElementById("message");
|
||||||
|
ws.send(input.value);
|
||||||
|
input.value = '';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user