|
|
| import pandas as pd
|
| from transformers import pipeline
|
| import gradio as gr
|
| import numpy as np
|
| import os
|
| from PIL import Image
|
|
|
|
|
| DATA_URL = "https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-01-21/spotify_songs.csv"
|
| DATA_PATH = "spotify_songs.csv"
|
|
|
| print("Veri seti indiriliyor...")
|
| try:
|
| if not os.path.exists(DATA_PATH):
|
| import requests
|
| response = requests.get(DATA_URL)
|
| response.raise_for_status()
|
| with open(DATA_PATH, 'wb') as f:
|
| f.write(response.content)
|
| print(f"Veri seti {DATA_PATH} konumuna başarıyla indirildi.")
|
| else:
|
| print(f"Veri seti {DATA_PATH} zaten mevcut, indirme atlandı.")
|
|
|
| df = pd.read_csv(DATA_PATH)
|
| df = df[['track_name', 'track_artist', 'playlist_genre', 'valence', 'energy', 'tempo', 'danceability']]
|
| df = df.dropna()
|
| df = df.drop_duplicates(subset=['track_name', 'track_artist'])
|
| df = df.rename(columns={'playlist_genre': 'genre', 'track_name': 'name', 'track_artist': 'artist'})
|
| print("Veri seti başarıyla yüklendi ve işlendi. Toplam şarkı sayısı:", len(df))
|
| except Exception as e:
|
| print(f"Veri seti yüklenirken veya işlenirken bir hata oluştu: {e}")
|
| print("Lütfen alternatif bir CSV dosyası deneyin veya manuel yükleyin.")
|
| df = pd.DataFrame(columns=['name', 'artist', 'genre', 'valence', 'energy', 'tempo', 'danceability'])
|
|
|
|
|
| print("\nHugging Face duygu analizi modeli yükleniyor (Metin için)...")
|
| sentiment_analyzer = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
|
| print("Metin duygu modeli yüklendi.")
|
|
|
|
|
|
|
| print("\nHugging Face sıfır-atış görüntü sınıflandırma modeli yükleniyor (Görsel için)...")
|
| image_classifier = pipeline("zero-shot-image-classification", model="openai/clip-vit-base-patch32")
|
| print("Görüntü sınıflandırma modeli yüklendi.")
|
|
|
|
|
| candidate_image_labels = [
|
| "happy photo", "sad photo", "energetic photo", "calm photo",
|
| "romantic photo", "mysterious photo", "party photo",
|
| "nature scene", "city scene", "travel photo", "food photo", "work photo",
|
| "bright photo", "dark photo", "warm colors", "cool colors",
|
| "adventure", "relaxation", "celebration", "reflection", "serenity"
|
| ]
|
|
|
|
|
|
|
| mood_mappings = {
|
| "Mutlu ve Coşkulu": {"valence": [0.7, 1.0], "energy": [0.7, 1.0]},
|
| "Hüzünlü ve Melankolik": {"valence": [0.0, 0.3], "energy": [0.0, 0.4]},
|
| "Sakin ve Huzurlu": {"valence": [0.5, 0.8], "energy": [0.2, 0.6]},
|
| "Enerjik ve Canlı": {"valence": [0.6, 1.0], "energy": [0.8, 1.0]},
|
| "Gergin ve Dramatik": {"valence": [0.2, 0.5], "energy": [0.6, 0.9]},
|
| "Romantik ve Duygusal": {"valence": [0.6, 0.9], "energy": [0.3, 0.7]},
|
| "Gizemli ve Derin": {"valence": [0.3, 0.6], "energy": [0.4, 0.7]},
|
| "Parti ve Eğlence": {"valence": [0.7, 1.0], "energy": [0.8, 1.0]},
|
| "Odaklanma ve Çalışma": {"valence": [0.4, 0.7], "energy": [0.3, 0.6]},
|
| "Seyahat ve Keşif": {"valence": [0.6, 0.9], "energy": [0.6, 0.9]},
|
| }
|
|
|
| available_genres = df['genre'].unique().tolist()
|
| available_genres.sort()
|
|
|
|
|
| def get_song_recommendations(story_text, uploaded_image, selected_mood, selected_genre, num_recommendations=5):
|
| if df.empty:
|
| return "Veri seti yüklenemediği için öneri yapılamıyor. Lütfen kontrol edin."
|
|
|
|
|
| text_sentiment_score = 0.5
|
| if story_text:
|
| try:
|
| sentiment_result = sentiment_analyzer(story_text)[0]
|
| text_sentiment_score = sentiment_result['score'] if sentiment_result['label'] == 'POSITIVE' else (1 - sentiment_result['score'])
|
| except Exception as e:
|
| print(f"Metin duygu analizi sırasında hata oluştu: {e}. Varsayılan nötr duygu atanıyor.")
|
|
|
|
|
| image_valence_adjustment = 0
|
| image_energy_adjustment = 0
|
|
|
| if uploaded_image is not None:
|
| try:
|
| print("Görsel analizi yapılıyor...")
|
|
|
| image_results = image_classifier(images=uploaded_image, candidate_labels=candidate_image_labels)
|
| print(f"Görsel analiz sonuçları: {image_results}")
|
|
|
|
|
|
|
| for res in image_results:
|
| label = res['label']
|
| score = res['score']
|
| if score > 0.6:
|
| if "happy photo" in label or "bright photo" in label or "celebration" in label:
|
| image_valence_adjustment += 0.1 * score
|
| image_energy_adjustment += 0.05 * score
|
| elif "sad photo" in label or "dark photo" in label or "reflection" in label:
|
| image_valence_adjustment -= 0.1 * score
|
| image_energy_adjustment -= 0.05 * score
|
| elif "energetic photo" in label or "party photo" in label or "city scene" in label or "adventure" in label:
|
| image_energy_adjustment += 0.1 * score
|
| elif "calm photo" in label or "nature scene" in label or "relaxation" in label or "serenity" in label:
|
| image_energy_adjustment -= 0.05 * score
|
| image_valence_adjustment += 0.03 * score
|
| elif "romantic photo" in label:
|
| image_valence_adjustment += 0.05 * score
|
| image_energy_adjustment -= 0.03 * score
|
| except Exception as e:
|
| print(f"Görsel analizi sırasında hata oluştu: {e}. Görsel analizi atlanıyor.")
|
|
|
|
|
| target_valence_range = list(mood_mappings[selected_mood]["valence"])
|
| target_energy_range = list(mood_mappings[selected_mood]["energy"])
|
|
|
|
|
| text_sentiment_adjustment = (text_sentiment_score - 0.5) * 0.4
|
| target_valence_range[0] = max(0, target_valence_range[0] + text_sentiment_adjustment)
|
| target_valence_range[1] = min(1, target_valence_range[1] + text_sentiment_adjustment)
|
|
|
|
|
| target_valence_range[0] = max(0, target_valence_range[0] + image_valence_adjustment)
|
| target_valence_range[1] = min(1, target_valence_range[1] + image_valence_adjustment)
|
| target_energy_range[0] = max(0, target_energy_range[0] + image_energy_adjustment)
|
| target_energy_range[1] = min(1, target_energy_range[1] + image_energy_adjustment)
|
|
|
|
|
| target_valence_range = [min(1, max(0, tv)) for tv in target_valence_range]
|
| target_energy_range = [min(1, max(0, te)) for te in target_energy_range]
|
|
|
|
|
|
|
|
|
| filtered_songs = df[df['genre'] == selected_genre].copy()
|
|
|
| if filtered_songs.empty:
|
| return f"'{selected_genre}' türünde şarkı bulunamadı. Lütfen başka bir tür seçin."
|
|
|
| filtered_songs['valence_diff'] = filtered_songs['valence'].apply(
|
| lambda x: min(abs(x - target_valence_range[0]), abs(x - target_valence_range[1]))
|
| )
|
| filtered_songs['energy_diff'] = filtered_songs['energy'].apply(
|
| lambda x: min(abs(x - target_energy_range[0]), abs(x - target_energy_range[1]))
|
| )
|
|
|
| filtered_songs['fit_score'] = 1 / (filtered_songs['valence_diff'] + filtered_songs['energy_diff'] + 0.01)
|
|
|
| recommended_songs = filtered_songs.sort_values(by='fit_score', ascending=False).head(num_recommendations)
|
|
|
| if recommended_songs.empty:
|
| return "Seçimlerinize uygun şarkı bulunamadı. Daha geniş kriterler deneyin."
|
|
|
| results = []
|
| for index, row in recommended_songs.iterrows():
|
| results.append(f"• {row['name']} - {row['artist']} ({row['genre']})")
|
| return "\n".join(results)
|
|
|
|
|
|
|
| print("\nGradio arayüzü başlatılıyor...")
|
| iface = gr.Interface(
|
| fn=get_song_recommendations,
|
| inputs=[
|
| gr.Textbox(lines=3, placeholder="Instagram hikayenizi buraya yazın (örneğin: 'Gün batımında sahilde yürüyorum, huzur veren bir an')", label="Hikaye Metni (İsteğe Bağlı)"),
|
| gr.Image(type="pil", label="Hikaye Görseli (İsteğe Bağlı, JPG/PNG)"),
|
| gr.Dropdown(list(mood_mappings.keys()), label="Hikayenin Ruh Hali"),
|
| gr.Dropdown(available_genres, label="Müzik Türü"),
|
| ],
|
| outputs=gr.Textbox(label="Önerilen Şarkılar", lines=5),
|
| title="🌟 Akıllı Hikaye Müzik Önerici (Görsel ve Metin Analizli) 🌟",
|
| description="Hikaye metninizi ve/veya görselinizi yükleyerek, ayrıca ruh hali ve müzik türü seçerek Instagram hikayeniz için mükemmel şarkı önerileri alın. Öneriler Kaggle veri seti ve Hugging Face NLP/Görsel analiz ile güçlendirilmiştir.",
|
| allow_flagging="never"
|
| )
|
|
|
| iface.launch(share=False) |