File size: 5,394 Bytes
07c0c7c
 
d78e18f
 
07c0c7c
d78e18f
 
07c0c7c
c969713
 
07c0c7c
 
d78e18f
 
 
07c0c7c
c969713
d78e18f
 
 
07c0c7c
 
d78e18f
 
 
c969713
d78e18f
 
c969713
 
d78e18f
c969713
d78e18f
 
c969713
d78e18f
 
07c0c7c
d78e18f
c969713
d78e18f
c969713
d78e18f
 
07c0c7c
 
d78e18f
 
 
 
 
 
07c0c7c
 
 
d78e18f
07c0c7c
d78e18f
 
 
 
07c0c7c
d78e18f
 
07c0c7c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec2d544
07c0c7c
 
 
 
 
 
 
 
 
 
 
 
 
 
ec4b640
07c0c7c
 
 
 
ec2d544
07c0c7c
 
 
 
ec2d544
07c0c7c
 
 
 
1fc3314
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
import gradio as gr
import os
import tempfile
import re
from pydub import AudioSegment  # Thư viện để kết hợp các file âm thanh
from openai import OpenAI

# API key và endpoint mặc định
DEFAULT_API_KEY = "sk-GINVEtfNbrXNcGQhf3rEUIgzoicNGIApovqZxe0AYJF5PkTV"
DEFAULT_BASE_URL = "https://open.keyai.shop"

# Giới hạn ký tự tối đa mỗi yêu cầu API
MAX_CHAR_LIMIT = 140964096

def clean_text(text):
    # Loại bỏ khoảng trắng thừa và xuống dòng
    cleaned_text = re.sub(r'\s+', ' ', text.strip())
    return cleaned_text

def split_text(text, limit=MAX_CHAR_LIMIT):
    # Tách văn bản thành các đoạn không vượt quá giới hạn ký tự
    words = text.split(' ')
    chunks = []
    current_chunk = ""
    for word in words:
        if len(current_chunk) + len(word) + 1 <= limit:
            current_chunk += word + " "
        else:
            chunks.append(current_chunk.strip())
            current_chunk = word + " "
    if current_chunk:
        chunks.append(current_chunk.strip())
    return chunks

def tts(text, model, voice, speed):
    cleaned_text = clean_text(text)
    chunks = split_text(cleaned_text)
    
    audio_segments = []
    
    try:
        client = OpenAI(api_key=DEFAULT_API_KEY, base_url=DEFAULT_BASE_URL + '/v1')
        for chunk in chunks:
            response = client.audio.speech.create(
                model=model,    # Các lựa chọn: "tts-1", "tts-1-hd"
                voice=voice,    # Các lựa chọn: 'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'
                input=chunk,
                speed=speed
            )
            with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
                temp_file.write(response.content)
                temp_file_path = temp_file.name
                audio_segments.append(AudioSegment.from_mp3(temp_file_path))
    except Exception as error:
        raise gr.Error("Đã xảy ra lỗi khi tạo giọng nói. Vui lòng kiểm tra API key hoặc thử lại sau.")
    
    # Nối các đoạn âm thanh lại thành một file duy nhất
    final_audio = sum(audio_segments)
    with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as final_temp_file:
        final_audio.export(final_temp_file.name, format="mp3")
        final_audio_path = final_temp_file.name

    return final_audio_path

# CSS tùy chỉnh với giao diện tối và tích hợp FontAwesome cho icon
custom_css = """
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css');

body {
    background-color: #1e1e2f;
    color: #e0e0e0;
    font-family: 'Arial', sans-serif;
}
.title {
    font-size: 2.5rem;
    font-weight: bold;
    text-align: center;
    margin-bottom: 30px;
    color: #f1f1f1;
}
.container {
    margin: auto;
    width: 90%;
    padding: 20px;
}
.card {
    background: #2e2e42;
    padding: 20px;
    border-radius: 8px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
    margin-bottom: 20px;
}
.gradio-container {
    background: #1e1e2f;
}
button {
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 8px;
    padding: 10px 20px;
    font-size: 1rem;
    cursor: pointer;
}
button:hover {
    background-color: #45a049;
}
input, textarea, select {
    background: #3a3a50;
    border: 1px solid #555;
    color: #e0e0e0;
    padding: 8px;
    border-radius: 4px;
}
select {
    padding: 8px 10px;
}
label {
    font-weight: bold;
    margin-bottom: 5px;
}
"""

with gr.Blocks(css=custom_css) as demo:
    # Tiêu đề với icon Microphone
    gr.Markdown("<div class='title'><i class='fas fa-microphone-alt'></i> OpenAI TTS</div>")
    
    with gr.Column(elem_classes="container"):
        with gr.Row():
            # Cột nhập văn bản (mở rộng với 15 dòng)
            with gr.Column(elem_classes="card"):
                text = gr.Textbox(label="Văn bản đầu vào", placeholder="Nhập văn bản cần chuyển giọng nói...", lines=15)
                char_counter = gr.Markdown("Character count: 0")
            # Cột cài đặt tham số TTS với menu được cải tiến
            with gr.Column(elem_classes="card"):
                model = gr.Dropdown(choices=['tts-1', 'tts-1-hd'], label='Chọn Model', value='tts-1')
                voice = gr.Dropdown(choices=['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'], label='Chọn Giọng', value='alloy')
                speed = gr.Slider(minimum=0.5, maximum=2.0, step=0.1, label="Tốc độ", value=1.0)
        
        # Nút chuyển đổi với icon Play
        with gr.Row(elem_classes="card"):
            btn = gr.Button(" Chuyển ")
        
        # Kết quả âm thanh
        with gr.Row(elem_classes="card"):
            output_audio = gr.Audio(label="Kết quả âm thanh")
    
    # Hàm cập nhật số lượng ký tự
    def update_char_counter(text):
        cleaned_text = clean_text(text)
        return f"Character count: {len(cleaned_text)}"
    
    text.change(fn=update_char_counter, inputs=text, outputs=char_counter)
    text.submit(fn=tts, inputs=[text, model, voice, speed], outputs=output_audio, api_name="tts_enter_key", concurrency_limit=None)
    btn.click(fn=tts, inputs=[text, model, voice, speed], outputs=output_audio, api_name="tts_button", concurrency_limit=None)

demo.launch()