hieu-nguyen2208 commited on
Commit
c9a39eb
·
1 Parent(s): 864775e
Files changed (5) hide show
  1. app.py +25 -2
  2. main.py +3 -1
  3. src/image_gen.py +13 -12
  4. src/text_processing.py +19 -13
  5. 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(OUTPUT_VIDEO_PATH, "rb") as video_file:
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
- load_dotenv()
8
- GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
9
- client = genai.Client(api_key=GOOGLE_API_KEY)
 
 
 
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 = response = client.models.generate_content(
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)