Spaces:
Sleeping
Sleeping
File size: 5,780 Bytes
da81d74 60eef7a da81d74 971b843 1458bd1 da81d74 60eef7a da81d74 9d31a97 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# 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 |