Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -2,106 +2,105 @@ import gradio as gr
|
|
2 |
import requests
|
3 |
from bs4 import BeautifulSoup
|
4 |
import google.generativeai as genai
|
5 |
-
import os
|
6 |
-
import time
|
7 |
-
|
8 |
-
# Configure Gemini API
|
9 |
-
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
10 |
-
if not GEMINI_API_KEY:
|
11 |
-
raise ValueError("GEMINI_API_KEY not found in environment variables")
|
12 |
-
|
13 |
-
genai.configure(api_key=GEMINI_API_KEY)
|
14 |
|
15 |
def fetch_article_content(url):
|
16 |
-
"""Fetch article content with
|
17 |
try:
|
18 |
headers = {'User-Agent': 'Mozilla/5.0'}
|
19 |
-
response = requests.get(url, headers=headers, timeout=8)
|
20 |
response.raise_for_status()
|
21 |
soup = BeautifulSoup(response.text, 'html.parser')
|
22 |
|
23 |
-
# Extract
|
24 |
-
paragraphs = soup.find_all('p')[:
|
25 |
content = ' '.join([p.get_text(strip=True) for p in paragraphs])
|
26 |
-
return content[:2000] #
|
27 |
except Exception as e:
|
28 |
-
return f"
|
29 |
|
30 |
-
def generate_platform_post(article_text):
|
31 |
-
"""Generate
|
32 |
try:
|
|
|
|
|
33 |
model = genai.GenerativeModel('gemini-1.5-pro')
|
34 |
|
35 |
prompt = f"""
|
36 |
-
|
37 |
|
38 |
-
Article content:
|
39 |
{article_text}
|
40 |
|
41 |
Output format:
|
42 |
Title: [short title]
|
43 |
-
Post: [clean HTML with
|
44 |
|
45 |
Requirements:
|
46 |
-
-
|
47 |
-
- Include
|
48 |
-
-
|
49 |
- Mobile-friendly
|
50 |
-
- No markdown
|
51 |
"""
|
52 |
|
53 |
-
|
54 |
-
start_time = time.time()
|
55 |
-
response = model.generate_content(prompt)
|
56 |
-
print(f"AI Response received in {time.time()-start_time:.2f} seconds")
|
57 |
-
|
58 |
return parse_gemini_response(response.text)
|
59 |
except Exception as e:
|
60 |
-
return {"title": "
|
61 |
|
62 |
def parse_gemini_response(response):
|
63 |
-
"""Robust parsing
|
64 |
try:
|
65 |
title = response.split("Title:")[1].split("Post:")[0].strip()[:100]
|
66 |
content = response.split("Post:")[1].strip()
|
67 |
except:
|
68 |
-
title = "
|
69 |
content = "<p>Failed to parse AI response</p>"
|
70 |
|
71 |
return {"title": title, "content": content}
|
72 |
|
73 |
-
def process_url(url):
|
74 |
"""Main processing pipeline with status updates"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
yield {"title": "Fetching Article...", "content": "<p>Connecting to URL...</p>"}
|
76 |
|
77 |
article_text = fetch_article_content(url)
|
78 |
-
if article_text.startswith("
|
79 |
-
yield {"title": "Fetch
|
80 |
return
|
81 |
|
82 |
-
yield {"title": "Generating Post...", "content": "<p>Creating content with
|
83 |
|
84 |
-
result = generate_platform_post(article_text)
|
85 |
yield result
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
88 |
title_output = gr.Textbox(label="Generated Title")
|
89 |
content_output = gr.HTML(label="Formatted Post")
|
90 |
|
91 |
app = gr.Interface(
|
92 |
fn=process_url,
|
93 |
-
inputs=url_input,
|
94 |
outputs=[
|
95 |
gr.Textbox(label="Generated Title"),
|
96 |
gr.HTML(label="Formatted Post")
|
97 |
],
|
98 |
examples=[
|
99 |
-
["https://example.com/sample-article"]
|
100 |
],
|
101 |
title="Article to Reddit/Quora Post Converter",
|
102 |
description="Convert news articles into optimized posts with AI-generated formatting and image descriptions",
|
103 |
allow_flagging="never",
|
104 |
-
live=False
|
|
|
105 |
)
|
106 |
|
107 |
if __name__ == "__main__":
|
|
|
2 |
import requests
|
3 |
from bs4 import BeautifulSoup
|
4 |
import google.generativeai as genai
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
6 |
def fetch_article_content(url):
|
7 |
+
"""Fetch article content with basic error handling"""
|
8 |
try:
|
9 |
headers = {'User-Agent': 'Mozilla/5.0'}
|
10 |
+
response = requests.get(url, headers=headers, timeout=8)
|
11 |
response.raise_for_status()
|
12 |
soup = BeautifulSoup(response.text, 'html.parser')
|
13 |
|
14 |
+
# Extract first 8 paragraphs
|
15 |
+
paragraphs = soup.find_all('p')[:8]
|
16 |
content = ' '.join([p.get_text(strip=True) for p in paragraphs])
|
17 |
+
return content[:2000] # Keep it concise
|
18 |
except Exception as e:
|
19 |
+
return f"FETCH_ERROR: {str(e)}"
|
20 |
|
21 |
+
def generate_platform_post(article_text, api_key):
|
22 |
+
"""Generate post using user-provided API key"""
|
23 |
try:
|
24 |
+
# Configure Gemini with user's API key
|
25 |
+
genai.configure(api_key=api_key)
|
26 |
model = genai.GenerativeModel('gemini-1.5-pro')
|
27 |
|
28 |
prompt = f"""
|
29 |
+
Create a Reddit/Quora-style post from this article:
|
30 |
|
|
|
31 |
{article_text}
|
32 |
|
33 |
Output format:
|
34 |
Title: [short title]
|
35 |
+
Post: [clean HTML with 1 image tag + alt text]
|
36 |
|
37 |
Requirements:
|
38 |
+
- Title < 100 characters
|
39 |
+
- Include <img> with descriptive alt text
|
40 |
+
- Minimal styling
|
41 |
- Mobile-friendly
|
|
|
42 |
"""
|
43 |
|
44 |
+
response = model.generate_content(prompt, timeout=15)
|
|
|
|
|
|
|
|
|
45 |
return parse_gemini_response(response.text)
|
46 |
except Exception as e:
|
47 |
+
return {"title": "AI ERROR", "content": f"<p>API Error: {str(e)}</p>"}
|
48 |
|
49 |
def parse_gemini_response(response):
|
50 |
+
"""Robust response parsing"""
|
51 |
try:
|
52 |
title = response.split("Title:")[1].split("Post:")[0].strip()[:100]
|
53 |
content = response.split("Post:")[1].strip()
|
54 |
except:
|
55 |
+
title = "Formatting Error"
|
56 |
content = "<p>Failed to parse AI response</p>"
|
57 |
|
58 |
return {"title": title, "content": content}
|
59 |
|
60 |
+
def process_url(url, api_key):
|
61 |
"""Main processing pipeline with status updates"""
|
62 |
+
if not api_key or len(api_key.strip()) < 30:
|
63 |
+
yield {"title": "API Key Required", "content": "<p>Please enter your Gemini API key above</p>"}
|
64 |
+
return
|
65 |
+
|
66 |
+
if not url.startswith("http"):
|
67 |
+
yield {"title": "Invalid URL", "content": "<p>Please enter a valid article URL</p>"}
|
68 |
+
return
|
69 |
+
|
70 |
yield {"title": "Fetching Article...", "content": "<p>Connecting to URL...</p>"}
|
71 |
|
72 |
article_text = fetch_article_content(url)
|
73 |
+
if article_text.startswith("FETCH_ERROR:"):
|
74 |
+
yield {"title": "Fetch Failed", "content": f"<p>{article_text.replace('FETCH_ERROR: ', '')}</p>"}
|
75 |
return
|
76 |
|
77 |
+
yield {"title": "Generating Post...", "content": "<p>Creating content with Gemini...</p>"}
|
78 |
|
79 |
+
result = generate_platform_post(article_text, api_key)
|
80 |
yield result
|
81 |
+
|
82 |
+
# Create Gradio interface
|
83 |
+
url_input = gr.Textbox(label="Article URL", placeholder="https://example.com/article...")
|
84 |
+
api_key_input = gr.Textbox(label="Gemini API Key", placeholder="AIzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", type="password")
|
85 |
+
|
86 |
title_output = gr.Textbox(label="Generated Title")
|
87 |
content_output = gr.HTML(label="Formatted Post")
|
88 |
|
89 |
app = gr.Interface(
|
90 |
fn=process_url,
|
91 |
+
inputs=[url_input, api_key_input],
|
92 |
outputs=[
|
93 |
gr.Textbox(label="Generated Title"),
|
94 |
gr.HTML(label="Formatted Post")
|
95 |
],
|
96 |
examples=[
|
97 |
+
["https://example.com/sample-article", "AIzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"]
|
98 |
],
|
99 |
title="Article to Reddit/Quora Post Converter",
|
100 |
description="Convert news articles into optimized posts with AI-generated formatting and image descriptions",
|
101 |
allow_flagging="never",
|
102 |
+
live=False,
|
103 |
+
theme="default"
|
104 |
)
|
105 |
|
106 |
if __name__ == "__main__":
|