Liori25 commited on
Commit
d6f2ce5
·
verified ·
1 Parent(s): e18af7d

Upload 3 files

Browse files
Files changed (3) hide show
  1. app (1).py +180 -0
  2. apps_clustered (3).pkl +3 -0
  3. requirements (3).txt +5 -0
app (1).py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ import ast
5
+ from sentence_transformers import SentenceTransformer
6
+ from sklearn.metrics.pairwise import cosine_similarity
7
+
8
+ # --- 1. Load Data ---
9
+ print("⏳ Loading Data...")
10
+ try:
11
+ df = pd.read_pickle("apps_clustered.pkl")
12
+ print("✅ Data Loaded")
13
+ except Exception as e:
14
+ print(f"❌ Error loading data: {e}")
15
+ df = pd.DataFrame()
16
+
17
+ # --- Column Setup ---
18
+ def get_col_name(candidates, df_cols):
19
+ return next((col for col in candidates if col in df_cols), None)
20
+
21
+ image_col = get_col_name(['artworkUrl512', 'artworkUrl100', 'artworkUrl60', 'image_url', 'icon'], df.columns)
22
+ desc_col = get_col_name(['description', 'longDescription', 'shortDescription', 'summary'], df.columns)
23
+ lang_col = get_col_name(['languageCodesISO2A', 'primaryLanguage', 'languages', 'language'], df.columns)
24
+ rating_col = 'averageUserRating'
25
+
26
+ print(f"🔍 Mapped Columns: Image='{image_col}', Desc='{desc_col}', Rating='{rating_col}', Lang='{lang_col}'")
27
+
28
+ print("⏳ Loading AI Model...")
29
+ model = SentenceTransformer('all-MiniLM-L6-v2')
30
+ print("✅ Ready!")
31
+
32
+ # --- 2. The Logic ---
33
+ def search_apps(user_query):
34
+ if not user_query:
35
+ return ""
36
+
37
+ try:
38
+ # Search
39
+ user_vector = model.encode(user_query).reshape(1, -1)
40
+ app_embeddings = np.vstack(df["text_embedding"].values)
41
+ scores = cosine_similarity(user_vector, app_embeddings).flatten()
42
+
43
+ df_results = df.copy()
44
+ df_results["similarity_score"] = scores
45
+ top_results = df_results.sort_values(by="similarity_score", ascending=False).head(3)
46
+
47
+ # --- HTML GENERATION ---
48
+
49
+ # 1. The Header Message
50
+ html_content = """
51
+ <div style="margin-bottom: 20px; text-align: center;">
52
+ <h3 style="color: #374151; margin: 0;">Here is what our recommendation system found for you:</h3>
53
+ </div>
54
+ """
55
+
56
+ # 2. The Cards Container
57
+ html_content += '<div style="display: flex; gap: 20px; justify-content: center; flex-wrap: wrap;">'
58
+
59
+ for _, row in top_results.iterrows():
60
+ # Image Logic
61
+ img_url = row.get(image_col, "")
62
+ if pd.isna(img_url) or not isinstance(img_url, str):
63
+ img_tag = '<div style="width: 100%; height: 180px; background: #eee; border-radius: 15px; display: flex; align-items: center; justify-content: center;">No Image</div>'
64
+ else:
65
+ 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);">'
66
+
67
+ # Rating Logic
68
+ score = row.get(rating_col, 0)
69
+ if pd.isna(score) or score == 0:
70
+ rating_text = "No ratings yet"
71
+ else:
72
+ rating_text = f"{float(score):.1f} ⭐"
73
+
74
+ # Language Logic
75
+ lang_val = row.get(lang_col, "N/A")
76
+ if pd.isna(lang_val): lang_val = "N/A"
77
+ if isinstance(lang_val, str) and lang_val.startswith('[') and lang_val.endswith(']'):
78
+ try: lang_val = ast.literal_eval(lang_val)
79
+ except: pass
80
+
81
+ if isinstance(lang_val, list):
82
+ if len(lang_val) > 1:
83
+ lang_text = f"{lang_val[0]} and more"
84
+ elif len(lang_val) == 1:
85
+ lang_text = str(lang_val[0])
86
+ else:
87
+ lang_text = "N/A"
88
+ else:
89
+ lang_text = str(lang_val)
90
+
91
+ # Description Logic
92
+ desc = str(row.get(desc_col, "No description"))
93
+ if len(desc) > 120: desc = desc[:120] + "..."
94
+
95
+ # Link Logic
96
+ url = row.get('trackViewUrl', '#')
97
+ if pd.isna(url) and 'trackId' in row: url = f"https://apps.apple.com/app/id{row['trackId']}"
98
+
99
+ # Card HTML
100
+ card_html = f"""
101
+ <div style="
102
+ width: 280px;
103
+ padding: 20px;
104
+ background-color: white;
105
+ border: 1px solid #e5e7eb;
106
+ border-radius: 20px;
107
+ box-shadow: 0 10px 25px rgba(0,0,0,0.05);
108
+ display: flex;
109
+ flex-direction: column;
110
+ align-items: flex-start;
111
+ font-family: sans-serif;
112
+ ">
113
+ {img_tag}
114
+ <h3 style="margin: 0 0 5px 0; color: #1f2937; font-size: 18px;">{row['trackName']}</h3>
115
+ <p style="margin: 0 0 10px 0; color: #6b7280; font-size: 14px; font-weight: 500;">{row['primaryGenreName']}</p>
116
+
117
+ <div style="display: flex; gap: 10px; margin-bottom: 10px; font-size: 13px; color: #4b5563;">
118
+ <span style="background: #f3f4f6; padding: 4px 8px; border-radius: 6px;">{rating_text}</span>
119
+ <span style="background: #f3f4f6; padding: 4px 8px; border-radius: 6px;">🗣️ {lang_text}</span>
120
+ </div>
121
+
122
+ <p style="font-size: 13px; color: #6b7280; margin-bottom: 15px; line-height: 1.4;">{desc}</p>
123
+
124
+ <a href="{url}" target="_blank" style="
125
+ margin-top: auto;
126
+ width: 100%;
127
+ text-align: center;
128
+ background-color: #2563eb;
129
+ color: white;
130
+ padding: 10px 0;
131
+ border-radius: 10px;
132
+ text-decoration: none;
133
+ font-weight: bold;
134
+ transition: background 0.2s;
135
+ ">Get App ↗️</a>
136
+ </div>
137
+ """
138
+ html_content += card_html
139
+
140
+ html_content += '</div>'
141
+ return html_content
142
+
143
+ except Exception as e:
144
+ return f"<div style='color:red;'>Error: {str(e)}</div>"
145
+
146
+ # --- 3. The UI ---
147
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
148
+
149
+ gr.Markdown("# 📱 AI App Recommender")
150
+ gr.Markdown("Describe what you need, and the AI will find the best apps for you.")
151
+
152
+ with gr.Column():
153
+ with gr.Row():
154
+ txt_input = gr.Textbox(
155
+ show_label=False,
156
+ placeholder="Type here... (e.g., 'I need a puzzle game for kids')",
157
+ scale=4
158
+ )
159
+ btn_submit = gr.Button("🚀 Find Apps", variant="primary", scale=1)
160
+
161
+ gr.Examples(
162
+ examples=[["I want a timer for my kitchen"], ["A game to learn math"]],
163
+ inputs=txt_input
164
+ )
165
+
166
+ output_html = gr.HTML(label="Recommended Apps")
167
+
168
+ # --- FOOTER ---
169
+ gr.Markdown(
170
+ """
171
+ <div style="text-align: center; margin-top: 40px; color: #9ca3af; font-size: 14px;">
172
+ app developed by Karin M & Lior F
173
+ </div>
174
+ """
175
+ )
176
+
177
+ btn_submit.click(fn=search_apps, inputs=txt_input, outputs=output_html)
178
+ txt_input.submit(fn=search_apps, inputs=txt_input, outputs=output_html)
179
+
180
+ demo.launch()
apps_clustered (3).pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd952682cf9afbb479ab37046f51bf20ab8be317d13193124512e3c014449344
3
+ size 33947133
requirements (3).txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ pandas
2
+ numpy
3
+ scikit-learn
4
+ sentence-transformers
5
+ gradio