Spaces:
Sleeping
Sleeping
File size: 7,217 Bytes
d6f2ce5 1bd8b25 d6f2ce5 1bd8b25 d6f2ce5 1bd8b25 d6f2ce5 1bd8b25 d6f2ce5 ddd1563 d6f2ce5 ddd1563 d6f2ce5 ddd1563 e686e66 d6f2ce5 ddd1563 e686e66 ddd1563 e686e66 1bd8b25 e686e66 1bd8b25 e686e66 ddd1563 e686e66 ddd1563 1bd8b25 ddd1563 1bd8b25 e686e66 d6f2ce5 1bd8b25 d6f2ce5 e686e66 d6f2ce5 ddd1563 26b8bd4 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
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 = """
<div style="margin-bottom: 20px; text-align: center;">
<h3 style="color: #374151; margin: 0;">Here is what our recommendation system found for you:</h3>
</div>
"""
html_content += '<div style="display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;">'
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 = '<div style="width: 100%; height: 180px; background: #eee; border-radius: 15px; display: flex; align-items: center; justify-content: center;">No Image</div>'
else:
img_tag = f'<img src="{img_url}" style="width: 100%; height: auto; border-radius: 15px; margin-bottom: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.1);">'
# 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"""
<div style="width: 280px; padding: 20px; background-color: white; border: 1px solid #e5e7eb; border-radius: 20px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); display: flex; flex-direction: column; align-items: flex-start; font-family: sans-serif;">
{img_tag}
<h3 style="margin: 0 0 5px 0; color: #1f2937; font-size: 18px;">{row['trackName']}</h3>
<p style="margin: 0 0 10px 0; color: #6b7280; font-size: 14px; font-weight: 500;">{row['primaryGenreName']}</p>
<div style="display: flex; gap: 10px; margin-bottom: 10px; font-size: 13px; color: #4b5563;">
<span style="background: #f3f4f6; padding: 4px 8px; border-radius: 6px;">{rating_text}</span>
<span style="background: #f3f4f6; padding: 4px 8px; border-radius: 6px;">π£οΈ {lang_text}</span>
</div>
<p style="font-size: 13px; color: #6b7280; margin-bottom: 15px; line-height: 1.4;">{desc}</p>
<a href="{url}" target="_blank" style="margin-top: auto; width: 100%; text-align: center; background-color: #2563eb; color: white; padding: 10px 0; border-radius: 10px; text-decoration: none; font-weight: bold; transition: background 0.2s;">Get App βοΈ</a>
</div>
"""
html_content += card_html
html_content += '</div>'
return html_content
except Exception as e:
return f"<div style='color:red;'>Error: {str(e)}</div>"
# --- 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("""
<div style="display: flex; justify-content: center; align-items: center;">
<video width="600" controls style="border-radius: 10px; box-shadow: 0 4px 10px rgba(0,0,0,0.1);">
<source src="https://huggingface.co/spaces/Liori25/ReccomendationSystemForApps/resolve/main/PresentationVideo.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
""")
# --- FOOTER ---
gr.Markdown("""<div style="text-align: center; margin-top: 40px; color: #9ca3af; font-size: 14px;">app developed by Karin M & Lior F</div>""")
# 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()) |