File size: 8,004 Bytes
28df62a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5cd87f
 
28df62a
 
 
 
b5cd87f
28df62a
 
 
b5cd87f
28df62a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5cd87f
 
 
 
 
 
 
 
 
 
 
 
28df62a
 
 
 
b5cd87f
 
28df62a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5cd87f
28df62a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5cd87f
28df62a
 
b5cd87f
 
 
28df62a
 
b5cd87f
28df62a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353ef89
b5cd87f
 
 
 
 
 
 
 
 
 
 
 
 
 
28df62a
 
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import os
import re
import streamlit as st
import folium
from streamlit_folium import st_folium
import openai
from bs4 import BeautifulSoup

# Configuraci贸n de la p谩gina
st.set_page_config(page_title="Mapa Interactivo de Puerto Rico", layout="wide")
st.title("Mapa Interactivo de Puerto Rico y Chatbot de Recomendaciones")

# =============================================================================
# Funciones para parsear archivos
# =============================================================================

def parse_text_file(filepath):
    """
    Parseo para archivos de texto plano.
    Busca l铆neas con 'Name:', 'Latitude:' y 'Longitude:'.
    """
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    
    name_match = re.search(r'Name:\s*(.*)', content, re.IGNORECASE)
    name = name_match.group(1).strip() if name_match else os.path.splitext(os.path.basename(filepath))[0]
    
    lat_match = re.search(r'Latitude:\s*([-+]?[0-9]*\.?[0-9]+)', content, re.IGNORECASE)
    lon_match = re.search(r'Longitude:\s*([-+]?[0-9]*\.?[0-9]+)', content, re.IGNORECASE)
    if lat_match and lon_match:
        try:
            lat = float(lat_match.group(1))
        except ValueError:
            lat = None
        try:
            lon = float(lon_match.group(1))
        except ValueError:
            lon = None
    else:
        lat, lon = None, None

    return {
        "name": name,
        "lat": lat,
        "lon": lon,
        "content": content
    }

def parse_html_file(filepath):
    """
    Parseo para archivos HTML (por ejemplo, de Wikipedia).
    Extrae el t铆tulo, las coordenadas desde el bloque "wgCoordinates" y, si es posible,
    la secci贸n hist贸rica (buscando un encabezado que contenga "History" o "Historia").
    """
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Parsear con BeautifulSoup
    soup = BeautifulSoup(content, "html.parser")
    title = soup.title.string.strip() if soup.title else os.path.splitext(os.path.basename(filepath))[0]
    
    # Extraer coordenadas (pueden venir en el bloque "wgCoordinates")
    coord_match = re.search(r'"wgCoordinates":\s*{\s*"lat":\s*([0-9\.-]+),\s*"lon":\s*([0-9\.-]+)', content)
    if coord_match:
        lat_str = coord_match.group(1)
        lon_str = coord_match.group(2)
        try:
            lat = float(lat_str) if lat_str not in ['-', ''] else None
        except ValueError:
            lat = None
        try:
            lon = float(lon_str) if lon_str not in ['-', ''] else None
        except ValueError:
            lon = None
    else:
        lat, lon = None, None

    # Intentar extraer datos hist贸ricos: se busca un encabezado que contenga "History" o "Historia"
    history = ""
    history_header = soup.find(lambda tag: tag.name in ["h2", "h3"] and ("History" in tag.get_text() or "Historia" in tag.get_text()))
    if history_header:
        history_parts = []
        # Recorrer los hermanos hasta llegar a otro encabezado del mismo nivel (o superior)
        for sibling in history_header.find_next_siblings():
            if sibling.name and sibling.name.startswith("h"):
                break
            history_parts.append(sibling.get_text(strip=True))
        history = "\n".join(history_parts)
         
    return {
        "name": title,
        "lat": lat,
        "lon": lon,
        "content": content,
        "history": history
    }

def load_data_from_directory(directory, parser_func):
    """
    Carga todos los archivos .txt de un directorio usando la funci贸n de parseo indicada.
    """
    data_points = []
    if os.path.exists(directory):
        for filename in os.listdir(directory):
            if filename.endswith(".txt"):
                filepath = os.path.join(directory, filename)
                data_points.append(parser_func(filepath))
    return data_points

# =============================================================================
# Carga de los datos desde las carpetas correspondientes
# =============================================================================

landmarks_dir = os.path.join("data", "landmarks")
municipalities_dir = os.path.join("data", "municipalities")
news_dir = os.path.join("data", "news")

# Para landmarks y news se asume que los archivos son de texto plano.
landmarks = load_data_from_directory(landmarks_dir, parse_text_file)
news_data = load_data_from_directory(news_dir, parse_text_file)

# Para municipalities, se usa el parseo de HTML (que ahora incluye datos hist贸ricos)
municipalities = load_data_from_directory(municipalities_dir, parse_html_file)

# =============================================================================
# Creaci贸n del mapa interactivo usando Folium
# =============================================================================

# Coordenadas centrales aproximadas de Puerto Rico
map_center = [18.2208, -66.5901]
m = folium.Map(location=map_center, zoom_start=10)

# Agregar marcadores para Landmarks
for landmark in landmarks:
    if landmark["lat"] is not None and landmark["lon"] is not None:
        folium.Marker(
            location=[landmark["lat"], landmark["lon"]],
            popup=folium.Popup(f"<b>{landmark['name']}</b><br>{landmark['content'][:200]}...", max_width=300),
            icon=folium.Icon(color='blue', icon='info-sign')
        ).add_to(m)

# Agregar marcadores para Municipios, incluyendo datos hist贸ricos si est谩n disponibles
for municipality in municipalities:
    if municipality["lat"] is not None and municipality["lon"] is not None:
        history_text = municipality.get("history", "")
        history_excerpt = history_text[:300] + "..." if len(history_text) > 300 else history_text
        popup_content = f"<b>{municipality['name']}</b><br><b>Historia:</b><br>{history_excerpt}"
        folium.Marker(
            location=[municipality["lat"], municipality["lon"]],
            popup=folium.Popup(popup_content, max_width=300),
            icon=folium.Icon(color='green', icon='home')
        ).add_to(m)

# Agregar marcadores para Noticias (si se disponen de coordenadas)
for news_item in news_data:
    if news_item["lat"] is not None and news_item["lon"] is not None:
        folium.Marker(
            location=[news_item["lat"], news_item["lon"]],
            popup=folium.Popup(f"<b>{news_item['name']}</b><br>{news_item['content'][:200]}...", max_width=300),
            icon=folium.Icon(color='red', icon='newspaper')
        ).add_to(m)

st.subheader("Mapa Interactivo")
st_data = st_folium(m, width=700, height=500)

# =============================================================================
# Secci贸n del Chatbot con API de OpenAI
# =============================================================================

st.markdown("---")
st.subheader("Chatbot de Recomendaciones")
st.write("Consulta recomendaciones sobre Puerto Rico.")

# Entrada de usuario para la consulta
user_input = st.text_input("Escribe tu consulta:")

if st.button("Enviar consulta"):
    if user_input:
        # Configura tu clave API de OpenAI (def铆nela en st.secrets)
        openai.api_key = st.secrets[""]
        with st.spinner("Consultando a OpenAI..."):
            try:
                response = openai.ChatCompletion.create(
                    model="gpt-3.5-turbo",
                    messages=[
                        {"role": "system", "content": "Eres un asistente experto en recomendaciones tur铆sticas y culturales de Puerto Rico. Ayudas a los usuarios a descubrir lugares de inter茅s y actividades en la isla."},
                        {"role": "user", "content": user_input}
                    ]
                )
                answer = response.choices[0].message.content.strip()
                st.markdown("**Respuesta:**")
                st.write(answer)
            except Exception as e:
                st.error(f"Error al conectarse con la API de OpenAI: {e}")
    else:
        st.warning("Por favor, ingresa una consulta.")