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