fix stuff

This commit is contained in:
2026-09-21 01:55:42 -04:00
commit 02d7c10f7d
26 changed files with 953 additions and 0 deletions

0
utils/__init__.py Normal file
View File

43
utils/ai_client.py Normal file
View File

@@ -0,0 +1,43 @@
import re
import ollama
from audio.tts import speak
AI_MODEL = "gemma4:e2b-it-qat"
AI_HOST = "http://localhost:11434"
def clean_response(text):
cleaned = re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL | re.IGNORECASE)
lines = [line for line in cleaned.splitlines() if line.strip()]
return "\n".join(lines).strip()
def ask_ai(prompt):
try:
full_prompt = (
"You must answer in exactly one or two sentences.\n\n"
f"Question: {prompt}\n"
"Answer:"
)
print("Thinking...", end="", flush=True)
client = ollama.Client(host=AI_HOST)
stream = client.generate(
model=AI_MODEL,
prompt=full_prompt,
stream=True
)
ai_text = ""
for chunk in stream:
text_piece = chunk.get("response", "")
if text_piece:
print(text_piece, end="", flush=True)
ai_text += text_piece
print()
final_text = clean_response(ai_text)
if not final_text:
speak("Sorry, I got no response from the AI.")
else:
speak(final_text)
except Exception as e:
print("\nAI Error:", e)
speak("Sorry, I couldn't connect to the AI.")

23
utils/time_utils.py Normal file
View File

@@ -0,0 +1,23 @@
from datetime import datetime
def time_to_words(dt: datetime):
hour = dt.hour % 12 or 12
minute = dt.minute
numbers = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
"eighteen", "nineteen", "twenty", "twenty-one", "twenty-two", "twenty-three",
"twenty-four", "twenty-five", "twenty-six", "twenty-seven", "twenty-eight",
"twenty-nine", "thirty", "thirty-one", "thirty-two", "thirty-three", "thirty-four",
"thirty-five", "thirty-six", "thirty-seven", "thirty-eight", "thirty-nine",
"forty", "forty-one", "forty-two", "forty-three", "forty-four", "forty-five",
"forty-six", "forty-seven", "forty-eight", "forty-nine", "fifty", "fifty-one",
"fifty-two", "fifty-three", "fifty-four", "fifty-five", "fifty-six", "fifty-seven",
"fifty-eight", "fifty-nine"]
am_pm = "AM" if dt.hour < 12 else "PM"
if minute == 0:
return f"{numbers[hour]} o'clock {am_pm}"
elif minute < 10:
return f"{numbers[hour]} oh {numbers[minute]} {am_pm}"
else:
return f"{numbers[hour]} {numbers[minute]} {am_pm}"

22
utils/vosk_setup.py Normal file
View File

@@ -0,0 +1,22 @@
import os
import zipfile
import requests
import vosk
from config import VOSK_MODEL_FOLDER, VOSK_MODEL_URL, VOSK_MODEL_ZIP
def setup_vosk_model():
if not os.path.isdir(VOSK_MODEL_FOLDER):
print("Downloading Vosk model")
response = requests.get(VOSK_MODEL_URL)
with open(VOSK_MODEL_ZIP, "wb") as file:
file.write(response.content)
with zipfile.ZipFile(VOSK_MODEL_ZIP, 'r') as zip_ref:
zip_ref.extractall()
print("Downloaded!")
model = vosk.Model(VOSK_MODEL_FOLDER)
rec = vosk.KaldiRecognizer(model, 16000)
return rec

95
utils/weather.py Normal file
View File

@@ -0,0 +1,95 @@
import requests
def get_local_weather(
fallback_lat=40.59,
fallback_lon=-74.62,
fallback_city="Bridgewater",
fallback_region="New Jersey",
fallback_country_code="US"
):
"""
Fetches the user's current location and automatically determines
whether to return Metric or Imperial units based on their country.
"""
lat, lon = fallback_lat, fallback_lon
city, region = fallback_city, fallback_region
country_code = fallback_country_code
# Geolocation Lookup
try:
geo_url = "http://ip-api.com/json"
geo_response = requests.get(geo_url, timeout=5).json()
if geo_response.get("status") == "success":
lat = geo_response["lat"]
lon = geo_response["lon"]
city = geo_response["city"]
region = geo_response["regionName"]
country_code = geo_response.get("countryCode", "US")
else:
print("IP lookup API returned an error status. Using fallback coordinates.")
except Exception:
print("Network error during IP lookup. Using fallback coordinates.")
# Unit System 'n Weather URL
is_imperial = country_code in ["US", "LR", "MM"]
unit_suffix = ""
if is_imperial:
unit_suffix = "&temperature_unit=fahrenheit&precipitation_unit=inch"
weather_url = (
f"https://api.open-meteo.com/v1/forecast?"
f"latitude={lat}&longitude={lon}"
f"&current=temperature_2m,precipitation,cloud_cover"
f"&daily=temperature_2m_max,temperature_2m_min"
f"&timezone=auto"
f"{unit_suffix}"
)
try:
response = requests.get(weather_url, timeout=5)
if response.status_code == 200:
data = response.json()
current = data["current"]
daily = data["daily"]
temp_unit = "°F" if is_imperial else "°C"
precip_unit = "inch" if is_imperial else "mm"
return {
"location": {
"city": city,
"region": region,
"country_code": country_code,
"lat": lat,
"lon": lon
},
"unit_system": "imperial" if is_imperial else "metric",
"units": {"temp": temp_unit, "precipitation": precip_unit},
"current_temp": current['temperature_2m'],
"high_temp": daily['temperature_2m_max'][0],
"low_temp": daily['temperature_2m_min'][0],
"precipitation": current['precipitation'],
"cloud_cover_pct": current['cloud_cover']
}
else:
print(f"Weather API returned error code: {response.status_code}")
return None
except Exception as e:
print(f"Network error while fetching weather: {e}")
return None
if __name__ == "__main__":
# Test block
weather_data = get_local_weather()
if weather_data:
u = weather_data["units"]
print(f"\n--- Location: {weather_data['location']['city']}, {weather_data['location']['region']} ({weather_data['location']['country_code']}) ---")
print(f"System Chosen: {weather_data['unit_system'].upper()}")
print(f"Current Temperature: {weather_data['current_temp']}{u['temp']}")
print(f"Today's High: {weather_data['high_temp']}{u['temp']}")
print(f"Precipitation: {weather_data['precipitation']} {u['precipitation']}")