Files
OpenCode Test daa4de8832 Add morning-report and stock-lookup skills
Add comprehensive morning report skill with collectors for calendar, email, tasks,
infrastructure status, news, stocks, and weather. Add stock lookup skill for quote queries.
2026-01-03 10:54:54 -08:00

126 lines
3.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""Weather collector using wttr.in."""
import json
import subprocess
import urllib.request
from pathlib import Path
def fetch_weather(location: str) -> dict:
"""Fetch weather data from wttr.in."""
# Use wttr.in JSON format
url = f"https://wttr.in/{location}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
try:
with urllib.request.urlopen(req, timeout=5) as resp:
return json.load(resp)
except Exception as e:
return {"error": str(e)}
def format_weather_basic(data: dict, location: str) -> str:
"""Format weather data without LLM - basic fallback."""
if "error" in data:
return f"Weather unavailable: {data['error']}"
try:
current = data["current_condition"][0]
today = data["weather"][0]
temp_f = current.get("temp_F", "?")
desc = current.get("weatherDesc", [{}])[0].get("value", "Unknown")
high = today.get("maxtempF", "?")
low = today.get("mintempF", "?")
return f"{location}: {temp_f}°F, {desc} | High {high}° Low {low}°"
except Exception as e:
return f"Weather parse error: {e}"
def format_weather_with_haiku(data: dict, location: str) -> str:
"""Use Haiku to format weather data nicely."""
if "error" in data:
return f"Weather unavailable: {data['error']}"
try:
current = data["current_condition"][0]
today = data["weather"][0]
# Extract key data
temp_f = current.get("temp_F", "?")
feels_like = current.get("FeelsLikeF", temp_f)
desc = current.get("weatherDesc", [{}])[0].get("value", "Unknown")
humidity = current.get("humidity", "?")
high = today.get("maxtempF", "?")
low = today.get("mintempF", "?")
# Check for precipitation
hourly = today.get("hourly", [])
rain_hours = [h for h in hourly if int(h.get("chanceofrain", 0)) > 50]
# Build context for Haiku
weather_context = f"""Current: {temp_f}°F (feels like {feels_like}°F), {desc}
High: {high}°F, Low: {low}°F
Humidity: {humidity}%
Rain chance >50%: {len(rain_hours)} hours today"""
# Check if claude is available
claude_path = Path.home() / ".local/bin/claude"
if not claude_path.exists():
claude_path = "claude" # Try PATH
prompt = f"""Format this weather data for {location} into a single concise line for a morning report.
Add a brief hint if relevant (e.g., "bring umbrella", "nice day for a walk").
Keep it under 80 characters if possible.
{weather_context}
Output ONLY the formatted weather line, nothing else."""
result = subprocess.run(
[str(claude_path), "--print", "--model", "haiku", "-p", prompt],
capture_output=True,
text=True,
timeout=30
)
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
else:
# Fallback to basic format
return format_weather_basic(data, location)
except Exception as e:
# Fallback to basic format
return format_weather_basic(data, location)
def collect(config: dict) -> dict:
"""Main collector entry point."""
location = config.get("weather", {}).get("location", "Seattle,WA,USA")
city_name = location.split(",")[0]
data = fetch_weather(location)
# Try Haiku formatting, fall back to basic
formatted = format_weather_with_haiku(data, city_name)
return {
"section": "Weather",
"icon": "🌤",
"content": formatted,
"raw": data if "error" not in data else None,
"error": data.get("error")
}
if __name__ == "__main__":
# Test
config = {"weather": {"location": "Seattle,WA,USA"}}
result = collect(config)
print(f"## {result['icon']} {result['section']}")
print(result["content"])