Last active
May 13, 2025 14:14
-
-
Save lamviechappy/4c25269bc9531215e54c1da0f4cb3ad4 to your computer and use it in GitHub Desktop.
Streamlit app to rewrite video scripts using OpenAI, Claude, DeepSeek
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 🔹 Phần 1/3 — Khởi tạo, dotenv, UI cơ bản | |
import streamlit as st | |
import os | |
import textwrap | |
from dotenv import load_dotenv | |
from datetime import datetime | |
import openai | |
import anthropic | |
import httpx | |
# Load environment variables | |
load_dotenv() | |
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") | |
ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") | |
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY") | |
# Session management | |
if "generated_prompt" not in st.session_state: | |
st.session_state["generated_prompt"] = "" | |
if "final_script" not in st.session_state: | |
st.session_state["final_script"] = "" | |
if "custom_prompt" not in st.session_state: | |
st.session_state["custom_prompt"] = "" | |
if "use_custom_prompt" not in st.session_state: | |
st.session_state["use_custom_prompt"] = False | |
# Title | |
st.title("🎬 AI Video Script Rewriter") | |
# Input: Old script | |
old_script = st.text_area("📜 Enter your old video script:", height=200) | |
# Preset templates | |
preset_templates = { | |
"None": {}, | |
"YouTube - Educational": { | |
"tone": "Informative and friendly", | |
"sentence_length": "Short to medium", | |
"use_questions": "Yes", | |
"vocabulary_level": "Intermediate", | |
"hook_style": "Bold statement or intriguing question", | |
"cta_strength": "Moderate, toward end", | |
}, | |
"YouTube - Motivational": { | |
"tone": "Inspirational and emotional", | |
"emotional_tone": "High", | |
"sentence_length": "Short and punchy", | |
"use_humor": "Optional", | |
"cta_strength": "Strong", | |
"ending_style": "Call to greatness", | |
}, | |
} | |
preset = st.selectbox("🎨 Choose a preset style (optional):", options=list(preset_templates.keys())) | |
preset_data = preset_templates.get(preset, {}) | |
st.markdown("---") | |
# 🔹 Phần 2/3 — Cấu hình phần tử kịch bản và tạo Prompt | |
# Collapsible section for script elements | |
with st.expander("🛠️ Script Elements Configuration", expanded=True): | |
col1, col2 = st.columns(2) | |
def checkbox_text_input(col, label, key, default=""): | |
checked = col.checkbox(f"Enable {label}", key=f"{key}_enabled") | |
value = col.text_input(f"{label}:", value=preset_data.get(key, default), key=key) if checked else "" | |
return value if checked else None | |
# Column 1 | |
tone = checkbox_text_input(col1, "Tone", "tone") | |
sentence_length = checkbox_text_input(col1, "Sentence and Paragraph Length", "sentence_length") | |
sentence_variety = checkbox_text_input(col1, "Sentence Variety", "sentence_variety") | |
level_of_detail = checkbox_text_input(col1, "Level of Detail", "level_of_detail") | |
use_humor = checkbox_text_input(col1, "Use of Humor", "use_humor") | |
use_questions = checkbox_text_input(col1, "Use of Questions", "use_questions") | |
readability = checkbox_text_input(col1, "Readability Level", "readability") | |
vocabulary_level = checkbox_text_input(col1, "Vocabulary Level", "vocabulary_level") | |
# Column 2 | |
emotional_tone = checkbox_text_input(col2, "Emotional Tone", "emotional_tone") | |
target_audience = checkbox_text_input(col2, "Target Audience", "target_audience") | |
pacing = checkbox_text_input(col2, "Pacing & Rhythm", "pacing") | |
pov = checkbox_text_input(col2, "Point of View", "pov") | |
cta_strength = checkbox_text_input(col2, "Call-to-action Strength", "cta_strength") | |
storytelling_style = checkbox_text_input(col2, "Storytelling Style", "storytelling_style") | |
visual_descriptiveness = checkbox_text_input(col2, "Visual Imagery", "visual_descriptiveness") | |
transition_style = checkbox_text_input(col2, "Transitions", "transition_style") | |
hook_style = checkbox_text_input(col2, "Hook Style", "hook_style") | |
ending_style = checkbox_text_input(col2, "Ending Style", "ending_style") | |
additional_notes = checkbox_text_input(col2, "Additional Notes", "additional_notes") | |
# Generate Prompt Button | |
if st.button("📝 Generate Prompt"): | |
prompt = f"Rewrite this video script:\n\n{old_script}\n\ninto a new version with the following adjustments:\n" | |
def add_if(label, value): | |
return f"- {label}: {value}\n" if value else "" | |
prompt += "".join([ | |
add_if("Tone", tone), | |
add_if("Sentence and Paragraph Length", sentence_length), | |
add_if("Sentence Variety", sentence_variety), | |
add_if("Level of Detail", level_of_detail), | |
add_if("Use of Humor", use_humor), | |
add_if("Use of Questions", use_questions), | |
add_if("Readability Level", readability), | |
add_if("Vocabulary Level", vocabulary_level), | |
add_if("Emotional Tone", emotional_tone), | |
add_if("Target Audience", target_audience), | |
add_if("Pacing & Rhythm", pacing), | |
add_if("Point of view", pov), | |
add_if("Call-to-action strength", cta_strength), | |
add_if("Storytelling style", storytelling_style), | |
add_if("Visual imagery", visual_descriptiveness), | |
add_if("Transitions", transition_style), | |
add_if("Hook style", hook_style), | |
add_if("Ending style", ending_style), | |
add_if("Additional notes", additional_notes), | |
]) | |
st.session_state.generated_prompt = prompt | |
st.session_state.custom_prompt = prompt | |
st.session_state.use_custom_prompt = False | |
# 🔹 Phần 3/3 — Cấu hình AI, tạo script với API, hiển thị & xuất file | |
st.markdown("---") | |
st.markdown("### 🤖 AI Model Configuration") | |
col_a, col_b = st.columns(2) | |
with col_a: | |
platform = st.selectbox("Platform", ["OpenAI", "Claude", "DeepSeek"]) | |
model = st.text_input("Model Name", value="gpt-4o" if platform == "OpenAI" else "claude-3-opus-20240229") | |
temperature = st.slider("Temperature", 0.0, 1.5, 0.7) | |
with col_b: | |
max_tokens = st.number_input("Prompt Max Tokens", min_value=100, value=3000) | |
max_completion_tokens = st.number_input("Max Output Tokens", min_value=100, value=2048) | |
top_p = st.slider("Top-p (nucleus sampling)", 0.1, 1.0, 1.0) | |
# Allow prompt editing | |
st.markdown("### ✏️ Review & Edit Prompt") | |
prompt_editor = st.text_area("Prompt to send to AI", value=st.session_state.custom_prompt, height=300) | |
copy_col, edit_col = st.columns(2) | |
with copy_col: | |
st.code(prompt_editor, language="markdown") | |
with edit_col: | |
if st.button("Apply Edited Prompt"): | |
st.session_state.custom_prompt = prompt_editor | |
st.session_state.use_custom_prompt = True | |
# AI GENERATION | |
if st.button("🚀 Generate Script with AI"): | |
final_prompt = st.session_state.custom_prompt if st.session_state.use_custom_prompt else st.session_state.generated_prompt | |
headers = {"Content-Type": "application/json"} | |
try: | |
if platform == "OpenAI": | |
client = openai.OpenAI(api_key=OPENAI_API_KEY) | |
response = client.chat.completions.create( | |
model=model, | |
messages=[ | |
{"role": "system", "content": "You are a helpful assistant that rewrites video scripts."}, | |
{"role": "user", "content": final_prompt} | |
], | |
temperature=temperature, | |
top_p=top_p, | |
max_tokens=max_completion_tokens, | |
) | |
script = response.choices[0].message.content.strip() | |
elif platform == "Claude": | |
client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) | |
response = client.messages.create( | |
model=model, | |
max_tokens=max_completion_tokens, | |
temperature=temperature, | |
top_p=top_p, | |
system="You are a creative and helpful assistant that rewrites scripts clearly.", | |
messages=[{"role": "user", "content": final_prompt}] | |
) | |
script = response.content[0].text.strip() | |
elif platform == "DeepSeek": | |
headers["Authorization"] = f"Bearer {DEEPSEEK_API_KEY}" | |
url = "https://api.deepseek.com/chat/completions" | |
payload = { | |
"model": model, | |
"messages": [ | |
{"role": "system", "content": "You are a helpful assistant that rewrites video scripts."}, | |
{"role": "user", "content": final_prompt} | |
], | |
"temperature": temperature, | |
"top_p": top_p, | |
"max_tokens": max_completion_tokens, | |
} | |
with httpx.Client() as client: | |
resp = client.post(url, json=payload, headers=headers, timeout=30) | |
script = resp.json()["choices"][0]["message"]["content"].strip() | |
st.session_state.final_script = script | |
except Exception as e: | |
st.error(f"Error generating script: {e}") | |
# Show generated script | |
if st.session_state.final_script: | |
st.markdown("### 🧾 Rewritten Script") | |
st.text_area("AI-Generated Script", value=st.session_state.final_script, height=400) | |
now = datetime.now().strftime("%Y%m%d_%H%M%S") | |
prompt_filename_md = f"generated_prompt_{now}.md" | |
script_filename_md = f"rewritten_script_{now}.md" | |
prompt_filename_txt = f"generated_prompt_{now}.txt" | |
script_filename_txt = f"rewritten_script_{now}.txt" | |
st.download_button("⬇️ Download Prompt (.txt)", st.session_state.custom_prompt, file_name=prompt_filename_txt) | |
st.download_button("⬇️ Download Prompt (.md)", st.session_state.custom_prompt, file_name=prompt_filename_md) | |
st.download_button("⬇️ Download Script (.txt)", st.session_state.final_script, file_name=script_filename_txt) | |
st.download_button("⬇️ Download Script (.md)", st.session_state.final_script, file_name=script_filename_md) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment