Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import re | |
| import ast | |
| import pandas as pd | |
| from geopy.geocoders import Nominatim | |
| from geopy.distance import geodesic | |
| from geopy.exc import GeocoderTimedOut | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| import google.generativeai as genai | |
| from dotenv import load_dotenv | |
| from supabase import create_client | |
| import os | |
| # --- Supabase & Gemini --- | |
| load_dotenv() | |
| SUPABASE_URL = os.getenv("SUPABASE_URL") | |
| SUPABASE_KEY = os.getenv("SBASEKEY") | |
| API_KEY = os.getenv("GEMINI_API_KEY") | |
| supabase = create_client(SUPABASE_URL, SUPABASE_KEY) | |
| genai.configure(api_key=API_KEY) | |
| # --- Load data dari Supabase --- | |
| def fetch_data_from_supabase(): | |
| response = supabase.table("Maps").select("*").execute() | |
| return pd.DataFrame(response.data) | |
| df = fetch_data_from_supabase() | |
| # --- Ekstraksi Kata Kunci --- | |
| def extract_keywords(user_input): | |
| prompt = f""" | |
| Ekstrak 3–7 kata kunci penting dari deskripsi wisata berikut: | |
| "{user_input}" | |
| Tulis langsung sebagai list Python tanpa variabel apapun. | |
| """ | |
| try: | |
| response = genai.GenerativeModel("gemini-1.5-flash").generate_content(prompt) | |
| matches = re.findall(r'\[.*?\]', response.text) | |
| if matches: | |
| return ast.literal_eval(matches[0]) | |
| else: | |
| return [] | |
| except Exception as e: | |
| return [f"Error: {e}"] | |
| # --- Lokasi --- | |
| def get_coordinates_from_location(location_name): | |
| try: | |
| geolocator = Nominatim(user_agent="geoapi") | |
| location = geolocator.geocode(location_name, timeout=10) | |
| return (location.latitude, location.longitude) if location else (None, None) | |
| except GeocoderTimedOut: | |
| return (None, None) | |
| def get_location_name_from_coordinates(lat, lon): | |
| try: | |
| geolocator = Nominatim(user_agent="geoapi") | |
| location = geolocator.reverse((lat, lon), timeout=10) | |
| return location.address if location else "Tidak ditemukan" | |
| except GeocoderTimedOut: | |
| return "Tidak ditemukan" | |
| # --- Enhancement untuk deskripsi singkat --- | |
| def enhance_description_with_gemini(short_desc): | |
| prompt = f""" | |
| Deskripsi berikut terlalu singkat: "{short_desc}" | |
| Tolong kembangkan menjadi paragraf singkat (2–3 kalimat) yang menggambarkan keinginan wisata pengguna secara lebih lengkap. | |
| Contohnya: sebutkan suasana, aktivitas, atau lokasi ideal. | |
| """ | |
| try: | |
| response = genai.GenerativeModel("gemini-1.5-flash").generate_content(prompt) | |
| return response.text.strip() | |
| except Exception as e: | |
| return short_desc | |
| # --- TF-IDF dan Cosine Similarity --- | |
| def prepare_and_recommend(df, user_description): | |
| tfidf = TfidfVectorizer() | |
| tfidf_matrix = tfidf.fit_transform(df['deskripsi'].astype(str).tolist() + [user_description]) | |
| similarity = cosine_similarity(tfidf_matrix[-1], tfidf_matrix[:-1]).flatten() | |
| df['similarity'] = similarity | |
| return df.sort_values(by='similarity', ascending=False).head(10) | |
| # --- Jarak Lokasi --- | |
| def sort_by_nearest_location(df, user_lat, user_lon): | |
| df['distance_km'] = df.apply( | |
| lambda row: geodesic((user_lat, user_lon), (row['latitude'], row['longitude'])).km, | |
| axis=1 | |
| ) | |
| df['distance_km'] = df['distance_km'].round(2) | |
| return df.sort_values(by='distance_km') | |
| # --- Fungsi Utama --- | |
| def wisata_rekomendasi(deskripsi, lokasi): | |
| if df.empty: | |
| return "Data tidak tersedia.", pd.DataFrame([["Data tidak tersedia"]], columns=["nama"]) | |
| if len(deskripsi.strip().split()) < 3 or len(deskripsi.strip()) < 20: | |
| deskripsi = enhance_description_with_gemini(deskripsi) | |
| # Lokasi → Koordinat | |
| lat, lon = get_coordinates_from_location(lokasi) | |
| if lat is None or lon is None: | |
| return "Lokasi tidak ditemukan.", pd.DataFrame([["Lokasi tidak ditemukan"]], columns=["nama"]) | |
| # Tambahkan lokasi ke deskripsi | |
| deskripsi_lengkap = f"{deskripsi} di sekitar {lokasi}" | |
| keywords = extract_keywords(deskripsi_lengkap) | |
| if "Error:" in str(keywords): | |
| return f"Kata kunci gagal diambil: {keywords[0]}", pd.DataFrame([[keywords[0]]], columns=["nama"]) | |
| user_description_joined = " ".join(keywords) | |
| top_place = prepare_and_recommend(df.copy(), user_description_joined) | |
| top_place = top_place[top_place['total_ulasan'] > 10] | |
| sorted_place = sort_by_nearest_location(top_place, lat, lon) | |
| sorted_place = sorted_place[sorted_place["gambar"].apply(lambda x: isinstance(x, str) and x.startswith("https"))] | |
| # Urutkan berdasarkan similarity tertinggi dan tampilkan kolom similarity | |
| sorted_place = sorted_place.sort_values(by='similarity', ascending=False) | |
| return f"Kata kunci: {', '.join(keywords)}", sorted_place[[ | |
| "id", "nama", "alamat", "distance_km", "deskripsi", "harga", "rating", "total_ulasan", "gambar", "similarity" | |
| ]] | |
| # --- Gradio UI --- | |
| demo = gr.Interface( | |
| fn=wisata_rekomendasi, | |
| inputs=[ | |
| gr.Textbox(label="Deskripsi Wisata yang Anda Inginkan"), | |
| gr.Textbox(label="Lokasi Anda (Contoh: Cilacap, Jawa Tengah, Indonesia)"), | |
| ], | |
| outputs=[ | |
| gr.Textbox(label="Kata Kunci yang Diekstrak"), | |
| gr.Dataframe( | |
| headers=["id", "nama", "alamat", "distance_km", "deskripsi", "harga", "rating", "total_ulasan", "gambar", "similarity"], | |
| label="Rekomendasi Tempat Wisata" | |
| ) | |
| ], | |
| title="Sistem Rekomendasi Wisata", | |
| description="Masukkan deskripsi dan lokasi, lalu dapatkan rekomendasi tempat wisata terdekat beserta skor kecocokannya." | |
| ) | |
| demo.launch() | |