File size: 9,746 Bytes
2e13c1a
 
 
 
 
 
 
 
 
 
 
93931c2
2e13c1a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d575794
 
2e13c1a
 
 
 
 
 
 
 
 
 
 
31e2fdc
 
 
 
 
4a85ea2
31e2fdc
 
 
 
 
 
 
 
 
 
 
 
2e13c1a
31e2fdc
2e13c1a
 
 
31e2fdc
2e13c1a
 
c021d14
2e13c1a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbc159c
2d01678
2b48802
f1000eb
 
 
b0ce6eb
 
 
 
 
38103d4
b0ce6eb
f1000eb
966861e
fbc159c
 
 
 
 
 
f072d45
38103d4
e02c2b9
 
 
 
f072d45
451d3ce
e02c2b9
 
 
f072d45
38103d4
 
 
 
 
 
 
3e677d8
451d3ce
e02c2b9
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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)