Ekaropolus f2180483f0
All checks were successful
continuous-integration/drone/push Build is passing
Adding DB to Whatsaap AI
2025-05-19 23:04:20 -06:00

282 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.views.generic.base import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
class AppsView(LoginRequiredMixin, TemplateView):
pass
# ───── Existing ──────────────────────────────────────────────────────────────
# Calendar
apps_calendar_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-calendar.html")
# Chat
apps_chat_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-chat.html")
# Email
apps_email_inbox_view = AppsView.as_view(template_name="pxy_dashboard/apps/apps-email-inbox.html")
apps_email_read = AppsView.as_view(template_name="pxy_dashboard/apps/apps-email-read.html")
# Tasks
apps_tasks = AppsView.as_view(template_name="pxy_dashboard/apps/apps-tasks.html")
apps_tasks_details = AppsView.as_view(template_name="pxy_dashboard/apps/apps-tasks-details.html")
# Kanban
apps_kanban_board = AppsView.as_view(template_name="pxy_dashboard/apps/apps-kanban.html")
# File Manager
apps_file_manager = AppsView.as_view(template_name="pxy_dashboard/apps/apps-file-manager.html")
# ───── Waste Collection Intelligence ─────────────────────────────────────────
# Pre-Operation
#apps_zone_definition = AppsView.as_view(template_name="pxy_dashboard/apps/apps-zone-definition.html")
#apps_route_optimization = AppsView.as_view(template_name="pxy_dashboard/apps/apps-route-optimization.html")
apps_dispatch_plan = AppsView.as_view(template_name="pxy_dashboard/apps/apps-dispatch-plan.html")
# Operation Physical & Social Digital Twin
apps_urban_digital_twin = AppsView.as_view(template_name="pxy_dashboard/apps/apps-urban-digital-twin.html")
#apps_whatsapp_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-whatsapp-bot.html")
apps_telegram_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-telegram-bot.html")
apps_facebook_pages_bot = AppsView.as_view(template_name="pxy_dashboard/apps/apps-facebook-pages-bot.html")
apps_feedback_loop = AppsView.as_view(template_name="pxy_dashboard/apps/apps-feedback-loop.html")
# Post-Operation
apps_route_analytics = AppsView.as_view(template_name="pxy_dashboard/apps/apps-route-analytics.html")
apps_feedback_review = AppsView.as_view(template_name="pxy_dashboard/apps/apps-feedback-review.html")
apps_twin_refinement = AppsView.as_view(template_name="pxy_dashboard/apps/apps-twin-refinement.html")
# System Control
apps_sync_monitor = AppsView.as_view(template_name="pxy_dashboard/apps/apps-sync-monitor.html")
apps_logs_webhooks = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-webhooks.html")
apps_logs_parsing = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-parsing.html")
apps_logs_limits = AppsView.as_view(template_name="pxy_dashboard/apps/apps-logs-limits.html")
apps_config_api = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-api.html")
apps_config_map = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-map.html")
apps_config_collection = AppsView.as_view(template_name="pxy_dashboard/apps/apps-config-collection.html")
from django.shortcuts import render
from .models import GeoScenario
import pandas as pd
def zone_definition_view(request):
scenario = GeoScenario.objects.last()
chart_data = {}
viviendas_data = {}
city_options = []
scatter_series = {}
if scenario and scenario.csv_file:
df = pd.read_csv(scenario.csv_file.path)
df = df.fillna(0)
# Solo conservar zonas con generación total > 0
df = df[df["GEN_TOT"] > 0]
# Opciones de ciudad
city_options = sorted(df["N_URBANO"].dropna().unique())
selected_city = request.GET.get("city") or (city_options[0] if city_options else None)
# Barras por zona (residuos)
if selected_city:
city_df = df[df["N_URBANO"] == selected_city]
grouped = (
city_df.groupby("COD_ZONA")[["GEN_ORG", "GEN_INVA", "GEN_RESTO"]]
.sum()
.reset_index()
.sort_values(by="GEN_ORG", ascending=False)
)
chart_data = {
"zones": grouped["COD_ZONA"].astype(str).tolist(),
"gen_org": grouped["GEN_ORG"].round(2).tolist(),
"gen_inva": grouped["GEN_INVA"].round(2).tolist(),
"gen_resto": grouped["GEN_RESTO"].round(2).tolist(),
}
# Barras por zona (viviendas)
viviendas_grouped = (
city_df.groupby("COD_ZONA")["num_viviendas"]
.sum()
.reset_index()
.sort_values(by="num_viviendas", ascending=False)
)
viviendas_data = {
"zones": viviendas_grouped["COD_ZONA"].astype(str).tolist(),
"viviendas": viviendas_grouped["num_viviendas"].astype(int).tolist(),
}
# Dispersión por ciudad
scatter_series = {
"GEN_ORG": [],
"GEN_INVA": [],
"GEN_RESTO": [],
}
city_grouped = (
df.groupby("N_URBANO")[["num_viviendas", "GEN_ORG", "GEN_INVA", "GEN_RESTO"]]
.sum()
.reset_index()
)
for _, row in city_grouped.iterrows():
viviendas = float(row["num_viviendas"])
if viviendas == 0:
continue
city = row["N_URBANO"]
if row["GEN_ORG"] > 0:
scatter_series["GEN_ORG"].append({"x": viviendas, "y": float(row["GEN_ORG"]), "city": city})
if row["GEN_INVA"] > 0:
scatter_series["GEN_INVA"].append({"x": viviendas, "y": float(row["GEN_INVA"]), "city": city})
if row["GEN_RESTO"] > 0:
scatter_series["GEN_RESTO"].append({"x": viviendas, "y": float(row["GEN_RESTO"]), "city": city})
return render(request, "pxy_dashboard/apps/apps-zone-definition.html", {
"chart_data": chart_data,
"viviendas_data": viviendas_data,
"scatter_series": scatter_series,
"cities": city_options,
"selected_city": selected_city,
})
from .models import OptScenario
def route_optimization_view(request):
scenario = OptScenario.objects.last()
route_data = {}
subdivisions = []
selected_subdivision = None
scenario_name = scenario.name if scenario else "No scenario loaded"
if scenario and scenario.optimized_csv:
df = pd.read_csv(scenario.optimized_csv.path)
df = df.fillna(0)
# Filtrar por subdivisión
subdivisions = sorted(df["subdivision"].dropna().unique().tolist())
selected_subdivision = request.GET.get("subdivision") or (subdivisions[0] if subdivisions else None)
if selected_subdivision:
df = df[df["subdivision"] == selected_subdivision]
# Seleccionar solo filas de tipo 'end' para obtener acumulados
end_rows = df[df["type"] == "end"].copy()
route_data = {
"routes": end_rows["route_id"].astype(str).tolist(),
"distance_km": end_rows["distance_km"].round(2).tolist(),
"load_kg": end_rows["load_kg"].round(2).tolist(),
"cost_clp": end_rows["step_cost_clp"].round(2).tolist(),
}
return render(request, "pxy_dashboard/apps/apps-route-optimization.html", {
"route_data": route_data,
"subdivisions": subdivisions,
"selected_subdivision": selected_subdivision,
"scenario_name": scenario_name,
})
import json
import polyline
from django.shortcuts import render
from .models import OptScenario
def dispatch_plan_view(request):
scenario = OptScenario.objects.last()
geojson_by_subdivision = {}
routes_by_subdivision = {}
selected_subdivision = request.GET.get("subdivision")
selected_route = request.GET.get("route")
if scenario and scenario.dispatch_json:
with open(scenario.dispatch_json.path, encoding='utf-8') as f:
raw_data = json.load(f)
for subdiv, result in raw_data.items():
features = []
route_ids = []
for idx, route in enumerate(result.get("routes", [])):
route_id = str(idx + 1)
route_ids.append(route_id)
if selected_subdivision and subdiv != selected_subdivision:
continue
if selected_route and route_id != selected_route:
continue
geometry = route.get("geometry")
if geometry:
# decode returns [[lat, lon], …]
decoded = polyline.decode(geometry)
# swap to [lon, lat] for GeoJSON
coords = [[lng, lat] for lat, lng in decoded]
features.append({
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": coords
},
"properties": {
"type": "route",
"subdivision": subdiv,
"route_id": route_id
}
})
for step in route.get("steps", []):
# step["location"] is [lon, lat]
lat, lon = step["location"][1], step["location"][0]
step_type = step.get("type", "job")
step_id = step.get("id", "")
load = step.get("load", [0])[0]
distance = step.get("distance", 0)
arrival = step.get("arrival", 0)
popup = (
f"<b>{step_type.title()}</b><br>"
f"Job ID: {step_id}<br>"
f"Load: {load} kg<br>"
f"Distance: {distance / 1000:.2f} km<br>"
f"Arrival: {arrival / 60:.1f} min"
)
features.append({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [lon, lat]
},
"properties": {
"popup": popup,
"step_type": step_type,
"subdivision": subdiv,
"route_id": route_id
}
})
geojson_by_subdivision[subdiv] = {
"type": "FeatureCollection",
"features": features
}
routes_by_subdivision[subdiv] = route_ids
return render(request, "pxy_dashboard/apps/apps-dispatch-plan.html", {
"geojson_by_subdivision": json.dumps(geojson_by_subdivision),
"routes_by_subdivision": json.dumps(routes_by_subdivision), # ← JSON-encodes the route lists
"subdivisions": list(geojson_by_subdivision.keys()),
"selected_subdivision": selected_subdivision,
"selected_route": selected_route,
})
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
import requests
@login_required
def apps_whatsapp_bot(request):
stats = request.user.has_perm("pxy_whatsapp.view_whatsappstats") and \
requests.get(request.build_absolute_uri("/whatsapp/stats/"), cookies=request.COOKIES).json()
return render(request, "pxy_dashboard/apps/apps-whatsapp-bot.html", {"stats": stats})