ssenaay commited on
Commit
f94b6a2
·
verified ·
1 Parent(s): 31c35ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -401
app.py CHANGED
@@ -2,8 +2,8 @@ import pandas as pd
2
  import numpy as np
3
  import gradio as gr
4
  import os
5
- from sentence_transformers import SentenceTransformer, util
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) ---")
@@ -11,56 +11,30 @@ print("--- Film Öneri Sistemi Başlatılıyor (Popülerlik Sıralaması ve Yeni
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
- print("DEMO AMAÇLI SAHTE CSV OLUŞTURULUYOR...")
20
- # Test amaçlı minimal bir sahte DataFrame oluştur
21
- dummy_data = {
22
- 'Title': ["Django Unchained", "The Departed", "Pulp Fiction", "Inception", "The Dark Knight", "Forrest Gump", "The Matrix", "Interstellar", "Spirited Away", "Whiplash"],
23
- 'IMDb Rating': [8.4, 8.5, 8.9, 8.8, 9.0, 8.8, 8.7, 8.6, 8.6, 8.5],
24
- 'Tags': ["Drama, Western, Comedy", "Crime, Drama, Thriller", "Crime, Drama", "Action, Adventure, Sci-Fi", "Action, Crime, Drama", "Drama, Romance", "Action, Sci-Fi", "Adventure, Drama, Sci-Fi", "Animation, Adventure, Family", "Drama, Music"],
25
- 'Director': ["Quentin Tarantino", "Martin Scorsese", "Quentin Tarantino", "Christopher Nolan", "Christopher Nolan", "Robert Zemeckis", "Lana Wachowski, Lilly Wachowski", "Christopher Nolan", "Hayao Miyazaki", "Damien Chazelle"],
26
- 'Stars': ["Jamie Foxx, Christoph Waltz, Leonardo DiCaprio", "Leonardo DiCaprio, Matt Damon, Jack Nicholson", "John Travolta, Uma Thurman, Samuel L. Jackson", "Leonardo DiCaprio, Joseph Gordon-Levitt, Elliot Page", "Christian Bale, Heath Ledger, Aaron Eckhart", "Tom Hanks, Robin Wright, Gary Sinise", "Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss", "Matthew McConaughey, Anne Hathaway, Jessica Chastain", "Daveigh Chase, Suzanne Pleshette, Jason Marsden", "Miles Teller, J.K. Simmons, Melissa Benoist"],
27
- 'Votes': ["1,800,000", "1,500,000", "2,100,000", "2,300,000", "2,800,000", "2,200,000", "2,000,000", "1,700,000", "1,100,000", "900,000"],
28
- 'Description': [
29
- "With the help of a German bounty hunter, a freed slave sets out to rescue his wife from a brutal Mississippi plantation owner.",
30
- "An undercover state cop and a mole in the police force try to identify each other.",
31
- "The lives of two mob hitmen, a boxer, a gangster's wife, and a pair of diner bandits intertwine in four tales of violence and redemption.",
32
- "A thief who steals corporate secrets through the use of dream-sharing technology is given the inverse task of planting an idea into the mind of a C.E.O.",
33
- "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, Batman must accept one of the greatest psychological and physical tests of his ability to fight injustice.",
34
- "The presidencies of Kennedy and Johnson, the Vietnam War, the Watergate scandal and other historical events unfold from the perspective of an Alabama man with an IQ of 75.",
35
- "A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.",
36
- "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
37
- "During her family's move to the suburbs, a sullen 10-year-old girl wanders into a world ruled by gods, witches, and spirits, and where humans are changed into beasts.",
38
- "A promising young drummer enrolls at a cut-throat music conservatory where his unorthodox instructor pushes him to the breaking point."
39
- ],
40
- 'Poster URL': ["", "", "", "", "", "", "", "", "", ""] # Demo için boş bırakıldı, gerçek poster URL'leri buraya gelebilir
41
- }
42
- df = pd.DataFrame(dummy_data)
43
- # Sahte CSV'yi kaydedelim ki sonraki çalıştırmalarda tekrar oluşturmasın (isteğe bağlı)
44
- df.to_csv(file_path, index=False)
45
- print(f"Sahte CSV '{csv_file_name}' oluşturuldu ve yüklendi. Toplam {len(df)} film bulundu.")
46
- else:
47
- try:
48
- df = pd.read_csv(file_path)
49
- print(f"'{csv_file_name}' başarıyla yüklendi. Toplam {len(df)} film bulundu.")
50
- except Exception as e:
51
- print(f"HATA: CSV dosyası yüklenirken hata oluştu: {e}")
52
- exit(1)
53
  print("ADIM 1: Veri Seti Keşfi Tamamlandı.")
54
 
55
 
56
  # --- ADIM 2: Veri Temizliği ve Ön İşleme ---
57
  print("\nADIM 2: Veri Temizliği ve Ön İşleme Başlıyor...")
58
 
59
- df_filtered = df[['Title', 'IMDb Rating', 'Tags', 'Director', 'Stars', 'Votes', 'Description', 'Poster URL']].copy()
60
 
61
- df_filtered['Stars'].fillna('', inplace=True)
62
- df_filtered['Description'].fillna('', inplace=True)
63
- df_filtered['Poster URL'].fillna('', inplace=True)
64
 
65
  genre_mapping = {
66
  'action': ['action', 'action epic', 'gun fu', 'one-person army action', 'car action', 'kung fu', 'martial arts', 'martial-arts'],
@@ -92,15 +66,17 @@ def map_to_main_genres(tag_list):
92
  main_genres = set()
93
  for tag in tag_list:
94
  if tag in reverse_genre_map:
95
- main_genres.add(reverse_genre_map[tag])
96
  return list(main_genres)
97
 
98
  def clean_and_split(text_series):
99
  if pd.isna(text_series):
100
  return []
 
101
  item = str(text_series)
102
  item = item.replace('"', '').replace("'", '').strip()
103
- item = item.replace('sci, fi', 'sci-fi')
 
104
  split_items = [s.strip().lower() for s in item.split(',') if s.strip()]
105
  return split_items
106
 
@@ -114,19 +90,19 @@ df_filtered['Tags_cleaned'] = df_filtered['Tags_cleaned_raw'].apply(map_to_main_
114
 
115
  def convert_votes_to_numeric(votes_str):
116
  if isinstance(votes_str, str):
117
- votes_str = votes_str.replace(",", "")
118
  if 'K' in votes_str:
119
  return float(votes_str.replace('K', '')) * 1000
120
  elif 'M' in votes_str:
121
  return float(votes_str.replace('M', '')) * 1_000_000
122
- try:
123
  return float(votes_str)
124
  except ValueError:
125
- return np.nan
126
 
127
  df_filtered['Votes_numeric'] = df_filtered['Votes'].apply(convert_votes_to_numeric)
128
  df_filtered.drop('Votes', axis=1, inplace=True)
129
- df_filtered.dropna(subset=['Votes_numeric'], inplace=True)
130
 
131
  df_filtered['Combined_Text'] = df_filtered['Title'] + ". " + \
132
  df_filtered['Description'] + ". " + \
@@ -141,30 +117,24 @@ print("\nADIM 2: Veri Temizliği ve Ön İşleme Tamamlandı.")
141
  print("\nADIM 3: NLP Modelini Yükleniyor ve Önceden Oluşturulmuş Embedding'ler Yükleniyor...")
142
 
143
  model_name = 'sentence-transformers/all-MiniLM-L6-v2'
144
- sentence_model = None # Modeli başlangıçta None olarak ayarla
145
  try:
146
  sentence_model = SentenceTransformer(model_name)
147
  print(f"'{model_name}' modeli başarıyla yüklendi.")
148
  except Exception as e:
149
  print(f"HATA: Sentence Transformer modeli yüklenirken hata oluştu: {e}")
150
- print("NLP modeli yüklenemedi, arama metni özelliği devre dışı bırakılacak.")
151
 
152
  embeddings_file_path = os.path.join(".", "film_embeddings.npy")
153
  if not os.path.exists(embeddings_file_path):
154
  print(f"HATA: '{embeddings_file_path}' dosyası bulunamadı. Lütfen Space'e yüklediğinizden emin olun.")
155
- print("DEMO AMAÇLI SAHTE EMBEDDING'LER OLUŞTURULUYOR...")
156
- # Sahte embedding'ler oluştur - her film için rastgele bir vektör
157
- dummy_embeddings = np.random.rand(len(df_filtered), 384) # all-MiniLM-L6-v2 boyutu 384
158
- film_embeddings = torch.from_numpy(dummy_embeddings).float()
159
- np.save(embeddings_file_path, dummy_embeddings) # Sonraki çalıştırmalar için kaydet
160
- print("Film embedding'leri başarıyla 'film_embeddings.npy' dosyasından oluşturuldu.")
161
- else:
162
- try:
163
- film_embeddings = torch.from_numpy(np.load(embeddings_file_path)).float() # Float tipini sağla
164
- print("Film embedding'leri başarıyla 'film_embeddings.npy' dosyasından yüklendi.")
165
- except Exception as e:
166
- print(f"HATA: film_embeddings.npy yüklenirken hata oluştu: {e}")
167
- exit(1)
168
 
169
  print("ADIM 3: NLP Modelini Yükleme ve Film Embedding'lerini Oluşturma Tamamlandı.")
170
 
@@ -187,46 +157,14 @@ for index, row in df_filtered.iterrows():
187
  all_tags = sorted(list(set([tag for sublist in df_filtered['Tags_cleaned'] for tag in sublist if tag in genre_mapping])))
188
 
189
  # Popülerliğe göre sıralanmış yönetmen ve oyuncu listeleri
 
190
  all_directors = sorted(list(director_popularity.keys()), key=lambda d: director_popularity[d], reverse=True)
191
  all_stars = sorted(list(star_popularity.keys()), key=lambda s: star_popularity[s], reverse=True)
192
  # --- YENİ EKLENTİ SONU ---
193
 
194
- # --- YENİ EKLENTİ: Türlere göre renk ve ikon eşleme ---
195
- genre_visual_map = {
196
- 'action': {'color': '#E74C3C', 'icon': '💥'}, # Kırmızı
197
- 'adventure': {'color': '#F39C12', 'icon': '🗺️'}, # Turuncu
198
- 'comedy': {'color': '#F1C40F', 'icon': '😂'}, # Sarı
199
- 'drama': {'color': '#C0392B', 'icon': '🎭'}, # Koyu Kırmızı
200
- 'thriller': {'color': '#34495E', 'icon': '😨'}, # Koyu Mavi
201
- 'sci-fi': {'color': '#2980B9', 'icon': '🚀'}, # Mavi
202
- 'fantasy': {'color': '#9B59B6', 'icon': '✨'}, # Açık Mor
203
- 'horror': {'color': '#2C3E50', 'icon': '👻'}, # Çok Koyu Mavi
204
- 'mystery': {'color': '#7F8C8D', 'icon': '❓'}, # Gri
205
- 'crime': {'color': '#8E44AD', 'icon': '🔪'}, # Mor
206
- 'romance': {'color': '#E84393', 'icon': '❤️'}, # Pembe
207
- 'animation': {'color': '#2ECC71', 'icon': '🎬'}, # Yeşil
208
- 'family': {'color': '#1ABC9C', 'icon': '👨‍👩‍👧‍👦'}, # Turkuaz
209
- 'western': {'color': '#D35400', 'icon': '🤠'}, # Turuncu-kahverengi
210
- 'war': {'color': '#BDC3C7', 'icon': '⚔️'}, # Açık Gri
211
- 'history': {'color': '#95A5A6', 'icon': '📜'}, # Orta Gri
212
- 'music': {'color': '#E67E22', 'icon': '🎵'}, # Koyu Turuncu
213
- 'documentary': {'color': '#3498DB', 'icon': '🎥'} # Açık Mavi
214
- }
215
-
216
- def get_genre_color(tags):
217
- if tags:
218
- first_genre = tags[0] # İlk ana türü al
219
- return genre_visual_map.get(first_genre, {}).get('color', '#444444') # Varsayılan koyu gri
220
- return '#444444' # Varsayılan koyu gri
221
-
222
- def get_genre_icon(tags):
223
- if tags:
224
- first_genre = tags[0] # İlk ana türü al
225
- return genre_visual_map.get(first_genre, {}).get('icon', '🎞️') # Varsayılan film şeridi
226
- return '🎞️' # Varsayılan film şeridi
227
 
228
  def get_movie_recommendations(selected_tags, selected_directors, selected_stars, min_imdb_rating_slider, num_recommendations_slider, search_text=""):
229
-
230
  print(f"\n--- Öneri İsteği ---")
231
  print(f"Seçilen Türler: {selected_tags}")
232
  print(f"Seçilen Yönetmenler: {selected_directors}")
@@ -241,124 +179,100 @@ def get_movie_recommendations(selected_tags, selected_directors, selected_stars,
241
  selected_stars_list = list(selected_stars) if selected_stars else []
242
 
243
  recommendations_df = df_filtered.copy()
244
-
245
  recommendations_df = recommendations_df[recommendations_df['IMDb Rating'] >= min_imdb_rating_slider]
246
  print(f"IMDb Puanı filtrelemesi sonrası: {len(recommendations_df)} film")
247
-
248
  if selected_tags_list:
249
  recommendations_df = recommendations_df[
250
  recommendations_df['Tags_cleaned'].apply(lambda x: any(tag in x for tag in selected_tags_list))
251
  ]
252
  print(f"Tür filtrelemesi sonrası: {len(recommendations_df)} film")
253
-
254
  if selected_directors_list:
255
  recommendations_df = recommendations_df[
256
  recommendations_df['Director_cleaned'].apply(lambda x: any(director in x for director in selected_directors_list))
257
  ]
258
  print(f"Yönetmen filtrelemesi sonrası: {len(recommendations_df)} film")
259
-
260
  if selected_stars_list:
261
  recommendations_df = recommendations_df[
262
  recommendations_df['Stars_cleaned'].apply(lambda x: any(star in x for star in selected_stars_list))
263
  ]
264
  print(f"Oyuncu filtrelemesi sonrası: {len(recommendations_df)} film")
265
-
266
- if search_text and len(recommendations_df) > 0 and sentence_model is not None: # Model yüklendiyse NLP ara
267
  print(f"'{search_text}' için NLP benzerlik araması yapılıyor...")
268
-
269
  try:
270
  query_embedding = sentence_model.encode(search_text, convert_to_tensor=True)
271
  except Exception as e:
272
  print(f"HATA: Arama metni embedding'i oluşturulurken hata oluştu: {e}")
273
  return "Arama metni işlenirken bir hata oluştu. Lütfen tekrar deneyin."
274
-
275
  filtered_indices = recommendations_df.index.tolist()
276
  if not filtered_indices or len(film_embeddings) == 0:
277
  print("HATA: Filtrelenmiş film indeksi bulunamadı veya embedding'ler boş.")
278
  return "Filtreleme sonrası film bulunamadı."
279
 
280
- try:
281
- # film_embeddings dizin aralığını kontrol et
282
- if filtered_indices and (max(filtered_indices) >= film_embeddings.shape[0] or min(filtered_indices) < 0):
283
- print(f"HATA: film_embeddings dizin aralığı dışında bir indeks var. Max index: {max(filtered_indices)}, Embedding boyutu: {film_embeddings.shape[0]}")
284
- return "Benzerlik hesaplanırken bir hata oluştu (dizin hatası). Lütfen tekrar deneyin."
285
 
 
286
  current_film_embeddings = film_embeddings[filtered_indices]
287
  cosine_scores = util.cos_sim(query_embedding, current_film_embeddings)[0]
288
- recommendations_df['Similarity_Score'] = cosine_scores.cpu().numpy()
289
  recommendations_df = recommendations_df.sort_values(
290
- by=['Similarity_Score', 'IMDb Rating', 'Votes_numeric'],
291
- ascending=[False, False, False]
292
  ).reset_index(drop=True)
293
  print(f"NLP benzerlik filtrelemesi sonrası: {len(recommendations_df)} film")
294
  except Exception as e:
295
  print(f"HATA: NLP benzerlik hesaplanırken hata oluştu: {e}")
296
  return "Benzerlik hesaplanırken bir hata oluştu. Lütfen tekrar deneyin."
297
- elif search_text and sentence_model is None:
298
- print("NLP modeli yüklenemediği için arama metni filtrelemesi atlandı.")
299
 
300
- # Arama metni yoksa veya NLP modeli başarısız olursa, popülerliğe göre sırala
301
- if not search_text or sentence_model is None:
302
  recommendations_df = recommendations_df.sort_values(
303
- by=['IMDb Rating', 'Votes_numeric'],
304
  ascending=[False, False]
305
  ).reset_index(drop=True)
306
-
307
  top_recommendations = recommendations_df.head(num_recommendations_slider)
308
-
309
  if top_recommendations.empty:
310
  print("Kriterlere uygun film bulunamadı.")
311
- return "<p style='text-align: center; color: #f39c12; font-size: 1.2em; padding: 20px;'>Üzgünüz, seçtiğiniz kriterlere uygun film bulunamadı.</p>"
312
  else:
313
  print(f"Toplam {len(top_recommendations)} öneri bulundu.")
314
- html_output = "<div class='recommendations-grid'>" # Önerileri bir grid içinde göster
315
  for idx, row in top_recommendations.iterrows():
316
  directors_str = ", ".join([d.title() for d in row['Director_cleaned']])
317
  stars_str = ", ".join([s.title() for s in row['Stars_cleaned']])
318
  tags_str = ", ".join([t.title() for t in row['Tags_cleaned']])
319
 
320
  similarity_info = ""
321
- if 'Similarity_Score' in row and search_text and sentence_model is not None:
322
- similarity_info = f"<span style='font-size: 0.9em; color: #aaa;'> (Benzerlik: {row['Similarity_Score']:.2f})</span>"
323
-
324
- # Dinamik poster HTML'i
325
- if row['Poster URL'] and row['Poster URL'].strip() != "":
326
- poster_div = f"""
327
- <div class="movie-poster">
328
- <img src="{row['Poster URL']}" alt="{row['Title']}" loading="lazy">
329
- </div>
330
- """
331
- else:
332
- genre_color = get_genre_color(row['Tags_cleaned'])
333
- genre_icon = get_genre_icon(row['Tags_cleaned'])
334
- title_initial = row['Title'][0].upper() if row['Title'] else '?'
335
- poster_div = f"""
336
- <div class="movie-poster no-poster" style="background-color: {genre_color};">
337
- <span class="genre-icon">{genre_icon}</span>
338
- <span class="title-initial">{title_initial}</span>
339
- <span class="no-poster-text">POSTER YOK</span>
340
- </div>
341
- """
342
 
343
  html_output += f"""
344
- <div class="movie-card">
345
- <div class="movie-card-poster-section">
346
- {poster_div}
347
  </div>
348
- <div class="movie-card-info">
349
- <h3 class="movie-title">{row['Title']}</h3>
350
- <p class="movie-rating">
351
- IMDb: <b>{row['IMDb Rating']:.1f}</b>
352
- <span class="movie-votes">Oylar: <b>{int(row['Votes_numeric']):,}</b> 🗳️</span>
353
- {similarity_info}
354
- </p>
355
- <p class="movie-detail">Yönetmen: <span class="detail-value">{directors_str if directors_str else 'Bilinmiyor'}</span></p>
356
- <p class="movie-detail">Oyuncular: <span class="detail-value">{stars_str if stars_str else 'Bilinmiyor'}</span></p>
357
- <p class="movie-detail">Türler: <span class="detail-value">{tags_str if tags_str else 'Bilinmiyor'}</span></p>
358
  </div>
359
  </div>
360
  """
361
- html_output += "</div>" # recommendations-grid'i kapat
362
  return html_output
363
 
364
  print("\nADIM 4: Film Öneri Sistemi Mantığı Oluşturuldu.")
@@ -368,234 +282,37 @@ print("\nADIM 4: Film Öneri Sistemi Mantığı Oluşturuldu.")
368
  print("\nADIM 5: Gradio Web Arayüzü Oluşturuluyor (Yeniden Tasarlanmış Arayüz ve Popülerlik Sıralaması)...")
369
 
370
  with gr.Blocks(theme=gr.themes.Soft(), css="""
371
- /* Özel CSS Stil Kuralları */
372
- .gradio-container {
373
- max-width: 1200px !important; /* Maksimum genişlik */
374
- font-family: 'Segoe UI', sans-serif; /* Okunabilir font */
375
- background-color: #1a1a1a !important; /* Genel koyu arka plan */
376
- color: #eee; /* Genel metin rengi */
377
- }
378
- h1 {
379
- color: #f39c12; /* Turuncu başlık */
380
- text-align: center;
381
- padding-bottom: 10px;
382
- border-bottom: 2px solid #333; /* Alt çizgi */
383
- font-size: 2.5em;
384
- margin-bottom: 20px;
385
- }
386
- h3 {
387
- color: #f39c12; /* Turuncu alt başlıklar */
388
- margin-top: 15px;
389
- margin-bottom: 10px;
390
- font-size: 1.5em;
391
- }
392
- /* Birincil düğme stili */
393
- .gr-button.gr-button-primary {
394
- background-color: #e67e22 !important; /* Koyu Turuncu */
395
- border-color: #e67e22 !important;
396
- color: #fff !important;
397
- font-weight: bold;
398
- padding: 12px 20px;
399
- border-radius: 8px;
400
- transition: background-color 0.3s ease, transform 0.2s ease;
401
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
402
- }
403
- .gr-button.gr-button-primary:hover {
404
- background-color: #d35400 !important; /* Daha koyu turuncu */
405
- border-color: #d35400 !important;
406
- transform: translateY(-2px); /* Hafif yukarı kayma efekti */
407
- box-shadow: 0 6px 10px rgba(0, 0, 0, 0.4);
408
- }
409
- /* CheckboxGroup etiketleri */
410
- .gr-checkbox-group label {
411
- color: #ccc;
412
- background-color: #333; /* Checkbox arka planı */
413
- border: 1px solid #555;
414
- border-radius: 5px;
415
- padding: 8px 12px;
416
- margin: 4px;
417
- transition: all 0.2s ease;
418
- cursor: pointer;
419
- }
420
  .gr-checkbox-group input[type='checkbox']:checked + label {
421
- background-color: #f39c12 !important; /* Turuncu seçili */
422
  border-color: #f39c12 !important;
423
  color: #1a1a1a !important; /* Koyu metin rengi */
424
- font-weight: bold;
425
  }
426
- .gr-checkbox-group input[type='checkbox'] + label:hover {
427
- background-color: #444;
428
- border-color: #f39c12; /* Hover'da turuncu çerçeve */
429
- }
430
- /* Dropdown, Slider, Textbox genel stili */
431
- .gr-dropdown, .gr-slider, .gr-textbox {
432
- background-color: #2c2c2c;
433
  color: #eee;
434
- border-color: #555;
435
- border-radius: 5px;
436
- padding: 5px; /* İç boşluk */
437
  }
438
- .gr-dropdown-item {
439
- color: #eee;
440
  }
441
  .gr-dropdown-item.selected {
442
- background-color: #f39c12 !important; /* Turuncu seçili */
443
  color: #1a1a1a !important;
444
  }
445
  .gr-dropdown-item:hover {
446
- background-color: #e67e22 !important; /* Koyu Turuncu hover */
447
  color: #1a1a1a !important;
448
  }
449
- /* Slider dolgu ve tutucu */
450
- .gr-slider-fill {
451
- background-color: #e67e22 !important; /* Koyu Turuncu */
452
- }
453
- .gr-slider-handle {
454
- border-color: #f39c12 !important; /* Turuncu çerçeve */
455
- background-color: #1a1a1a !important; /* Koyu arka plan */
456
- }
457
- /* Textbox input metni */
458
- .gr-textbox input {
459
- color: #eee;
460
- }
461
-
462
- /* Film Kartları Tasarımı - Resimdeki yapıya uygun */
463
- .recommendations-grid {
464
- display: grid;
465
- grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); /* Duyarlı grid */
466
- gap: 20px; /* Kartlar arası boşluk */
467
- padding: 20px 0;
468
- }
469
- .movie-card {
470
- display: flex;
471
- background-color: #2a2a2a; /* Kart arka planı */
472
- border-radius: 10px;
473
- overflow: hidden;
474
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
475
- transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out, border-color 0.2s ease-in-out;
476
- border: 1px solid #333; /* Hafif kenarlık */
477
- }
478
- .movie-card:hover {
479
- transform: translateY(-5px);
480
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.6);
481
- border-color: #f39c12; /* Hover'da turuncu kenarlık */
482
- }
483
- .movie-card-poster-section {
484
- flex-shrink: 0;
485
- width: 120px; /* Poster genişliği */
486
- height: 180px; /* Poster yüksekliği */
487
- background-color: #333; /* Varsayılan arka plan */
488
- display: flex;
489
- align-items: center;
490
- justify-content: center;
491
- }
492
- .movie-poster {
493
- width: 100%;
494
- height: 100%;
495
- display: flex;
496
- flex-direction: column;
497
- align-items: center;
498
- justify-content: center;
499
- text-align: center;
500
- color: #fff;
501
- font-size: 0.8em;
502
- line-height: 1.2;
503
- }
504
- .movie-poster img {
505
- display: block;
506
- width: 100%;
507
- height: 100%;
508
- object-fit: cover; /* Resmi kutuya sığdır */
509
- border-radius: 4px; /* Hafif yuvarlak köşeler */
510
- }
511
- .movie-poster.no-poster {
512
- font-size: 1em;
513
- text-transform: uppercase;
514
- position: relative; /* Çocuk öğeleri konumlandırmak için */
515
- border-radius: 4px; /* Resimdeki gibi yuvarlak köşeler */
516
- }
517
- .movie-poster .genre-icon {
518
- font-size: 3em; /* İkon boyutu */
519
- margin-bottom: 5px;
520
- opacity: 0.7; /* Hafif şeffaf */
521
- color: #fff; /* İkon rengi */
522
- }
523
- .movie-poster .title-initial {
524
- font-size: 2.5em; /* Baş harf boyutu */
525
- font-weight: bold;
526
- position: absolute;
527
- top: 50%;
528
- left: 50%;
529
- transform: translate(-50%, -50%); /* Tam ortala */
530
- color: rgba(255, 255, 255, 0.2); /* Yarı şeffaf beyaz */
531
- pointer-events: none; /* Metnin tıklanmasını engeller */
532
- }
533
- .movie-poster .no-poster-text {
534
- font-size: 0.7em;
535
- position: absolute;
536
- bottom: 10px;
537
- color: rgba(255, 255, 255, 0.5); /* Yarı şeffaf metin */
538
- pointer-events: none;
539
- }
540
- .movie-card-info {
541
- flex-grow: 1;
542
- padding: 15px;
543
- display: flex; /* İçeriği dikeyde düzenlemek için */
544
- flex-direction: column;
545
- justify-content: center; /* Dikey ortala */
546
- }
547
- .movie-title {
548
- margin-top: 0;
549
- margin-bottom: 8px;
550
- color: #f39c12; /* Turuncu başlık */
551
- font-size: 1.4em;
552
- line-height: 1.2;
553
- }
554
- .movie-rating {
555
- margin-bottom: 10px;
556
- color: #bbb;
557
- font-size: 0.95em;
558
- display: flex;
559
- align-items: center;
560
- flex-wrap: wrap;
561
- }
562
- .movie-rating b {
563
- color: #eee; /* Kalın metin rengi */
564
- }
565
- .movie-rating .movie-votes {
566
- margin-left: 10px;
567
- white-space: nowrap; /* Oy sayısını tek satırda tut */
568
- }
569
- .movie-detail {
570
- margin-bottom: 4px;
571
- color: #ccc;
572
- font-size: 0.9em;
573
- }
574
- .movie-detail .detail-value {
575
- color: #eee;
576
- }
577
- /* Alt bilgi bölümü */
578
- .gr-markdown p {
579
- color: #ccc;
580
- }
581
- .gr-examples {
582
- background-color: #2c2c2c;
583
- border-radius: 8px;
584
- padding: 15px;
585
- margin-top: 20px;
586
- border: 1px solid #333;
587
- }
588
- .gr-examples-label {
589
- color: #f39c12 !important;
590
- font-weight: bold;
591
- }
592
- /* Gradio Panel geçersiz kılmaları */
593
- .gr-panel {
594
- background-color: #2c2c2c;
595
- border-color: #333;
596
- border-radius: 10px;
597
- box-shadow: none;
598
- }
599
  """) as demo:
600
  gr.Markdown(
601
  """
@@ -604,26 +321,26 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
604
  İstediğiniz bir film veya konu hakkında yazın, benzerlerini de bulalım.
605
  """
606
  )
607
-
608
  # Yeni yerleşim düzeni: Öneriler üstte, girişler altta
609
  with gr.Row():
610
  with gr.Column(scale=2): # Öneriler sütununu daha geniş yaptık
611
  gr.Markdown("### Önerilen Filmler:")
612
- output_html = gr.HTML(label="Önerileriniz burada listelenecektir.", value="<p style='text-align: center; color: #bbb; padding: 20px;'>Henüz bir öneri yapılmadı. Özellikleri seçip butona tıklayın!</p>")
613
-
614
  with gr.Row():
615
  with gr.Column(scale=1):
616
  gr.Markdown("### Film Özelliklerini Seçin:")
617
-
618
  tags_input = gr.CheckboxGroup(
619
- label="Film Türleri",
620
- choices=all_tags,
621
  value=['action', 'drama'], # Varsayılan değerler
622
  interactive=True
623
  )
624
-
625
  directors_input = gr.Dropdown(
626
- label="Yönetmenler",
627
  choices=all_directors, # Popülerliğe göre sıralanmış liste
628
  multiselect=True,
629
  allow_custom_value=False,
@@ -631,26 +348,26 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
631
  )
632
 
633
  stars_input = gr.Dropdown(
634
- label="Oyuncular",
635
  choices=all_stars, # Popülerliğe göre sıralanmış liste
636
  multiselect=True,
637
  allow_custom_value=False,
638
  interactive=True
639
  )
640
-
641
  min_imdb_rating_slider = gr.Slider(
642
- minimum=float(df_filtered['IMDb Rating'].min()),
643
- maximum=float(df_filtered['IMDb Rating'].max()),
644
- step=0.1,
645
- value=7.6,
646
  label="Minimum IMDb Puanı"
647
  )
648
 
649
  num_recommendations_slider = gr.Slider(
650
- minimum=1,
651
- maximum=20,
652
- step=1,
653
- value=10,
654
  label="Öneri Sayısı"
655
  )
656
 
@@ -658,9 +375,9 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
658
  label="Film Adı veya Konu Hakkında Ara (NLP Tabanlı Benzerlik)",
659
  placeholder="Örneğin: Batman, uzay filmi, zamanda yolculuk..."
660
  )
661
-
662
  recommend_btn = gr.Button("🚀 Film Önerilerini Getir", variant="primary", size="lg")
663
-
664
  recommend_btn.click(
665
  fn=get_movie_recommendations,
666
  inputs=[tags_input, directors_input, stars_input, min_imdb_rating_slider, num_recommendations_slider, search_text_input],
@@ -669,19 +386,19 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
669
 
670
  gr.Examples(
671
  examples=[
672
- [['action'], [], [], 7.6, 5, ""],
673
- [['comedy', 'drama'], [], [], 7.8, 3, ""],
674
- [[], ['christopher nolan'], [], 8.0, 5, ""],
675
- [[], [], ['leonardo dicaprio'], 7.8, 3, ""],
676
- [[], [], [], 8.0, 5, "kahramanlık ve bilim kurgu"],
677
- [['action', 'sci-fi'], [], [], 7.8, 5, "uzaylı istilası ve kaçış"],
678
  ],
679
  inputs=[tags_input, directors_input, stars_input, min_imdb_rating_slider, num_recommendations_slider, search_text_input],
680
- outputs=output_html,
681
  fn=get_movie_recommendations,
682
  label="Örnek Önerileri Deneyin"
683
  )
684
-
685
  gr.Markdown(
686
  """
687
  ---
@@ -695,4 +412,4 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
695
  )
696
 
697
  demo.launch(share=True)
698
- print("\nADIM 5: Gradio Web Arayüzü Başlatıldı.")
 
2
  import numpy as np
3
  import gradio as gr
4
  import os
5
+ from sentence_transformers import SentenceTransformer, util
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) ---")
 
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:
22
+ df = pd.read_csv(file_path)
23
+ print(f"'{csv_file_name}' başarıyla yüklendi. Toplam {len(df)} film bulundu.")
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)
38
 
39
  genre_mapping = {
40
  'action': ['action', 'action epic', 'gun fu', 'one-person army action', 'car action', 'kung fu', 'martial arts', 'martial-arts'],
 
66
  main_genres = set()
67
  for tag in tag_list:
68
  if tag in reverse_genre_map:
69
+ main_genres.add(reverse_genre_map[tag])
70
  return list(main_genres)
71
 
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
 
 
90
 
91
  def convert_votes_to_numeric(votes_str):
92
  if isinstance(votes_str, str):
93
+ votes_str = votes_str.replace(",", "")
94
  if 'K' in votes_str:
95
  return float(votes_str.replace('K', '')) * 1000
96
  elif 'M' in votes_str:
97
  return float(votes_str.replace('M', '')) * 1_000_000
98
+ try:
99
  return float(votes_str)
100
  except ValueError:
101
+ return np.nan
102
 
103
  df_filtered['Votes_numeric'] = df_filtered['Votes'].apply(convert_votes_to_numeric)
104
  df_filtered.drop('Votes', axis=1, inplace=True)
105
+ df_filtered.dropna(subset=['Votes_numeric'], inplace=True)
106
 
107
  df_filtered['Combined_Text'] = df_filtered['Title'] + ". " + \
108
  df_filtered['Description'] + ". " + \
 
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
 
 
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
+
168
  print(f"\n--- Öneri İsteği ---")
169
  print(f"Seçilen Türler: {selected_tags}")
170
  print(f"Seçilen Yönetmenler: {selected_directors}")
 
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(
234
+ by=['IMDb Rating', 'Votes_numeric'],
235
  ascending=[False, False]
236
  ).reset_index(drop=True)
237
+
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']])
249
  tags_str = ", ".join([t.title() for t in row['Tags_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.")
 
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
  """
 
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,
 
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
356
  )
357
+
358
  min_imdb_rating_slider = gr.Slider(
359
+ minimum=df_filtered['IMDb Rating'].min(),
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(
367
+ minimum=1,
368
+ maximum=20,
369
+ step=1,
370
+ value=10,
371
  label="Öneri Sayısı"
372
  )
373
 
 
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,
383
  inputs=[tags_input, directors_input, stars_input, min_imdb_rating_slider, num_recommendations_slider, search_text_input],
 
386
 
387
  gr.Examples(
388
  examples=[
389
+ [['action'], [], [], 7.6, 5, ""],
390
+ [['comedy', 'drama'], [], [], 7.8, 3, ""],
391
+ [[], ['christopher nolan'], [], 8.0, 5, ""],
392
+ [[], [], ['leonardo dicaprio'], 7.8, 3, ""],
393
+ [[], [], [], 8.0, 5, "kahramanlık ve bilim kurgu"],
394
+ [['action', 'sci-fi'], [], [], 7.8, 5, "uzaylı istilası ve kaçış"],
395
  ],
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
  ---
 
412
  )
413
 
414
  demo.launch(share=True)
415
+ print("\nADIM 5: Gradio Web Arayüzü Başlatıldı.")