time4et commited on
Commit
9d31a97
·
verified ·
1 Parent(s): 661af1b

Upload 2 files

Browse files

Added requirements and app main files

Files changed (2) hide show
  1. app.py +155 -0
  2. requirements.txt +8 -0
app.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # blog_app.py
2
+ import streamlit as st
3
+ from typing import TypedDict, List, Optional
4
+ from langgraph.graph import StateGraph, END
5
+ import groq
6
+ import re
7
+ import os
8
+ from dotenv import load_dotenv
9
+ load_dotenv()
10
+
11
+ # Configure Groq client
12
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
13
+ # Configure Groq client
14
+ client = groq.Groq(api_key=GROQ_API_KEY)
15
+ # Define state structure
16
+ class BlogState(TypedDict):
17
+ keyword: str
18
+ titles: List[str]
19
+ selected_title: Optional[str]
20
+ blog_content: Optional[str]
21
+
22
+ # Initialize LangGraph workflow
23
+ def create_workflow():
24
+ workflow = StateGraph(BlogState)
25
+
26
+ # Define nodes
27
+ def generate_titles(state: BlogState):
28
+ prompt = f"""Generate 5 compelling blog titles on {state['keyword']}.
29
+ Ensure below standards
30
+ 1. The titles should be attention-grabbing, SEO-friendly, and formatted in a way that encourages clicks.
31
+ 2. Use a mix of listicles, how-to guides, thought leadership, and trending topics.
32
+ 3. Ensure the titles are unique and cater to a wide audience.
33
+ 4. Each Title should be Maximum 50 characters
34
+ 5. Generate 5 Titles """
35
+
36
+ try:
37
+ response = client.chat.completions.create(
38
+ messages=[{"role": "user", "content": prompt}],
39
+ model="qwen-2.5-32b",
40
+ temperature=0.7,
41
+ max_tokens=200
42
+ )
43
+ raw_output = re.sub(r'<\/?[a-zA-Z]+>', '', response.choices[0].message.content, flags=re.DOTALL).strip()
44
+ titles = [line.split(". ", 1)[1].strip() for line in raw_output.split("\n") if ". " in line[:4]][:5]
45
+ return {"titles": titles}
46
+ except Exception as e:
47
+ st.error(f"Title generation failed: {str(e)}")
48
+ return {"titles": []}
49
+
50
+ def generate_content(state: BlogState):
51
+ prompt = f"""Write a comprehensive 1500-word blog post titled "{state['selected_title']}".
52
+ Write a detailed and engaging blog post on the topic '[topic]'.
53
+ The blog should have a captivating introduction, well-structured sections with informative subheadings, and a strong conclusion.
54
+ Use a conversational yet professional tone, include real-world examples, and provide actionable insights.
55
+ Ensure the content is SEO-optimized with relevant keywords, bullet points, and headings to improve readability.
56
+ Keep the word count between 1000 and 1500 words.
57
+ """
58
+
59
+ try:
60
+ response = client.chat.completions.create(
61
+ messages=[{"role": "user", "content": prompt}],
62
+ model="llama3-70b-8192",
63
+ temperature=0.8,
64
+ max_tokens=3000
65
+ )
66
+ content = re.sub(r'<\/?[a-zA-Z]+>', '', response.choices[0].message.content, flags=re.DOTALL).strip()
67
+ return {"blog_content": content}
68
+ except Exception as e:
69
+ st.error(f"Content generation failed: {str(e)}")
70
+ return {"blog_content": ""}
71
+
72
+ # Add nodes to workflow
73
+ workflow.add_node("generate_titles", generate_titles)
74
+ workflow.add_node("generate_content", generate_content)
75
+
76
+ # Define edges
77
+ workflow.set_entry_point("generate_titles")
78
+
79
+ def route_after_titles(state: BlogState):
80
+ return "generate_content" if state.get("selected_title") else END
81
+
82
+ workflow.add_conditional_edges(
83
+ "generate_titles",
84
+ route_after_titles
85
+ )
86
+ workflow.add_edge("generate_content", END)
87
+
88
+ return workflow.compile()
89
+
90
+ # Streamlit UI
91
+ st.title("AI Blog Generator")
92
+ app = create_workflow()
93
+
94
+ # Initialize session state
95
+ if 'blog_state' not in st.session_state:
96
+ st.session_state.blog_state = {
97
+ "keyword": "",
98
+ "titles": [],
99
+ "selected_title": None,
100
+ "blog_content": None
101
+ }
102
+
103
+ # Input Section
104
+ keyword = st.text_input("Enter blog topic keyword:",
105
+ value=st.session_state.blog_state["keyword"])
106
+
107
+ # Generate Titles
108
+ if st.button("Generate Titles") and keyword.strip():
109
+ with st.spinner("Generating title options..."):
110
+ new_state = app.invoke({
111
+ "keyword": keyword.strip(),
112
+ "titles": [],
113
+ "selected_title": None,
114
+ "blog_content": None
115
+ })
116
+ st.session_state.blog_state = new_state
117
+
118
+ # Display Titles
119
+ if st.session_state.blog_state["titles"]:
120
+ st.subheader("Generated Titles")
121
+ selected_idx = st.radio("Select a title:",
122
+ options=range(len(st.session_state.blog_state["titles"])),
123
+ format_func=lambda x: st.session_state.blog_state["titles"][x])
124
+
125
+ # Store selection
126
+ st.session_state.blog_state["selected_title"] = st.session_state.blog_state["titles"][selected_idx]
127
+
128
+ # Generate Content
129
+ if st.session_state.blog_state["selected_title"] and not st.session_state.blog_state["blog_content"]:
130
+ if st.button("Generate Full Blog Post"):
131
+ with st.spinner("Writing blog post..."):
132
+ final_state = app.invoke(st.session_state.blog_state)
133
+ st.session_state.blog_state = final_state
134
+
135
+ # Display Content
136
+ if st.session_state.blog_state["blog_content"]:
137
+ st.subheader(st.session_state.blog_state["selected_title"])
138
+ st.markdown(st.session_state.blog_state["blog_content"])
139
+
140
+ # Download button
141
+ st.download_button(
142
+ "Download Markdown",
143
+ st.session_state.blog_state["blog_content"],
144
+ file_name=f"{st.session_state.blog_state['selected_title']}.md"
145
+ )
146
+
147
+ # Reset functionality (corrected)
148
+ if st.button("Reset"):
149
+ st.session_state.blog_state = {
150
+ "keyword": "",
151
+ "titles": [],
152
+ "selected_title": None,
153
+ "blog_content": None
154
+ }
155
+ st.rerun() # Using current rerun method
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ langgraph
2
+ groq
3
+ streamlit
4
+ ipykernel
5
+ python-dotenv
6
+ langchain-groq
7
+ langgraph
8
+ langgraph-cli[inmem]