|
''' |
|
import gradio as gr |
|
import os |
|
import time |
|
import tempfile |
|
import requests |
|
from PIL import Image |
|
from io import BytesIO |
|
import re |
|
from datetime import datetime |
|
from dotenv import load_dotenv |
|
|
|
# Load environment variables |
|
load_dotenv() |
|
|
|
# Hugging Face configuration |
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
TEXT_API_URL = "https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2" |
|
IMAGE_API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0" |
|
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} |
|
|
|
def generate_blog_content(topic, tone="professional", length="medium"): |
|
try: |
|
current_date = datetime.now().strftime("%B %d, %Y") |
|
reading_time = {"short": "5-8", "medium": "8-12", "long": "15-20"}[length] |
|
|
|
prompt = f"""<s>[INST] Write a {tone} blog post about {topic} with: |
|
- Title and subtitle |
|
- Introduction with statistics |
|
- 2 main sections with subsections |
|
- Conclusion |
|
- Markdown formatting |
|
- Published date: {current_date} |
|
- Reading time: {reading_time} minutes [/INST]</s>""" |
|
|
|
payload = { |
|
"inputs": prompt, |
|
"parameters": { |
|
"max_new_tokens": 1024, |
|
"temperature": 0.7, |
|
"return_full_text": False |
|
} |
|
} |
|
|
|
response = requests.post(TEXT_API_URL, headers=HEADERS, json=payload) |
|
|
|
if response.status_code == 503: |
|
estimate = response.json().get('estimated_time', 30) |
|
time.sleep(estimate) |
|
response = requests.post(TEXT_API_URL, headers=HEADERS, json=payload) |
|
|
|
response.raise_for_status() |
|
return response.json()[0]['generated_text'] |
|
|
|
except Exception as e: |
|
return f"Error generating content: {str(e)}" |
|
|
|
def generate_featured_image(topic): |
|
try: |
|
prompt = f"Professional digital illustration for blog about {topic}, high quality" |
|
payload = { |
|
"inputs": prompt, |
|
"parameters": { |
|
"height": 512, |
|
"width": 768, |
|
"num_inference_steps": 25 |
|
} |
|
} |
|
|
|
response = requests.post(IMAGE_API_URL, headers=HEADERS, json=payload) |
|
response.raise_for_status() |
|
|
|
image = Image.open(BytesIO(response.content)) |
|
temp_img = tempfile.NamedTemporaryFile(delete=False, suffix=".png") |
|
image.save(temp_img.name) |
|
return temp_img.name, None # Return path and no error |
|
|
|
except Exception as e: |
|
return None, f"Image error: {str(e)}" |
|
|
|
def create_download_file(content, title, author): |
|
try: |
|
temp_file = tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md", encoding="utf-8") |
|
full_content = content + f"\n\n**About the Author** \n{author}" |
|
temp_file.write(full_content) |
|
temp_file.close() |
|
|
|
sanitized_title = re.sub(r'[^\w\-_ ]', '_', title)[:50] |
|
return temp_file.name # Return only the file path |
|
|
|
except Exception as e: |
|
return None |
|
|
|
def generate_blog(topic, tone, length, author_name, publish_option, linkedin_user=None, linkedin_pass=None, hf_token=None): |
|
status_updates = [] |
|
blog_content = "" |
|
title = "" |
|
file_path = None |
|
|
|
try: |
|
# Generate content |
|
status_updates.append("π Starting blog generation...") |
|
blog_content = generate_blog_content(topic, tone, length) |
|
|
|
if "Error" in blog_content: |
|
return blog_content, "", "\n".join(status_updates), None |
|
|
|
# Extract title |
|
title_match = re.search(r'^#\s+(.+)$', blog_content, re.MULTILINE) |
|
title = title_match.group(1).strip() if title_match else topic |
|
|
|
# Generate image |
|
status_updates.append("πΌοΈ Generating featured image...") |
|
image_path, image_error = generate_featured_image(topic) |
|
if image_error: |
|
status_updates.append(image_error) |
|
else: |
|
status_updates.append("β
Image generated!") |
|
|
|
# Create downloadable file |
|
status_updates.append("π₯ Preparing download...") |
|
file_path = create_download_file(blog_content, title, author_name) |
|
status_updates.append("β
Download ready!") |
|
|
|
return blog_content, title, "\n".join(status_updates), file_path |
|
|
|
except Exception as e: |
|
status_updates.append(f"β Critical error: {str(e)}") |
|
return blog_content, title, "\n".join(status_updates), None |
|
|
|
# Gradio interface |
|
with gr.Blocks(title="AI Blog Generator", theme=gr.themes.Soft()) as app: |
|
gr.Markdown("# π AI Blog Generator") |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=1): |
|
topic_input = gr.Textbox(label="Blog Topic") |
|
tone_input = gr.Dropdown( |
|
["professional", "casual", "technical", "storytelling"], |
|
label="Writing Style", |
|
value="professional" |
|
) |
|
length_input = gr.Dropdown( |
|
["short", "medium", "long"], |
|
label="Article Length", |
|
value="medium" |
|
) |
|
author_input = gr.Textbox(label="Author Name") |
|
generate_btn = gr.Button("Generate", variant="primary") |
|
|
|
with gr.Column(scale=2): |
|
title_output = gr.Textbox(label="Generated Title") |
|
blog_output = gr.Markdown() |
|
status_output = gr.Textbox(label="Status") |
|
download_output = gr.File(label="Download") |
|
|
|
generate_btn.click( |
|
generate_blog, |
|
inputs=[topic_input, tone_input, length_input, author_input, gr.Radio(["none"], visible=False)], |
|
outputs=[blog_output, title_output, status_output, download_output] |
|
) |
|
|
|
if __name__ == "__main__": |
|
app.launch(share=False)''' |
|
|
|
'''import gradio as gr |
|
import os |
|
import time |
|
import requests |
|
import re |
|
import uuid |
|
import markdown |
|
from datetime import datetime |
|
from dotenv import load_dotenv |
|
from huggingface_hub import HfApi, upload_file |
|
|
|
load_dotenv() |
|
|
|
# Configuration |
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
HF_USERNAME = "jsakshi" |
|
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} |
|
|
|
def generate_blog_content(topic): |
|
try: |
|
prompt = f"""Create a professional blog post about {topic} including: |
|
- Title and subtitle |
|
- 3 sections with subsections |
|
- 2 image placeholders [IMAGE1][IMAGE2] |
|
- Data points and examples |
|
- Conclusion |
|
Use markdown formatting""" |
|
|
|
response = requests.post( |
|
"https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2", |
|
headers=HEADERS, |
|
json={"inputs": prompt, "parameters": {"max_length": 2000}} |
|
) |
|
|
|
if response.status_code != 200: |
|
return None, f"API Error: {response.text}" |
|
|
|
return response.json()[0]['generated_text'], None |
|
|
|
except Exception as e: |
|
return None, f"Error: {str(e)}" |
|
|
|
def create_hosted_blog(topic): |
|
try: |
|
# Generate blog content first |
|
content, error = generate_blog_content(topic) |
|
if error or not content: |
|
return f"Error generating content: {error}", "" |
|
|
|
# Create unique space |
|
space_id = f"blog-{uuid.uuid4().hex[:8]}" |
|
space_name = f"{HF_USERNAME}/{space_id}" |
|
|
|
# Initialize Hub API |
|
api = HfApi(token=HF_TOKEN) |
|
api.create_repo( |
|
repo_id=space_name, |
|
repo_type="space", |
|
space_sdk="static", |
|
private=False |
|
) |
|
|
|
# Generate and upload images |
|
image_paths = [] |
|
for idx in range(2): |
|
response = requests.post( |
|
"https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0", |
|
headers=HEADERS, |
|
json={"inputs": f"Professional illustration about {topic}, clean design"} |
|
) |
|
if response.status_code == 200: |
|
upload_file( |
|
path_or_fileobj=response.content, |
|
path_in_repo=f"image_{idx}.png", |
|
repo_id=space_name, |
|
repo_type="space" |
|
) |
|
image_paths.append(f"image_{idx}.png") |
|
time.sleep(1) |
|
|
|
# Replace image placeholders |
|
if content: |
|
updated_content = content.replace("[IMAGE1]", f'').replace("[IMAGE2]", f'') |
|
else: |
|
return "Error: No content generated", "" |
|
|
|
# Create HTML template |
|
html_content = f""" |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>{topic}</title> |
|
<style> |
|
body {{ |
|
max-width: 800px; |
|
margin: 0 auto; |
|
padding: 40px; |
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
|
line-height: 1.6; |
|
color: #333; |
|
}} |
|
.header {{ |
|
text-align: center; |
|
padding: 40px 0; |
|
border-bottom: 1px solid #eee; |
|
margin-bottom: 40px; |
|
}} |
|
h1 {{ |
|
color: #2c3e50; |
|
font-size: 2.5em; |
|
margin-bottom: 10px; |
|
}} |
|
img {{ |
|
width: 100%; |
|
height: auto; |
|
margin: 25px 0; |
|
border-radius: 8px; |
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
|
}} |
|
.content {{ |
|
background: white; |
|
padding: 30px; |
|
border-radius: 8px; |
|
}} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="header"> |
|
<h1>{topic}</h1> |
|
<p>Published on {datetime.now().strftime("%B %d, %Y")}</p> |
|
</div> |
|
<div class="content"> |
|
{markdown.markdown(updated_content)} |
|
</div> |
|
</body> |
|
</html> |
|
""" |
|
|
|
# Upload HTML file |
|
upload_file( |
|
path_or_fileobj=html_content.encode(), |
|
path_in_repo="index.html", |
|
repo_id=space_name, |
|
repo_type="space" |
|
) |
|
|
|
return f"https://huggingface.co/spaces/{space_name}", content |
|
|
|
except Exception as e: |
|
return f"Error: {str(e)}", "" |
|
|
|
# Gradio interface |
|
with gr.Blocks(theme=gr.themes.Soft()) as app: |
|
gr.Markdown("# π Professional Blog Generator") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
topic_input = gr.Textbox(label="Enter Blog Topic", |
|
placeholder="e.g., Future of AI in Healthcare") |
|
generate_btn = gr.Button("Generate Blog", variant="primary") |
|
|
|
with gr.Column(): |
|
gr.Markdown("### Generated Content") |
|
blog_output = gr.Markdown() |
|
gr.Markdown("### Blog URL") |
|
blog_link = gr.Markdown("Your blog link will appear here...") |
|
status = gr.Textbox(label="Status", interactive=False) |
|
|
|
generate_btn.click( |
|
fn=create_hosted_blog, |
|
inputs=topic_input, |
|
outputs=[blog_link, blog_output] |
|
) |
|
|
|
if __name__ == "__main__": |
|
app.launch(share=True)''' |
|
|
|
|
|
'''import gradio as gr |
|
import os |
|
import time |
|
import requests |
|
import re |
|
import uuid |
|
import markdown |
|
from datetime import datetime |
|
from dotenv import load_dotenv |
|
from huggingface_hub import HfApi, upload_file |
|
|
|
load_dotenv() |
|
|
|
# Configuration |
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
HF_USERNAME = "jsakshi" |
|
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} |
|
|
|
def generate_blog_content(topic): |
|
try: |
|
prompt = f"""Create a detailed, professional blog post about {topic} including: |
|
- A compelling title and subtitle |
|
- An introduction |
|
- 3 main sections with descriptive headings |
|
- Key points and data examples in each section |
|
- A conclusion |
|
Use an informative, professional tone.""" |
|
|
|
response = requests.post( |
|
"https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2", |
|
headers=HEADERS, |
|
json={"inputs": prompt, "parameters": {"max_length": 2000}} |
|
) |
|
|
|
if response.status_code != 200: |
|
return None, f"API Error: {response.text}" |
|
|
|
blog_text = response.json()[0]['generated_text'] |
|
|
|
# Extract title (assuming first line contains the title) |
|
lines = blog_text.split('\n') |
|
title = topic |
|
subtitle = "A comprehensive analysis and exploration" |
|
|
|
for line in lines[:5]: |
|
if line.strip() and not line.startswith('#'): |
|
title = line.strip() |
|
break |
|
|
|
# Look for a possible subtitle |
|
for line in lines[1:10]: |
|
if line.strip() and line != title and not line.startswith('#'): |
|
subtitle = line.strip() |
|
break |
|
|
|
return { |
|
"title": title, |
|
"subtitle": subtitle, |
|
"content": blog_text |
|
}, None |
|
|
|
except Exception as e: |
|
return None, f"Error: {str(e)}" |
|
|
|
def create_hosted_blog(topic): |
|
try: |
|
# Generate blog content first |
|
content_data, error = generate_blog_content(topic) |
|
if error or not content_data: |
|
return f"Error generating content: {error}", "" |
|
|
|
# Create unique space |
|
space_id = f"blog-{uuid.uuid4().hex[:8]}" |
|
space_name = f"{HF_USERNAME}/{space_id}" |
|
|
|
# Initialize Hub API |
|
api = HfApi(token=HF_TOKEN) |
|
api.create_repo( |
|
repo_id=space_name, |
|
repo_type="space", |
|
space_sdk="static", |
|
private=False |
|
) |
|
|
|
# Generate and upload images |
|
image_paths = [] |
|
image_prompts = [ |
|
f"Professional illustration about {topic}, clean design, minimalist style", |
|
f"Data visualization or concept diagram related to {topic}, professional look" |
|
] |
|
|
|
for idx, img_prompt in enumerate(image_prompts): |
|
response = requests.post( |
|
"https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0", |
|
headers=HEADERS, |
|
json={"inputs": img_prompt} |
|
) |
|
if response.status_code == 200: |
|
img_filename = f"image_{idx}.png" |
|
upload_file( |
|
path_or_fileobj=response.content, |
|
path_in_repo=img_filename, |
|
repo_id=space_name, |
|
repo_type="space" |
|
) |
|
image_paths.append(img_filename) |
|
time.sleep(2) # Add delay to prevent rate limiting |
|
|
|
# Format the current date |
|
current_date = datetime.now().strftime("%B %d, %Y") |
|
|
|
# Create HTML using the modern template from the example |
|
title = content_data.get("title", topic) |
|
subtitle = content_data.get("subtitle", "A comprehensive analysis") |
|
content = content_data.get("content", "") |
|
|
|
# Process the content to get sections for TOC |
|
sections = [] |
|
section_pattern = re.compile(r'^##?\s+(.+)$', re.MULTILINE) |
|
section_matches = section_pattern.findall(content) |
|
|
|
for i, section in enumerate(section_matches[:6]): |
|
section_id = section.lower().replace(' ', '-').replace(':', '') |
|
sections.append({ |
|
"title": section, |
|
"id": section_id |
|
}) |
|
|
|
# Convert markdown content to HTML with proper section IDs |
|
html_content = content |
|
for section in sections: |
|
pattern = f"## {section['title']}" |
|
replacement = f"<h2 id=\"{section['id']}\">{section['title']}</h2>" |
|
html_content = html_content.replace(pattern, replacement) |
|
|
|
html_content = markdown.markdown(html_content) |
|
|
|
# Create complete HTML |
|
complete_html = f"""<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>{title}</title> |
|
<style> |
|
:root {{ |
|
--primary-color: #2D68C4; |
|
--secondary-color: #f8f9fa; |
|
--text-color: #333; |
|
--light-gray: #e9ecef; |
|
--dark-gray: #495057; |
|
}} |
|
|
|
* {{ |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
}} |
|
|
|
body {{ |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
line-height: 1.6; |
|
color: var(--text-color); |
|
background-color: #fff; |
|
}} |
|
|
|
header {{ |
|
background: linear-gradient(135deg, var(--primary-color), #1d4ed8); |
|
color: white; |
|
padding: 2rem 0; |
|
text-align: center; |
|
}} |
|
|
|
.container {{ |
|
max-width: 1200px; |
|
margin: 0 auto; |
|
padding: 0 2rem; |
|
}} |
|
|
|
.blog-header {{ |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
}} |
|
|
|
.blog-title {{ |
|
font-size: 2.5rem; |
|
margin-bottom: 1rem; |
|
}} |
|
|
|
.blog-subtitle {{ |
|
font-size: 1.2rem; |
|
opacity: 0.9; |
|
}} |
|
|
|
.blog-meta {{ |
|
display: flex; |
|
margin-top: 1rem; |
|
font-size: 0.9rem; |
|
}} |
|
|
|
.blog-meta div {{ |
|
margin-right: 1.5rem; |
|
display: flex; |
|
align-items: center; |
|
}} |
|
|
|
.blog-content {{ |
|
display: grid; |
|
grid-template-columns: 1fr; |
|
gap: 2rem; |
|
margin: 3rem 0; |
|
}} |
|
|
|
@media (min-width: 768px) {{ |
|
.blog-content {{ |
|
grid-template-columns: 7fr 3fr; |
|
}} |
|
}} |
|
|
|
.main-content {{ |
|
background-color: white; |
|
border-radius: 8px; |
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05); |
|
padding: 2rem; |
|
}} |
|
|
|
.sidebar {{ |
|
position: sticky; |
|
top: 2rem; |
|
height: fit-content; |
|
}} |
|
|
|
.sidebar-section {{ |
|
background-color: white; |
|
border-radius: 8px; |
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05); |
|
padding: 1.5rem; |
|
margin-bottom: 2rem; |
|
}} |
|
|
|
.sidebar-title {{ |
|
font-size: 1.2rem; |
|
margin-bottom: 1rem; |
|
padding-bottom: 0.5rem; |
|
border-bottom: 2px solid var(--light-gray); |
|
}} |
|
|
|
.toc-list {{ |
|
list-style: none; |
|
}} |
|
|
|
.toc-list li {{ |
|
margin-bottom: 0.5rem; |
|
}} |
|
|
|
.toc-list a {{ |
|
color: var(--primary-color); |
|
text-decoration: none; |
|
}} |
|
|
|
.toc-list a:hover {{ |
|
text-decoration: underline; |
|
}} |
|
|
|
h1, h2, h3, h4 {{ |
|
margin: 1.5rem 0 1rem 0; |
|
line-height: 1.3; |
|
}} |
|
|
|
h1 {{ |
|
font-size: 2rem; |
|
}} |
|
|
|
h2 {{ |
|
font-size: 1.75rem; |
|
border-bottom: 2px solid var(--light-gray); |
|
padding-bottom: 0.5rem; |
|
}} |
|
|
|
h3 {{ |
|
font-size: 1.4rem; |
|
}} |
|
|
|
p {{ |
|
margin-bottom: 1.5rem; |
|
}} |
|
|
|
.blog-image {{ |
|
width: 100%; |
|
height: auto; |
|
border-radius: 8px; |
|
margin: 1.5rem 0; |
|
}} |
|
|
|
.highlight-box {{ |
|
background-color: var(--secondary-color); |
|
border-left: 4px solid var(--primary-color); |
|
padding: 1.5rem; |
|
margin: 1.5rem 0; |
|
border-radius: 0 8px 8px 0; |
|
}} |
|
|
|
.highlight-box h4 {{ |
|
margin-top: 0; |
|
color: var(--primary-color); |
|
}} |
|
|
|
footer {{ |
|
background-color: var(--dark-gray); |
|
color: white; |
|
padding: 2rem 0; |
|
margin-top: 3rem; |
|
}} |
|
|
|
.footer-content {{ |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
text-align: center; |
|
}} |
|
|
|
@media (min-width: 768px) {{ |
|
.footer-content {{ |
|
flex-direction: row; |
|
justify-content: space-between; |
|
text-align: left; |
|
}} |
|
}} |
|
|
|
.footer-links {{ |
|
list-style: none; |
|
display: flex; |
|
margin-top: 1rem; |
|
}} |
|
|
|
.footer-links li {{ |
|
margin-right: 1rem; |
|
}} |
|
|
|
.footer-links a {{ |
|
color: white; |
|
text-decoration: none; |
|
}} |
|
|
|
.footer-links a:hover {{ |
|
text-decoration: underline; |
|
}} |
|
</style> |
|
</head> |
|
<body> |
|
<header> |
|
<div class="container"> |
|
<div class="blog-header"> |
|
<h1 class="blog-title">{title}</h1> |
|
<p class="blog-subtitle">{subtitle}</p> |
|
<div class="blog-meta"> |
|
<div>Published: {current_date}</div> |
|
<div>Reading time: 8 minutes</div> |
|
</div> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
<div class="container"> |
|
<div class="blog-content"> |
|
<article class="main-content"> |
|
{f'<img src="{image_paths[0]}" alt="{topic} illustration" class="blog-image" />' if image_paths else ''} |
|
|
|
{html_content} |
|
|
|
{f'<img src="{image_paths[1]}" alt="{topic} visualization" class="blog-image" />' if len(image_paths) > 1 else ''} |
|
|
|
<div class="highlight-box"> |
|
<h4>Key Takeaways</h4> |
|
<p>This article explores the essential aspects of {topic}, providing insights into current trends, challenges, and future opportunities in this field.</p> |
|
</div> |
|
</article> |
|
|
|
<aside class="sidebar"> |
|
<div class="sidebar-section"> |
|
<h3 class="sidebar-title">Table of Contents</h3> |
|
<ul class="toc-list"> |
|
{''.join([f'<li><a href="#{section["id"]}">{section["title"]}</a></li>' for section in sections])} |
|
</ul> |
|
</div> |
|
|
|
<div class="sidebar-section"> |
|
<h3 class="sidebar-title">About the Author</h3> |
|
<p>This article was created by Sakshi Jadhav that combines research, writing, and design capabilities to produce comprehensive, informative content on cutting-edge topics.</p> |
|
</div> |
|
|
|
<div class="sidebar-section"> |
|
<h3 class="sidebar-title">Related Topics</h3> |
|
<ul class="toc-list"> |
|
<li><a href="#">Latest Developments in {topic}</a></li> |
|
<li><a href="#">Industry Perspectives on {topic}</a></li> |
|
<li><a href="#">Research Advancements in {topic}</a></li> |
|
<li><a href="#">Case Studies: {topic} in Action</a></li> |
|
</ul> |
|
</div> |
|
</aside> |
|
</div> |
|
</div> |
|
|
|
<footer> |
|
<div class="container"> |
|
<div class="footer-content"> |
|
<div> |
|
<p>© {datetime.now().year} Professional Blog Hub</p> |
|
<p>Created with AI Blog Generator</p> |
|
</div> |
|
<ul class="footer-links"> |
|
<li><a href="#">Home</a></li> |
|
<li><a href="#">About</a></li> |
|
<li><a href="#">Topics</a></li> |
|
<li><a href="#">Contact</a></li> |
|
</ul> |
|
</div> |
|
</div> |
|
</footer> |
|
</body> |
|
</html> |
|
""" |
|
|
|
# Upload HTML file |
|
upload_file( |
|
path_or_fileobj=complete_html.encode(), |
|
path_in_repo="index.html", |
|
repo_id=space_name, |
|
repo_type="space" |
|
) |
|
|
|
return f"https://huggingface.co/spaces/{space_name}", content_data.get("content", "") |
|
|
|
except Exception as e: |
|
return f"Error: {str(e)}", "" |
|
|
|
# Gradio interface |
|
with gr.Blocks(theme=gr.themes.Soft()) as app: |
|
gr.Markdown("# π Professional Blog Generator") |
|
gr.Markdown("Create well-structured, professional blog posts with just a topic") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
topic_input = gr.Textbox(label="Enter Blog Topic", |
|
placeholder="e.g., Future of AI in Healthcare") |
|
generate_btn = gr.Button("Generate Blog", variant="primary") |
|
status = gr.Textbox(label="Status", interactive=False) |
|
|
|
with gr.Column(): |
|
gr.Markdown("### Blog URL") |
|
blog_link = gr.Markdown("Your blog link will appear here...") |
|
gr.Markdown("### Preview") |
|
blog_output = gr.Markdown() |
|
|
|
generate_btn.click( |
|
fn=create_hosted_blog, |
|
inputs=topic_input, |
|
outputs=[blog_link, blog_output] |
|
) |
|
|
|
if __name__ == "__main__": |
|
app.launch(share=True)''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import gradio as gr |
|
import os |
|
import time |
|
import requests |
|
import re |
|
import uuid |
|
import markdown |
|
from datetime import datetime |
|
from dotenv import load_dotenv |
|
from huggingface_hub import HfApi, upload_file |
|
|
|
load_dotenv() |
|
|
|
|
|
HF_TOKEN = os.getenv("HF_TOKEN") |
|
HF_USERNAME = "jsakshi" |
|
AUTHOR_NAME = "Sarah Johnson" |
|
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} |
|
|
|
def generate_blog_content(topic, seo_keywords): |
|
try: |
|
prompt = f"""Write a high-quality blog post about {topic} that sounds human-written. Include: |
|
- Engaging introduction with a hook |
|
- 3-5 main sections with subheadings |
|
- Bold key terms using **bold** |
|
- SEO keywords: {', '.join(seo_keywords)} |
|
- Conclusion with actionable advice |
|
- Author attribution for {AUTHOR_NAME} |
|
Avoid AI-sounding language. Use conversational tone.""" |
|
|
|
response = requests.post( |
|
"https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2", |
|
headers=HEADERS, |
|
json={"inputs": prompt, "parameters": {"max_length": 2500}} |
|
) |
|
|
|
if response.status_code != 200: |
|
return None, f"API Error: {response.text}" |
|
|
|
blog_text = response.json()[0]['generated_text'] |
|
blog_text += f"\n\n*This article was written by {AUTHOR_NAME}, combining research and practical experience.*" |
|
|
|
return { |
|
"title": extract_title(blog_text), |
|
"content": blog_text, |
|
"bold_terms": re.findall(r'\*\*(.*?)\*\*', blog_text) |
|
}, None |
|
|
|
except Exception as e: |
|
return None, f"Error: {str(e)}" |
|
|
|
def extract_title(text): |
|
lines = text.split('\n') |
|
for line in lines: |
|
if line.strip() and not line.startswith('#'): |
|
return line.strip().replace('#', '') |
|
return "Professional Analysis" |
|
|
|
def create_hosted_blog(topic, seo_keywords): |
|
try: |
|
|
|
content_data, error = generate_blog_content(topic, seo_keywords) |
|
if error: |
|
return f"Error: {error}", "" |
|
|
|
|
|
space_id = f"blog-{uuid.uuid4().hex[:8]}" |
|
space_name = f"{HF_USERNAME}/{space_id}" |
|
api = HfApi(token=HF_TOKEN) |
|
api.create_repo( |
|
repo_id=space_name, |
|
repo_type="space", |
|
space_sdk="static", |
|
private=False |
|
) |
|
|
|
|
|
html_content = f""" |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>{content_data['title']}</title> |
|
<style> |
|
body {{ |
|
font-family: Arial, sans-serif; |
|
line-height: 1.6; |
|
background-color: #f4f4f4; |
|
color: #333; |
|
margin: 0; |
|
padding: 0; |
|
}} |
|
.container {{ |
|
width: 80%; |
|
margin: auto; |
|
overflow: hidden; |
|
background: white; |
|
padding: 20px; |
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
|
border-radius: 10px; |
|
}} |
|
h1, h2, h3 {{ |
|
color: #222; |
|
}} |
|
header {{ |
|
background: linear-gradient(135deg, #ff7e5f, #feb47b); |
|
color: white; |
|
padding: 20px 0; |
|
text-align: center; |
|
border-radius: 10px 10px 0 0; |
|
}} |
|
footer {{ |
|
text-align: center; |
|
padding: 10px; |
|
background: #222; |
|
color: white; |
|
margin-top: 20px; |
|
border-radius: 0 0 10px 10px; |
|
}} |
|
img {{ |
|
width: 100%; |
|
border-radius: 10px; |
|
margin-bottom: 10px; |
|
}} |
|
</style> |
|
</head> |
|
<body> |
|
<header> |
|
<h1>{content_data['title']}</h1> |
|
</header> |
|
<div class="container"> |
|
{markdown.markdown(content_data['content'])} |
|
</div> |
|
<footer> |
|
<p>Β© 2025 {AUTHOR_NAME}. All Rights Reserved.</p> |
|
</footer> |
|
</body> |
|
</html> |
|
""" |
|
|
|
|
|
upload_file( |
|
path_or_fileobj=html_content.encode(), |
|
path_in_repo="index.html", |
|
repo_id=space_name, |
|
repo_type="space" |
|
) |
|
|
|
return f"https://huggingface.co/spaces/{space_name}", content_data['content'] |
|
|
|
except Exception as e: |
|
return f"Error: {str(e)}", "" |
|
|
|
|
|
with gr.Blocks() as app: |
|
gr.Markdown("# Professional Blog Generator") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
topic_input = gr.Textbox(label="Topic") |
|
seo_input = gr.Textbox(label="SEO Keywords (comma-separated)") |
|
generate_btn = gr.Button("Generate", variant="primary") |
|
|
|
with gr.Column(): |
|
blog_link = gr.Markdown() |
|
blog_output = gr.Markdown() |
|
|
|
generate_btn.click( |
|
fn=create_hosted_blog, |
|
inputs=[topic_input, seo_input], |
|
outputs=[blog_link, blog_output] |
|
) |
|
|
|
if __name__ == "__main__": |
|
app.launch(share=True) |
|
|