"""Wildlife journal blueprint — sighting log, stats, export.""" import csv import io from flask import Blueprint, Response, current_app, jsonify, render_template, request wildlife_bp = Blueprint("wildlife", __name__, url_prefix="/wildlife") def _engine(): return current_app.config.get("DB_ENGINE") @wildlife_bp.route("/") def journal(): return render_template("wildlife/journal.html") @wildlife_bp.route("/api/sightings") def sightings_api(): engine = _engine() if engine is None: return jsonify({"sightings": []}) from vigilar.storage.queries import get_wildlife_sightings_paginated sightings = get_wildlife_sightings_paginated( engine, species=request.args.get("species"), threat_level=request.args.get("threat_level"), camera_id=request.args.get("camera_id"), since_ts=request.args.get("since", type=float), until_ts=request.args.get("until", type=float), limit=min(request.args.get("limit", 50, type=int), 500), offset=request.args.get("offset", 0, type=int), ) return jsonify({"sightings": sightings}) @wildlife_bp.route("/api/stats") def stats_api(): engine = _engine() if engine is None: return jsonify({"total": 0, "species_count": 0, "per_species": {}}) from vigilar.storage.queries import get_wildlife_stats return jsonify(get_wildlife_stats(engine)) @wildlife_bp.route("/api/frequency") def frequency_api(): engine = _engine() if engine is None: return jsonify({}) from vigilar.storage.queries import get_wildlife_frequency return jsonify(get_wildlife_frequency(engine)) @wildlife_bp.route("/api/export") def export_csv(): engine = _engine() if engine is None: return Response("No data", mimetype="text/csv") from vigilar.storage.queries import get_wildlife_sightings_paginated sightings = get_wildlife_sightings_paginated(engine, limit=10000, offset=0) output = io.StringIO() writer = csv.writer(output) writer.writerow(["id", "timestamp", "species", "threat_level", "camera_id", "confidence", "temperature_c", "conditions"]) for s in sightings: writer.writerow([s["id"], s["ts"], s["species"], s["threat_level"], s["camera_id"], s.get("confidence"), s.get("temperature_c"), s.get("conditions")]) return Response(output.getvalue(), mimetype="text/csv", headers={"Content-Disposition": "attachment; filename=wildlife_sightings.csv"})