mroccuper commited on
Commit
8ccc555
·
verified ·
1 Parent(s): 1c011e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +236 -92
app.py CHANGED
@@ -1,97 +1,241 @@
1
- import gradio as gr import html2text import google.generativeai as genai
2
-
3
- Insert your Gemini API key manually
4
-
5
- GEMINI_API_KEY = "your-gemini-api-key-here" genai.configure(api_key=GEMINI_API_KEY)
6
-
7
- model = genai.GenerativeModel("gemini-1.5-pro-latest")
8
-
9
- Example HTML input (for demo/testing)
10
-
11
- EXAMPLE_HTML = """
12
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  <html>
14
- <head><title>How I Brew Kombucha at Home</title></head>
 
 
 
 
 
 
 
 
 
 
15
  <body>
16
- <h1>How I Brew Kombucha at Home</h1>
17
- <p>Brewing kombucha at home has changed my wellness journey. I start with black tea and sugar, let it cool, and then introduce the SCOBY. After 7 days, I bottle it with fresh ginger or berries for a second ferment. It's fizzy, healthy, and deeply satisfying.</p>
18
- <h2>Ingredients</h2>
19
- <ul>
20
- <li>1 SCOBY</li>
21
- <li>1 cup sugar</li>
22
- <li>8 cups filtered water</li>
23
- <li>4 bags black tea</li>
24
- </ul>
25
  </body>
26
  </html>
27
- """Humanized prompt builder
28
-
29
- def build_prompt(html_content, platform, styles, emotions): markdown = html2text.html2text(html_content) prompt = f""" You are an expert copywriter and SEO specialist writing for a Reddit or Quora audience. Rewrite the following content into a post that feels genuinely human and experience-based.
30
-
31
- Platform: {platform}
32
-
33
- Writing style: {', '.join(styles)}
34
-
35
- Emotional tone: {', '.join(emotions)}
36
-
37
- Format as a personal story or real experience, not as polished marketing copy.
38
-
39
- Include imperfections, uncertainty, and real-life observations when possible.
40
-
41
- Use natural language and conversational tone. Avoid generic AI-sounding phrases.
42
-
43
- Add light humor, personal opinions, and authentic transitions.
44
-
45
- End with a relatable thought or casual call to action (like "What do you think?" or "Curious if anyone else has tried this?").
46
-
47
- Summarize where needed but preserve the heart of the experience.
48
-
49
- Output: A suggested title + post body. No tags, no metadata.
50
-
51
-
52
- Content: """ prompt += markdown return prompt
53
-
54
- Generator function
55
-
56
- def generate_post(file, platform, styles, emotions): if file is None: return "Please upload an HTML file."
57
-
58
- content = file.read().decode("utf-8")
59
- prompt = build_prompt(content, platform, styles, emotions)
60
- response = model.generate_content(prompt)
61
- return response.text
62
-
63
- Download helper
64
-
65
- def save_file(text, file_type): ext = ".html" if file_type == "HTML" else ".txt" return (text, f"generated_post{ext}")
66
-
67
- Gradio UI
68
-
69
- def launch_app(): with gr.Blocks(title="Reddit/Quora Post Generator") as demo: gr.Markdown("# Reddit/Quora Post Generator\nGenerate engaging posts based on SEO HTML content.")
70
-
71
- with gr.Row():
72
- file_input = gr.File(label="Upload your HTML file")
73
-
74
- with gr.Row():
75
- platform = gr.CheckboxGroup(["Reddit", "Quora"], label="Choose platform (one only)", value=["Reddit"])
76
- style = gr.CheckboxGroup(["Friendly", "Humanized", "Personal/Storytelling"], label="Choose writing style")
77
- emotions = gr.CheckboxGroup(["Curious", "Enthusiastic", "Skeptical", "Inspiring"], label="Emotional Tone")
78
-
79
- generate_btn = gr.Button("Generate Post")
80
- output_text = gr.Textbox(label="Generated Post", lines=15)
81
-
82
  with gr.Row():
83
- download_format = gr.Radio(["Text", "HTML"], value="Text", label="Download Format")
84
- download_btn = gr.DownloadButton("Download", label="Download Post")
85
-
86
- def generate_and_return(file, platform, style, emotions, file_type):
87
- platform_selected = platform[0] if platform else "Reddit"
88
- result = generate_post(file, platform_selected, style, emotions)
89
- return result, save_file(result, file_type)
90
-
91
- generate_btn.click(generate_and_return,
92
- inputs=[file_input, platform, style, emotions, download_format],
93
- outputs=[output_text, download_btn])
94
-
95
- demo.launch()
96
-
97
- launch_app()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import google.generativeai as genai
4
+ from bs4 import BeautifulSoup
5
+ import datetime
6
+ import re
7
+ import html
8
+
9
+ # Function to extract text from HTML
10
+ def extract_text_from_html(html_content):
11
+ soup = BeautifulSoup(html_content, 'html.parser')
12
+ # Remove script and style elements
13
+ for script in soup(["script", "style"]):
14
+ script.extract()
15
+
16
+ # Get text
17
+ text = soup.get_text(separator='\n')
18
+
19
+ # Remove extra whitespace
20
+ lines = (line.strip() for line in text.splitlines())
21
+ chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
22
+ text = '\n'.join(chunk for chunk in chunks if chunk)
23
+
24
+ return text
25
+
26
+ # Generate post using Gemini API
27
+ def generate_post(api_key, html_content, platform, styles, emotional_tone):
28
+ genai.configure(api_key=api_key)
29
+ model = genai.GenerativeModel('gemini-1.5-pro')
30
+
31
+ # Extract text from HTML
32
+ content_text = extract_text_from_html(html_content)
33
+
34
+ # Create a summary first (this helps control the context length)
35
+ summary_prompt = f"""
36
+ You are an expert content summarizer specializing in fermentation topics.
37
+ Please create a concise summary of the following content, focusing on the main points,
38
+ techniques, and unique aspects of the fermentation process described:
39
+
40
+ {content_text[:8000]} # Limiting to first 8000 chars for summary
41
+ """
42
+
43
+ summary_response = model.generate_content(summary_prompt)
44
+ summary = summary_response.text
45
+
46
+ # Prepare style instructions
47
+ style_instruction = ", ".join(styles)
48
+ if emotional_tone:
49
+ style_instruction += f" with a {emotional_tone} emotional tone"
50
+
51
+ # Platform-specific formatting
52
+ if platform == "Reddit":
53
+ platform_instruction = "Format this as a Reddit post with a catchy title, engaging introduction, clear sections, and end with a question to encourage comments."
54
+ else: # Quora
55
+ platform_instruction = "Format this as a Quora answer that demonstrates expertise, provides personal experience, includes detailed steps, and shows passion for fermentation."
56
+
57
+ # Main generation prompt
58
+ prompt = f"""
59
+ You are an expert content creator specializing in fermentation topics.
60
+
61
+ Create a {platform} post about fermentation based on the following content summary.
62
+ Use a {style_instruction} writing style.
63
+
64
+ Write the post as if you have personally tried or experienced this fermentation technique/recipe.
65
+ Include sensory details (how it looked, tasted, smelled), challenges you faced, and results.
66
+
67
+ The post should feel authentic, like it's written by a real fermentation enthusiast sharing their experience, not like marketing material.
68
+
69
+ Content summary to base the post on:
70
+ {summary}
71
+
72
+ Special instructions:
73
+ 1. {platform_instruction}
74
+ 2. Include a compelling title
75
+ 3. Be specific and detailed about the fermentation process
76
+ 4. Use conversational language that would engage the {platform} community
77
+ 5. End with a question or call for the community to share their experiences
78
+
79
+ Structure the response with:
80
+ TITLE: [Your generated title]
81
+
82
+ [The body of your post]
83
+ """
84
+
85
+ response = model.generate_content(prompt)
86
+ return response.text
87
+
88
+ # Function to extract title and body from generated content
89
+ def extract_title_and_body(generated_text):
90
+ # Find the title
91
+ title_match = re.search(r'TITLE:\s*(.*?)(?:\n\n|\n|$)', generated_text)
92
+ title = title_match.group(1) if title_match else "Generated Post"
93
+
94
+ # Remove the title part to get the body
95
+ body = re.sub(r'TITLE:\s*.*?(?:\n\n|\n|$)', '', generated_text, count=1, flags=re.DOTALL).strip()
96
+
97
+ return title, body
98
+
99
+ # Create formatted HTML for download
100
+ def create_html_output(title, body):
101
+ return f"""<!DOCTYPE html>
102
  <html>
103
+ <head>
104
+ <title>{html.escape(title)}</title>
105
+ <meta charset="UTF-8">
106
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
107
+ <style>
108
+ body {{ font-family: Arial, sans-serif; line-height: 1.6; max-width: 800px; margin: 0 auto; padding: 20px; }}
109
+ h1 {{ color: #333; }}
110
+ .post-body {{ margin-top: 20px; }}
111
+ .post-meta {{ color: #666; font-size: 0.9em; margin-bottom: 20px; }}
112
+ </style>
113
+ </head>
114
  <body>
115
+ <h1>{html.escape(title)}</h1>
116
+ <div class="post-meta">Generated on {datetime.datetime.now().strftime('%Y-%m-%d')} for {html.escape(platform_choice)}</div>
117
+ <div class="post-body">
118
+ {body.replace('\n', '<br>')}
119
+ </div>
 
 
 
 
120
  </body>
121
  </html>
122
+ """
123
+
124
+ # Function to handle file upload and process request
125
+ def process_upload(html_file, api_key, platform_choice, humanized, friendly, storytelling, emotional_tone):
126
+ try:
127
+ # Check if API key is provided
128
+ if not api_key.strip():
129
+ return "Please enter your Gemini API key", None, None, None, None
130
+
131
+ # Read file content
132
+ html_content = html_file.decode('utf-8')
133
+
134
+ # Collect selected styles
135
+ styles = []
136
+ if humanized:
137
+ styles.append("humanized")
138
+ if friendly:
139
+ styles.append("friendly")
140
+ if storytelling:
141
+ styles.append("personal storytelling")
142
+
143
+ # Generate post
144
+ generated_post = generate_post(api_key, html_content, platform_choice, styles, emotional_tone)
145
+
146
+ # Extract title and body
147
+ title, body = extract_title_and_body(generated_post)
148
+
149
+ # Create formatted outputs for download
150
+ html_output = create_html_output(title, body)
151
+ text_output = f"{title}\n\n{body}"
152
+
153
+ return f"## {title}\n\n{body}", title, body, html_output, text_output
154
+
155
+ except Exception as e:
156
+ return f"Error: {str(e)}", None, None, None, None
157
+
158
+ # Define the Gradio interface
159
+ with gr.Blocks(title="Fermentation Content Generator") as app:
160
+ gr.Markdown("# 🧪 Fermentation Content Generator for Reddit & Quora")
161
+ gr.Markdown("Upload your fermentation content HTML file and generate engaging posts optimized for Reddit or Quora.")
162
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  with gr.Row():
164
+ with gr.Column(scale=1):
165
+ # Input section
166
+ gr.Markdown("### 1. Configure Your Post")
167
+
168
+ api_key = gr.Textbox(label="Gemini API Key", placeholder="Enter your API key", type="password")
169
+
170
+ html_file = gr.File(label="Upload HTML Content", file_types=[".html", ".htm"])
171
+
172
+ platform_choice = gr.Radio(
173
+ label="Choose Platform",
174
+ choices=["Reddit", "Quora"],
175
+ value="Reddit"
176
+ )
177
+
178
+ with gr.Accordion("Style Options"):
179
+ gr.Markdown("Select the writing style:")
180
+ with gr.Row():
181
+ humanized = gr.Checkbox(label="Humanized", value=True)
182
+ friendly = gr.Checkbox(label="Friendly", value=True)
183
+ storytelling = gr.Checkbox(label="Personal/Storytelling", value=True)
184
+
185
+ emotional_tone = gr.Dropdown(
186
+ label="Emotional Tone",
187
+ choices=["Curious", "Enthusiastic", "Skeptical", "Inspiring", "Helpful", "None"],
188
+ value="Enthusiastic"
189
+ )
190
+
191
+ generate_btn = gr.Button("Generate Post", variant="primary")
192
+
193
+ with gr.Column(scale=2):
194
+ # Output section
195
+ gr.Markdown("### 2. Generated Post Preview")
196
+
197
+ output = gr.Markdown(label="Generated Post")
198
+
199
+ with gr.Accordion("Post Details", open=False):
200
+ title_output = gr.Textbox(label="Title")
201
+ body_output = gr.Textbox(label="Body", lines=10)
202
+
203
+ with gr.Row():
204
+ html_download = gr.File(label="Download as HTML")
205
+ text_download = gr.File(label="Download as Text")
206
+
207
+ # Process when button is clicked
208
+ generate_btn.click(
209
+ fn=process_upload,
210
+ inputs=[html_file, api_key, platform_choice, humanized, friendly, storytelling, emotional_tone],
211
+ outputs=[output, title_output, body_output, html_download, text_download]
212
+ )
213
+
214
+ # Examples and tips
215
+ with gr.Accordion("Tips & Examples", open=False):
216
+ gr.Markdown("""
217
+ ### Tips for Best Results
218
+
219
+ 1. **Content Quality**: Ensure your HTML file contains comprehensive information about the fermentation process.
220
+ 2. **File Size**: For optimal results, keep your HTML file under 100KB.
221
+ 3. **Style Selection**: Experiment with different style combinations to find what works best for your target audience.
222
+ 4. **Emotional Tones**:
223
+ - **Curious**: Good for experimental fermentation techniques
224
+ - **Enthusiastic**: Works well for successful recipes and projects
225
+ - **Skeptical**: Useful for discussing common myths or challenges
226
+ - **Inspiring**: Great for showcasing transformative projects or health benefits
227
+ - **Helpful**: Best for educational content and guides
228
+
229
+ ### Example Content
230
+
231
+ Your HTML content should ideally include:
232
+ - Detailed fermentation process
233
+ - Ingredients and equipment used
234
+ - Timeline and observations
235
+ - Results and flavor notes
236
+ - Any troubleshooting tips
237
+ """)
238
+
239
+ # Launch the app
240
+ if __name__ == "__main__":
241
+ app.launch(share=True)