Aitherway2 / app.py
GwFirman's picture
Update app.py
0db6247 verified
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()