MIPESCA_test / app.py
Edoruin's picture
debug: add verbose logging for Google Sheets sync
6cdfe59
import os
import csv
import re
from datetime import datetime
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
from models import Capture, Species, ClosedSeason
app = Flask(__name__, static_folder='static', static_url_path='')
CORS(app)
def slugify(text):
"""Simple slugify for species IDs."""
text = text.lower()
text = re.sub(r'[^\w\s-]', '', text)
return re.sub(r'[-\s]+', '-', text).strip('-')
def load_species():
"""Load unique species from the provided CSV file."""
species_list = []
seen_products = set()
csv_path = 'produccion_pesca_limpia_refined.csv'
# Pre-defined base species (with more metadata if available)
base_metadata = {
'chillo': {'sci': 'Lutjanus campechanus', 'img': 'assets/species/chillo.jpg', 'veda': ClosedSeason(start='04-01', end='06-30', description='Veda de reproducci贸n')},
'dorado': {'sci': 'Coryphaena hippurus', 'img': 'assets/species/dorado.jpg'},
'langosta-comun-del-caribe': {'sci': 'Panulirus argus', 'img': 'assets/species/langosta.jpg', 'veda': ClosedSeason(start='03-01', end='06-30', description='Veda de reproducci贸n')}
}
if os.path.exists(csv_path):
with open(csv_path, mode='r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
product_name = row['Producto']
category = row['categoria']
if product_name not in seen_products:
species_id = slugify(product_name)
metadata = base_metadata.get(species_id, {})
species_list.append(Species(
id=species_id,
commonName=product_name,
scientificName=metadata.get('sci', ''),
category=category,
imageUrl=metadata.get('img', 'assets/species/placeholder.jpg'),
protected=False,
closedSeason=metadata.get('veda')
))
seen_products.add(product_name)
# If CSV failed or is empty, use defaults
if not species_list:
print("CSV not found or empty, using expanded fallback list")
species_list = [
Species(id='chillo', commonName='Chillo', scientificName='Lutjanus campechanus', category='Peces', imageUrl='assets/species/chillo.jpg', protected=False, closedSeason=ClosedSeason(start='04-01', end='06-30', description='Veda de reproducci贸n')),
Species(id='dorado', commonName='Dorado', scientificName='Coryphaena hippurus', category='Peces', imageUrl='assets/species/dorado.jpg', protected=False),
Species(id='langosta', commonName='Langosta del Caribe', scientificName='Panulirus argus', category='Crust谩ceos', imageUrl='assets/species/langosta.jpg', protected=False, closedSeason=ClosedSeason(start='03-01', end='06-30', description='Veda de reproducci贸n')),
Species(id='mero', commonName='Mero', scientificName='Epinephelus itajara', category='Peces', imageUrl='assets/species/placeholder.jpg', protected=False),
Species(id='atun', commonName='At煤n', scientificName='Thunnus', category='Peces', imageUrl='assets/species/placeholder.jpg', protected=False),
Species(id='pulpo', commonName='Pulpo', scientificName='Octopus vulgaris', category='Moluscos', imageUrl='assets/species/placeholder.jpg', protected=False),
Species(id='lamb铆', commonName='Lamb铆', scientificName='Lobatus gigas', category='Moluscos', imageUrl='assets/species/placeholder.jpg', protected=False),
]
return species_list
# Load Data
SPECIES_DATA = load_species()
captures_storage = []
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/health')
def health_check():
return jsonify({
'status': 'healthy',
'timestamp': datetime.now().isoformat()
})
@app.route('/api/species', methods=['GET'])
def get_species():
return jsonify([s.to_dict() for s in SPECIES_DATA])
@app.route('/api/captures', methods=['POST'])
def create_capture():
try:
data = request.get_json()
capture = Capture.from_dict(data)
captures_storage.append(capture)
return jsonify({'success': True, 'id': capture.id}), 201
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 400
@app.route('/api/sync', methods=['POST'])
def sync_captures():
"""Batch synchronization endpoint with Google Sheets forwarding."""
try:
data = request.get_json()
captures_data = data.get('captures', [])
# Store locally (in-memory for now)
for c_data in captures_data:
capture = Capture.from_dict(c_data)
captures_storage.append(capture)
# Forward to Google Sheets if configured
gas_url = os.environ.get('GAS_DEPLOYMENT_URL')
if gas_url and captures_data:
print(f"Forwarding {len(captures_data)} captures to Google Sheets...")
for c in captures_data:
# Explicitly log that these are device coordinates being forwarded
print(f" [DEVICE SYNC] Capture {c.get('id')}:")
print(f" - Port: {c.get('port')}")
print(f" - Latitude: {c.get('latitude')} (captured on device)")
print(f" - Longitude: {c.get('longitude')} (captured on device)")
print(f" - Place: {c.get('placeName')}")
try:
import requests
# Forward the exact payload expected by the GAS script
print(f"DEBUG: Forwarding to GAS URL: {gas_url[:50]}...")
response = requests.post(gas_url, json={'captures': captures_data}, timeout=15)
print(f"DEBUG: GAS Response Status: {response.status_code}")
print(f"DEBUG: GAS Response Body: {response.text}")
if not response.ok:
print(f"ERROR: Google Sheets sync failed. Status: {response.status_code}, Body: {response.text}")
else:
print(f"SUCCESS: Data accepted by Google Sheets: {response.text}")
except Exception as e:
print(f"CRITICAL: Error communicating with GAS: {str(e)}")
synced_ids = [c.get('id') for c in captures_data]
return jsonify({
'success': True,
'synced': synced_ids,
'total': len(synced_ids)
}), 200
except Exception as e:
print(f"Sync error: {str(e)}")
return jsonify({'success': False, 'error': str(e)}), 400
@app.route('/debug/files')
def debug_files():
files = []
for root, _, filenames in os.walk('static'):
for f in filenames:
rel_path = os.path.relpath(os.path.join(root, f), 'static')
files.append({
"path": rel_path,
"size": os.path.getsize(os.path.join(root, f))
})
return jsonify(files)
if __name__ == '__main__':
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port)
# Deployment trigger: 2026-01-23 18:55