Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import re | |
| import json | |
| import time | |
| from google import genai | |
| # Filter songs based on region and time period | |
| def filter_songs(region, time_period): | |
| time_map = { | |
| "过去7天": 7, | |
| "过去30天": 30 | |
| } | |
| region_map = { | |
| "美国": "us", | |
| "英国": "uk", | |
| "韩国": "kr", | |
| "日本": "jp" | |
| } | |
| file_name = f"trend_data_{region_map[region]}_{time_map[time_period]}.json" | |
| with open(file_name, "r", encoding="utf-8") as file: | |
| data = json.load(file) # 解析 JSON 文件 | |
| return data | |
| # Initial song data | |
| ALL_SONGS = filter_songs("美国", "过去7天") | |
| # Simulate API call for song analysis | |
| def analyze_song(song_name): | |
| prompt = """ | |
| 根据我上传的歌曲音频,站在乐评人的角度进行专业点评,要求包含两方面信息: | |
| ## 一. 对歌曲的详细解析,必须使用中文描述,需包含以下方面(确保每个部分尽可能详细和具体,以生成精准的音乐评价): | |
| 1. 流派/风格 (Genre/Style):{在此处填写一个或多个音乐流派,多个流派可以用逗号或 "和" 连接,例如:classic rock, synthwave 和 nostalgic} | |
| 2. 乐器 (Instrumentation) | |
| - 主要乐器:{列出主要乐器,并用形容词修饰其音色或演奏方式,例如:distorted electric guitar, soft piano melody} | |
| - 次要乐器(可选):{列出次要乐器,同样可以添加修饰,例如:pulsating bass, rhythmic percussion} | |
| 3. 人声 (Vocal Style) (可选) | |
| - 性别:{male/female/无} | |
| - 音色/风格:{用形容词描述人声的特点,例如:raspy, warm, soulful, slight reverb} | |
| - 演唱方式(可选):{例如:call-and-response vocals, harmonies, spoken word} | |
| 4. 情绪/氛围 (Mood/Atmosphere):{使用形容词或短语描述音乐的整体感觉,例如:high-energy, smooth, dreamy, uplifting, melancholic} | |
| - 场景描述(可选):{用简短的场景描述来进一步强化氛围,例如:late-night lounge setting, driving down a desert highway} | |
| 5. 具体元素/参考 (Specific Elements/References) (可选):{提供更具体的风格指导、年代参考或特定元素,例如:anthemic chorus, '80s stadium rock, 80s-inspired, reminiscent of Vangelis} | |
| 6. 节奏/动态 (Tempo/Dynamics) (可选):使用动词或形容词描述节奏的特点, 或乐器动态, 例如: Pulsating, driving, laid-back, syncopated,乐器动态: Crescendo, diminuendo, staccato 等 | |
| 基于上述详细解析,总结一句用于音乐生成的英文文本提示词,不要超过180个字符,必须使用英文描述,示例如下:An 80s-inspired synthwave track with analog synthesizers, pulsating bass, and dreamy atmospheric pads. Male vocals with slight reverb for a nostalgic, futuristic feel. | |
| 最终使用json返回内容,json格式示例如下,禁止其他多余输出: | |
| { | |
| "chinese_description": "..." | |
| "english_prompt": "..." | |
| } | |
| """ | |
| client = genai.Client(api_key=os.getenv("GOOGLE_GEN_KEY")) | |
| myfile = client.files.upload(file=f'media/{song_name}.mp3') | |
| response = client.models.generate_content( | |
| model='gemini-2.0-flash', | |
| contents=[prompt, myfile] | |
| ) | |
| text = response.text | |
| print(text) | |
| match = re.search(r'```json\n(.*?)\n```', text, re.DOTALL) | |
| if match: | |
| json_str = match.group(1) | |
| try: | |
| result = json.loads(json_str) | |
| except json.JSONDecodeError as e: | |
| print(f"JSON parsing error: {e}") | |
| return { | |
| "song_description": result["chinese_description"], | |
| "suno_prompt": result["english_prompt"] | |
| } | |
| # Simulate Suno API call | |
| def generate_similar_song(suno_prompt): | |
| # Simulate API call delay | |
| time.sleep(3) | |
| # Simulated response | |
| return { | |
| "audio_url": "https://sf16-ies-music-sg.tiktokcdn.com/obj/tos-alisg-ve-2774/oYYOWM1aKGyB8Eixn0hiAfhWsAjzswMoIItQMI", | |
| "status": "success" | |
| } | |
| # Create song list HTML | |
| def create_song_list(songs): | |
| html = """ | |
| <style> | |
| .song-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 16px; | |
| padding: 16px; | |
| } | |
| .song-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| padding: 12px; | |
| border-radius: 8px; | |
| background-color: #f9f9f9; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| } | |
| .rank { | |
| font-size: 24px; | |
| font-weight: bold; | |
| min-width: 40px; | |
| text-align: center; | |
| } | |
| .cover { | |
| width: 80px; | |
| height: 80px; | |
| border-radius: 4px; | |
| object-fit: cover; | |
| } | |
| .song-info { | |
| flex: 1; | |
| } | |
| .song-name { | |
| font-size: 18px; | |
| font-weight: bold; | |
| margin-bottom: 4px; | |
| } | |
| .video-count { | |
| color: #666; | |
| font-size: 14px; | |
| } | |
| .button-group { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .button { | |
| padding: 8px 12px; | |
| border-radius: 4px; | |
| border: none; | |
| cursor: pointer; | |
| font-size: 14px; | |
| font-weight: bold; | |
| } | |
| .tiktok-btn { | |
| color: white; | |
| } | |
| .play-btn { | |
| background-color: #1db954; | |
| color: white; | |
| } | |
| .stats-btn { | |
| background-color: #0077b5; | |
| color: white; | |
| } | |
| .analyze-btn { | |
| background-color: #6c5ce7; | |
| color: white; | |
| } | |
| </style> | |
| <div class="song-container"> | |
| """ | |
| # <div class="video-count">{song['video_count']}</div> | |
| # <button class="button play-btn" onclick='playSong("{song['title']}")'>播放</button> | |
| # <button class="button analyze-btn" onclick='analyzeSong("{song['title']}")'>分析歌曲</button> | |
| for song in songs: | |
| html += f""" | |
| <div class="song-item" id="song-{song['rank']}"> | |
| <div class="rank">{song['rank']}</div> | |
| <img class="cover" src="{song['cover_url']}" alt="{song['title']}"> | |
| <div class="song-info"> | |
| <div class="song-name">{song['title']} - {song['author']}</div> | |
| </div> | |
| <div class="button-group"> | |
| <a href="{song['link']}" target="_blank" class="button tiktok-btn">TikTok地址</a> | |
| </div> | |
| </div> | |
| """ | |
| html += "</div>" | |
| return html | |
| # Main app function | |
| def app(): | |
| # Create the Gradio interface | |
| with gr.Blocks() as demo: | |
| # App title | |
| gr.Markdown("# TikTok Song Trends Analyzer") | |
| # Main tabs | |
| with gr.Tabs(): | |
| # Song trends tab | |
| with gr.TabItem("Song Trends"): | |
| with gr.Row(): | |
| region_dropdown = gr.Dropdown( | |
| choices=["美国", "英国", "韩国", "日本"], | |
| #choices=["All Regions", "US", "UK", "JP", "KR", "CN", "IN", "BR", "FR", "DE", "ES"], | |
| value="美国", | |
| label="Region" | |
| ) | |
| time_period = gr.Dropdown( | |
| choices=["过去7天", "过去30天"], | |
| value="过去7天", | |
| label="Time Period" | |
| ) | |
| # Song list container | |
| song_list = gr.HTML(create_song_list(ALL_SONGS)) | |
| # Update song list when filters change | |
| def update_song_list(region, time_period): | |
| filtered_songs = filter_songs(region, time_period) | |
| return create_song_list(filtered_songs) | |
| region_dropdown.change( | |
| fn=update_song_list, | |
| inputs=[region_dropdown, time_period], | |
| outputs=song_list | |
| ) | |
| time_period.change( | |
| fn=update_song_list, | |
| inputs=[region_dropdown, time_period], | |
| outputs=song_list | |
| ) | |
| # Song analysis tab | |
| with gr.TabItem("Song Analysis"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| song_name = gr.Dropdown( | |
| choices=list(map(lambda x: x["title"], ALL_SONGS)), | |
| label="Select a Song", | |
| interactive=True | |
| ) | |
| analysis_btn = gr.Button("分析歌曲") | |
| song_description = gr.Markdown(label="Song Description") | |
| suno_prompt = gr.Textbox(label="Suno Prompt", interactive=False, lines=5) | |
| # with gr.Column(scale=2): | |
| # suno_prompt = gr.Textbox(label="Suno Prompt", interactive=False, lines=5) | |
| # generate_btn = gr.Button("生成相似歌曲") | |
| # Audio player for generated song | |
| audio_player = gr.Audio(label="Generated Song", type="filepath", interactive=False) | |
| # Handle song analysis | |
| def do_song_analysis(song_name): | |
| if not song_name: | |
| return "", "", "", "Please select a song from the trends list." | |
| analysis_result = analyze_song(song_name) | |
| return analysis_result["song_description"], analysis_result["suno_prompt"], f'media/{song_name}.mp3' | |
| # Handle similar song generation | |
| def do_generate_similar(suno_prompt): | |
| if not suno_prompt: | |
| return None, "Please analyze a song first to get a Suno prompt." | |
| result = generate_similar_song(suno_prompt) | |
| if result["status"] == "success": | |
| return result["audio_url"] | |
| else: | |
| return None | |
| # generate_btn.click( | |
| # fn=do_generate_similar, | |
| # inputs=suno_prompt, | |
| # outputs=[audio_player] | |
| # ) | |
| analysis_btn.click( | |
| fn=do_song_analysis, | |
| inputs=song_name, | |
| outputs=[song_description, suno_prompt, audio_player] | |
| ) | |
| # Launch the app | |
| demo.launch() | |
| if __name__ == "__main__": | |
| app() |