Ansnaeem commited on
Commit
8f46cb8
·
verified ·
1 Parent(s): cb4594e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -145
app.py CHANGED
@@ -1,145 +1,145 @@
1
- import gradio as gr
2
- import os
3
- import requests
4
- import re
5
-
6
- # Load GROQ API key from environment
7
- GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
8
- GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
9
- MODEL_NAME = "llama3-8b-8192"
10
-
11
- SYSTEM_PROMPT = """You are 'ScriptForge AI', a professional YouTube Script Writer.
12
- Your goal is to write highly engaging, audience-first scripts in the 2nd person (using 'You', 'Your').
13
- Talk directly to the viewer as if you are the creator speaking to the camera.
14
-
15
- FORMATTING RULES:
16
- 1. Every script must alternate between [SCENE DESCRIPTION] and [SCRIPT].
17
- 2. [SCENE DESCRIPTION] should describe the visuals, camera angles, or B-roll.
18
- 3. [SCRIPT] should be the actual spoken words.
19
- 4. Structure the script with a Hook, Intro, Main Points, and a Call to Action (CTA).
20
- 5. Maintain the requested Tone and Duration.
21
-
22
- Example:
23
- [SCENE DESCRIPTION]: Close-up of the product.
24
- [SCRIPT]: You need to see this to believe it.
25
- """
26
-
27
- def parse_script(full_text):
28
- # Extract [SCRIPT] parts for TTS
29
- script_parts = re.findall(r'\[SCRIPT\]:(.*?)(?=\[SCENE DESCRIPTION\]|$)', full_text, re.DOTALL | re.IGNORECASE)
30
- clean_script = "\n".join([p.strip() for p in script_parts])
31
-
32
- # Extract [SCENE DESCRIPTION] parts for Visuals
33
- scene_parts = re.findall(r'\[SCENE DESCRIPTION\]:(.*?)(?=\[SCRIPT\]|$)', full_text, re.DOTALL | re.IGNORECASE)
34
- clean_scenes = "\n".join([p.strip() for p in scene_parts])
35
-
36
- # Calculate stats
37
- word_count = len(clean_script.split())
38
- # Est duration: ~150 words per minute
39
- duration_minutes = word_count / 150
40
- minutes = int(duration_minutes)
41
- seconds = int((duration_minutes - minutes) * 60)
42
- duration_str = f"{minutes}m {seconds}s"
43
-
44
- return clean_script, clean_scenes, word_count, duration_str
45
-
46
- def query_groq(topic, tone, duration, hook_strength, chat_history):
47
- if not GROQ_API_KEY:
48
- return "Error: GROQ_API_KEY not found in environment secrets. Please add it in Settings > Secrets.", "", "", 0, "0m 0s"
49
-
50
- headers = {
51
- "Authorization": f"Bearer {GROQ_API_KEY}",
52
- "Content-Type": "application/json"
53
- }
54
-
55
- user_input = f"Topic: {topic}\nTone: {tone}\nTarget Duration: {duration}\nAction: Write a full YouTube script."
56
-
57
- messages = [{"role": "system", "content": SYSTEM_PROMPT}]
58
- # Add history for context (optional but helpful)
59
- for user, bot in chat_history[-3:]: # Keep last 3 exchanges to avoid context bloat
60
- messages.append({"role": "user", "content": user})
61
- messages.append({"role": "assistant", "content": bot})
62
-
63
- messages.append({"role": "user", "content": user_input})
64
-
65
- try:
66
- response = requests.post(GROQ_API_URL, headers=headers, json={
67
- "model": MODEL_NAME,
68
- "messages": messages,
69
- "temperature": hook_strength
70
- }, timeout=30)
71
-
72
- if response.status_code == 200:
73
- full_reply = response.json()["choices"][0]["message"]["content"]
74
- tts_script, scenes, wc, dur = parse_script(full_reply)
75
- return full_reply, tts_script, scenes, wc, dur
76
- else:
77
- return f"Error {response.status_code}: {response.text}", "", "", 0, "0m 0s"
78
- except Exception as e:
79
- return f"Request failed: {str(e)}", "", "", 0, "0m 0s"
80
-
81
- def respond(topic, tone, duration, hook_strength, chat_history):
82
- full_reply, tts_script, scenes, wc, dur = query_groq(topic, tone, duration, hook_strength, chat_history)
83
- chat_history.append((topic, full_reply))
84
- return chat_history, tts_script, scenes, f"{wc} words", dur
85
-
86
- css = """
87
- footer {visibility: hidden}
88
- .stat-box {
89
- background-color: #f0f2f6;
90
- padding: 10px;
91
- border-radius: 10px;
92
- text-align: center;
93
- border: 1px solid #ddd;
94
- }
95
- """
96
-
97
- with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
98
- gr.Markdown("# 🎬 ScriptForge AI: YouTube Script Master")
99
- gr.Markdown("Transform your video ideas into high-retention, audience-first scripts. *Powered by GROQ*")
100
-
101
- with gr.Row():
102
- with gr.Column(scale=1):
103
- topic = gr.Textbox(label="Video Topic/Description", placeholder="E.g., How to build a PC in 2025", lines=3)
104
- tone = gr.Dropdown(
105
- choices=["High Energy", "Storytelling", "Educational", "Minimalist", "Aggressive/Hype"],
106
- label="Video Tone",
107
- value="High Energy"
108
- )
109
- duration = gr.Dropdown(
110
- choices=["Shorts (<60s)", "Standard (5-10 mins)", "Deep Dive (15+ mins)"],
111
- label="Target Duration",
112
- value="Standard (5-10 mins)"
113
- )
114
- hook_strength = gr.Slider(minimum=0.1, maximum=1.5, value=0.7, step=0.1, label="Hook Strength (Creativity)")
115
- generate_btn = gr.Button("🚀 Generate Script", variant="primary")
116
- clear = gr.Button("Clear")
117
-
118
- with gr.Column(scale=2):
119
- with gr.Row():
120
- word_count_display = gr.Textbox(label="Word Count", interactive=False, elem_classes="stat-box")
121
- duration_display = gr.Textbox(label="Est. Speaking Time", interactive=False, elem_classes="stat-box")
122
-
123
- with gr.Tabs():
124
- with gr.TabItem("Combined View"):
125
- chatbot = gr.Chatbot(height=500)
126
-
127
- with gr.TabItem("TTS Only (Dialogue)"):
128
- tts_output = gr.Textbox(label="Copy this for Text-to-Speech", show_copy_button=True, lines=20)
129
-
130
- with gr.TabItem("Visuals Only (Shot List)"):
131
- scenes_output = gr.Textbox(label="Video Scene Descriptions", lines=20)
132
-
133
- # State for history
134
- state = gr.State([])
135
-
136
- generate_btn.click(
137
- respond,
138
- [topic, tone, duration, hook_strength, state],
139
- [chatbot, tts_output, scenes_output, word_count_display, duration_display]
140
- )
141
-
142
- clear.click(lambda: (None, "", "", "", "", []), None, [topic, chatbot, tts_output, scenes_output, word_count_display, duration_display])
143
-
144
- if __name__ == "__main__":
145
- demo.launch()
 
1
+ import gradio as gr
2
+ import os
3
+ import requests
4
+ import re
5
+
6
+ # Load GROQ API key from environment
7
+ GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
8
+ GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"
9
+ MODEL_NAME = "llama3-8b-8192"
10
+
11
+ SYSTEM_PROMPT = """You are 'ScriptForge AI', a professional YouTube Script Writer.
12
+ Your goal is to write highly engaging, audience-first scripts in the 2nd person (using 'You', 'Your').
13
+ Talk directly to the viewer as if you are the creator speaking to the camera.
14
+
15
+ FORMATTING RULES:
16
+ 1. Every script must alternate between [SCENE DESCRIPTION] and [SCRIPT].
17
+ 2. [SCENE DESCRIPTION] should describe the visuals, camera angles, or B-roll.
18
+ 3. [SCRIPT] should be the actual spoken words.
19
+ 4. Structure the script with a Hook, Intro, Main Points, and a Call to Action (CTA).
20
+ 5. Maintain the requested Tone and Duration.
21
+
22
+ Example:
23
+ [SCENE DESCRIPTION]: Close-up of the product.
24
+ [SCRIPT]: You need to see this to believe it.
25
+ """
26
+
27
+ def parse_script(full_text):
28
+ # Extract [SCRIPT] parts for TTS
29
+ script_parts = re.findall(r'\[SCRIPT\]:(.*?)(?=\[SCENE DESCRIPTION\]|$)', full_text, re.DOTALL | re.IGNORECASE)
30
+ clean_script = "\n".join([p.strip() for p in script_parts])
31
+
32
+ # Extract [SCENE DESCRIPTION] parts for Visuals
33
+ scene_parts = re.findall(r'\[SCENE DESCRIPTION\]:(.*?)(?=\[SCRIPT\]|$)', full_text, re.DOTALL | re.IGNORECASE)
34
+ clean_scenes = "\n".join([p.strip() for p in scene_parts])
35
+
36
+ # Calculate stats
37
+ word_count = len(clean_script.split())
38
+ # Est duration: ~150 words per minute
39
+ duration_minutes = word_count / 150
40
+ minutes = int(duration_minutes)
41
+ seconds = int((duration_minutes - minutes) * 60)
42
+ duration_str = f"{minutes}m {seconds}s"
43
+
44
+ return clean_script, clean_scenes, word_count, duration_str
45
+
46
+ def query_groq(topic, tone, duration, hook_strength, chat_history):
47
+ if not GROQ_API_KEY:
48
+ return "Error: GROQ_API_KEY not found in environment secrets. Please add it in Settings > Secrets.", "", "", 0, "0m 0s"
49
+
50
+ headers = {
51
+ "Authorization": f"Bearer {GROQ_API_KEY}",
52
+ "Content-Type": "application/json"
53
+ }
54
+
55
+ user_input = f"Topic: {topic}\nTone: {tone}\nTarget Duration: {duration}\nAction: Write a full YouTube script."
56
+
57
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
58
+ # Add history for context (optional but helpful)
59
+ for user, bot in chat_history[-3:]: # Keep last 3 exchanges to avoid context bloat
60
+ messages.append({"role": "user", "content": user})
61
+ messages.append({"role": "assistant", "content": bot})
62
+
63
+ messages.append({"role": "user", "content": user_input})
64
+
65
+ try:
66
+ response = requests.post(GROQ_API_URL, headers=headers, json={
67
+ "model": MODEL_NAME,
68
+ "messages": messages,
69
+ "temperature": hook_strength
70
+ }, timeout=30)
71
+
72
+ if response.status_code == 200:
73
+ full_reply = response.json()["choices"][0]["message"]["content"]
74
+ tts_script, scenes, wc, dur = parse_script(full_reply)
75
+ return full_reply, tts_script, scenes, wc, dur
76
+ else:
77
+ return f"Error {response.status_code}: {response.text}", "", "", 0, "0m 0s"
78
+ except Exception as e:
79
+ return f"Request failed: {str(e)}", "", "", 0, "0m 0s"
80
+
81
+ def respond(topic, tone, duration, hook_strength, chat_history):
82
+ full_reply, tts_script, scenes, wc, dur = query_groq(topic, tone, duration, hook_strength, chat_history)
83
+ chat_history.append((topic, full_reply))
84
+ return chat_history, tts_script, scenes, f"{wc} words", dur
85
+
86
+ css = """
87
+ footer {visibility: hidden}
88
+ .stat-box {
89
+ background-color: #f0f2f6;
90
+ padding: 10px;
91
+ border-radius: 10px;
92
+ text-align: center;
93
+ border: 1px solid #ddd;
94
+ }
95
+ """
96
+
97
+ with gr.Blocks() as demo:
98
+ gr.Markdown("# 🎬 ScriptForge AI: YouTube Script Master")
99
+ gr.Markdown("Transform your video ideas into high-retention, audience-first scripts. *Powered by GROQ*")
100
+
101
+ with gr.Row():
102
+ with gr.Column(scale=1):
103
+ topic = gr.Textbox(label="Video Topic/Description", placeholder="E.g., How to build a PC in 2025", lines=3)
104
+ tone = gr.Dropdown(
105
+ choices=["High Energy", "Storytelling", "Educational", "Minimalist", "Aggressive/Hype"],
106
+ label="Video Tone",
107
+ value="High Energy"
108
+ )
109
+ duration = gr.Dropdown(
110
+ choices=["Shorts (<60s)", "Standard (5-10 mins)", "Deep Dive (15+ mins)"],
111
+ label="Target Duration",
112
+ value="Standard (5-10 mins)"
113
+ )
114
+ hook_strength = gr.Slider(minimum=0.1, maximum=1.5, value=0.7, step=0.1, label="Hook Strength (Creativity)")
115
+ generate_btn = gr.Button("🚀 Generate Script", variant="primary")
116
+ clear = gr.Button("Clear")
117
+
118
+ with gr.Column(scale=2):
119
+ with gr.Row():
120
+ word_count_display = gr.Textbox(label="Word Count", interactive=False, elem_classes="stat-box")
121
+ duration_display = gr.Textbox(label="Est. Speaking Time", interactive=False, elem_classes="stat-box")
122
+
123
+ with gr.Tabs():
124
+ with gr.TabItem("Combined View"):
125
+ chatbot = gr.Chatbot(height=500)
126
+
127
+ with gr.TabItem("TTS Only (Dialogue)"):
128
+ tts_output = gr.Textbox(label="Copy this for Text-to-Speech", lines=20)
129
+
130
+ with gr.TabItem("Visuals Only (Shot List)"):
131
+ scenes_output = gr.Textbox(label="Video Scene Descriptions", lines=20)
132
+
133
+ # State for history
134
+ state = gr.State([])
135
+
136
+ generate_btn.click(
137
+ respond,
138
+ [topic, tone, duration, hook_strength, state],
139
+ [chatbot, tts_output, scenes_output, word_count_display, duration_display]
140
+ )
141
+
142
+ clear.click(lambda: (None, "", "", "", "", []), None, [topic, chatbot, tts_output, scenes_output, word_count_display, duration_display])
143
+
144
+ if __name__ == "__main__":
145
+ demo.launch(theme=gr.themes.Soft(), css=css)