import gradio as gr import pandas as pd import numpy as np import ast from sentence_transformers import SentenceTransformer from sklearn.metrics.pairwise import cosine_similarity # --- 1. Load Data --- print("⏳ Loading Data...") try: df = pd.read_pickle("apps_clustered.pkl") print("✅ Data Loaded") except Exception as e: print(f"❌ Error loading data: {e}") df = pd.DataFrame() # --- Column Setup --- def get_col_name(candidates, df_cols): return next((col for col in candidates if col in df_cols), None) image_col = get_col_name(['artworkUrl512', 'artworkUrl100', 'artworkUrl60', 'image_url', 'icon'], df.columns) desc_col = get_col_name(['description', 'longDescription', 'shortDescription', 'summary'], df.columns) lang_col = get_col_name(['languageCodesISO2A', 'primaryLanguage', 'languages', 'language'], df.columns) rating_col = 'averageUserRating' print("⏳ Loading AI Model...") model = SentenceTransformer('all-MiniLM-L6-v2') print("✅ Ready!") # --- 2. The Logic --- def search_apps(user_query): if not user_query: return "" try: # Search user_vector = model.encode(user_query).reshape(1, -1) app_embeddings = np.vstack(df["text_embedding"].values) scores = cosine_similarity(user_vector, app_embeddings).flatten() df_results = df.copy() df_results["similarity_score"] = scores top_results = df_results.sort_values(by="similarity_score", ascending=False).head(3) # --- HTML GENERATION --- html_content = """

Here is what our recommendation system found for you:

""" html_content += '
' for _, row in top_results.iterrows(): # Image Logic img_url = row.get(image_col, "") if pd.isna(img_url) or not isinstance(img_url, str): img_tag = '
No Image
' else: img_tag = f'' # Rating Logic score = row.get(rating_col, 0) rating_text = "No ratings yet" if (pd.isna(score) or score == 0) else f"{float(score):.1f} ⭐" # Language Logic lang_val = row.get(lang_col, "N/A") if pd.isna(lang_val): lang_val = "N/A" if isinstance(lang_val, str) and lang_val.startswith('[') and lang_val.endswith(']'): try: lang_val = ast.literal_eval(lang_val) except: pass if isinstance(lang_val, list): lang_text = f"{lang_val[0]} and more" if len(lang_val) > 1 else (str(lang_val[0]) if len(lang_val) == 1 else "N/A") else: lang_text = str(lang_val) # Description Logic desc = str(row.get(desc_col, "No description")) if len(desc) > 120: desc = desc[:120] + "..." # Link Logic url = row.get('trackViewUrl', '#') if pd.isna(url) and 'trackId' in row: url = f"https://apps.apple.com/app/id{row['trackId']}" # Card HTML card_html = f"""
{img_tag}

{row['trackName']}

{row['primaryGenreName']}

{rating_text} 🗣️ {lang_text}

{desc}

Get App ↗️
""" html_content += card_html html_content += '
' return html_content except Exception as e: return f"
Error: {str(e)}
" # --- 3. The UI (Rearranged Layout) --- with gr.Blocks() as demo: # Title stays at the absolute top (Header) gr.Markdown("# 📱 AI App Recommender") # TABS are now at the top of the content with gr.Tabs(): # --- TAB 1: SEARCH --- with gr.Tab("🔍 Find Apps"): # Description is now INSIDE the tab, above the search bar gr.Markdown("Describe what you need, and the AI will find the best apps for you.") with gr.Column(): with gr.Row(): txt_input = gr.Textbox(show_label=False, placeholder="Type here... (e.g., 'I need a puzzle game for kids')", scale=4) btn_submit = gr.Button("🚀 Find Apps", variant="primary", scale=1) gr.Examples(examples=[["I want a timer for my kitchen"], ["A game to learn math"]], inputs=txt_input) output_html = gr.HTML(label="Recommended Apps") # --- TAB 2: VIDEO (Smaller & Centered) --- with gr.Tab("🎥 Video Presentation"): gr.Markdown("### Watch our project presentation below:") # Smaller video (600px) and centered gr.HTML("""
""") # --- FOOTER --- gr.Markdown("""
app developed by Karin M & Lior F
""") # Logic connection btn_submit.click(fn=search_apps, inputs=txt_input, outputs=output_html) txt_input.submit(fn=search_apps, inputs=txt_input, outputs=output_html) # --- Launch --- demo.launch(theme=gr.themes.Soft())