|
|
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 |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
def fetch_data_from_supabase(): |
|
|
response = supabase.table("Maps").select("*").execute() |
|
|
return pd.DataFrame(response.data) |
|
|
|
|
|
df = fetch_data_from_supabase() |
|
|
|
|
|
|
|
|
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}"] |
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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') |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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"]) |
|
|
|
|
|
|
|
|
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"))] |
|
|
|
|
|
|
|
|
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" |
|
|
]] |
|
|
|
|
|
|
|
|
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() |
|
|
|