TDN-M commited on
Commit
1e23c4b
·
verified ·
1 Parent(s): d00426c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -116
app.py CHANGED
@@ -2,27 +2,22 @@ import asyncio
2
  import mimetypes
3
  import os
4
  import tempfile
 
5
  import fitz # PyMuPDF
6
  import random
7
  import gradio as gr
8
  from docx import Document
 
 
 
 
 
 
9
  from content_generation import create_content, CONTENT_TYPES
10
  from openai import OpenAI
11
- import edge_tts
12
- from moviepy.editor import VideoFileClip, AudioFileClip, CompositeVideoClip, TextClip
13
-
14
- # Kiểm tra file video nền
15
- background_video = "default_background.mp4"
16
- if not os.path.exists(background_video):
17
- raise FileNotFoundError(f"File video nền không tồn tại: {background_video}")
18
-
19
- # Kiểm tra file font
20
- font_file = "/LHanoienne.otf"
21
- if not os.path.exists(font_file):
22
- raise FileNotFoundError(f"File font không tồn tại: {font_file}")
23
 
24
  # Khởi tạo client OpenAI với API key từ biến môi trường
25
- client_openai = OpenAI(api_key=os.environ.get('OPENAI_API_KEY'))
26
 
27
  def create_docx(content, output_path):
28
  """
@@ -52,80 +47,53 @@ def process_docx(file_path):
52
  text += para.text
53
  return text
54
 
55
- async def convert_text_to_speech(text, language='vi', output_file="output.wav"):
56
  """
57
- Chuyển đổi văn bản thành giọng nói sử dụng edge_tts.
58
  """
59
- try:
60
- communicate = edge_tts.Communicate(text, "vi-VN-JennyNeural")
61
- with open(output_file, "wb") as file:
62
- await communicate.save(file)
63
- return output_file
64
- except Exception as e:
65
- raise Exception(f"Lỗi khi chuyển đổi văn bản thành giọng nói: {str(e)}")
66
 
67
- def create_video(audio_file, custom_text, text_color, output_video="output.mp4"):
68
  """
69
- Tạo video với văn bản tùy chỉnh.
70
  """
71
- # Định nghĩa màu sắc chữ
72
- color_map = {
73
- "Trắng": "white",
74
- "Đỏ": "red",
75
- "Xanh dương": "blue",
76
- "Xanh lá": "green",
77
- "Vàng": "yellow"
78
- }
79
- font_color = color_map.get(text_color, "white") # Mặc định trắng nếu không tìm thấy
80
-
81
- # Tạo video nền
82
- video_clip = VideoFileClip(background_video)
83
-
84
- # Tạo audio clip
85
- audio_clip = AudioFileClip(audio_file)
86
-
87
- # Tạo video clip với audio
88
- final_video = video_clip.set_audio(audio_clip)
89
-
90
- # Tạo text clip nếu có văn bản tùy chỉnh
91
- if custom_text:
92
- txt_clip = TextClip(custom_text, fontsize=50, color=font_color, font=font_file)
93
- txt_clip = txt_clip.set_position(('left', 'top')).set_duration(final_video.duration)
94
- final_video = CompositeVideoClip([final_video, txt_clip])
95
-
96
- # Lưu video cuối cùng
97
- final_video.write_videofile(output_video, codec='libx264', audio_codec='aac')
98
- return output_video
99
 
100
  def interface():
101
- with gr.Blocks(theme=gr.themes.Soft(font=[gr.themes.GoogleFont("Roboto Mono")])) as app:
102
  gr.Markdown("# Ứng dụng Tạo Nội dung và Video")
 
103
  with gr.Tab("Tạo Nội dung"):
104
- with gr.Row():
105
- with gr.Column():
106
- prompt = gr.Textbox(label="Nhập yêu cầu nội dung")
107
- file_upload = gr.File(label="Tải lên file kèm theo", type="filepath")
108
- content_type = gr.Radio(label="Chọn loại nội dung",
109
- choices=CONTENT_TYPES,
110
- value=None) # Giá trị mặc định là không có gì được chọn
111
- content_button = gr.Button("Tạo Nội dung")
112
-
113
- with gr.Column():
114
- content_output = gr.Textbox(label="Nội dung tạo ra", interactive=True)
115
- use_generated_text = gr.Checkbox(label="Sử dụng văn bản được tạo bởi LLM", value=True)
116
- manual_text_input = gr.Textbox(label="Nhập văn bản thủ công", visible=False)
117
- language = gr.Dropdown(label="Chọn ngôn ngữ", choices=["vi", "en"], value="vi")
118
- custom_text_input = gr.Textbox(label="Nhập văn bản tùy chỉnh (trống nếu không muốn hiển thị)", value="")
119
- text_color = gr.Dropdown(label="Chọn màu chữ", choices=["Trắng", "Đỏ", "Xanh dương", "Xanh lá", "Vàng"], value="Trắng")
120
- confirm_button = gr.Button("Xác nhận nội dung")
121
- download_docx = gr.File(label="Tải xuống file DOCX", interactive=False)
122
- download_audio = gr.File(label="Tải xuống file âm thanh", interactive=False)
123
- download_video = gr.File(label="Tải xuống file video", interactive=False)
124
- status_message = gr.Label(label="Trạng thái")
125
-
126
- def toggle_manual_text(use_generated_text):
127
- return {"visible": not use_generated_text}
128
-
129
  def generate_content(prompt, file, content_type):
130
  try:
131
  status = "Đang xử lý..."
@@ -141,56 +109,116 @@ def interface():
141
  prompt = f"{prompt}\n\nDưới đây là nội dung của file tài liệu:\n\n{file_content}"
142
  else:
143
  raise ValueError("Định dạng file không được hỗ trợ.")
 
144
  if not content_type:
145
  raise ValueError("Vui lòng chọn một loại nội dung")
 
146
  script_content = create_content(prompt, content_type, "Tiếng Việt")
147
  docx_path = "script.docx"
148
  create_docx(script_content, docx_path)
 
149
  status = "Đã tạo nội dung thành công!"
150
- return script_content, docx_path, True, None, status
151
  except Exception as e:
152
  status = f"Đã xảy ra lỗi: {str(e)}"
153
- return "", None, True, None, status
154
-
155
- async def confirm_content(content_output, use_generated_text, manual_text_input, language, custom_text_input, text_color):
156
- try:
157
- if use_generated_text:
158
- text_to_convert = content_output
159
- else:
160
- text_to_convert = manual_text_input
161
-
162
- if not text_to_convert:
163
- return None, None, None, "Vui lòng cung cấp văn bản để chuyển đổi."
164
-
165
- docx_path = "script.docx"
166
- create_docx(text_to_convert, docx_path)
167
- status_message.value = "Đang chuyển đổi văn bản thành giọng nói..."
168
- audio_path = await convert_text_to_speech(text_to_convert, language)
169
- status_message.value = "Đã chuyển đổi văn bản thành giọng nói thành công!"
170
- status_message.value = "Đang tạo video..."
171
- video_path = create_video(audio_path, custom_text_input, text_color)
172
- status_message.value = "Đã tạo video thành công!"
173
- return docx_path, audio_path, video_path, status_message.value
174
- except Exception as e:
175
- status_message.value = f"Đã xảy ra lỗi: {str(e)}"
176
- return None, None, None, status_message.value
177
-
178
- # Liên kết sự kiện change của checkbox với hàm toggle_manual_text
179
- use_generated_text.change(fn=toggle_manual_text, inputs=[use_generated_text], outputs=[manual_text_input])
180
-
181
- # Liên kết sự kiện click của nút Tạo Nội dung
182
  content_button.click(generate_content,
183
  inputs=[prompt, file_upload, content_type],
184
- outputs=[content_output, download_docx, use_generated_text, manual_text_input, status_message])
185
-
186
- # Liên kết sự kiện click của nút Xác nhận nội dung
187
- confirm_button.click(confirm_content,
188
- inputs=[content_output, use_generated_text, manual_text_input, language, custom_text_input, text_color],
189
- outputs=[download_docx, download_audio, download_video, status_message])
190
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  return app
192
 
193
  # Khởi chạy ứng dụng
194
  if __name__ == "__main__":
195
  app = interface()
196
- app.launch(share=True)
 
2
  import mimetypes
3
  import os
4
  import tempfile
5
+ import glob
6
  import fitz # PyMuPDF
7
  import random
8
  import gradio as gr
9
  from docx import Document
10
+ from audio_processing import async_text_to_speech, text_to_speech
11
+ from content_generation import create_content, CONTENT_TYPES
12
+ from video_processing import create_video_func
13
+ from moviepy.editor import AudioFileClip, VideoFileClip, CompositeAudioClip
14
+ from utils import (combine_videos, get_pexels_video, get_bgm_file, download_video)
15
+ from video_processing import create_video
16
  from content_generation import create_content, CONTENT_TYPES
17
  from openai import OpenAI
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  # Khởi tạo client OpenAI với API key từ biến môi trường
20
+ client = OpenAI(api_key=os.environ.get('OPENAI_API_KEY'))
21
 
22
  def create_docx(content, output_path):
23
  """
 
47
  text += para.text
48
  return text
49
 
50
+ def get_bgm_file_list():
51
  """
52
+ Trả về danh sách các tệp nhạc nền.
53
  """
54
+ # Giả sử bạn có một thư mục chứa các tệp nhạc nền
55
+ song_dir = "/data/bg-music"
56
+ return [os.path.basename(file) for file in glob.glob(os.path.join(song_dir, "*.mp3"))]
 
 
 
 
57
 
58
+ def extract_key_contents(script, num_contents=10):
59
  """
60
+ Trích xuất các ý chính từ script.
61
  """
62
+ try:
63
+ response = client.chat.completions.create(
64
+ model="gpt-3.5-turbo",
65
+ messages=[
66
+ {"role": "system", "content": f"Bạn là một chuyên gia phân tích nội dung. Hãy trích xuất chính xác {num_contents} ý chính quan trọng nhất từ đoạn văn sau, mỗi ý không quá 20 từ."},
67
+ {"role": "user", "content": script}
68
+ ]
69
+ )
70
+ # Sửa lỗi truy cập đối tượng không thể subscript
71
+ key_contents = response.choices[0].message.content.split('\n')
72
+ return key_contents[:num_contents]
73
+ except Exception as e:
74
+ print(f"Lỗi khi trích xuất nội dung: {str(e)}")
75
+ return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
  def interface():
78
+ with gr.Blocks() as app:
79
  gr.Markdown("# Ứng dụng Tạo Nội dung và Video")
80
+
81
  with gr.Tab("Tạo Nội dung"):
82
+ prompt = gr.Textbox(label="Nhập yêu cầu nội dung")
83
+ file_upload = gr.File(label="Tải lên file kèm theo", type="filepath")
84
+
85
+ # Sử dụng gr.Radio thay gr.CheckboxGroup
86
+ content_type = gr.Radio(label="Chọn loại nội dung",
87
+ choices=CONTENT_TYPES,
88
+ value=None) # Giá trị mặc định là không có gì được chọn
89
+
90
+ content_button = gr.Button("Tạo Nội dung")
91
+ content_output = gr.Textbox(label="Nội dung tạo ra", interactive=True)
92
+ confirm_button = gr.Button("Xác nhận nội dung")
93
+ download_docx = gr.File(label="Tải xuống file DOCX", interactive=False)
94
+ download_audio = gr.File(label="Tải xuống file âm thanh", interactive=False)
95
+ status_message = gr.Label(label="Trạng thái")
96
+
 
 
 
 
 
 
 
 
 
 
97
  def generate_content(prompt, file, content_type):
98
  try:
99
  status = "Đang xử lý..."
 
109
  prompt = f"{prompt}\n\nDưới đây là nội dung của file tài liệu:\n\n{file_content}"
110
  else:
111
  raise ValueError("Định dạng file không được hỗ trợ.")
112
+
113
  if not content_type:
114
  raise ValueError("Vui lòng chọn một loại nội dung")
115
+
116
  script_content = create_content(prompt, content_type, "Tiếng Việt")
117
  docx_path = "script.docx"
118
  create_docx(script_content, docx_path)
119
+
120
  status = "Đã tạo nội dung thành công!"
121
+ return script_content, docx_path, status
122
  except Exception as e:
123
  status = f"Đã xảy ra lỗi: {str(e)}"
124
+ return "", None, status
125
+
126
+ async def confirm_content(content):
127
+ docx_path = "script.docx"
128
+ create_docx(content, docx_path)
129
+
130
+ audio_path = await async_text_to_speech(content, "alloy", "Tiếng Việt")
131
+ return docx_path, audio_path, "Nội dung đã được xác nhận và âm thanh đã được tạo!"
132
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  content_button.click(generate_content,
134
  inputs=[prompt, file_upload, content_type],
135
+ outputs=[content_output, download_docx, status_message])
136
+
137
+ confirm_button.click(lambda x: asyncio.run(confirm_content(x)),
138
+ inputs=[content_output],
139
+ outputs=[download_docx, download_audio, status_message])
140
+
141
+ # Định nghĩa danh sách giọng đọc
142
+ VOICES = ["vi-VN-HoaiMyNeural"]
143
+
144
+ with gr.Tab("Tạo Âm thanh"):
145
+ text_input = gr.Textbox(label="Nhập văn bản để chuyển đổi")
146
+ voice_select = gr.Dropdown(label="Chọn giọng đọc", choices=VOICES) # Dropdown cho voice_select
147
+ audio_button = gr.Button("Tạo Âm thanh")
148
+ audio_output = gr.Audio(label="Âm thanh tạo ra")
149
+ download_audio = gr.File(label="Tải xuống file âm thanh", interactive=False)
150
+
151
+ def text_to_speech_func(text, voice):
152
+ try:
153
+ audio_path = await async_text_to_speech(text, voice, "Tiếng Việt")
154
+ return audio_path, audio_path
155
+ except Exception as e:
156
+ print(f"Lỗi khi chuyển đổi văn bản thành giọng nói: {e}")
157
+ return None, None
158
+
159
+ audio_button.click(text_to_speech_func,
160
+ inputs=[text_input, voice_select],
161
+ outputs=[audio_output, download_audio])
162
+
163
+ with gr.Tab("Tạo Video"):
164
+ script_input = gr.Textbox(label="Nhập kịch bản")
165
+ audio_file = gr.File(label="Chọn file âm thanh", type="filepath")
166
+ keywords_output = gr.Textbox(label="Từ khóa", interactive=True)
167
+ max_clip_duration = gr.Slider(minimum=2, maximum=5, step=1, label="Thời lượng tối đa mỗi video (giây)")
168
+ join_order = gr.Checkbox(label="Ghép ngẫu nhiên", value=True)
169
+ bgm_files = gr.Dropdown(choices=get_bgm_file_list(), label="Chọn nhạc nền")
170
+ video_output = gr.Video(label="Video tạo ra")
171
+ video_button = gr.Button("Tạo Video")
172
+ status_message = gr.Label(label="Trạng thái") # Thêm thông báo trạng thái
173
+
174
+ def create_video_func(script, audio_file, max_clip_duration, join_order, bgm_file):
175
+ """ Tạo video từ các thông tin đầu vào. """
176
+ try:
177
+ # Cập nhật trạng thái ban đầu
178
+ status = "Đang xử lý..."
179
+
180
+ # 1. Tính toán thời lượng video
181
+ audio_clip = AudioFileClip(audio_file)
182
+ video_duration = audio_clip.duration
183
+
184
+ # 2. Trích xuất từ khóa từ kịch bản
185
+ keywords = extract_key_contents(script)
186
+ video_paths = []
187
+ for keyword in keywords:
188
+ video_url = get_pexels_video(keyword.strip())
189
+ if video_url:
190
+ video_path = download_video(video_url)
191
+ video_paths.append(video_path)
192
+
193
+ # 3. Ghép video
194
+ temp_dir = tempfile.mkdtemp()
195
+ if join_order:
196
+ random.shuffle(video_paths)
197
+ combined_video_path = os.path.join(temp_dir, "combined_video.mp4")
198
+ combine_videos(combined_video_path, video_paths, audio_file, max_clip_duration)
199
+
200
+ # 4. Gộp audio và nhạc nền
201
+ final_video_path = "final_video.mp4"
202
+ bgm_clip = AudioFileClip(bgm_file)
203
+ final_audio = CompositeAudioClip([audio_clip, bgm_clip])
204
+ final_video = VideoFileClip(combined_video_path).set_audio(final_audio)
205
+ final_video.write_videofile(final_video_path)
206
+
207
+ # Cập nhật trạng thái thành công
208
+ status = "Video đã được tạo thành công!"
209
+ return final_video_path, status
210
+ except Exception as e:
211
+ # Cập nhật trạng thái lỗi
212
+ status = f"Lỗi khi tạo video: {e}"
213
+ return None, status
214
+
215
+ video_button.click(create_video_func,
216
+ inputs=[script_input, audio_file, max_clip_duration, join_order, bgm_files],
217
+ outputs=[video_output, status_message])
218
+
219
  return app
220
 
221
  # Khởi chạy ứng dụng
222
  if __name__ == "__main__":
223
  app = interface()
224
+ app.launch(share=True)