Spaces:
Running
Running
File size: 7,327 Bytes
3ca9355 3f85e49 3ca9355 563a9a1 3ca9355 3f85e49 daaab34 3f85e49 daaab34 3f85e49 7089e8d 3ca9355 563a9a1 3ca9355 0e760c3 3ca9355 09e02a5 3ca9355 09e02a5 3ca9355 563a9a1 e2bfcae 563a9a1 e2bfcae 563a9a1 e2bfcae 5621792 16bcbad fa9cf94 16bcbad e2bfcae 6cdfe59 e2bfcae 6cdfe59 16bcbad 6cdfe59 e2bfcae 6cdfe59 e2bfcae 563a9a1 e2bfcae 563a9a1 0e760c3 3ca9355 0e760c3 ab29c48 4f31b48 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
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
|