Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -4,7 +4,7 @@ import gradio as gr
|
|
4 |
import re
|
5 |
|
6 |
# === API SETUP ===
|
7 |
-
GROQ_API_KEY = "
|
8 |
GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
|
9 |
|
10 |
HEADERS = {
|
@@ -12,7 +12,7 @@ HEADERS = {
|
|
12 |
"Content-Type": "application/json"
|
13 |
}
|
14 |
|
15 |
-
# ===
|
16 |
BLOCKED_KEYWORDS = [
|
17 |
"sex", "drugs", "violence", "suicide", "death", "kill", "murder", "gun",
|
18 |
"abuse", "politics", "terror", "crime", "war", "religion", "racism",
|
@@ -24,18 +24,18 @@ def is_safe_topic(topic: str) -> bool:
|
|
24 |
return not any(bad_word in topic_lower for bad_word in BLOCKED_KEYWORDS)
|
25 |
|
26 |
# === PODCAST GENERATION ===
|
27 |
-
def generate_educational_podcast(topic: str, model: str = "llama3-70b-8192") -> str:
|
28 |
prompt = f"""
|
29 |
-
You are a scriptwriter for an educational podcast
|
30 |
|
31 |
-
Create a short and engaging podcast script on the topic: "{topic}".
|
32 |
-
|
33 |
-
The two hosts are named Ali and Talha. Ali starts the conversation.
|
34 |
-
They should have a back-and-forth conversation about the topic.
|
35 |
-
The tone should be friendly, easy to understand, and informative.
|
36 |
|
|
|
|
|
|
|
37 |
Avoid music or sound effects. Keep the total length under 800 words.
|
38 |
-
|
|
|
39 |
"""
|
40 |
|
41 |
data = {
|
@@ -49,67 +49,35 @@ Only write their dialogue and a few narration lines if needed. Do NOT use Host 1
|
|
49 |
}
|
50 |
|
51 |
response = requests.post(GROQ_API_URL, headers=HEADERS, json=data)
|
52 |
-
|
53 |
if response.status_code == 200:
|
54 |
return response.json()["choices"][0]["message"]["content"].strip()
|
55 |
else:
|
56 |
return f"<b>Error {response.status_code}</b>: {response.text}"
|
57 |
|
58 |
-
# ===
|
59 |
def format_script(script: str) -> str:
|
60 |
-
# Remove markdown bolding like **text**
|
61 |
script = re.sub(r'\*\*(.*?)\*\*', r'\1', script)
|
62 |
-
|
63 |
-
# Remove music and direction lines
|
64 |
script = re.sub(r'(?i)^.*(music|sound effect).*$','', script, flags=re.MULTILINE)
|
65 |
-
|
66 |
-
# Normalize host names to Ali and Talha
|
67 |
-
script = script.replace("Host 1:", "Ali:")
|
68 |
-
script = script.replace("Host 2:", "Talha:")
|
69 |
script = re.sub(r'\b[Aa]lex:', 'Ali:', script)
|
70 |
script = re.sub(r'\b[Mm]aya:', 'Talha:', script)
|
71 |
|
72 |
lines = script.strip().split("\n")
|
73 |
formatted = ""
|
74 |
-
|
75 |
for line in lines:
|
76 |
line = line.strip()
|
77 |
if not line:
|
78 |
continue
|
79 |
-
# Only keep lines that are spoken by Ali or Talha
|
80 |
if line.startswith("Ali:"):
|
81 |
content = line.replace("Ali:", "").strip()
|
82 |
formatted += f"<div class='host1'>🎙️ <b>Ali:</b> {content}</div>\n"
|
83 |
elif line.startswith("Talha:"):
|
84 |
content = line.replace("Talha:", "").strip()
|
85 |
formatted += f"<div class='host2'>🎧 <b>Talha:</b> {content}</div>\n"
|
86 |
-
|
87 |
return formatted
|
88 |
|
89 |
-
# ===
|
90 |
-
def generate(topic):
|
91 |
-
if not is_safe_topic(topic):
|
92 |
-
return "<b style='color:red;'>⚠️ Restricted content. Please enter an appropriate educational topic.</b>"
|
93 |
-
raw_script = generate_educational_podcast(topic)
|
94 |
-
return format_script(raw_script)
|
95 |
-
|
96 |
-
# === DARK GLOSSY CSS ===
|
97 |
custom_css = """
|
98 |
-
# body {
|
99 |
-
# background-color: darkslateblue !important;
|
100 |
-
# color: #ffffff;
|
101 |
-
# }
|
102 |
-
|
103 |
-
# .gradio-container {
|
104 |
-
# background-color: darkslateblue !important;
|
105 |
-
# }
|
106 |
-
|
107 |
-
# textarea, input, .gr-button {
|
108 |
-
# background-color: darkslategray !important;
|
109 |
-
# color: #ffffff !important;
|
110 |
-
# border: 1px solid #aaa !important;
|
111 |
-
# }
|
112 |
-
|
113 |
.host1, .host2 {
|
114 |
border-radius: 16px;
|
115 |
padding: 14px;
|
@@ -119,32 +87,33 @@ custom_css = """
|
|
119 |
line-height: 1.6;
|
120 |
color: #ffffff;
|
121 |
}
|
122 |
-
|
123 |
.host1 {
|
124 |
-
background: linear-gradient(135deg, #4b6cb7, #182848);
|
125 |
}
|
126 |
-
|
127 |
.host2 {
|
128 |
-
background: linear-gradient(135deg, #2c3e50, #4ca1af);
|
129 |
-
}
|
130 |
-
|
131 |
-
.narration {
|
132 |
-
font-style: italic;
|
133 |
-
color: #cccccc;
|
134 |
-
margin: 10px 0;
|
135 |
-
font-size: 15px;
|
136 |
}
|
137 |
"""
|
138 |
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
140 |
with gr.Blocks(css=custom_css) as demo:
|
141 |
-
gr.Markdown("## 🎙️ Educational Podcast Generator for Students"
|
142 |
-
gr.Markdown("Enter
|
143 |
|
144 |
topic_input = gr.Textbox(label="Enter educational topic")
|
|
|
|
|
|
|
|
|
|
|
145 |
generate_btn = gr.Button("🎧 Generate Podcast")
|
146 |
output_box = gr.HTML()
|
147 |
|
148 |
-
generate_btn.click(fn=generate, inputs=topic_input, outputs=output_box)
|
149 |
|
150 |
demo.launch()
|
|
|
4 |
import re
|
5 |
|
6 |
# === API SETUP ===
|
7 |
+
GROQ_API_KEY = os.getenv("GROQ_API_KEY") # Bạn nên dùng biến môi trường
|
8 |
GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
|
9 |
|
10 |
HEADERS = {
|
|
|
12 |
"Content-Type": "application/json"
|
13 |
}
|
14 |
|
15 |
+
# === BLOCKED TOPICS ===
|
16 |
BLOCKED_KEYWORDS = [
|
17 |
"sex", "drugs", "violence", "suicide", "death", "kill", "murder", "gun",
|
18 |
"abuse", "politics", "terror", "crime", "war", "religion", "racism",
|
|
|
24 |
return not any(bad_word in topic_lower for bad_word in BLOCKED_KEYWORDS)
|
25 |
|
26 |
# === PODCAST GENERATION ===
|
27 |
+
def generate_educational_podcast(topic: str, language: str, model: str = "llama3-70b-8192") -> str:
|
28 |
prompt = f"""
|
29 |
+
You are a scriptwriter for an educational podcast for students in grades 8 to 12.
|
30 |
|
31 |
+
Create a short and engaging podcast script in **{language}** on the topic: "{topic}".
|
|
|
|
|
|
|
|
|
32 |
|
33 |
+
The two hosts are named Ali and Talha. Ali starts the conversation.
|
34 |
+
They should have a back-and-forth conversation about the topic.
|
35 |
+
The tone should be friendly, easy to understand, and informative.
|
36 |
Avoid music or sound effects. Keep the total length under 800 words.
|
37 |
+
|
38 |
+
Only write their dialogue and a few narration lines if needed. Do NOT use Host 1/2 or generic names.
|
39 |
"""
|
40 |
|
41 |
data = {
|
|
|
49 |
}
|
50 |
|
51 |
response = requests.post(GROQ_API_URL, headers=HEADERS, json=data)
|
|
|
52 |
if response.status_code == 200:
|
53 |
return response.json()["choices"][0]["message"]["content"].strip()
|
54 |
else:
|
55 |
return f"<b>Error {response.status_code}</b>: {response.text}"
|
56 |
|
57 |
+
# === SCRIPT FORMATTING ===
|
58 |
def format_script(script: str) -> str:
|
|
|
59 |
script = re.sub(r'\*\*(.*?)\*\*', r'\1', script)
|
|
|
|
|
60 |
script = re.sub(r'(?i)^.*(music|sound effect).*$','', script, flags=re.MULTILINE)
|
61 |
+
script = script.replace("Host 1:", "Ali:").replace("Host 2:", "Talha:")
|
|
|
|
|
|
|
62 |
script = re.sub(r'\b[Aa]lex:', 'Ali:', script)
|
63 |
script = re.sub(r'\b[Mm]aya:', 'Talha:', script)
|
64 |
|
65 |
lines = script.strip().split("\n")
|
66 |
formatted = ""
|
|
|
67 |
for line in lines:
|
68 |
line = line.strip()
|
69 |
if not line:
|
70 |
continue
|
|
|
71 |
if line.startswith("Ali:"):
|
72 |
content = line.replace("Ali:", "").strip()
|
73 |
formatted += f"<div class='host1'>🎙️ <b>Ali:</b> {content}</div>\n"
|
74 |
elif line.startswith("Talha:"):
|
75 |
content = line.replace("Talha:", "").strip()
|
76 |
formatted += f"<div class='host2'>🎧 <b>Talha:</b> {content}</div>\n"
|
|
|
77 |
return formatted
|
78 |
|
79 |
+
# === GRADIO UI ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
custom_css = """
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
.host1, .host2 {
|
82 |
border-radius: 16px;
|
83 |
padding: 14px;
|
|
|
87 |
line-height: 1.6;
|
88 |
color: #ffffff;
|
89 |
}
|
|
|
90 |
.host1 {
|
91 |
+
background: linear-gradient(135deg, #4b6cb7, #182848);
|
92 |
}
|
|
|
93 |
.host2 {
|
94 |
+
background: linear-gradient(135deg, #2c3e50, #4ca1af);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
}
|
96 |
"""
|
97 |
|
98 |
+
def generate(topic, language):
|
99 |
+
if not is_safe_topic(topic):
|
100 |
+
return "<b style='color:red;'>⚠️ Restricted content. Please enter an appropriate educational topic.</b>"
|
101 |
+
raw_script = generate_educational_podcast(topic, language)
|
102 |
+
return format_script(raw_script)
|
103 |
+
|
104 |
with gr.Blocks(css=custom_css) as demo:
|
105 |
+
gr.Markdown("## 🎙️ Educational Podcast Generator for Students")
|
106 |
+
gr.Markdown("Enter a topic and choose your language to generate a friendly podcast between Ali and Talha.")
|
107 |
|
108 |
topic_input = gr.Textbox(label="Enter educational topic")
|
109 |
+
lang_input = gr.Dropdown(
|
110 |
+
choices=["English", "Vietnamese", "Spanish", "French", "Japanese"],
|
111 |
+
value="English",
|
112 |
+
label="Select output language"
|
113 |
+
)
|
114 |
generate_btn = gr.Button("🎧 Generate Podcast")
|
115 |
output_box = gr.HTML()
|
116 |
|
117 |
+
generate_btn.click(fn=generate, inputs=[topic_input, lang_input], outputs=output_box)
|
118 |
|
119 |
demo.launch()
|