mroccuper commited on
Commit
8322bc8
Β·
verified Β·
1 Parent(s): ef43207

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +365 -0
app.py ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import google.generativeai as genai
3
+ import textstat
4
+ import re
5
+ import os
6
+ from datetime import datetime
7
+ import tempfile
8
+
9
+ class PRArticleGenerator:
10
+ def __init__(self):
11
+ self.pr_prompt = """
12
+ πŸ”§ SYSTEM ROLE: You are an elite PR content creator and strategic brand storyteller trusted by top agencies, corporate media teams, and high-level entrepreneurs. Your task is to read and transform any provided content, story, or news lead into a **highly polished PR-style article** that mimics the tone, structure, and strategic formatting of elite publications like Forbes, Bloomberg, and Business Insider.
13
+
14
+ 🎯 OBJECTIVE:
15
+ - Convert raw input (facts, story, business news, public figure achievements, etc.) into a **public relations-style news article**.
16
+ - Write in **neutral-positive, professional tone** suitable for public and media consumption.
17
+ - Follow a structure optimized for **reader engagement**, **media authority**, and **SEO discoverability**.
18
+
19
+ 🧠 CONTENT STRATEGY:
20
+ Your output must follow the typical PR-style article structure:
21
+ 1. **Headline**: Catchy, clear, and subtly sensational. Include target keyword naturally.
22
+ 2. **Lead Paragraph**: Who, what, when, where, and why β€” as a newsworthy hook.
23
+ 3. **Impact Section**: Explain the deal's relevance (economic, public, cultural).
24
+ 4. **About the Person/Company**: Short biography with credentials and accomplishments.
25
+ 5. **Portfolio Highlights**: List of key acquisitions or achievements.
26
+ 6. **Vision or Quote**: Add a forward-looking statement or vision from the person.
27
+ 7. **Closing Paragraph**: Recap the significance and future outlook.
28
+
29
+ βœ… SEO OPTIMIZATION:
30
+ - Include the **primary keyword** naturally in:
31
+ - Title (H1)
32
+ - First 100 words
33
+ - 1–2 subheadings
34
+ - Last 100 words
35
+ - Use **Rank Math-friendly structure**:
36
+ - Add appropriate **H2** subheadings
37
+ - Use bullet lists for skimmable value
38
+ - Maintain readability and engagement
39
+ - Ensure **minimum 600 words** (unless input content is too short)
40
+ - Avoid keyword stuffing β€” aim for **natural semantic variation** (LSI keywords)
41
+ - Optimize for **search intent**: informational + navigational
42
+
43
+ 🌐 AUDIENCE:
44
+ - Journalists, business professionals, investors, and curious online readers
45
+ - Must feel "official," trustworthy, and newsworthy
46
+ - Tone: authoritative yet accessible (no jargon, no exaggeration)
47
+
48
+ 🎨 FORMATTING RULES:
49
+ - Use proper HTML headings: `<h1>`, `<h2>`, `<p>`, `<ul>`, `<strong>` when needed.
50
+ - Format like a WordPress blog post, ready to paste directly into WordPress editor.
51
+ - If quote is not provided, create one that sounds realistic and vision-driven.
52
+
53
+ πŸ“₯ INPUT FORMAT:
54
+ The user will paste raw content, an article, a story draft, or a list of facts.
55
+
56
+ πŸ“€ OUTPUT FORMAT:
57
+ Return a fully structured and SEO-optimized PR-style article, ready for WordPress publishing using Rank Math.
58
+
59
+ ⚠️ DO NOT:
60
+ - Generate listicles, opinion pieces, or promotional fluff
61
+ - Use phrases like "This article was written by AI"
62
+ - Include fake dates or unverifiable claims
63
+
64
+ 🎁 BONUS (if relevant input is provided):
65
+ - Suggest a **meta title** and **meta description** optimized for Rank Math
66
+ - Suggest **target keyword**
67
+
68
+ Please transform the following content into a professional PR-style article:
69
+ """
70
+
71
+ def setup_gemini(self, api_key):
72
+ """Configure Gemini API"""
73
+ try:
74
+ genai.configure(api_key=api_key)
75
+ model = genai.GenerativeModel('gemini-1.5-pro')
76
+ return model, None
77
+ except Exception as e:
78
+ return None, f"API Configuration Error: {str(e)}"
79
+
80
+ def calculate_readability_score(self, text):
81
+ """Calculate readability score using textstat and custom PR metrics"""
82
+ try:
83
+ # Remove HTML tags for analysis
84
+ clean_text = re.sub(r'<[^>]+>', '', text)
85
+
86
+ # Basic readability metrics
87
+ flesch_score = textstat.flesch_reading_ease(clean_text)
88
+ avg_sentence_length = textstat.avg_sentence_length(clean_text)
89
+ syllable_count = textstat.avg_syllables_per_word(clean_text)
90
+
91
+ # Custom PR writing metrics
92
+ pr_score = self.calculate_pr_score(text, clean_text)
93
+
94
+ # Normalize Flesch score to 1-10 scale
95
+ readability_base = min(10, max(1, (flesch_score / 10)))
96
+
97
+ # Combined score (60% readability, 40% PR best practices)
98
+ final_score = (readability_base * 0.6) + (pr_score * 0.4)
99
+
100
+ return round(final_score, 1), self.get_improvement_suggestions(flesch_score, avg_sentence_length, syllable_count, text)
101
+
102
+ except Exception as e:
103
+ return 5.0, f"Error calculating readability: {str(e)}"
104
+
105
+ def calculate_pr_score(self, html_text, clean_text):
106
+ """Calculate score based on PR writing best practices"""
107
+ score = 0
108
+ max_score = 10
109
+
110
+ # Check for proper HTML structure (H1, H2 tags)
111
+ if re.search(r'<h1>', html_text, re.IGNORECASE):
112
+ score += 1.5
113
+ if re.search(r'<h2>', html_text, re.IGNORECASE):
114
+ score += 1.5
115
+
116
+ # Check for bullet points/lists
117
+ if re.search(r'<ul>|<ol>', html_text, re.IGNORECASE):
118
+ score += 1
119
+
120
+ # Check for strong/bold text
121
+ if re.search(r'<strong>|<b>', html_text, re.IGNORECASE):
122
+ score += 1
123
+
124
+ # Check word count (600+ words is ideal for PR)
125
+ word_count = len(clean_text.split())
126
+ if word_count >= 600:
127
+ score += 2
128
+ elif word_count >= 400:
129
+ score += 1.5
130
+ elif word_count >= 200:
131
+ score += 1
132
+
133
+ # Check for quotes (professional credibility)
134
+ if '"' in clean_text and clean_text.count('"') >= 2:
135
+ score += 1
136
+
137
+ # Check for numbers/statistics (authority building)
138
+ if re.search(r'\d+%|\$\d+|[\d,]+\s*(million|billion|thousand)', clean_text):
139
+ score += 1.5
140
+
141
+ # Check for professional language patterns
142
+ professional_indicators = ['according to', 'announced', 'reported', 'confirmed', 'revealed']
143
+ if any(indicator in clean_text.lower() for indicator in professional_indicators):
144
+ score += 0.5
145
+
146
+ return min(max_score, score)
147
+
148
+ def get_improvement_suggestions(self, flesch_score, avg_sentence_length, syllable_count, html_text):
149
+ """Generate specific improvement suggestions"""
150
+ suggestions = []
151
+
152
+ if flesch_score < 50:
153
+ suggestions.append("β€’ Simplify complex sentences - aim for 15-20 words per sentence")
154
+ if avg_sentence_length > 25:
155
+ suggestions.append("β€’ Break down long sentences for better readability")
156
+ if syllable_count > 1.8:
157
+ suggestions.append("β€’ Use simpler words where possible without losing professionalism")
158
+ if not re.search(r'<h2>', html_text, re.IGNORECASE):
159
+ suggestions.append("β€’ Add more H2 subheadings to improve structure and SEO")
160
+ if not re.search(r'<ul>|<ol>', html_text, re.IGNORECASE):
161
+ suggestions.append("β€’ Include bullet points or lists for better scannability")
162
+ if len(html_text.split()) < 600:
163
+ suggestions.append("β€’ Expand content to reach 600+ words for better SEO performance")
164
+ if html_text.count('"') < 2:
165
+ suggestions.append("β€’ Add relevant quotes to increase credibility and engagement")
166
+ if not re.search(r'\d+%|\$\d+|[\d,]+', html_text):
167
+ suggestions.append("β€’ Include specific numbers, statistics, or financial data for authority")
168
+
169
+ if not suggestions:
170
+ suggestions.append("β€’ Excellent! Your content meets PR writing best practices.")
171
+
172
+ return "\n".join(suggestions)
173
+
174
+ def generate_article(self, api_key, content, max_length=4000):
175
+ """Generate PR-style article using Gemini API"""
176
+ if not api_key.strip():
177
+ return "❌ Error: Please enter your Gemini API key", "", 0.0, "", None
178
+
179
+ if not content.strip():
180
+ return "❌ Error: Please enter content to transform", "", 0.0, "", None
181
+
182
+ if len(content) > max_length:
183
+ return f"❌ Error: Content exceeds {max_length} characters limit", "", 0.0, "", None
184
+
185
+ model, error = self.setup_gemini(api_key)
186
+ if error:
187
+ return f"❌ {error}", "", 0.0, "", None
188
+
189
+ try:
190
+ # Generate article
191
+ full_prompt = self.pr_prompt + "\n\nCONTENT TO TRANSFORM:\n" + content
192
+ response = model.generate_content(full_prompt)
193
+
194
+ if not response.text:
195
+ return "❌ Error: No response generated from API", "", 0.0, "", None
196
+
197
+ article_html = response.text.strip()
198
+
199
+ # Calculate readability score
200
+ score, suggestions = self.calculate_readability_score(article_html)
201
+
202
+ # Create downloadable file
203
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
204
+ filename = f"pr_article_{timestamp}.html"
205
+
206
+ # Create temporary file
207
+ temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8')
208
+ temp_file.write(f"""<!DOCTYPE html>
209
+ <html>
210
+ <head>
211
+ <meta charset="UTF-8">
212
+ <title>PR Article - Generated {datetime.now().strftime("%Y-%m-%d")}</title>
213
+ <style>
214
+ body {{ font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }}
215
+ h1 {{ color: #2c3e50; }}
216
+ h2 {{ color: #34495e; border-bottom: 2px solid #3498db; padding-bottom: 5px; }}
217
+ p {{ line-height: 1.6; }}
218
+ ul {{ margin: 15px 0; }}
219
+ li {{ margin: 5px 0; }}
220
+ </style>
221
+ </head>
222
+ <body>
223
+ {article_html}
224
+ </body>
225
+ </html>""")
226
+ temp_file.close()
227
+
228
+ success_msg = f"βœ… Article generated successfully! Readability Score: {score}/10"
229
+
230
+ return success_msg, article_html, score, suggestions, temp_file.name
231
+
232
+ except Exception as e:
233
+ return f"❌ Generation Error: {str(e)}", "", 0.0, "", None
234
+
235
+ def create_interface():
236
+ generator = PRArticleGenerator()
237
+
238
+ # Custom CSS for better styling
239
+ css = """
240
+ .container { max-width: 1200px; margin: 0 auto; }
241
+ .header { text-align: center; margin-bottom: 30px; }
242
+ .score-display {
243
+ font-size: 18px;
244
+ font-weight: bold;
245
+ padding: 10px;
246
+ border-radius: 5px;
247
+ margin: 10px 0;
248
+ }
249
+ .error { color: #e74c3c; }
250
+ .success { color: #27ae60; }
251
+ .warning { color: #f39c12; }
252
+ """
253
+
254
+ with gr.Blocks(css=css, title="PR Article Generator", theme=gr.themes.Soft()) as interface:
255
+ gr.HTML("""
256
+ <div class="header">
257
+ <h1>🎯 Elite PR Article Generator</h1>
258
+ <p>Transform any content into professional PR-style articles optimized for SEO and media consumption</p>
259
+ </div>
260
+ """)
261
+
262
+ with gr.Row():
263
+ with gr.Column(scale=1):
264
+ gr.HTML("<h3>πŸ“ Input Configuration</h3>")
265
+
266
+ api_key_input = gr.Textbox(
267
+ label="πŸ”‘ Gemini API Key",
268
+ placeholder="Enter your Gemini 1.5 Pro API key here...",
269
+ type="password",
270
+ lines=1
271
+ )
272
+
273
+ content_input = gr.Textbox(
274
+ label="πŸ“„ Content to Transform",
275
+ placeholder="Paste your raw content, news, facts, or story here...\n\nExample:\n- Company announcement\n- Business news\n- Achievement story\n- Product launch details\n- Executive biography",
276
+ lines=15,
277
+ max_lines=20
278
+ )
279
+
280
+ with gr.Row():
281
+ max_length_slider = gr.Slider(
282
+ minimum=1000,
283
+ maximum=4000,
284
+ value=4000,
285
+ step=500,
286
+ label="πŸ“ Max Input Length (characters)"
287
+ )
288
+
289
+ generate_btn = gr.Button(
290
+ "πŸš€ Generate PR Article",
291
+ variant="primary",
292
+ size="lg"
293
+ )
294
+
295
+ with gr.Column(scale=1):
296
+ gr.HTML("<h3>πŸ“Š Output & Analysis</h3>")
297
+
298
+ status_output = gr.Textbox(
299
+ label="πŸ“‹ Status",
300
+ lines=2,
301
+ interactive=False
302
+ )
303
+
304
+ with gr.Row():
305
+ score_output = gr.Number(
306
+ label="πŸ“ˆ Readability Score",
307
+ precision=1,
308
+ interactive=False
309
+ )
310
+
311
+ suggestions_output = gr.Textbox(
312
+ label="πŸ’‘ Improvement Suggestions",
313
+ lines=8,
314
+ interactive=False,
315
+ placeholder="Suggestions will appear here..."
316
+ )
317
+
318
+ download_file = gr.File(
319
+ label="πŸ“₯ Download HTML Article",
320
+ interactive=False
321
+ )
322
+
323
+ with gr.Row():
324
+ with gr.Column():
325
+ gr.HTML("<h3>🎨 Generated Article Preview</h3>")
326
+ article_output = gr.HTML(
327
+ label="Generated PR Article",
328
+ show_label=False
329
+ )
330
+
331
+ # Event handlers
332
+ generate_btn.click(
333
+ fn=generator.generate_article,
334
+ inputs=[api_key_input, content_input, max_length_slider],
335
+ outputs=[status_output, article_output, score_output, suggestions_output, download_file]
336
+ )
337
+
338
+ # Add examples
339
+ gr.HTML("""
340
+ <div style="margin-top: 30px; padding: 20px; background-color: #f8f9fa; border-radius: 10px;">
341
+ <h3>πŸ’‘ Example Input Content:</h3>
342
+ <p><strong>Business Acquisition:</strong> "Tech entrepreneur John Smith announced the acquisition of downtown office building for $15M. Smith, who previously founded two successful startups, plans to convert the space into a modern co-working hub."</p>
343
+ <p><strong>Product Launch:</strong> "AI company releases new software that reduces processing time by 60%. The tool has been tested by 500+ businesses with positive results."</p>
344
+ <p><strong>Executive Profile:</strong> "Sarah Johnson, CEO of GreenTech Solutions, graduated from MIT and led three successful IPOs. Her company just secured $50M in Series B funding."</p>
345
+ </div>
346
+ """)
347
+
348
+ return interface
349
+
350
+ if __name__ == "__main__":
351
+ # Install required packages
352
+ try:
353
+ import google.generativeai
354
+ import textstat
355
+ except ImportError:
356
+ print("Installing required packages...")
357
+ os.system("pip install google-generativeai textstat")
358
+
359
+ app = create_interface()
360
+ app.launch(
361
+ server_name="0.0.0.0",
362
+ server_port=7860,
363
+ share=True,
364
+ show_error=True
365
+ )