ssenaay commited on
Commit
77e28c5
·
verified ·
1 Parent(s): 8ed688c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -745
app.py CHANGED
@@ -6,14 +6,16 @@ from sentence_transformers import SentenceTransformer, util
6
  import torch
7
  import re
8
 
9
- print("--- Film Öneri Sistemi Başlatılıyor (Premium Arayüz) ---")
 
 
 
10
 
11
- # --- ADIM 1-3: Veri yükleme ve model hazırlama kodları aynı kalıyor ---
12
  csv_file_name = "imdb-top-rated-movies-user-rated.csv"
13
  file_path = os.path.join(".", csv_file_name)
14
 
15
  if not os.path.exists(file_path):
16
- print(f"HATA: '{csv_file_name}' dosyası '{file_path}' yolunda bulunamadı.")
17
  exit(1)
18
 
19
  try:
@@ -22,8 +24,14 @@ try:
22
  except Exception as e:
23
  print(f"HATA: CSV dosyası yüklenirken hata oluştu: {e}")
24
  exit(1)
 
 
 
 
 
25
 
26
  df_filtered = df[['Title', 'IMDb Rating', 'Tags', 'Director', 'Stars', 'Votes', 'Description', 'Poster URL']].copy()
 
27
  df_filtered['Stars'].fillna('', inplace=True)
28
  df_filtered['Description'].fillna('', inplace=True)
29
  df_filtered['Poster URL'].fillna('', inplace=True)
@@ -64,17 +72,22 @@ def map_to_main_genres(tag_list):
64
  def clean_and_split(text_series):
65
  if pd.isna(text_series):
66
  return []
 
67
  item = str(text_series)
68
  item = item.replace('"', '').replace("'", '').strip()
69
  item = item.replace('sci, fi', 'sci-fi')
 
70
  split_items = [s.strip().lower() for s in item.split(',') if s.strip()]
71
  return split_items
72
 
 
73
  df_filtered['Tags_cleaned_raw'] = df_filtered['Tags'].apply(clean_and_split)
74
  df_filtered['Director_cleaned'] = df_filtered['Director'].apply(clean_and_split)
75
  df_filtered['Stars_cleaned'] = df_filtered['Stars'].apply(clean_and_split)
 
76
  df_filtered['Tags_cleaned'] = df_filtered['Tags_cleaned_raw'].apply(map_to_main_genres)
77
 
 
78
  def convert_votes_to_numeric(votes_str):
79
  if isinstance(votes_str, str):
80
  votes_str = votes_str.replace(",", "")
@@ -97,28 +110,39 @@ df_filtered['Combined_Text'] = df_filtered['Title'] + ". " + \
97
  df_filtered['Director_cleaned'].apply(lambda x: ", ".join(x)) + ". " + \
98
  df_filtered['Stars_cleaned'].apply(lambda x: ", ".join(x))
99
 
 
 
 
 
 
 
100
  model_name = 'sentence-transformers/all-MiniLM-L6-v2'
101
  try:
102
- # Hugging Face Space'lerde model yükleme optimizasyonu
103
- sentence_model = SentenceTransformer(model_name, device='cpu')
104
  print(f"'{model_name}' modeli başarıyla yüklendi.")
105
  except Exception as e:
106
  print(f"HATA: Sentence Transformer modeli yüklenirken hata oluştu: {e}")
107
- print("Model yükleme hatası, uygulama devam ediyor...")
108
- sentence_model = None
109
 
110
  embeddings_file_path = os.path.join(".", "film_embeddings.npy")
111
  if not os.path.exists(embeddings_file_path):
112
- print(f"HATA: '{embeddings_file_path}' dosyası bulunamadı.")
113
  exit(1)
114
 
115
  try:
116
  film_embeddings = torch.from_numpy(np.load(embeddings_file_path))
117
- print("Film embedding'leri başarıyla yüklendi.")
118
  except Exception as e:
119
  print(f"HATA: film_embeddings.npy yüklenirken hata oluştu: {e}")
120
  exit(1)
121
 
 
 
 
 
 
 
 
122
  director_popularity = {}
123
  for index, row in df_filtered.iterrows():
124
  for director in row['Director_cleaned']:
@@ -129,9 +153,15 @@ for index, row in df_filtered.iterrows():
129
  for star in row['Stars_cleaned']:
130
  star_popularity[star] = star_popularity.get(star, 0) + row['Votes_numeric']
131
 
 
132
  all_tags = sorted(list(set([tag for sublist in df_filtered['Tags_cleaned'] for tag in sublist if tag in genre_mapping])))
 
 
 
133
  all_directors = sorted(list(director_popularity.keys()), key=lambda d: director_popularity[d], reverse=True)
134
  all_stars = sorted(list(star_popularity.keys()), key=lambda s: star_popularity[s], reverse=True)
 
 
135
 
136
  def get_movie_recommendations(selected_tags, selected_directors, selected_stars, min_imdb_rating_slider, num_recommendations_slider, search_text=""):
137
 
@@ -142,57 +172,62 @@ def get_movie_recommendations(selected_tags, selected_directors, selected_stars,
142
  print(f"Minimum IMDb Puanı: {min_imdb_rating_slider}")
143
  print(f"Öneri Sayısı: {num_recommendations_slider}")
144
  print(f"Arama Metni: '{search_text}'")
 
145
 
146
  selected_tags_list = list(selected_tags) if selected_tags else []
147
  selected_directors_list = list(selected_directors) if selected_directors else []
148
  selected_stars_list = list(selected_stars) if selected_stars else []
149
 
150
  recommendations_df = df_filtered.copy()
 
151
  recommendations_df = recommendations_df[recommendations_df['IMDb Rating'] >= min_imdb_rating_slider]
 
152
 
153
  if selected_tags_list:
154
  recommendations_df = recommendations_df[
155
  recommendations_df['Tags_cleaned'].apply(lambda x: any(tag in x for tag in selected_tags_list))
156
  ]
 
157
 
158
  if selected_directors_list:
159
  recommendations_df = recommendations_df[
160
  recommendations_df['Director_cleaned'].apply(lambda x: any(director in x for director in selected_directors_list))
161
  ]
 
162
 
163
  if selected_stars_list:
164
  recommendations_df = recommendations_df[
165
  recommendations_df['Stars_cleaned'].apply(lambda x: any(star in x for star in selected_stars_list))
166
  ]
 
167
 
168
  if search_text and len(recommendations_df) > 0:
169
- if sentence_model is None:
170
- print("NLP modeli yüklenemedi, sadece filtreleme yapılıyor...")
171
- # Model yoksa sadece filtreleme yap, NLP araması yapma
172
- else:
173
- print(f"'{search_text}' için NLP benzerlik araması yapılıyor...")
174
- try:
175
- query_embedding = sentence_model.encode(search_text, convert_to_tensor=True)
176
- except Exception as e:
177
- print(f"HATA: Arama metni embedding'i oluşturulurken hata oluştu: {e}")
178
- return "Arama metni işlenirken bir hata oluştu. Lütfen tekrar deneyin."
179
 
180
- filtered_indices = recommendations_df.index.tolist()
181
- if not filtered_indices or len(film_embeddings) == 0:
182
- print("HATA: Filtrelenmiş film indeksi bulunamadı veya embedding'ler boş.")
183
- return "Filtreleme sonrası film bulunamadı."
184
-
185
- try:
186
- current_film_embeddings = film_embeddings[filtered_indices]
187
- cosine_scores = util.cos_sim(query_embedding, current_film_embeddings)[0]
188
- recommendations_df['Similarity_Score'] = cosine_scores.cpu().numpy()
189
- recommendations_df = recommendations_df.sort_values(
190
- by=['Similarity_Score', 'IMDb Rating', 'Votes_numeric'],
191
- ascending=[False, False, False]
192
- ).reset_index(drop=True)
193
- except Exception as e:
194
- print(f"HATA: NLP benzerlik hesaplanırken hata oluştu: {e}")
195
- return "Benzerlik hesaplanırken bir hata oluştu. Lütfen tekrar deneyin."
 
 
 
 
 
 
 
 
196
 
197
  if not search_text:
198
  recommendations_df = recommendations_df.sort_values(
@@ -203,22 +238,11 @@ def get_movie_recommendations(selected_tags, selected_directors, selected_stars,
203
  top_recommendations = recommendations_df.head(num_recommendations_slider)
204
 
205
  if top_recommendations.empty:
206
- return """
207
- <div style="text-align: center; padding: 60px 20px; background: linear-gradient(135deg, #1a1a1a 0%, #2d1810 100%); border-radius: 16px; border: 2px solid #ff6b35;">
208
- <div style="font-size: 64px; margin-bottom: 20px;">🎬</div>
209
- <h2 style="color: #ff6b35; margin-bottom: 10px; font-size: 28px;">Sonuç Bulunamadı</h2>
210
- <p style="color: #d4d4d4; font-size: 16px;">Seçtiğiniz kriterlere uygun film bulunamadı. Filtreleri değiştirerek tekrar deneyin.</p>
211
- </div>
212
- """
213
  else:
214
- html_output = f"""
215
- <div style="margin-bottom: 25px; padding: 20px; background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%); border-radius: 12px; box-shadow: 0 8px 32px rgba(255, 107, 53, 0.3);">
216
- <h2 style="margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 700; text-shadow: 0 2px 4px rgba(0,0,0,0.1);">
217
- ✨ Sizin İçin {len(top_recommendations)} Film Seçtik
218
- </h2>
219
- </div>
220
- """
221
-
222
  for idx, row in top_recommendations.iterrows():
223
  directors_str = ", ".join([d.title() for d in row['Director_cleaned']])
224
  stars_str = ", ".join([s.title() for s in row['Stars_cleaned']])
@@ -226,689 +250,106 @@ def get_movie_recommendations(selected_tags, selected_directors, selected_stars,
226
 
227
  similarity_info = ""
228
  if 'Similarity_Score' in row and search_text:
229
- sim_percentage = int(row['Similarity_Score'] * 100)
230
- similarity_info = f"""
231
- <div style="margin-top: 8px; padding: 8px 12px; background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%); border-radius: 8px; display: inline-block;">
232
- <span style="color: #1a1a1a; font-weight: 700; font-size: 14px;">🎯 Eşleşme: %{sim_percentage}</span>
233
- </div>
234
- """
235
-
236
- rating_color = "#4ade80" if row['IMDb Rating'] >= 8.0 else "#fbbf24" if row['IMDb Rating'] >= 7.5 else "#fb923c"
237
 
238
  poster_html = f"""
239
- <div style="width: 140px; height: 210px; background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%); border-radius: 12px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; color: #888; font-size: 0.85em; line-height: 1.3; padding: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.4); border: 2px solid #3a3a3a;">
240
- <div style="font-size: 32px; margin-bottom: 10px;">🎬</div>
241
- <span style="font-weight: 600; color: #ddd; margin-bottom: 5px;">{row['Title'][:30]}...</span>
242
- <span style="color: #999; font-size: 0.8em;">Poster Yok</span>
243
  </div>
244
  """
245
 
246
  html_output += f"""
247
- <div style="display: flex; margin-bottom: 20px; border: 2px solid #3a3a3a; padding: 20px; border-radius: 16px; background: linear-gradient(135deg, #1a1a1a 0%, #252525 100%); box-shadow: 0 8px 24px rgba(0,0,0,0.3); transition: all 0.3s ease; position: relative; overflow: hidden;">
248
- <div style="position: absolute; top: 0; left: 0; width: 6px; height: 100%; background: linear-gradient(180deg, #ff6b35 0%, #ff8c42 100%);"></div>
249
- <div style="flex-shrink: 0; margin-right: 20px; margin-left: 6px;">
250
  {poster_html}
251
  </div>
252
  <div style="flex-grow: 1;">
253
- <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
254
- <h3 style="margin: 0; color: #ffffff; font-size: 22px; font-weight: 700;">{row['Title']}</h3>
255
- <div style="background: {rating_color}; padding: 6px 12px; border-radius: 8px; display: inline-flex; align-items: center; gap: 4px;">
256
- <span style="font-size: 16px;"></span>
257
- <span style="color: #1a1a1a; font-weight: 700; font-size: 16px;">{row['IMDb Rating']:.1f}</span>
258
- </div>
259
- </div>
260
-
261
- <div style="display: flex; gap: 16px; margin-bottom: 12px; flex-wrap: wrap;">
262
- <div style="background: rgba(255, 107, 53, 0.15); padding: 8px 14px; border-radius: 8px; border: 1px solid rgba(255, 107, 53, 0.3);">
263
- <span style="color: #ff8c42; font-weight: 600;">🗳️ {int(row['Votes_numeric']):,} Oy</span>
264
- </div>
265
- {similarity_info}
266
- </div>
267
-
268
- <div style="margin-bottom: 10px;">
269
- <span style="color: #ff8c42; font-weight: 600; font-size: 14px;">🎬 Yönetmen:</span>
270
- <span style="color: #d4d4d4; font-size: 14px; margin-left: 8px;">{directors_str if directors_str else 'Bilinmiyor'}</span>
271
- </div>
272
-
273
- <div style="margin-bottom: 10px;">
274
- <span style="color: #ff8c42; font-weight: 600; font-size: 14px;">⭐ Oyuncular:</span>
275
- <span style="color: #d4d4d4; font-size: 14px; margin-left: 8px;">{stars_str if stars_str else 'Bilinmiyor'}</span>
276
- </div>
277
-
278
- <div style="display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px;">
279
- {''.join([f'<span style="background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%); color: #1a1a1a; padding: 6px 12px; border-radius: 20px; font-size: 13px; font-weight: 600; box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3);">{tag.title()}</span>' for tag in row['Tags_cleaned']])}
280
- </div>
281
  </div>
282
  </div>
283
  """
284
  return html_output
285
 
286
- # --- ADIM 5: Premium Gradio Arayüzü ---
287
- # Özel tema oluştur - tüm mor/mavi renkleri turuncu yap
288
- custom_theme = gr.themes.Base(
289
- primary_hue=gr.themes.colors.orange,
290
- secondary_hue=gr.themes.colors.orange,
291
- neutral_hue=gr.themes.colors.slate,
292
- ).set(
293
- button_primary_background_fill="*primary_500",
294
- button_primary_background_fill_hover="*primary_400",
295
- button_primary_text_color="white",
296
- button_primary_text_color_dark="white",
297
- checkbox_label_background_fill="*neutral_800",
298
- checkbox_label_background_fill_dark="*neutral_800",
299
- checkbox_label_background_fill_hover="*neutral_700",
300
- checkbox_label_background_fill_selected="*primary_500",
301
- checkbox_label_background_fill_selected_dark="*primary_500",
302
- checkbox_label_text_color_selected="white",
303
- checkbox_label_border_color_selected="*primary_500",
304
- )
305
-
306
- with gr.Blocks(theme=custom_theme, head="""
307
- <script>
308
- document.addEventListener('DOMContentLoaded', function() {
309
- function updateSliderProgress(slider) {
310
- const min = parseFloat(slider.min);
311
- const max = parseFloat(slider.max);
312
- const value = parseFloat(slider.value);
313
- const progress = ((value - min) / (max - min)) * 100;
314
- slider.style.setProperty('--slider-progress', progress + '%');
315
-
316
- // Tüm slider container'larını güncelle
317
- const sliderContainer = slider.closest('.gr-slider');
318
- if (sliderContainer) {
319
- sliderContainer.style.setProperty('--slider-progress', progress + '%');
320
- }
321
- }
322
-
323
- function forceOrangeTheme() {
324
- // Tüm mor/mavi elementleri bul ve turuncu yap
325
- const purpleElements = document.querySelectorAll('[style*="rgb(99, 102, 241)"], [style*="rgb(139, 92, 246)"], [style*="#6366f1"], [style*="#8b5cf6"]');
326
- purpleElements.forEach(el => {
327
- if (el.getAttribute('aria-checked') === 'true') {
328
- el.style.background = 'linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%)';
329
- el.style.color = 'white';
330
- } else {
331
- el.style.background = '#2a2a2a';
332
- el.style.color = '#d4d4d4';
333
- }
334
- });
335
- }
336
-
337
- // Tüm slider'ları bul ve event listener ekle
338
- const sliders = document.querySelectorAll('input[type="range"]');
339
- sliders.forEach(slider => {
340
- updateSliderProgress(slider);
341
- slider.addEventListener('input', function() {
342
- updateSliderProgress(this);
343
- });
344
- });
345
-
346
- // Gradio component'leri yüklendiğinde de çalıştır
347
- const observer = new MutationObserver(function(mutations) {
348
- mutations.forEach(function(mutation) {
349
- if (mutation.type === 'childList') {
350
- const newSliders = mutation.target.querySelectorAll('input[type="range"]');
351
- newSliders.forEach(slider => {
352
- updateSliderProgress(slider);
353
- slider.addEventListener('input', function() {
354
- updateSliderProgress(this);
355
- });
356
- });
357
-
358
- // Yeni elementler eklendiğinde tema kontrolü yap
359
- setTimeout(forceOrangeTheme, 100);
360
- }
361
- });
362
- });
363
-
364
- observer.observe(document.body, {
365
- childList: true,
366
- subtree: true
367
- });
368
-
369
- // Sayfa yüklendiğinde tema kontrolü yap
370
- setTimeout(forceOrangeTheme, 500);
371
- setInterval(forceOrangeTheme, 1000);
372
- });
373
- </script>
374
- """, css="""
375
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
376
-
377
- .gradio-container {
378
- max-width: 1400px !important;
379
- font-family: 'Inter', 'Segoe UI', sans-serif !important;
380
- background: #0a0a0a !important;
381
- }
382
-
383
- h1 {
384
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 50%, #ffa94d 100%);
385
- -webkit-background-clip: text;
386
- -webkit-text-fill-color: transparent;
387
- background-clip: text;
388
- text-align: center;
389
- font-size: 48px !important;
390
- font-weight: 800 !important;
391
- margin-bottom: 10px !important;
392
- text-shadow: 0 0 30px rgba(255, 107, 53, 0.3);
393
- }
394
-
395
- h3 {
396
- color: #ff8c42 !important;
397
- font-weight: 700 !important;
398
- font-size: 20px !important;
399
- margin-bottom: 16px !important;
400
- }
401
-
402
- .gr-button-primary {
403
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
404
- border: none !important;
405
- font-weight: 700 !important;
406
- font-size: 16px !important;
407
- padding: 14px 32px !important;
408
- border-radius: 12px !important;
409
- box-shadow: 0 8px 24px rgba(255, 107, 53, 0.4) !important;
410
- transition: all 0.3s ease !important;
411
- text-transform: uppercase !important;
412
- letter-spacing: 0.5px !important;
413
- color: white !important;
414
- }
415
-
416
- .gr-button-primary:hover {
417
- background: linear-gradient(135deg, #ff8c42 0%, #ffa94d 100%) !important;
418
- transform: translateY(-2px) !important;
419
- box-shadow: 0 12px 32px rgba(255, 107, 53, 0.6) !important;
420
- }
421
-
422
- /* Buton içindeki text ve emoji'leri beyaz yap */
423
- .gr-button-primary span,
424
- .gr-button-primary *,
425
- button[variant="primary"] span,
426
- button[variant="primary"] * {
427
- color: white !important;
428
- background: transparent !important;
429
- }
430
-
431
- /* Tüm primary butonları hedefle */
432
- button.primary,
433
- button[variant="primary"],
434
- .primary.gr-button {
435
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
436
- color: white !important;
437
- border: none !important;
438
- }
439
-
440
- /* Buton içindeki text ve emoji'leri beyaz yap */
441
- .gr-button-primary span,
442
- .gr-button-primary * {
443
- color: white !important;
444
- }
445
-
446
- /* Tüm butonlardaki mor renkleri kaldır */
447
- button, .gr-button {
448
- background-color: transparent !important;
449
- }
450
-
451
- button svg, .gr-button svg {
452
- color: inherit !important;
453
- }
454
-
455
- /* Primary buton özel */
456
- button.gr-button-primary,
457
- .gr-button.gr-button-primary {
458
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
459
- color: white !important;
460
- }
461
-
462
- .gr-checkbox-group label, .gr-dropdown label, .gr-slider label, .gr-textbox label {
463
- color: #ff8c42 !important;
464
- font-weight: 600 !important;
465
- font-size: 15px !important;
466
- margin-bottom: 8px !important;
467
- }
468
-
469
- /* Label başlıkları için turuncu arka plan */
470
- label span {
471
- background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
472
- color: white !important;
473
- }
474
-
475
- /* Tüm label başlıklarını turuncu yap */
476
- .gr-block.gr-box span.svelte-1wj3sew,
477
- .gr-block.gr-box span.svelte-9gxdi0,
478
- label > span:first-child {
479
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
480
- color: white !important;
481
- padding: 8px 16px !important;
482
- border-radius: 8px !important;
483
- font-weight: 700 !important;
484
- display: inline-block !important;
485
- margin-bottom: 12px !important;
486
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3) !important;
487
- }
488
-
489
- /* Gradio'nun tüm label'ları için genel kural */
490
- .gr-form label > span,
491
- .gr-box label > span,
492
- fieldset legend,
493
- .svelte-1wj3sew,
494
- .svelte-9gxdi0 {
495
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
496
- color: white !important;
497
- padding: 8px 16px !important;
498
- border-radius: 8px !important;
499
- font-weight: 700 !important;
500
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3) !important;
501
- }
502
-
503
- /* Sadece başlık label'larını turuncu yap, checkbox içindekileri değil */
504
- .gr-form > label:first-child > span:first-child,
505
- .gr-box > label:first-child > span:first-child,
506
- .gr-input-label > span,
507
- fieldset > legend > span {
508
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
509
- color: white !important;
510
- padding: 8px 16px !important;
511
- border-radius: 8px !important;
512
- font-weight: 700 !important;
513
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3) !important;
514
- }
515
-
516
- .gr-checkbox-group, .gr-dropdown, .gr-slider, .gr-textbox {
517
- background: #1a1a1a !important;
518
- border: 2px solid #2a2a2a !important;
519
- border-radius: 12px !important;
520
- padding: 12px !important;
521
- }
522
-
523
- /* Checkbox container ve label'ları - Tüm mavi/mor renkleri kaldır */
524
- .gr-checkbox-group label,
525
- .gr-check-radio label,
526
- .gr-checkbox-group .gr-check-radio,
527
- .gr-checkbox-group [role="checkbox"],
528
- .gr-checkbox-group .gr-check-radio label,
529
- .gr-checkbox-group [role="checkbox"] label,
530
- .gr-checkbox-group .gr-check-radio span,
531
- .gr-checkbox-group [role="checkbox"] span {
532
- background: #2a2a2a !important;
533
- color: #d4d4d4 !important;
534
- border: 2px solid #3a3a3a !important;
535
- border-radius: 8px !important;
536
- padding: 10px 16px !important;
537
- transition: all 0.2s ease !important;
538
- font-weight: 500 !important;
539
- margin: 4px !important;
540
- }
541
-
542
- /* Seçili checkbox'lar - Turuncu tema */
543
- .gr-checkbox-group input:checked + label,
544
- .gr-check-radio input:checked + label,
545
- .gr-checkbox-group label[data-testid*="checked"],
546
- .gr-checkbox-group label[aria-checked="true"],
547
- .gr-checkbox-group [role="checkbox"][aria-checked="true"],
548
- .gr-checkbox-group .gr-check-radio[aria-checked="true"],
549
- .gr-checkbox-group [role="checkbox"][aria-checked="true"] label,
550
- .gr-checkbox-group .gr-check-radio[aria-checked="true"] label,
551
- .gr-checkbox-group [role="checkbox"][aria-checked="true"] span,
552
- .gr-checkbox-group .gr-check-radio[aria-checked="true"] span,
553
- label[data-selected="true"] {
554
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
555
- border-color: #ff6b35 !important;
556
- color: white !important;
557
- font-weight: 700 !important;
558
- box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3) !important;
559
- }
560
-
561
- /* Hover durumu */
562
- .gr-checkbox-group label:hover,
563
- .gr-check-radio label:hover {
564
- background: #3a3a3a !important;
565
- border-color: #ff6b35 !important;
566
- transform: translateY(-1px) !important;
567
- }
568
-
569
- /* Tüm mavi/mor arka planları zorla kaldır */
570
- .gr-checkbox-group label[style*="background"],
571
- .gr-check-radio label[style*="background"],
572
- .gr-checkbox-group .gr-check-radio[style*="background"],
573
- .gr-checkbox-group [role="checkbox"][style*="background"] {
574
- background: #2a2a2a !important;
575
- }
576
-
577
- .gr-checkbox-group input:checked + label[style*="background"],
578
- .gr-check-radio input:checked + label[style*="background"],
579
- .gr-checkbox-group [role="checkbox"][aria-checked="true"][style*="background"] {
580
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
581
- }
582
-
583
- /* Gradio'nun özel checkbox yapısı için ek kurallar */
584
- .gr-checkbox-group .gr-check-radio[aria-checked="true"],
585
- .gr-checkbox-group [role="checkbox"][aria-checked="true"] {
586
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
587
- border-color: #ff6b35 !important;
588
- color: white !important;
589
- }
590
-
591
- /* Checkbox içindeki span'ları da hedefle */
592
- .gr-checkbox-group .gr-check-radio span,
593
- .gr-checkbox-group [role="checkbox"] span {
594
- color: inherit !important;
595
- background: transparent !important;
596
  }
597
-
598
- .gr-checkbox-group .gr-check-radio[aria-checked="true"] span,
599
- .gr-checkbox-group [role="checkbox"][aria-checked="true"] span {
600
- color: white !important;
601
  }
602
-
603
- /* Checkbox içindeki text'leri beyaz yap */
604
- .gr-checkbox-group label span {
605
- color: inherit !important;
606
- background: transparent !important;
607
- padding: 0 !important;
608
- box-shadow: none !important;
609
  }
610
-
611
- /* Seçili checkbox'ların text'ini siyah yap */
612
- .gr-checkbox-group input[type='checkbox']:checked + label span {
613
  color: #1a1a1a !important;
614
- background: transparent !important;
615
- }
616
-
617
- /* Gradio'nun özel checkbox yapısı için */
618
- .gr-check-radio label,
619
- .gr-checkbox-group > label,
620
- fieldset label {
621
- color: #d4d4d4 !important;
622
- }
623
-
624
- /* Checkbox grup içindeki tüm span'ları hedefle */
625
- .gr-checkbox-group .gr-check-radio span,
626
- .gr-checkbox-group label > span:not(:first-child),
627
- .gr-checkbox-group [role="checkbox"] + span {
628
- background: transparent !important;
629
- color: inherit !important;
630
- padding: 0 !important;
631
- margin: 0 !important;
632
- box-shadow: none !important;
633
- font-weight: inherit !important;
634
  }
635
-
636
- .gr-input, .gr-textbox textarea, .gr-dropdown-container {
637
- background: #2a2a2a !important;
638
- color: #ffffff !important;
639
- border: 2px solid #3a3a3a !important;
640
- border-radius: 10px !important;
641
- font-size: 15px !important;
642
- }
643
-
644
- .gr-input:focus, .gr-textbox textarea:focus {
645
- border-color: #ff6b35 !important;
646
- box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.2) !important;
647
- }
648
-
649
- /* Dropdown ok işaretini turuncu yap */
650
- .gr-dropdown svg,
651
- .gr-dropdown path,
652
- button[aria-label="Clear"] svg,
653
- button svg {
654
- color: #ff8c42 !important;
655
- fill: #ff8c42 !important;
656
- stroke: #ff8c42 !important;
657
- }
658
-
659
- /* Dropdown içindeki tüm butonları turuncu yap */
660
- .gr-dropdown button,
661
- .gr-dropdown-container button {
662
- background: transparent !important;
663
- }
664
-
665
- .gr-dropdown button svg path,
666
- .gr-dropdown-container button svg path {
667
- fill: #ff8c42 !important;
668
- stroke: #ff8c42 !important;
669
- }
670
-
671
- /* Dropdown açılır menü */
672
- .gr-dropdown-menu {
673
- background: #2a2a2a !important;
674
- border: 2px solid #ff6b35 !important;
675
- border-radius: 10px !important;
676
- }
677
-
678
- .gr-dropdown-item {
679
- color: #d4d4d4 !important;
680
- background: transparent !important;
681
- }
682
-
683
  .gr-dropdown-item:hover {
684
- background: #3a3a3a !important;
685
- color: #ff8c42 !important;
686
- }
687
-
688
- .gr-dropdown-item.selected {
689
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
690
  color: #1a1a1a !important;
691
  }
692
-
693
- .gr-form {
694
- background: #1a1a1a !important;
695
- border: 2px solid #2a2a2a !important;
696
- border-radius: 16px !important;
697
- padding: 24px !important;
698
- box-shadow: 0 8px 32px rgba(0,0,0,0.4) !important;
699
- }
700
-
701
- .gr-panel {
702
- background: #1a1a1a !important;
703
- border: 2px solid #2a2a2a !important;
704
- border-radius: 16px !important;
705
- }
706
-
707
- /* Slider özelleştirmesi - Dinamik renk takibi */
708
- input[type="range"] {
709
- background: transparent !important;
710
- height: 6px !important;
711
- border-radius: 3px !important;
712
- -webkit-appearance: none !important;
713
- appearance: none !important;
714
- }
715
-
716
- input[type="range"]::-webkit-slider-thumb {
717
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
718
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.4) !important;
719
- width: 20px !important;
720
- height: 20px !important;
721
- border-radius: 50% !important;
722
- -webkit-appearance: none !important;
723
- appearance: none !important;
724
- cursor: pointer !important;
725
- border: none !important;
726
- }
727
-
728
- input[type="range"]::-moz-range-thumb {
729
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
730
- box-shadow: 0 2px 8px rgba(255, 107, 53, 0.4) !important;
731
- width: 20px !important;
732
- height: 20px !important;
733
- border-radius: 50% !important;
734
- cursor: pointer !important;
735
- border: none !important;
736
- }
737
-
738
- input[type="range"]::-webkit-slider-runnable-track {
739
- background: linear-gradient(to right,
740
- #ff6b35 0%,
741
- #ff8c42 calc(var(--slider-progress, 50%)),
742
- #2a2a2a calc(var(--slider-progress, 50%))) !important;
743
- height: 6px !important;
744
- border-radius: 3px !important;
745
- border: none !important;
746
- }
747
-
748
- /* IMDb slider için özel stil */
749
- .gr-slider input[type="range"]::-webkit-slider-runnable-track {
750
- background: linear-gradient(to right,
751
- #ff6b35 0%,
752
- #ff8c42 calc(var(--slider-progress, 50%)),
753
- #2a2a2a calc(var(--slider-progress, 50%))) !important;
754
- }
755
-
756
- input[type="range"]::-moz-range-track {
757
- background: #2a2a2a !important;
758
- height: 6px !important;
759
- border-radius: 3px !important;
760
- border: none !important;
761
- }
762
-
763
- input[type="range"]::-moz-range-progress {
764
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
765
- height: 6px !important;
766
- border-radius: 3px !important;
767
- border: none !important;
768
- }
769
-
770
- /* Slider container için özel stil */
771
- .gr-slider {
772
- position: relative !important;
773
- }
774
-
775
- .gr-slider::before {
776
- content: '' !important;
777
- position: absolute !important;
778
- top: 50% !important;
779
- left: 0 !important;
780
- right: 0 !important;
781
- height: 6px !important;
782
- background: #2a2a2a !important;
783
- border-radius: 3px !important;
784
- transform: translateY(-50%) !important;
785
- z-index: 1 !important;
786
- }
787
-
788
- .gr-slider::after {
789
- content: '' !important;
790
- position: absolute !important;
791
- top: 50% !important;
792
- left: 0 !important;
793
- width: var(--slider-progress, 50%) !important;
794
- height: 6px !important;
795
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
796
- border-radius: 3px !important;
797
- transform: translateY(-50%) !important;
798
- z-index: 2 !important;
799
- transition: width 0.1s ease !important;
800
- }
801
-
802
- /* Scroll bar */
803
- ::-webkit-scrollbar {
804
- width: 12px;
805
- background: #1a1a1a;
806
- }
807
-
808
- ::-webkit-scrollbar-thumb {
809
- background: linear-gradient(180deg, #ff6b35 0%, #ff8c42 100%);
810
- border-radius: 6px;
811
- }
812
-
813
- ::-webkit-scrollbar-thumb:hover {
814
- background: linear-gradient(180deg, #ff8c42 0%, #ffa94d 100%);
815
- }
816
-
817
- /* Örnekler bölümü */
818
- .gr-examples {
819
- background: #1a1a1a !important;
820
- border: 2px solid #2a2a2a !important;
821
- border-radius: 12px !important;
822
- padding: 16px !important;
823
- }
824
-
825
- .gr-examples .gr-button {
826
- background: #2a2a2a !important;
827
- color: #d4d4d4 !important;
828
- border: 1px solid #3a3a3a !important;
829
- border-radius: 8px !important;
830
- }
831
-
832
- .gr-examples .gr-button:hover {
833
- background: #3a3a3a !important;
834
- border-color: #ff6b35 !important;
835
- color: #ff8c42 !important;
836
- }
837
-
838
- /* TÜM MOR/MAVİ RENKLERİ ZORLA KALDIR */
839
- * {
840
- --primary-500: #ff6b35 !important;
841
- --primary-400: #ff8c42 !important;
842
- --primary-600: #ff6b35 !important;
843
- }
844
-
845
- /* Gradio'nun tüm mor/mavi renklerini turuncu yap */
846
- [style*="background-color: rgb(99, 102, 241)"],
847
- [style*="background-color: rgb(139, 92, 246)"],
848
- [style*="background-color: #6366f1"],
849
- [style*="background-color: #8b5cf6"],
850
- [style*="background: rgb(99, 102, 241)"],
851
- [style*="background: rgb(139, 92, 246)"],
852
- [style*="background: #6366f1"],
853
- [style*="background: #8b5cf6"] {
854
- background: #2a2a2a !important;
855
- }
856
-
857
- /* Seçili checkbox'lar için özel kural */
858
- [style*="background-color: rgb(99, 102, 241)"][aria-checked="true"],
859
- [style*="background-color: rgb(139, 92, 246)"][aria-checked="true"],
860
- [style*="background: rgb(99, 102, 241)"][aria-checked="true"],
861
- [style*="background: rgb(139, 92, 246)"][aria-checked="true"] {
862
- background: linear-gradient(135deg, #ff6b35 0%, #ff8c42 100%) !important;
863
- }
864
  """) as demo:
865
-
866
  gr.Markdown(
867
  """
868
- # 🎬 CineMate Film Öneri Sistemi
869
-
870
- <p style='text-align: center; color: #d4d4d4; font-size: 18px; margin-top: -10px; font-weight: 500;'>
871
- Yapay Zeka Destekli Kişiselleştirilmiş Film Keşfi
872
- </p>
873
  """
874
  )
875
 
 
876
  with gr.Row():
877
- with gr.Column(scale=3):
878
- gr.Markdown("### 🎯 Sizin İçin Seçtiklerimiz")
879
- output_html = gr.HTML(
880
- label="Film Önerileri",
881
- value="""
882
- <div style="text-align: center; padding: 80px 20px; background: linear-gradient(135deg, #1a1a1a 0%, #2d1810 100%); border-radius: 16px; border: 2px dashed #3a3a3a;">
883
- <div style="font-size: 72px; margin-bottom: 20px; filter: grayscale(100%) opacity(0.3);">🎬</div>
884
- <h2 style="color: #6a6a6a; margin-bottom: 15px; font-size: 24px;">Filmler Yükleniyor...</h2>
885
- <p style="color: #5a5a5a; font-size: 16px;">Tercihlerinizi seçin ve keşfetmeye başlayın!</p>
886
- </div>
887
- """
888
- )
889
 
890
  with gr.Row():
891
  with gr.Column(scale=1):
892
- gr.Markdown("### 🎨 Film Tercihleriniz")
893
 
894
  tags_input = gr.CheckboxGroup(
895
- label="🎭 Film Türleri",
896
  choices=all_tags,
897
- value=['action', 'drama'],
898
  interactive=True
899
  )
900
 
901
  directors_input = gr.Dropdown(
902
- label="🎬 Favori Yönetmenler",
903
- choices=all_directors,
904
  multiselect=True,
905
  allow_custom_value=False,
906
  interactive=True
907
  )
908
 
909
  stars_input = gr.Dropdown(
910
- label="⭐ Favori Oyuncular",
911
- choices=all_stars,
912
  multiselect=True,
913
  allow_custom_value=False,
914
  interactive=True
@@ -919,7 +360,7 @@ with gr.Blocks(theme=custom_theme, head="""
919
  maximum=df_filtered['IMDb Rating'].max(),
920
  step=0.1,
921
  value=7.6,
922
- label="📊 Minimum IMDb Puanı"
923
  )
924
 
925
  num_recommendations_slider = gr.Slider(
@@ -927,20 +368,15 @@ with gr.Blocks(theme=custom_theme, head="""
927
  maximum=20,
928
  step=1,
929
  value=10,
930
- label="🎯 Öneri Sayısı"
931
  )
932
 
933
  search_text_input = gr.Textbox(
934
- label="🔍 Akıllı Arama (Yapay Zeka Destekli)",
935
- placeholder="Örn: Uzayda geçen, aksiyon dolu bir macera...",
936
- lines=2
937
  )
938
 
939
- recommend_btn = gr.Button(
940
- "🚀 FİLMLERİ KEŞFET",
941
- variant="primary",
942
- size="lg"
943
- )
944
 
945
  recommend_btn.click(
946
  fn=get_movie_recommendations,
@@ -948,7 +384,6 @@ with gr.Blocks(theme=custom_theme, head="""
948
  outputs=output_html
949
  )
950
 
951
- gr.Markdown("### 💡 Hızlı Başlangıç Örnekleri")
952
  gr.Examples(
953
  examples=[
954
  [['action'], [], [], 7.6, 5, ""],
@@ -961,57 +396,20 @@ with gr.Blocks(theme=custom_theme, head="""
961
  inputs=[tags_input, directors_input, stars_input, min_imdb_rating_slider, num_recommendations_slider, search_text_input],
962
  outputs=output_html,
963
  fn=get_movie_recommendations,
964
- label="Popüler Aramalar"
965
  )
966
 
967
  gr.Markdown(
968
  """
969
  ---
970
-
971
- <div style='background: linear-gradient(135deg, #1a1a1a 0%, #2d1810 100%); padding: 30px; border-radius: 16px; border: 2px solid #3a3a3a; margin-top: 20px;'>
972
-
973
- ### 📖 Nasıl Kullanılır?
974
-
975
- <div style='display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-top: 20px;'>
976
-
977
- <div style='background: #2a2a2a; padding: 20px; border-radius: 12px; border-left: 4px solid #ff6b35;'>
978
- <h4 style='color: #ff8c42; margin-top: 0;'>🎭 1. Tür Seçin</h4>
979
- <p style='color: #d4d4d4; font-size: 14px; line-height: 1.6;'>İlginizi çeken film türlerini seçin. Birden fazla tür kombinleyebilirsiniz.</p>
980
- </div>
981
-
982
- <div style='background: #2a2a2a; padding: 20px; border-radius: 12px; border-left: 4px solid #ff8c42;'>
983
- <h4 style='color: #ff8c42; margin-top: 0;'>🎬 2. Filtre Uygulayın</h4>
984
- <p style='color: #d4d4d4; font-size: 14px; line-height: 1.6;'>Favori yönetmen ve oyuncularınızı, minimum IMDb puanını ayarlayın.</p>
985
- </div>
986
-
987
- <div style='background: #2a2a2a; padding: 20px; border-radius: 12px; border-left: 4px solid #ffa94d;'>
988
- <h4 style='color: #ff8c42; margin-top: 0;'>🔍 3. Akıllı Arama</h4>
989
- <p style='color: #d4d4d4; font-size: 14px; line-height: 1.6;'>Yapay zeka destekli arama ile konu, tema veya film adı arayın.</p>
990
- </div>
991
-
992
- <div style='background: #2a2a2a; padding: 20px; border-radius: 12px; border-left: 4px solid #ff6b35;'>
993
- <h4 style='color: #ff8c42; margin-top: 0;'>🚀 4. Keşfedin</h4>
994
- <p style='color: #d4d4d4; font-size: 14px; line-height: 1.6;'>Butona tıklayın ve size özel seçilmiş filmleri keşfedin!</p>
995
- </div>
996
-
997
- </div>
998
-
999
- <div style='margin-top: 30px; padding: 20px; background: rgba(255, 107, 53, 0.1); border-radius: 12px; border: 2px solid rgba(255, 107, 53, 0.3);'>
1000
- <h4 style='color: #ff8c42; margin-top: 0; display: flex; align-items: center; gap: 10px;'>
1001
- <span style='font-size: 24px;'>💡</span> Pro İpucu
1002
- </h4>
1003
- <p style='color: #d4d4d4; font-size: 14px; line-height: 1.6; margin: 0;'>
1004
- Daha spesifik sonuçlar için birden fazla filtreyi kombine edin. Örneğin: "Christopher Nolan yönetmenliğinde, bilim kurgu türünde, 8.0 ve üzeri puanlı filmler" gibi.
1005
- </p>
1006
- </div>
1007
-
1008
- </div>
1009
-
1010
- <div style='text-align: center; margin-top: 30px; padding: 20px; color: #6a6a6a; font-size: 13px;'>
1011
- <p style='margin: 0;'>🤖 Yapay Zeka ile Güçlendirilmiş | ⚡ Anlık Sonuçlar | 🎯 Kişiselleştirilmiş Öneriler</p>
1012
- </div>
1013
  """
1014
  )
1015
 
1016
- demo.launch(server_name="0.0.0.0", server_port=7860)
1017
- print("\nADIM 5: Premium Gradio Web Arayüzü Başlatıldı.")
 
6
  import torch
7
  import re
8
 
9
+ print("--- Film Öneri Sistemi Başlatılıyor (Popülerlik Sıralaması ve Yeniden Tasarlanmış Arayüz ile) ---")
10
+
11
+ # --- ADIM 1: Veri Seti Yükleniyor ve Keşfediliyor ---
12
+ print("ADIM 1: Veri Seti Yükleniyor ve Keşfediliyor...")
13
 
 
14
  csv_file_name = "imdb-top-rated-movies-user-rated.csv"
15
  file_path = os.path.join(".", csv_file_name)
16
 
17
  if not os.path.exists(file_path):
18
+ print(f"HATA: '{csv_file_name}' dosyası '{file_path}' yolunda bulunamadı. Lütfen CSV dosyasını Space'e yüklediğinizden emin olun.")
19
  exit(1)
20
 
21
  try:
 
24
  except Exception as e:
25
  print(f"HATA: CSV dosyası yüklenirken hata oluştu: {e}")
26
  exit(1)
27
+ print("ADIM 1: Veri Seti Keşfi Tamamlandı.")
28
+
29
+
30
+ # --- ADIM 2: Veri Temizliği ve Ön İşleme ---
31
+ print("\nADIM 2: Veri Temizliği ve Ön İşleme Başlıyor...")
32
 
33
  df_filtered = df[['Title', 'IMDb Rating', 'Tags', 'Director', 'Stars', 'Votes', 'Description', 'Poster URL']].copy()
34
+
35
  df_filtered['Stars'].fillna('', inplace=True)
36
  df_filtered['Description'].fillna('', inplace=True)
37
  df_filtered['Poster URL'].fillna('', inplace=True)
 
72
  def clean_and_split(text_series):
73
  if pd.isna(text_series):
74
  return []
75
+
76
  item = str(text_series)
77
  item = item.replace('"', '').replace("'", '').strip()
78
  item = item.replace('sci, fi', 'sci-fi')
79
+
80
  split_items = [s.strip().lower() for s in item.split(',') if s.strip()]
81
  return split_items
82
 
83
+
84
  df_filtered['Tags_cleaned_raw'] = df_filtered['Tags'].apply(clean_and_split)
85
  df_filtered['Director_cleaned'] = df_filtered['Director'].apply(clean_and_split)
86
  df_filtered['Stars_cleaned'] = df_filtered['Stars'].apply(clean_and_split)
87
+
88
  df_filtered['Tags_cleaned'] = df_filtered['Tags_cleaned_raw'].apply(map_to_main_genres)
89
 
90
+
91
  def convert_votes_to_numeric(votes_str):
92
  if isinstance(votes_str, str):
93
  votes_str = votes_str.replace(",", "")
 
110
  df_filtered['Director_cleaned'].apply(lambda x: ", ".join(x)) + ". " + \
111
  df_filtered['Stars_cleaned'].apply(lambda x: ", ".join(x))
112
 
113
+ print("\nADIM 2: Veri Temizliği ve Ön İşleme Tamamlandı.")
114
+
115
+
116
+ # --- ADIM 3: NLP Modelini Yükleme ve ÖNCEDEN OLUŞTURULMUŞ Embedding'leri Yükleme ---
117
+ print("\nADIM 3: NLP Modelini Yükleniyor ve Önceden Oluşturulmuş Embedding'ler Yükleniyor...")
118
+
119
  model_name = 'sentence-transformers/all-MiniLM-L6-v2'
120
  try:
121
+ sentence_model = SentenceTransformer(model_name)
 
122
  print(f"'{model_name}' modeli başarıyla yüklendi.")
123
  except Exception as e:
124
  print(f"HATA: Sentence Transformer modeli yüklenirken hata oluştu: {e}")
125
+ exit(1)
 
126
 
127
  embeddings_file_path = os.path.join(".", "film_embeddings.npy")
128
  if not os.path.exists(embeddings_file_path):
129
+ print(f"HATA: '{embeddings_file_path}' dosyası bulunamadı. Lütfen Space'e yüklediğinizden emin olun.")
130
  exit(1)
131
 
132
  try:
133
  film_embeddings = torch.from_numpy(np.load(embeddings_file_path))
134
+ print("Film embedding'leri başarıyla 'film_embeddings.npy' dosyasından yüklendi.")
135
  except Exception as e:
136
  print(f"HATA: film_embeddings.npy yüklenirken hata oluştu: {e}")
137
  exit(1)
138
 
139
+ print("ADIM 3: NLP Modelini Yükleme ve Film Embedding'lerini Oluşturma Tamamlandı.")
140
+
141
+
142
+ # --- ADIM 4: Film Öneri Sistemi Mantığını Oluşturma (Popüler Yönetmen/Oyuncu Sıralaması Eklendi) ---
143
+ print("\nADIM 4: Film Öneri Sistemi Mantığı Oluşturuluyor...")
144
+
145
+ # --- YENİ EKLENTİ: Popüler Yönetmen/Oyuncu Listelerini Oluşturma ---
146
  director_popularity = {}
147
  for index, row in df_filtered.iterrows():
148
  for director in row['Director_cleaned']:
 
153
  for star in row['Stars_cleaned']:
154
  star_popularity[star] = star_popularity.get(star, 0) + row['Votes_numeric']
155
 
156
+ # all_tags listesini, sadece eşlenmiş ana türlerden oluşturalım
157
  all_tags = sorted(list(set([tag for sublist in df_filtered['Tags_cleaned'] for tag in sublist if tag in genre_mapping])))
158
+
159
+ # Popülerliğe göre sıralanmış yönetmen ve oyuncu listeleri
160
+ # Popülerlik skoruna (Votes_numeric toplamı) göre azalan sırada sırala
161
  all_directors = sorted(list(director_popularity.keys()), key=lambda d: director_popularity[d], reverse=True)
162
  all_stars = sorted(list(star_popularity.keys()), key=lambda s: star_popularity[s], reverse=True)
163
+ # --- YENİ EKLENTİ SONU ---
164
+
165
 
166
  def get_movie_recommendations(selected_tags, selected_directors, selected_stars, min_imdb_rating_slider, num_recommendations_slider, search_text=""):
167
 
 
172
  print(f"Minimum IMDb Puanı: {min_imdb_rating_slider}")
173
  print(f"Öneri Sayısı: {num_recommendations_slider}")
174
  print(f"Arama Metni: '{search_text}'")
175
+ print(f"Başlangıç DataFrame boyutu: {len(df_filtered)} (Poster URL'si dahil)")
176
 
177
  selected_tags_list = list(selected_tags) if selected_tags else []
178
  selected_directors_list = list(selected_directors) if selected_directors else []
179
  selected_stars_list = list(selected_stars) if selected_stars else []
180
 
181
  recommendations_df = df_filtered.copy()
182
+
183
  recommendations_df = recommendations_df[recommendations_df['IMDb Rating'] >= min_imdb_rating_slider]
184
+ print(f"IMDb Puanı filtrelemesi sonrası: {len(recommendations_df)} film")
185
 
186
  if selected_tags_list:
187
  recommendations_df = recommendations_df[
188
  recommendations_df['Tags_cleaned'].apply(lambda x: any(tag in x for tag in selected_tags_list))
189
  ]
190
+ print(f"Tür filtrelemesi sonrası: {len(recommendations_df)} film")
191
 
192
  if selected_directors_list:
193
  recommendations_df = recommendations_df[
194
  recommendations_df['Director_cleaned'].apply(lambda x: any(director in x for director in selected_directors_list))
195
  ]
196
+ print(f"Yönetmen filtrelemesi sonrası: {len(recommendations_df)} film")
197
 
198
  if selected_stars_list:
199
  recommendations_df = recommendations_df[
200
  recommendations_df['Stars_cleaned'].apply(lambda x: any(star in x for star in selected_stars_list))
201
  ]
202
+ print(f"Oyuncu filtrelemesi sonrası: {len(recommendations_df)} film")
203
 
204
  if search_text and len(recommendations_df) > 0:
205
+ print(f"'{search_text}' için NLP benzerlik araması yapılıyor...")
 
 
 
 
 
 
 
 
 
206
 
207
+ try:
208
+ query_embedding = sentence_model.encode(search_text, convert_to_tensor=True)
209
+ except Exception as e:
210
+ print(f"HATA: Arama metni embedding'i oluşturulurken hata oluştu: {e}")
211
+ return "Arama metni işlenirken bir hata oluştu. Lütfen tekrar deneyin."
212
+
213
+ filtered_indices = recommendations_df.index.tolist()
214
+ if not filtered_indices or len(film_embeddings) == 0:
215
+ print("HATA: Filtrelenmiş film indeksi bulunamadı veya embedding'ler boş.")
216
+ return "Filtreleme sonrası film bulunamadı."
217
+
218
+
219
+ try:
220
+ current_film_embeddings = film_embeddings[filtered_indices]
221
+ cosine_scores = util.cos_sim(query_embedding, current_film_embeddings)[0]
222
+ recommendations_df['Similarity_Score'] = cosine_scores.cpu().numpy()
223
+ recommendations_df = recommendations_df.sort_values(
224
+ by=['Similarity_Score', 'IMDb Rating', 'Votes_numeric'],
225
+ ascending=[False, False, False]
226
+ ).reset_index(drop=True)
227
+ print(f"NLP benzerlik filtrelemesi sonrası: {len(recommendations_df)} film")
228
+ except Exception as e:
229
+ print(f"HATA: NLP benzerlik hesaplanırken hata oluştu: {e}")
230
+ return "Benzerlik hesaplan��rken bir hata oluştu. Lütfen tekrar deneyin."
231
 
232
  if not search_text:
233
  recommendations_df = recommendations_df.sort_values(
 
238
  top_recommendations = recommendations_df.head(num_recommendations_slider)
239
 
240
  if top_recommendations.empty:
241
+ print("Kriterlere uygun film bulunamadı.")
242
+ return "Üzgünüz, seçtiğiniz kriterlere uygun film bulunamadı."
 
 
 
 
 
243
  else:
244
+ print(f"Toplam {len(top_recommendations)} öneri bulundu.")
245
+ html_output = ""
 
 
 
 
 
 
246
  for idx, row in top_recommendations.iterrows():
247
  directors_str = ", ".join([d.title() for d in row['Director_cleaned']])
248
  stars_str = ", ".join([s.title() for s in row['Stars_cleaned']])
 
250
 
251
  similarity_info = ""
252
  if 'Similarity_Score' in row and search_text:
253
+ similarity_info = f", Benzerlik: {row['Similarity_Score']:.2f}"
 
 
 
 
 
 
 
254
 
255
  poster_html = f"""
256
+ <div style="width: 120px; height: 180px; background-color: #2a2a2a; border-radius: 4px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; color: #888; font-size: 0.8em; line-height: 1.2; padding: 5px;">
257
+ <span style="font-weight: bold; margin-bottom: 5px;">{row['Title']}</span>
258
+ <span>Poster Yok</span>
 
259
  </div>
260
  """
261
 
262
  html_output += f"""
263
+ <div style="display: flex; margin-bottom: 20px; border: 1px solid #333; padding: 10px; border-radius: 8px; background-color: #1a1a1a;">
264
+ <div style="flex-shrink: 0; margin-right: 15px;">
 
265
  {poster_html}
266
  </div>
267
  <div style="flex-grow: 1;">
268
+ <h3 style="margin-top: 0px; margin-bottom: 5px; color: #f39c12;">{row['Title']}</h3>
269
+ <p style="margin-bottom: 5px; color: #eee;">IMDb: <b>{row['IMDb Rating']:.1f}</b> ⭐, Oylar: <b>{int(row['Votes_numeric']):,}</b> 🗳️{similarity_info}</p>
270
+ <p style="margin-bottom: 5px; color: #bbb;">Yönetmen: {directors_str if directors_str else 'Bilinmiyor'}</p>
271
+ <p style="margin-bottom: 5px; color: #bbb;">Oyuncular: {stars_str if stars_str else 'Bilinmiyor'}</p>
272
+ <p style="margin-bottom: 0px; color: #bbb;">Türler: {tags_str if tags_str else 'Bilinmiyor'}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  </div>
274
  </div>
275
  """
276
  return html_output
277
 
278
+ print("\nADIM 4: Film Öneri Sistemi Mantığı Oluşturuldu.")
279
+
280
+
281
+ # --- ADIM 5: Gradio Web Arayüzü Oluşturma ---
282
+ print("\nADIM 5: Gradio Web Arayüzü Oluşturuluyor (Yeniden Tasarlanmış Arayüz ve Popülerlik Sıralaması)...")
283
+
284
+ with gr.Blocks(theme=gr.themes.Soft(), css="""
285
+ /* Custom CSS */
286
+ .gradio-container { max-width: 1200px !important; font-family: 'Segoe UI', sans-serif; }
287
+ h1 { color: #f39c12; text-align: center; }
288
+ h3 { color: #eee; }
289
+ .gr-button.gr-button-primary { background-color: #f39c12 !important; border-color: #f39c12 !important; }
290
+ .gr-button.gr-button-primary:hover { background-color: #e67e22 !important; border-color: #e67e22 !important; }
291
+ .gr-checkbox-group label { color: #ccc; }
292
+ .gr-dropdown, .gr-slider, .gr-textbox { background-color: #2c2c2c; color: #eee; border-color: #555; }
293
+ .gr-dropdown-item { color: #eee; }
294
+ /* CheckboxGroup/Dropdown için sarı vurgu rengi */
295
+ .gr-checkbox-group input[type='checkbox']:checked + label {
296
+ background-color: #f39c12 !important;
297
+ border-color: #f39c12 !important;
298
+ color: #1a1a1a !important; /* Koyu metin rengi */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  }
300
+ .gr-checkbox-group input[type='checkbox'] + label {
301
+ background-color: #333;
302
+ color: #eee;
303
+ border: 1px solid #555;
304
  }
305
+ .gr-checkbox-group input[type='checkbox'] + label:hover {
306
+ background-color: #444;
 
 
 
 
 
307
  }
308
+ .gr-dropdown-item.selected {
309
+ background-color: #f39c12 !important;
 
310
  color: #1a1a1a !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  .gr-dropdown-item:hover {
313
+ background-color: #e67e22 !important;
 
 
 
 
 
314
  color: #1a1a1a !important;
315
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
  """) as demo:
 
317
  gr.Markdown(
318
  """
319
+ # 🎬 Film Öneri Sistemi
320
+ Favori film özelliklerinizi seçin, yüksek IMDb puanına sahip filmleri keşfedin!
321
+ İstediğiniz bir film veya konu hakkında yazın, benzerlerini de bulalım.
 
 
322
  """
323
  )
324
 
325
+ # Yeni yerleşim düzeni: Öneriler üstte, girişler altta
326
  with gr.Row():
327
+ with gr.Column(scale=2): # Öneriler sütununu daha geniş yaptık
328
+ gr.Markdown("### Önerilen Filmler:")
329
+ output_html = gr.HTML(label="Önerileriniz burada listelenecektir.", value="<p style='text-align: center; color: #bbb;'>Henüz bir öneri yapılmadı. Özellikleri seçip butona tıklayın!</p>")
 
 
 
 
 
 
 
 
 
330
 
331
  with gr.Row():
332
  with gr.Column(scale=1):
333
+ gr.Markdown("### Film Özelliklerini Seçin:")
334
 
335
  tags_input = gr.CheckboxGroup(
336
+ label="Film Türleri",
337
  choices=all_tags,
338
+ value=['action', 'drama'], # Varsayılan değerler
339
  interactive=True
340
  )
341
 
342
  directors_input = gr.Dropdown(
343
+ label="Yönetmenler",
344
+ choices=all_directors, # Popülerliğe göre sıralanmış liste
345
  multiselect=True,
346
  allow_custom_value=False,
347
  interactive=True
348
  )
349
 
350
  stars_input = gr.Dropdown(
351
+ label="Oyuncular",
352
+ choices=all_stars, # Popülerliğe göre sıralanmış liste
353
  multiselect=True,
354
  allow_custom_value=False,
355
  interactive=True
 
360
  maximum=df_filtered['IMDb Rating'].max(),
361
  step=0.1,
362
  value=7.6,
363
+ label="Minimum IMDb Puanı"
364
  )
365
 
366
  num_recommendations_slider = gr.Slider(
 
368
  maximum=20,
369
  step=1,
370
  value=10,
371
+ label="Öneri Sayısı"
372
  )
373
 
374
  search_text_input = gr.Textbox(
375
+ label="Film Adı veya Konu Hakkında Ara (NLP Tabanlı Benzerlik)",
376
+ placeholder="Örneğin: Batman, uzay filmi, zamanda yolculuk..."
 
377
  )
378
 
379
+ recommend_btn = gr.Button("🚀 Film Önerilerini Getir", variant="primary", size="lg")
 
 
 
 
380
 
381
  recommend_btn.click(
382
  fn=get_movie_recommendations,
 
384
  outputs=output_html
385
  )
386
 
 
387
  gr.Examples(
388
  examples=[
389
  [['action'], [], [], 7.6, 5, ""],
 
396
  inputs=[tags_input, directors_input, stars_input, min_imdb_rating_slider, num_recommendations_slider, search_text_input],
397
  outputs=output_html,
398
  fn=get_movie_recommendations,
399
+ label="Örnek Önerileri Deneyin"
400
  )
401
 
402
  gr.Markdown(
403
  """
404
  ---
405
+ ### ℹ️ Nasıl Kullanılır?
406
+ 1. **Film Türleri, Yönetmenler ve Oyuncular** bölümlerinden istediğiniz filtreleri seçin (birden fazla seçim yapabilirsiniz).
407
+ 2. **Minimum IMDb Puanı** ve **Öneri Sayısı** çubuklarını ayarlayın.
408
+ 3. İsterseniz **"Film Adı veya Konu Hakkında Ara"** kutucuğuna bir film adı, konu veya anahtar kelime yazın.
409
+ 4. **"🚀 Film Önerilerini Getir"** butonuna tıklayın.
410
+ 5. Öneriler üst panelde görünecektir!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
  """
412
  )
413
 
414
+ demo.launch(share=True)
415
+ print("\nADIM 5: Gradio Web Arayüzü Başlatıldı.")