aibloggenerator / app.py
time4et's picture
Update app.py
971b843 verified
# blog_app.py
import streamlit as st
from typing import TypedDict, List, Optional
from langgraph.graph import StateGraph, END
import groq
import re
import os
from dotenv import load_dotenv
import streamlit as st
load_dotenv()
# Configure Groq client
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
# Configure Groq client
client = groq.Groq(api_key=GROQ_API_KEY)
# Define state structure
class BlogState(TypedDict):
keyword: str
titles: List[str]
selected_title: Optional[str]
blog_content: Optional[str]
# Initialize LangGraph workflow
def create_workflow():
workflow = StateGraph(BlogState)
# Define nodes
def generate_titles(state: BlogState):
prompt = f"""Generate 5 compelling blog titles on {state['keyword']}.
Ensure below standards
1. The titles should be attention-grabbing, SEO-friendly, and formatted in a way that encourages clicks.
2. Use a mix of listicles, how-to guides, thought leadership, and trending topics.
3. Ensure the titles are unique and cater to a wide audience.
4. Each Title should be Maximum 50 characters
5. Generate 5 Titles """
try:
response = client.chat.completions.create(
messages=[{"role": "user", "content": prompt}],
model="llama3-70b-8192",
#model="qwen-2.5-32b",
temperature=0.7,
max_tokens=200
)
raw_output = re.sub(r'<\/?[a-zA-Z]+>', '', response.choices[0].message.content, flags=re.DOTALL).strip()
titles = [line.split(". ", 1)[1].strip() for line in raw_output.split("\n") if ". " in line[:4]][:5]
return {"titles": titles}
except Exception as e:
st.error(f"Title generation failed: {str(e)}")
return {"titles": []}
def generate_content(state: BlogState):
prompt = f"""Write a comprehensive 1500-word blog post titled "{state['selected_title']}".
Write a detailed and engaging blog post on the topic '[topic]'.
The blog should have a captivating introduction, well-structured sections with informative subheadings, and a strong conclusion.
Use a conversational yet professional tone, include real-world examples, and provide actionable insights.
Ensure the content is SEO-optimized with relevant keywords, bullet points, and headings to improve readability.
Keep the word count between 1000 and 1500 words.
"""
try:
response = client.chat.completions.create(
messages=[{"role": "user", "content": prompt}],
model="llama3-70b-8192",
temperature=0.8,
max_tokens=3000
)
content = re.sub(r'<\/?[a-zA-Z]+>', '', response.choices[0].message.content, flags=re.DOTALL).strip()
return {"blog_content": content}
except Exception as e:
st.error(f"Content generation failed: {str(e)}")
return {"blog_content": ""}
# Add nodes to workflow
workflow.add_node("generate_titles", generate_titles)
workflow.add_node("generate_content", generate_content)
# Define edges
workflow.set_entry_point("generate_titles")
def route_after_titles(state: BlogState):
return "generate_content" if state.get("selected_title") else END
workflow.add_conditional_edges(
"generate_titles",
route_after_titles
)
workflow.add_edge("generate_content", END)
return workflow.compile()
# Streamlit UI
st.title("AI Blog Generator")
app = create_workflow()
# Initialize session state
if 'blog_state' not in st.session_state:
st.session_state.blog_state = {
"keyword": "",
"titles": [],
"selected_title": None,
"blog_content": None
}
# Input Section
keyword = st.text_input("Enter blog topic keyword:",
value=st.session_state.blog_state["keyword"])
# Generate Titles
if st.button("Generate Titles") and keyword.strip():
with st.spinner("Generating title options..."):
new_state = app.invoke({
"keyword": keyword.strip(),
"titles": [],
"selected_title": None,
"blog_content": None
})
st.session_state.blog_state = new_state
# Display Titles
if st.session_state.blog_state["titles"]:
st.subheader("Generated Titles")
selected_idx = st.radio("Select a title:",
options=range(len(st.session_state.blog_state["titles"])),
format_func=lambda x: st.session_state.blog_state["titles"][x])
# Store selection
st.session_state.blog_state["selected_title"] = st.session_state.blog_state["titles"][selected_idx]
# Generate Content
if st.session_state.blog_state["selected_title"] and not st.session_state.blog_state["blog_content"]:
if st.button("Generate Full Blog Post"):
with st.spinner("Writing blog post..."):
final_state = app.invoke(st.session_state.blog_state)
st.session_state.blog_state = final_state
# Display Content
if st.session_state.blog_state["blog_content"]:
st.subheader(st.session_state.blog_state["selected_title"])
st.markdown(st.session_state.blog_state["blog_content"])
# Download button
st.download_button(
"Download Text",
st.session_state.blog_state["blog_content"],
file_name=f"{st.session_state.blog_state['selected_title']}.txt"
)
# Reset functionality (corrected)
if st.button("Reset"):
st.session_state.blog_state = {
"keyword": "",
"titles": [],
"selected_title": None,
"blog_content": None
}
st.rerun() # Using current rerun method