diff --git a/modules/services/wanikani-stats/app.py b/modules/services/wanikani-stats/app.py index ef2b2c4..2ec3615 100644 --- a/modules/services/wanikani-stats/app.py +++ b/modules/services/wanikani-stats/app.py @@ -1,30 +1,244 @@ import zipfile import json from pathlib import Path -import streamlit as st +from flask import Flask, render_template_string, Response import pandas as pd +from datetime import datetime +app = Flask(__name__) DATA_DIR = Path("/var/lib/wanikani-logs") -print("starting the WaniKani service") -def load_data(): - # records = [] - for zip_path in sorted(DATA_DIR.glob("wanikani_data_*.zip")): - st.write(f"Processing {zip_path.name}...") - with zipfile.ZipFile(zip_path) as z: - for name in z.namelist(): - print(f"Processing file: {name}") - # with z.open(name) as f: - # data = json.load(f) - # date = zip_path.stem.split("_")[-1] - # # Adapt below to match your JSON structure - # record = { - # "date": date, - # "available_lessons": data.get("lessons", {}).get("available", 0), - # "level": data.get("level", 0), - # } - # records.append(record) - # return pd.DataFrame(records) -st.title("📈 WaniKani Progress Tracker") -# df = load_data() -# st.line_chart(df.set_index("date")) +print("Starting WaniKani Flask service") + +def load_data(): + """Load and process WaniKani data from zip files""" + records = [] + try: + for zip_path in sorted(DATA_DIR.glob("wanikani_data_*.zip")): + print(f"Processing {zip_path.name}...") + with zipfile.ZipFile(zip_path) as z: + for name in z.namelist(): + if name.endswith('.json'): + try: + with z.open(name) as f: + data = json.load(f) + date = zip_path.stem.split("_")[-1] + # Extract relevant data from the JSON structure + record = { + "date": date, + "available_lessons": data.get("lessons", {}).get("available", 0) if isinstance(data.get("lessons"), dict) else 0, + "level": data.get("level", 0), + "reviews_available": data.get("reviews", {}).get("available", 0) if isinstance(data.get("reviews"), dict) else 0, + } + records.append(record) + except (json.JSONDecodeError, KeyError, TypeError) as e: + print(f"Error processing {name}: {e}") + continue + except Exception as e: + print(f"Error loading data: {e}") + + return pd.DataFrame(records) if records else pd.DataFrame() + +def generate_chart_html(df): + """Generate HTML with embedded chart using Chart.js""" + if df.empty: + return "

No data available

" + + # Prepare data for Chart.js + dates = df['date'].tolist() + levels = df['level'].tolist() + lessons = df['available_lessons'].tolist() + reviews = df['reviews_available'].tolist() + + chart_html = f""" +
+ +
+ + + """ + return chart_html + +HTML_TEMPLATE = """ + + + + + + + + +
+ {% if has_data %} +
+
+
{{ current_level }}
+
Current Level
+
+
+
{{ available_lessons }}
+
Lessons
+
+
+
{{ available_reviews }}
+
Reviews
+
+
+
+ {{ chart_html|safe }} +
+ {% else %} +
+

📚 No WaniKani data available

+

Check if data files exist in {{ data_dir }}

+
+ {% endif %} +
+ + +""" + +@app.route('/') +def index(): + """Main endpoint for Glance extension""" + df = load_data() + + # Prepare template variables + template_vars = { + 'has_data': not df.empty, + 'data_dir': str(DATA_DIR), + 'chart_html': '', + 'current_level': 0, + 'available_lessons': 0, + 'available_reviews': 0 + } + + if not df.empty: + # Get latest stats + latest = df.iloc[-1] + template_vars.update({ + 'current_level': int(latest['level']), + 'available_lessons': int(latest['available_lessons']), + 'available_reviews': int(latest['reviews_available']), + 'chart_html': generate_chart_html(df) + }) + + html = render_template_string(HTML_TEMPLATE, **template_vars) + + # Create response with Glance extension headers + response = Response(html, mimetype='text/html') + response.headers['Widget-Title'] = '📚 WaniKani Stats' + response.headers['Widget-Content-Type'] = 'html' + + return response + +@app.route('/health') +def health(): + """Health check endpoint""" + return {'status': 'ok', 'service': 'wanikani-stats'} + +if __name__ == '__main__': + import sys + port = int(sys.argv[1]) if len(sys.argv) > 1 else 8501 + print(f"Starting WaniKani Stats Flask app on port {port}") + app.run(host='0.0.0.0', port=port, debug=False)