|
import asyncio |
|
import mimetypes |
|
import os |
|
import tempfile |
|
import fitz |
|
import random |
|
import gradio as gr |
|
from docx import Document |
|
from content_generation import create_content, CONTENT_TYPES |
|
from openai import OpenAI |
|
from gradio_client import Client, handle_file |
|
import subprocess |
|
|
|
|
|
client_openai = OpenAI(api_key=os.environ.get('OPENAI_API_KEY')) |
|
client_vixtts = Client("thinhlpg/vixtts-demo") |
|
|
|
def create_docx(content, output_path): |
|
""" |
|
Tạo file docx từ nội dung. |
|
""" |
|
doc = Document() |
|
doc.add_paragraph(content) |
|
doc.save(output_path) |
|
|
|
def process_pdf(file_path): |
|
""" |
|
Xử lý file PDF và trích xuất nội dung. |
|
""" |
|
doc = fitz.open(file_path) |
|
text = "" |
|
for page in doc: |
|
text += page.get_text() |
|
return text |
|
|
|
def process_docx(file_path): |
|
""" |
|
Xử lý file DOCX và trích xuất nội dung. |
|
""" |
|
doc = Document(file_path) |
|
text = "" |
|
for para in doc.paragraphs: |
|
text += para.text |
|
return text |
|
|
|
def convert_text_to_speech(text, language='vi'): |
|
""" |
|
Chuyển đổi văn bản thành giọng nói. |
|
""" |
|
result = client_vixtts.predict( |
|
prompt=text, |
|
language=language, |
|
audio_file_pth=handle_file(''), |
|
normalize_text=True, |
|
api_name="/predict" |
|
) |
|
return result.audio_file_pth |
|
|
|
def create_video(audio_file, mc_choice, text_color, output_video="output.mp4"): |
|
""" |
|
Tạo video với người MC dẫn chương trình. |
|
""" |
|
|
|
background_videos = { |
|
"MC1": "mc1_background.mp4", |
|
"MC2": "mc2_background.mp4", |
|
"MC3": "mc3_background.mp4", |
|
"MC4": "mc4_background.mp4" |
|
} |
|
background_video = background_videos.get(mc_choice, "mc1_background.mp4") |
|
|
|
|
|
text_on_video = f"MC: {mc_choice}" |
|
|
|
|
|
color_map = { |
|
"Trắng": "white", |
|
"Đỏ": "red", |
|
"Xanh dương": "blue", |
|
"Xanh lá": "green", |
|
"Vàng": "yellow" |
|
} |
|
font_color = color_map.get(text_color, "white") |
|
|
|
|
|
command = [ |
|
"ffmpeg", |
|
"-stream_loop", "-1", |
|
"-i", background_video, |
|
"-i", audio_file, |
|
"-vf", f"drawtext=text='{text_on_video}':fontcolor={font_color}:fontsize=50:fontfile=/path/to/font.ttf:x=(w-text_w)/2:y=10:box=1:[email protected]:boxborderw=5", |
|
"-t", "45.7", |
|
"-c:v", "libx264", |
|
"-c:a", "aac", |
|
"-shortest", |
|
"-y", |
|
output_video |
|
] |
|
|
|
subprocess.run(command, check=True) |
|
return output_video |
|
|
|
def interface(): |
|
with gr.Blocks() as app: |
|
gr.Markdown("# Ứng dụng Tạo Nội dung và Video") |
|
with gr.Tab("Tạo Nội dung"): |
|
with gr.Row(): |
|
with gr.Column(): |
|
prompt = gr.Textbox(label="Nhập yêu cầu nội dung") |
|
file_upload = gr.File(label="Tải lên file kèm theo", type="filepath") |
|
content_type = gr.Radio(label="Chọn loại nội dung", |
|
choices=CONTENT_TYPES, |
|
value=None) |
|
content_button = gr.Button("Tạo Nội dung") |
|
|
|
with gr.Column(): |
|
content_output = gr.Textbox(label="Nội dung tạo ra", interactive=True) |
|
use_generated_text = gr.Checkbox(label="Sử dụng văn bản được tạo bởi LLM", value=True) |
|
manual_text_input = gr.Textbox(label="Nhập văn bản thủ công", visible=False) |
|
language = gr.Dropdown(label="Chọn ngôn ngữ", choices=["vi", "en"], value="vi") |
|
mc_choice = gr.Dropdown(label="Chọn MC", choices=["MC1", "MC2", "MC3", "MC4"], value="MC1") |
|
text_color = gr.Dropdown(label="Chọn màu chữ", choices=["Trắng", "Đỏ", "Xanh dương", "Xanh lá", "Vàng"], value="Trắng") |
|
confirm_button = gr.Button("Xác nhận nội dung") |
|
download_docx = gr.File(label="Tải xuống file DOCX", interactive=False) |
|
download_audio = gr.File(label="Tải xuống file âm thanh", interactive=False) |
|
download_video = gr.File(label="Tải xuống file video", interactive=False) |
|
status_message = gr.Label(label="Trạng thái") |
|
|
|
def toggle_manual_text(use_generated_text): |
|
return not use_generated_text |
|
|
|
def generate_content(prompt, file, content_type): |
|
try: |
|
status = "Đang xử lý..." |
|
if file and os.path.exists(file): |
|
mime_type, _ = mimetypes.guess_type(file) |
|
if mime_type == "application/pdf": |
|
file_content = process_pdf(file) |
|
prompt = f"{prompt}\n\nDưới đây là nội dung của file tài liệu:\n\n{file_content}" |
|
elif mime_type in ( |
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
|
"application/msword"): |
|
file_content = process_docx(file) |
|
prompt = f"{prompt}\n\nDưới đây là nội dung của file tài liệu:\n\n{file_content}" |
|
else: |
|
raise ValueError("Định dạng file không được hỗ trợ.") |
|
if not content_type: |
|
raise ValueError("Vui lòng chọn một loại nội dung") |
|
script_content = create_content(prompt, content_type, "Tiếng Việt") |
|
docx_path = "script.docx" |
|
create_docx(script_content, docx_path) |
|
status = "Đã tạo nội dung thành công!" |
|
return script_content, docx_path, True, None, status |
|
except Exception as e: |
|
status = f"Đã xảy ra lỗi: {str(e)}" |
|
return "", None, True, None, status |
|
|
|
async def confirm_content(content_output, use_generated_text, manual_text_input, language, mc_choice, text_color): |
|
if use_generated_text: |
|
text_to_convert = content_output |
|
else: |
|
text_to_convert = manual_text_input |
|
|
|
if not text_to_convert: |
|
return None, None, None, "Vui lòng cung cấp văn bản để chuyển đổi." |
|
|
|
docx_path = "script.docx" |
|
create_docx(text_to_convert, docx_path) |
|
audio_path = convert_text_to_speech(text_to_convert, language) |
|
video_path = create_video(audio_path, mc_choice, text_color) |
|
return docx_path, audio_path, video_path, "Đã xác nhận và tạo video thành công!" |
|
|
|
use_generated_text.change(toggle_manual_text, inputs=[use_generated_text], outputs=[manual_text_input.visible]) |
|
content_button.click(generate_content, |
|
inputs=[prompt, file_upload, content_type], |
|
outputs=[content_output, download_docx, use_generated_text, manual_text_input, status_message]) |
|
|
|
confirm_button.click(confirm_content, |
|
inputs=[content_output, use_generated_text, manual_text_input, language, mc_choice, text_color], |
|
outputs=[download_docx, download_audio, download_video, status_message]) |
|
|
|
return app |
|
|
|
|
|
if __name__ == "__main__": |
|
app = interface() |
|
app.launch(share=True) |