import streamlit as st import pandas as pd import pickle from nltk.tokenize import word_tokenize from nltk.stem import WordNetLemmatizer from typing import Dict, Any, List import nltk import os # --- NLTK PATH FIX (CRITICAL) --- # setup.sh, NLTK verilerini 'src/' içine indirir. # Uygulamanın da bu klasöre bakması gerektiğini belirtiyoruz. NLTK_DATA_PATH = os.path.join(os.getcwd(), 'src') if NLTK_DATA_PATH not in nltk.data.path: # 'src/' yolunu NLTK arama yollarına ekliyoruz. nltk.data.path.append(NLTK_DATA_PATH) # --- Streamlit Sayfa Ayarları --- st.set_page_config( # Sayfa başlığına bina emojisi (🏢) eklendi page_title="🏢 Hotel Recommendation System", layout="wide", initial_sidebar_state="collapsed" ) # ---------------------------------------------------- # 1. Veri ve NLP Araçlarını Yükleme # ---------------------------------------------------- # Verinin her etkileşimde yeniden yüklenmesini engellemek için önbelleğe alma @st.cache_resource def load_data(): """Pickle dosyalarını yükler ve DataFrame ile NLP araçlarını döndürür.""" try: # Dosyalar 'src/' içinden okunuyor (Lütfen dosya yollarınızın doğru olduğundan emin olun) with open('src/hotel_data.pkl', 'rb') as file: df_loaded = pickle.load(file) with open('src/nlp_tools.pkl', 'rb') as file: nlp_tools_loaded = pickle.load(file) return { 'df': df_loaded, 'stop_words': nlp_tools_loaded['stop_words'], 'lemmatizer': nlp_tools_loaded['lemmatizer'] } except FileNotFoundError as e: st.error(f"Error: Required file not found: {e.filename}. Please ensure all required files are in the 'src/' directory.") return None except Exception as e: st.error(f"An error occurred during loading: {e}") return None # Load the data bundle and unpack components data_bundle = load_data() if data_bundle is not None: df = data_bundle['df'] # NLP araçları global değişkenlere atanır STOP_WORDS = data_bundle['stop_words'] LEMMATIZER = data_bundle['lemmatizer'] else: # Veri yüklenemezse uygulamayı durdur st.stop() # ---------------------------------------------------- # 2. Tavsiye Fonksiyonu (Optimize Edilmiş) # ---------------------------------------------------- def recommend_hotel(location: str, description: str, data_df: pd.DataFrame) -> pd.DataFrame: """Kullanıcı açıklamasına göre otel benzerliğini hesaplar ve en iyi 5 öneriyi döndürür.""" if not isinstance(description, str): return pd.DataFrame({'Error': ['Description must be a string.']}) # 1. Kullanıcı Açıklamasını İşleme # NLTK, ayarlanmış yol sayesinde verileri bulacaktır. description_tokens = word_tokenize(description.lower()) user_processed_set = set() for word in description_tokens: if word not in STOP_WORDS: user_processed_set.add(LEMMATIZER.lemmatize(word)) if not user_processed_set: return pd.DataFrame({'Error': ['Please enter a more descriptive query.']}) # 2. Konuma Göre Filtreleme country = data_df[data_df['Country'] == location.lower()].copy() if country.empty: return pd.DataFrame({'Error': [f"No hotels found in '{location}'."]}) # 3. Benzerlik Hesaplama (Küme Kesişimi) similarity_scores = country['Processed_Tags'].apply( lambda hotel_tags: len(hotel_tags.intersection(user_processed_set))) country['similarity'] = similarity_scores # 4. Sıralama ve Filtreleme country.sort_values(by=['similarity', 'Average_Score'], ascending=[False, False], inplace=True) country.drop_duplicates(subset='Hotel_Name', keep='first', inplace=True) country.reset_index(drop=True, inplace=True) return country[["Hotel_Name", "Average_Score", "Hotel_Address"]].head(5) # ---------------------------------------------------- # 3. Streamlit Arayüzü # ---------------------------------------------------- # Ana başlıkta bina emojisi (🏢) st.title("🏢 Hotel Recommendation System") st.markdown("Find the top 5 hotels based on your preferred location and description.") # --- Kullanıcı Girişleri --- st.subheader("Find Your Optimal Hotel") # Mevcut ülke listesini alma available_countries = sorted(df['Country'].unique().tolist()) default_country = available_countries[0] if available_countries else "" col1, col2 = st.columns(2) with col1: location = st.selectbox( "Select Location (Country)", options=available_countries, # Hata düzeltildi index=available_countries.index(default_country) if default_country else 0 ) with col2: description = st.text_area( "Preference Description", placeholder="E.g., romantic trip with great breakfast and spa, or: business needs quiet room and gym", height=100 ) # --- Buton ve Çıktı --- if st.button("Get Recommendations", type="primary"): if location and description: # Tavsiye fonksiyonunu çağır recommendations_df = recommend_hotel(location, description, df) st.subheader("Top Recommended Hotels") # Sonuçları görüntüle if 'Error' in recommendations_df.columns: st.error(recommendations_df.iloc[0]['Error']) else: # Sütun isimlerini daha okunaklı hale getir recommendations_df.columns = ["Hotel Name", "Average Score", "Address"] st.dataframe(recommendations_df, use_container_width=True) else: st.warning("Please enter both location and description.")