from huggingface_hub import InferenceClient from pydub import AudioSegment import gradio as gr import datetime import edge_tts import asyncio import os import subprocess def create_video(audio_file, turn, output_video="output.mp4"): # Chọn file video nền dựa trên lượt background_video = "missVN.mp4" if turn == "Miss AI Vietnam" else "missCN.mp4" # Lệnh ffmpeg để tạo video command = [ "ffmpeg", "-stream_loop", "-1", # Lặp lại video nền vô hạn "-i", background_video, # Video nền (tùy thuộc vào lượt) "-i", audio_file, # File audio đầu vào "-vf", "drawtext=text='MISS AI':fontcolor=white:fontsize=100:fontfile=/path/to/font.ttf:x=10:y=10", # Văn bản trên video "-t", "45.7", # Thời lượng video "-c:v", "libx264", # Codec video "-c:a", "aac", # Codec audio "-shortest", # Dừng khi audio kết thúc "-y", # Ghi đè file nếu tồn tại output_video # File video đầu ra ] # Chạy lệnh ffmpeg subprocess.run(command, check=True) return output_video # Khởi tạo các mô hình từ Hugging Face MissAIVietnam = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1") MissAIChina = InferenceClient("mistralai/Mixtral-8x7B-Instruct-v0.1") # Biến toàn cục để lưu trữ chủ đề, vị trí và lịch sử tranh luận topic = None position_1 = None position_2 = None turn = None history = [] audio_files = [] # Danh sách lưu trữ các file audio # Hàm để tạo phản hồi tranh luận def generate_response(llm, position, who, topic, message): # Xác định hướng dẫn cụ thể cho từng bên if who == "Miss AI Vietnam": system_message = { "role": "system", "content": f"You are Miss AI Vietnam, tasked with defending the position '{position}' on the topic '{topic}'. " f"Only write the spoken content, without any notes or explanations. Your answer should be concise, logical and convincing, focusing on the topic and also trying to exploit the opponent's weak points to give insightful counter-arguments." f"Ensure that your responses are thoughtful, evidence-based, and persuasive. Keep them concise—aim for 4 to 5 lines in a single paragraph, with the entire response not exceeding 100 words. " } elif who == "Miss AI China": system_message = { "role": "system", "content": f"You are Miss AI China, tasked with defending the position '{position}' on the topic '{topic}'. " f"Your responses must be concise, logical, and persuasive, with a focus on economic and technological perspectives. " f"Ensure that your responses are thoughtful, evidence-based, and persuasive. Keep them concise—aim for 4 to 5 lines in a single paragraph, with the entire response not exceeding 100 words. " f"Only write the spoken content, without any notes or explanations." } else: raise ValueError("Invalid participant name.") # Thêm tin nhắn hệ thống và tin nhắn người dùng vào danh sách messages messages = [system_message] messages.append({"role": "user", "content": message}) # Tạo phản hồi từ mô hình response = f"{who}:\n" for message_chunk in llm.chat_completion( messages, max_tokens=256, stream=True, temperature=0.4, top_p=0.95): response += message_chunk.choices[0].delta.content return response # Hàm để chuyển văn bản thành âm thanh bằng edge_tts async def text_to_speech(text, voice, output_file="output.mp3"): communicate = edge_tts.Communicate(text, voice) # Chọn giọng nói await communicate.save(output_file) return output_file # Hàm để tạo file audio final def concatenate_audio_files(audio_files, output_file="final_debate.mp3"): if not audio_files: return None # Tạo một đối tượng AudioSegment rỗng final_audio = AudioSegment.empty() # Nối từng file audio vào final_audio for audio_file in audio_files: audio_segment = AudioSegment.from_file(audio_file) final_audio += audio_segment # Xuất file audio cuối cùng final_audio.export(output_file, format="mp3") return output_file # Hàm để bắt đầu tranh luận giữa Miss AI Vietnam và Miss AI China def start_debate(topic, position_1, position_2): global turn, history, audio_files if not topic or not position_1 or not position_2: return "Please provide the debate topic and positions for both participants.", [], None, None # Đảm bảo các vị trí là đối lập if position_1 == position_2: return "The positions of both participants must be opposite. Please adjust them.", [], None, None turn = "Miss AI Vietnam" history = [] # Đặt lại lịch sử audio_files = [] # Đặt lại danh sách file audio initial_message = "Opening Statement" response = generate_response(MissAIVietnam, position_1, 'Miss AI Vietnam', topic, initial_message) history.append((initial_message, response)) # Chuyển văn bản thành âm thanh với giọng của Miss AI Vietnam output_audio = asyncio.run(text_to_speech(response, "en-US-JennyNeural")) # Giọng nữ tiếng Anh Mỹ audio_files.append(output_audio) # Thêm file audio vào danh sách # Tạo video từ audio và lượt hiện tại output_video = create_video(output_audio, turn) return f"The debate has started! {turn} begins.", history, output_video, output_audio # Hàm để chuyển lượt trong tranh luận def next_turn(topic, position_1, position_2, current_history): global turn, history, audio_files if not current_history: return "No ongoing debate. Please start a debate first.", [], None, None # Logic chuyển lượt if turn == "Miss AI Vietnam": turn = "Miss AI China" llm, position, who = MissAIChina, position_2, 'Miss AI China' voice = "en-GB-LibbyNeural" # Giọng nữ tiếng Anh Anh else: turn = "Miss AI Vietnam" llm, position, who = MissAIVietnam, position_1, "Miss AI Vietnam" voice = "en-US-JennyNeural" # Giọng nữ tiếng Anh Mỹ last_response = current_history[-1][1] # Lấy tin nhắn cuối cùng response = generate_response(llm, position, who, topic, last_response) history.append(("", response)) # Thêm phản hồi vào lịch sử # Chuyển văn bản thành âm thanh với giọng tương ứng output_audio = asyncio.run(text_to_speech(response, voice)) audio_files.append(output_audio) # Thêm file audio vào danh sách # Tạo video từ audio và lượt hiện tại output_video = create_video(output_audio, turn) return f"It's now {turn}'s turn.", history, output_video, output_audio # Hàm để kết thúc tranh luận và nối các file audio def end_debate(): global audio_files if not audio_files: return "No debate audio found.", None # Nối các file audio thành một file duy nhất final_audio_file = concatenate_audio_files(audio_files) return "The debate has ended. Here is the full debate audio.", final_audio_file # Interface with gr.Blocks(theme=gr.themes.Soft(font=[gr.themes.GoogleFont("Roboto Mono")])) as demo: gr.Markdown("# Welcome to The Miss World AI 🗣️🤖") with gr.Row(): with gr.Column(scale=1): topic_input = gr.Textbox(label="STEP 1: Debate Topic", placeholder="Enter the debate topic") position_1_input = gr.Radio(["For", "Against"], label="STEP 2: Miss AI Vietnam's Position") position_2_input = gr.Radio(["For", "Against"], label="STEP 3: Miss AI China's Position") start_button = gr.Button("STEP 4: Start", variant='primary') next_button = gr.Button("Next Turn") end_button = gr.Button("End Debate", variant='stop') # Nút kết thúc tranh luận status_output = gr.Textbox(label="Status", interactive=False) with gr.Column(scale=2): with gr.Row(): # Chatbot chiếm 70% chiều rộng, Video chiếm 30% with gr.Column(scale=7): chatbot = gr.Chatbot(label="Debate Arena", height=500) # Hiển thị lịch sử tranh luận with gr.Column(scale=3): video_output = gr.Video(label="Debate Video", autoplay=True, height=500) # Hiển thị video # Audio và Final Audio được đặt bên dưới audio_output = gr.Audio(label="Debate Audio", autoplay=None) # Hiển thị audio hiện tại final_audio_output = gr.Audio(label="Full Debate Audio", visible=False) # Hiển thị audio cuối cùng start_button.click( fn=start_debate, inputs=[topic_input, position_1_input, position_2_input], outputs=[status_output, chatbot, video_output, audio_output], ) next_button.click( fn=next_turn, inputs=[topic_input, position_1_input, position_2_input, chatbot], outputs=[status_output, chatbot, video_output, audio_output], ) end_button.click( fn=end_debate, inputs=[], outputs=[status_output, final_audio_output], # Trả về audio cuối cùng ).then( lambda: gr.Audio(visible=True), None, final_audio_output # Hiển thị thành phần audio cuối cùng ) if __name__ == "__main__": demo.launch(share=True)