Spaces:
Running
Running
Commit
·
c9a39eb
1
Parent(s):
864775e
"LOL"
Browse files- app.py +25 -2
- main.py +3 -1
- src/image_gen.py +13 -12
- src/text_processing.py +19 -13
- src/text_to_video.py +0 -1
app.py
CHANGED
@@ -8,9 +8,11 @@ except RuntimeError:
|
|
8 |
import streamlit as st
|
9 |
from main import main
|
10 |
import os
|
|
|
11 |
|
12 |
# Định nghĩa đường dẫn video đầu ra
|
13 |
OUTPUT_VIDEO_PATH = "final_output.mp4"
|
|
|
14 |
|
15 |
# Tiêu đề ứng dụng
|
16 |
st.set_page_config(page_title="KnowFlow", page_icon="📖")
|
@@ -74,6 +76,24 @@ art_style = st.text_input("🖌️ Image Description Style", placeholder="Exampl
|
|
74 |
style = st.text_input("🎨 Image Style", placeholder="Example: realistic, anime,...")
|
75 |
color_palette = st.text_input("🌈 Color Palette", placeholder="Example: vibrant, monochrome,...")
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
# Nút chạy pipeline
|
78 |
if st.button("🚀 Generate Video"):
|
79 |
if file_path and os.path.exists(file_path):
|
@@ -83,11 +103,14 @@ if st.button("🚀 Generate Video"):
|
|
83 |
# Kiểm tra xem video đã được tạo chưa
|
84 |
if os.path.exists(OUTPUT_VIDEO_PATH):
|
85 |
st.success("🎉 Video generated successfully!")
|
|
|
|
|
|
|
86 |
|
87 |
# Tạo link tải về
|
88 |
-
with open(
|
89 |
st.download_button(label="📥 Download Video", data=video_file, file_name="final_output_fixed.mp4", mime="video/mp4")
|
90 |
else:
|
91 |
st.error("⚠️ Video generation failed. Please check the logs.")
|
92 |
else:
|
93 |
-
st.error("⚠️ Please upload a valid PDF file.")
|
|
|
8 |
import streamlit as st
|
9 |
from main import main
|
10 |
import os
|
11 |
+
import subprocess
|
12 |
|
13 |
# Định nghĩa đường dẫn video đầu ra
|
14 |
OUTPUT_VIDEO_PATH = "final_output.mp4"
|
15 |
+
OUTPUT_VIDEO_FIXED_PATH = "final_output_fixed.mp4"
|
16 |
|
17 |
# Tiêu đề ứng dụng
|
18 |
st.set_page_config(page_title="KnowFlow", page_icon="📖")
|
|
|
76 |
style = st.text_input("🎨 Image Style", placeholder="Example: realistic, anime,...")
|
77 |
color_palette = st.text_input("🌈 Color Palette", placeholder="Example: vibrant, monochrome,...")
|
78 |
|
79 |
+
def convert_audio_format(video_input, video_output):
|
80 |
+
"""Chuyển đổi định dạng âm thanh của video sang AAC."""
|
81 |
+
if not os.path.exists(video_input):
|
82 |
+
raise FileNotFoundError(f"File '{video_input}' không tồn tại!")
|
83 |
+
|
84 |
+
command = [
|
85 |
+
"ffmpeg", "-i", video_input,
|
86 |
+
"-c:v", "copy", "-c:a", "aac", "-b:a", "192k",
|
87 |
+
"-y", # Ghi đè nếu file output đã tồn tại
|
88 |
+
video_output
|
89 |
+
]
|
90 |
+
|
91 |
+
try:
|
92 |
+
subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
93 |
+
print(f"✅ Chuyển đổi thành công: {video_output}")
|
94 |
+
except subprocess.CalledProcessError as e:
|
95 |
+
print(f"❌ Lỗi khi chuyển đổi video: {e.stderr.decode()}")
|
96 |
+
|
97 |
# Nút chạy pipeline
|
98 |
if st.button("🚀 Generate Video"):
|
99 |
if file_path and os.path.exists(file_path):
|
|
|
103 |
# Kiểm tra xem video đã được tạo chưa
|
104 |
if os.path.exists(OUTPUT_VIDEO_PATH):
|
105 |
st.success("🎉 Video generated successfully!")
|
106 |
+
|
107 |
+
# Chuyển đổi định dạng âm thanh
|
108 |
+
convert_audio_format(OUTPUT_VIDEO_PATH, OUTPUT_VIDEO_FIXED_PATH)
|
109 |
|
110 |
# Tạo link tải về
|
111 |
+
with open(OUTPUT_VIDEO_FIXED_PATH, "rb") as video_file:
|
112 |
st.download_button(label="📥 Download Video", data=video_file, file_name="final_output_fixed.mp4", mime="video/mp4")
|
113 |
else:
|
114 |
st.error("⚠️ Video generation failed. Please check the logs.")
|
115 |
else:
|
116 |
+
st.error("⚠️ Please upload a valid PDF file.")
|
main.py
CHANGED
@@ -17,4 +17,6 @@ def main(file_path, analysis_level='basic', writting_style='academic', word_lowe
|
|
17 |
text_processing(file_path = file_path, analysis_level=analysis_level, writting_style=writting_style, word_lower_limit = word_lower_limit, word_upper_limit=word_upper_limit )
|
18 |
text_to_speech(gender = gender, speed = speed)
|
19 |
image_gen(number_of_images = number_of_images, detail_level=detail_level, perspective=perspective, emotion=emotion, time_setting=time_setting, art_style=art_style, style=style, color_palette=color_palette)
|
20 |
-
text_to_video()
|
|
|
|
|
|
17 |
text_processing(file_path = file_path, analysis_level=analysis_level, writting_style=writting_style, word_lower_limit = word_lower_limit, word_upper_limit=word_upper_limit )
|
18 |
text_to_speech(gender = gender, speed = speed)
|
19 |
image_gen(number_of_images = number_of_images, detail_level=detail_level, perspective=perspective, emotion=emotion, time_setting=time_setting, art_style=art_style, style=style, color_palette=color_palette)
|
20 |
+
text_to_video()
|
21 |
+
if __name__ == "__main__":
|
22 |
+
main('phan-tich-hinh-tuong-nguoi-lai-do-song-da-2.pdf')
|
src/image_gen.py
CHANGED
@@ -8,13 +8,13 @@ from huggingface_hub.utils import HfHubHTTPError
|
|
8 |
import random
|
9 |
import time
|
10 |
from dotenv import load_dotenv
|
11 |
-
|
12 |
-
load_dotenv()
|
13 |
-
HF_TOKEN = os.getenv("HF_TOKEN")
|
14 |
-
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
15 |
-
client_gemini = genai.Client(api_key = GOOGLE_API_KEY)
|
16 |
-
client = InferenceClient(provider="hf-inference", api_key=HF_TOKEN)
|
17 |
-
|
18 |
def split_text_for_images(number_of_images):
|
19 |
with open("text.txt", "r", encoding="utf-8") as file:
|
20 |
text = file.read().strip()
|
@@ -39,7 +39,7 @@ def split_text_for_images(number_of_images):
|
|
39 |
start = end # Bắt đầu đoạn tiếp theo từ đây
|
40 |
|
41 |
return chunks
|
42 |
-
def describe_image(description, detail_level="short", perspective="neutral", emotion=None, time_setting=None, art_style=None):
|
43 |
"""
|
44 |
Nhận một đoạn văn mô tả chi tiết và trả về một câu mô tả hình ảnh theo các tùy chỉnh.
|
45 |
|
@@ -71,13 +71,13 @@ def describe_image(description, detail_level="short", perspective="neutral", emo
|
|
71 |
|
72 |
try:
|
73 |
response = client_gemini.models.generate_content(
|
74 |
-
model = "gemini-2.0-flash", contents = prompt
|
75 |
)
|
76 |
return response.text.strip()
|
77 |
except Exception as e:
|
78 |
print(f"Lỗi khi gọi API Gemini: {e}")
|
79 |
return ""
|
80 |
-
def generate_image(prompt, output_path, style=None, color_palette=None):
|
81 |
model="stabilityai/stable-diffusion-3.5-large"
|
82 |
"""
|
83 |
Tạo hình ảnh từ mô tả văn bản với các tùy chỉnh linh hoạt.
|
@@ -99,11 +99,12 @@ def generate_image(prompt, output_path, style=None, color_palette=None):
|
|
99 |
image.save(output_path)
|
100 |
print(f"✅Image saved at {output_path}")
|
101 |
def image_gen(number_of_images = 3,detail_level = "short", perspective="neutral", emotion=None, time_setting=None, art_style=None, style=None, color_palette=None):
|
|
|
102 |
texts = split_text_for_images(number_of_images)
|
103 |
index = 0
|
104 |
for text in tqdm(texts, desc="Processing", unit="image"):
|
105 |
output_path = f"{index}.png"
|
106 |
-
prompt = describe_image(text, detail_level, perspective, emotion, time_setting, art_style)
|
107 |
print(prompt)
|
108 |
|
109 |
# Cơ chế retry với backoff
|
@@ -112,7 +113,7 @@ def image_gen(number_of_images = 3,detail_level = "short", perspective="neutral"
|
|
112 |
|
113 |
while retry_count < max_retries:
|
114 |
try:
|
115 |
-
generate_image(prompt, output_path, style, color_palette)
|
116 |
time.sleep(60) # Chờ sau khi tạo ảnh thành công
|
117 |
break # Nếu thành công thì thoát khỏi vòng lặp retry
|
118 |
except HfHubHTTPError as e:
|
|
|
8 |
import random
|
9 |
import time
|
10 |
from dotenv import load_dotenv
|
11 |
+
def set_up_api():
|
12 |
+
load_dotenv()
|
13 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
14 |
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
15 |
+
client_gemini = genai.Client(api_key = GOOGLE_API_KEY)
|
16 |
+
client = InferenceClient(provider="hf-inference", api_key=HF_TOKEN)
|
17 |
+
return client_gemini, client
|
18 |
def split_text_for_images(number_of_images):
|
19 |
with open("text.txt", "r", encoding="utf-8") as file:
|
20 |
text = file.read().strip()
|
|
|
39 |
start = end # Bắt đầu đoạn tiếp theo từ đây
|
40 |
|
41 |
return chunks
|
42 |
+
def describe_image(description, client_gemini, detail_level="short", perspective="neutral", emotion=None, time_setting=None, art_style=None):
|
43 |
"""
|
44 |
Nhận một đoạn văn mô tả chi tiết và trả về một câu mô tả hình ảnh theo các tùy chỉnh.
|
45 |
|
|
|
71 |
|
72 |
try:
|
73 |
response = client_gemini.models.generate_content(
|
74 |
+
model = "gemini-2.0-flash", contents = [prompt]
|
75 |
)
|
76 |
return response.text.strip()
|
77 |
except Exception as e:
|
78 |
print(f"Lỗi khi gọi API Gemini: {e}")
|
79 |
return ""
|
80 |
+
def generate_image(prompt, client, output_path, style=None, color_palette=None):
|
81 |
model="stabilityai/stable-diffusion-3.5-large"
|
82 |
"""
|
83 |
Tạo hình ảnh từ mô tả văn bản với các tùy chỉnh linh hoạt.
|
|
|
99 |
image.save(output_path)
|
100 |
print(f"✅Image saved at {output_path}")
|
101 |
def image_gen(number_of_images = 3,detail_level = "short", perspective="neutral", emotion=None, time_setting=None, art_style=None, style=None, color_palette=None):
|
102 |
+
client_gemini, client = set_up_api()
|
103 |
texts = split_text_for_images(number_of_images)
|
104 |
index = 0
|
105 |
for text in tqdm(texts, desc="Processing", unit="image"):
|
106 |
output_path = f"{index}.png"
|
107 |
+
prompt = describe_image(text, client_gemini, detail_level, perspective, emotion, time_setting, art_style)
|
108 |
print(prompt)
|
109 |
|
110 |
# Cơ chế retry với backoff
|
|
|
113 |
|
114 |
while retry_count < max_retries:
|
115 |
try:
|
116 |
+
generate_image(prompt, client, output_path, style, color_palette)
|
117 |
time.sleep(60) # Chờ sau khi tạo ảnh thành công
|
118 |
break # Nếu thành công thì thoát khỏi vòng lặp retry
|
119 |
except HfHubHTTPError as e:
|
src/text_processing.py
CHANGED
@@ -4,9 +4,12 @@ from docx import Document
|
|
4 |
from google import genai
|
5 |
from dotenv import load_dotenv
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
10 |
|
11 |
####################### - TEXT EXTRACTION - #######################
|
12 |
def extract_text_from_pdf(pdf_path):
|
@@ -37,7 +40,7 @@ def extract_text_from_file(file_path):
|
|
37 |
else:
|
38 |
raise ValueError("Unsupported file format. Only PDF and DOCX are supported.")
|
39 |
####################### - SEMANTIC CHUNKING - #######################
|
40 |
-
def split_text_by_semantics(text):
|
41 |
prompt = f"""
|
42 |
Bạn là một chuyên gia xử lý văn bản. Hãy chia văn bản sau thành một số đoạn có ý nghĩa sao cho mỗi đoạn vừa đủ để giải thích trong khoảng 3 đến 5 câu.
|
43 |
|
@@ -52,7 +55,7 @@ def split_text_by_semantics(text):
|
|
52 |
|
53 |
try:
|
54 |
response = client.models.generate_content(
|
55 |
-
model="gemini-2.0-flash", contents=prompt
|
56 |
)
|
57 |
result_text = response.text.strip()
|
58 |
print(result_text)
|
@@ -65,7 +68,7 @@ def split_text_by_semantics(text):
|
|
65 |
return []
|
66 |
|
67 |
####################### - CONTENT GENERATION - #######################
|
68 |
-
def generate_explaination_for_chunks(chunks, analysis_level='basic', writting_style='academic', word_lower_limit=100, word_upper_limit=150):
|
69 |
"""
|
70 |
Phân tích nội dung của văn bản theo mức độ và phong cách mong muốn.
|
71 |
|
@@ -99,9 +102,8 @@ def generate_explaination_for_chunks(chunks, analysis_level='basic', writting_st
|
|
99 |
|
100 |
try:
|
101 |
response = client.models.generate_content(
|
102 |
-
model="gemini-2.0-flash", contents=overview_prompt
|
103 |
)
|
104 |
-
print(response)
|
105 |
|
106 |
explanations = []
|
107 |
for idx, chunk in enumerate(chunks, start=1):
|
@@ -114,9 +116,10 @@ def generate_explaination_for_chunks(chunks, analysis_level='basic', writting_st
|
|
114 |
Hãy đảm bảo phần tóm tắt không vượt quá {word_upper_limit} từ và không ít hơn {word_lower_limit}.
|
115 |
"""
|
116 |
|
117 |
-
part_response =
|
118 |
-
model="gemini-2.0-flash", contents=part_prompt
|
119 |
)
|
|
|
120 |
explanations.append(part_response.text.strip())
|
121 |
|
122 |
return explanations
|
@@ -125,15 +128,16 @@ def generate_explaination_for_chunks(chunks, analysis_level='basic', writting_st
|
|
125 |
print(f"Lỗi khi gọi API Gemini: {e}")
|
126 |
return []
|
127 |
def text_processing(file_path, analysis_level='basic', writting_style='academic', word_lower_limit = 100, word_upper_limit = 150):
|
|
|
128 |
# Trích xuất văn bản từ file PDF
|
129 |
text = extract_text_from_file(file_path=file_path)
|
130 |
with open("./text.txt", "w", encoding="utf-8") as f:
|
131 |
f.write(text)
|
132 |
# Tách văn bản theo ngữ nghĩa
|
133 |
-
semantic_chunks = split_text_by_semantics(text)
|
134 |
|
135 |
# Tạo thuyết minh cho từng phần semantic chunk
|
136 |
-
explanations = generate_explaination_for_chunks(semantic_chunks, analysis_level=analysis_level, writting_style = writting_style, word_lower_limit = word_lower_limit, word_upper_limit=word_upper_limit)
|
137 |
|
138 |
# Tạo thư mục nếu chưa tồn tại
|
139 |
output_dir = "./"
|
@@ -150,4 +154,6 @@ def text_processing(file_path, analysis_level='basic', writting_style='academic'
|
|
150 |
output_file = os.path.join(output_dir, f"{chunk_idx}_{sentence_idx}.txt") # Tên file dạng "chunkID_sentenceID.txt"
|
151 |
with open(output_file, "w", encoding="utf-8") as f:
|
152 |
f.write(sentence.replace("*","") + ".") # Giữ dấu chấm cuối câu
|
153 |
-
print(f"Đã lưu: {output_file}")
|
|
|
|
|
|
4 |
from google import genai
|
5 |
from dotenv import load_dotenv
|
6 |
|
7 |
+
def set_up_api():
|
8 |
+
load_dotenv()
|
9 |
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
10 |
+
print(GOOGLE_API_KEY)
|
11 |
+
client = genai.Client(api_key=GOOGLE_API_KEY)
|
12 |
+
return client
|
13 |
|
14 |
####################### - TEXT EXTRACTION - #######################
|
15 |
def extract_text_from_pdf(pdf_path):
|
|
|
40 |
else:
|
41 |
raise ValueError("Unsupported file format. Only PDF and DOCX are supported.")
|
42 |
####################### - SEMANTIC CHUNKING - #######################
|
43 |
+
def split_text_by_semantics(text, client):
|
44 |
prompt = f"""
|
45 |
Bạn là một chuyên gia xử lý văn bản. Hãy chia văn bản sau thành một số đoạn có ý nghĩa sao cho mỗi đoạn vừa đủ để giải thích trong khoảng 3 đến 5 câu.
|
46 |
|
|
|
55 |
|
56 |
try:
|
57 |
response = client.models.generate_content(
|
58 |
+
model="gemini-2.0-flash", contents=[prompt]
|
59 |
)
|
60 |
result_text = response.text.strip()
|
61 |
print(result_text)
|
|
|
68 |
return []
|
69 |
|
70 |
####################### - CONTENT GENERATION - #######################
|
71 |
+
def generate_explaination_for_chunks(chunks, client, analysis_level='basic', writting_style='academic', word_lower_limit=100, word_upper_limit=150):
|
72 |
"""
|
73 |
Phân tích nội dung của văn bản theo mức độ và phong cách mong muốn.
|
74 |
|
|
|
102 |
|
103 |
try:
|
104 |
response = client.models.generate_content(
|
105 |
+
model="gemini-2.0-flash", contents=[overview_prompt]
|
106 |
)
|
|
|
107 |
|
108 |
explanations = []
|
109 |
for idx, chunk in enumerate(chunks, start=1):
|
|
|
116 |
Hãy đảm bảo phần tóm tắt không vượt quá {word_upper_limit} từ và không ít hơn {word_lower_limit}.
|
117 |
"""
|
118 |
|
119 |
+
part_response = client.models.generate_content(
|
120 |
+
model="gemini-2.0-flash", contents=[part_prompt]
|
121 |
)
|
122 |
+
print(part_response.text.strip())
|
123 |
explanations.append(part_response.text.strip())
|
124 |
|
125 |
return explanations
|
|
|
128 |
print(f"Lỗi khi gọi API Gemini: {e}")
|
129 |
return []
|
130 |
def text_processing(file_path, analysis_level='basic', writting_style='academic', word_lower_limit = 100, word_upper_limit = 150):
|
131 |
+
client = set_up_api()
|
132 |
# Trích xuất văn bản từ file PDF
|
133 |
text = extract_text_from_file(file_path=file_path)
|
134 |
with open("./text.txt", "w", encoding="utf-8") as f:
|
135 |
f.write(text)
|
136 |
# Tách văn bản theo ngữ nghĩa
|
137 |
+
semantic_chunks = split_text_by_semantics(text, client)
|
138 |
|
139 |
# Tạo thuyết minh cho từng phần semantic chunk
|
140 |
+
explanations = generate_explaination_for_chunks(semantic_chunks, client, analysis_level=analysis_level, writting_style = writting_style, word_lower_limit = word_lower_limit, word_upper_limit=word_upper_limit)
|
141 |
|
142 |
# Tạo thư mục nếu chưa tồn tại
|
143 |
output_dir = "./"
|
|
|
154 |
output_file = os.path.join(output_dir, f"{chunk_idx}_{sentence_idx}.txt") # Tên file dạng "chunkID_sentenceID.txt"
|
155 |
with open(output_file, "w", encoding="utf-8") as f:
|
156 |
f.write(sentence.replace("*","") + ".") # Giữ dấu chấm cuối câu
|
157 |
+
print(f"Đã lưu: {output_file}")
|
158 |
+
if __name__ == "__main__":
|
159 |
+
text_processing("phan-tich-hinh-tuong-nguoi-lai-do-song-da-2.pdf")
|
src/text_to_video.py
CHANGED
@@ -8,7 +8,6 @@ import os
|
|
8 |
from itertools import accumulate
|
9 |
import pysrt
|
10 |
|
11 |
-
|
12 |
def format_time(seconds):
|
13 |
"""Chuyển đổi thời gian (giây) thành định dạng SRT hh:mm:ss,ms"""
|
14 |
mins, sec = divmod(seconds, 60)
|
|
|
8 |
from itertools import accumulate
|
9 |
import pysrt
|
10 |
|
|
|
11 |
def format_time(seconds):
|
12 |
"""Chuyển đổi thời gian (giây) thành định dạng SRT hh:mm:ss,ms"""
|
13 |
mins, sec = divmod(seconds, 60)
|