| '''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}, integrating real-world images with clean design and minimalist style. " |
| f"Include conceptual diagrams, flowcharts, or graphs alongside real-world elements to enhance understanding. " |
| f"Use subtle colors, modern typography, and a well-structured layout for clarity and engagement.", |
| |
| f"Data visualization or concept diagram related to {topic}, combining infographic elements with real-world scenarios. " |
| f"Ensure a balance of artistic design and informative content, making it suitable for presentations or reports. " |
| f"Include 3D renders or photorealistic overlays to improve visualization." |
| ] |
| |
| 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> |
| <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 |
| import json |
| from functools import partial |
| import logging |
|
|
| |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
| logger = logging.getLogger(__name__) |
|
|
| load_dotenv() |
|
|
| |
| HF_TOKEN = os.getenv("HF_TOKEN") |
| if not HF_TOKEN: |
| logger.error("HF_TOKEN not found in .env file") |
| HF_USERNAME = "jsakshi" |
| HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"} |
|
|
| |
| AUTHORIZED_USERS = {"admin": "password123"} |
|
|
| |
| edit_history = [] |
| current_history_index = -1 |
|
|
| def generate_initial_content(topic): |
| """Generate initial blog content using Hugging Face API.""" |
| logger.info(f"Generating content for topic: {topic}") |
| try: |
| prompt = f"""Create a detailed blog post about {topic} including: |
| - A compelling title and subtitle |
| - An introduction |
| - 3 main sections with descriptive headings |
| - A conclusion |
| Use an informative 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: |
| logger.error(f"API request failed: {response.status_code} - {response.text}") |
| return f"Error: API request failed with status {response.status_code}" |
| return response.json()[0]['generated_text'] |
| except Exception as e: |
| logger.error(f"Error generating content: {str(e)}") |
| return f"Error generating content: {str(e)}" |
|
|
| def generate_image(prompt): |
| """Generate an image using Stable Diffusion API.""" |
| try: |
| response = requests.post( |
| "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0", |
| headers=HEADERS, |
| json={"inputs": prompt} |
| ) |
| if response.status_code == 200: |
| return response.content |
| logger.error(f"Image generation failed: {response.status_code} - {response.text}") |
| return None |
| except Exception as e: |
| logger.error(f"Error generating image: {str(e)}") |
| return None |
|
|
| def create_or_update_space(content_data, space_name=None, images=[]): |
| """Create or update a Hugging Face Space with editable content.""" |
| try: |
| api = HfApi(token=HF_TOKEN) |
| if not space_name: |
| space_id = f"blog-{uuid.uuid4().hex[:8]}" |
| space_name = f"{HF_USERNAME}/{space_id}" |
| api.create_repo(repo_id=space_name, repo_type="space", space_sdk="static", private=False) |
| logger.info(f"Created new space: {space_name}") |
|
|
| |
| sections = re.split(r'(## .+)', content_data) |
| html_content = '<div class="editable-container">' |
| current_section = "" |
| for part in sections: |
| if part.strip(): |
| if part.startswith('## '): |
| if current_section: |
| html_content += f'<div class="section-content" contenteditable="true">{markdown.markdown(current_section)}</div></div>' |
| html_content += f'<div class="section"><h2 class="editable-header" contenteditable="true">{part[3:]}</h2>' |
| current_section = "" |
| else: |
| current_section += part |
| if current_section: |
| html_content += f'<div class="section-content" contenteditable="true">{markdown.markdown(current_section)}</div></div>' |
| html_content += '</div>' |
|
|
| |
| image_html = "" |
| for i, img_path in enumerate(images): |
| image_html += f'<div class="image-container" draggable="true" data-index="{i}"><img src="{img_path}" class="editable-image" alt="Blog image" /><button class="delete-image">Delete</button></div>' |
|
|
| |
| complete_html = f"""<!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>Editable Blog</title> |
| <style> |
| .editable-container {{ max-width: 800px; margin: 20px auto; padding: 20px; }} |
| .editable-header {{ font-size: 1.5em; margin: 20px 0 10px; cursor: text; }} |
| .section-content {{ margin-bottom: 20px; cursor: text; }} |
| .image-container {{ position: relative; margin: 20px 0; }} |
| .editable-image {{ width: 100%; max-width: 500px; cursor: move; }} |
| .delete-image {{ position: absolute; top: 5px; right: 5px; }} |
| .editing-tools {{ position: fixed; top: 10px; left: 10px; background: white; padding: 10px; border: 1px solid #ccc; z-index: 1000; }} |
| [contenteditable]:focus {{ outline: 2px solid #2D68C4; }} |
| body {{ font-family: Arial, sans-serif; line-height: 1.6; }} |
| </style> |
| <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> |
| </head> |
| <body> |
| <div class="editing-tools" id="tools" style="display: none;"> |
| <button onclick="document.execCommand('bold')">B</button> |
| <button onclick="document.execCommand('italic')">I</button> |
| <select onchange="document.execCommand('formatBlock', false, this.value)"> |
| <option value="">Normal</option> |
| <option value="h1">H1</option> |
| <option value="h2">H2</option> |
| <option value="h3">H3</option> |
| </select> |
| <button onclick="saveChanges()">Save</button> |
| <button onclick="preview()">Preview</button> |
| <button onclick="undo()">Undo</button> |
| <button onclick="redo()">Redo</button> |
| </div> |
| {html_content} |
| {image_html} |
| <script> |
| let currentSpace = "{space_name}"; |
| let images = {json.dumps(images)}; |
| |
| function saveChanges() {{ |
| const content = document.querySelector('.editable-container').innerHTML; |
| fetch('/update', {{ |
| method: 'POST', |
| headers: {{ 'Content-Type': 'application/json' }}, |
| body: JSON.stringify({{ space: currentSpace, content: content, images: images }}) |
| }}).then(() => alert('Saved!')); |
| addToHistory(content); |
| }} |
| |
| function preview() {{ |
| const content = document.querySelector('.editable-container').innerHTML; |
| const previewWindow = window.open('', '_blank'); |
| previewWindow.document.write('<html><body>' + marked.parse(content) + '</body></html>'); |
| }} |
| |
| function addToHistory(content) {{ |
| if (window.historyIndex < window.history.length - 1) {{ |
| window.history.splice(window.historyIndex + 1); |
| }} |
| window.history.push(content); |
| window.historyIndex = window.history.length - 1; |
| localStorage.setItem('editHistory', JSON.stringify(window.history)); |
| localStorage.setItem('historyIndex', window.historyIndex); |
| }} |
| |
| window.history = JSON.parse(localStorage.getItem('editHistory') || '[]'); |
| window.historyIndex = parseInt(localStorage.getItem('historyIndex') || '-1'); |
| |
| function undo() {{ |
| if (window.historyIndex > 0) {{ |
| window.historyIndex--; |
| document.querySelector('.editable-container').innerHTML = window.history[window.historyIndex]; |
| localStorage.setItem('historyIndex', window.historyIndex); |
| }} |
| }} |
| |
| function redo() {{ |
| if (window.historyIndex < window.history.length - 1) {{ |
| window.historyIndex++; |
| document.querySelector('.editable-container').innerHTML = window.history[window.historyIndex]; |
| localStorage.setItem('historyIndex', window.historyIndex); |
| }} |
| }} |
| |
| // Drag and drop images |
| document.querySelectorAll('.image-container').forEach(container => {{ |
| container.addEventListener('dragstart', e => {{ |
| e.dataTransfer.setData('text/plain', container.dataset.index); |
| }}); |
| container.addEventListener('dragover', e => e.preventDefault()); |
| container.addEventListener('drop', e => {{ |
| e.preventDefault(); |
| const fromIndex = e.dataTransfer.getData('text/plain'); |
| const toIndex = container.dataset.index; |
| if (fromIndex !== toIndex) {{ |
| const temp = images[fromIndex]; |
| images[fromIndex] = images[toIndex]; |
| images[toIndex] = temp; |
| saveChanges(); |
| location.reload(); |
| }} |
| }}); |
| }}); |
| |
| // Delete image |
| document.querySelectorAll('.delete-image').forEach(btn => {{ |
| btn.addEventListener('click', () => {{ |
| const index = btn.parentElement.dataset.index; |
| images.splice(index, 1); |
| saveChanges(); |
| location.reload(); |
| }}); |
| }}); |
| |
| // Autosave every 30 seconds |
| setInterval(saveChanges, 30000); |
| |
| // Show tools on edit |
| document.querySelectorAll('[contenteditable]').forEach(el => {{ |
| el.addEventListener('focus', () => document.getElementById('tools').style.display = 'block'); |
| }}); |
| </script> |
| </body> |
| </html>""" |
|
|
| |
| upload_file( |
| path_or_fileobj=complete_html.encode(), |
| path_in_repo="index.html", |
| repo_id=space_name, |
| repo_type="space" |
| ) |
|
|
| |
| for i, img in enumerate(images): |
| if isinstance(img, bytes): |
| upload_file( |
| path_or_fileobj=img, |
| path_in_repo=f"image_{i}.png", |
| repo_id=space_name, |
| repo_type="space" |
| ) |
| images[i] = f"image_{i}.png" |
|
|
| logger.info(f"Updated space: {space_name}") |
| return f"https://huggingface.co/spaces/{space_name}" |
| except Exception as e: |
| logger.error(f"Error creating/updating space: {str(e)}") |
| return None |
|
|
| def authenticate(username, password): |
| """Authenticate user against hardcoded credentials.""" |
| if not username or not password: |
| logger.warning("Empty username or password provided") |
| return False |
| is_valid = username in AUTHORIZED_USERS and AUTHORIZED_USERS[username] == password |
| logger.info(f"Authentication attempt for {username}: {'Success' if is_valid else 'Failed'}") |
| return is_valid |
|
|
| def generate_and_edit(topic, username, password): |
| """Generate blog and create editable space.""" |
| logger.info(f"Starting generate_and_edit for topic: {topic}") |
| |
| |
| if not authenticate(username, password): |
| return "Authentication failed: Incorrect username or password", "", "Error" |
| |
| |
| if not HF_TOKEN: |
| return "Authentication failed: HF_TOKEN not set in .env", "", "Error" |
|
|
| |
| initial_content = generate_initial_content(topic) |
| if "Error" in initial_content: |
| return "Failed to generate content", initial_content, "Error" |
|
|
| |
| image_prompts = [ |
| f"Professional illustration about {topic}, clean design, minimalist style.", |
| f"Data visualization related to {topic}, infographic style." |
| ] |
| images = [] |
| for prompt in image_prompts: |
| img_data = generate_image(prompt) |
| if img_data: |
| images.append(img_data) |
| time.sleep(2) |
|
|
| |
| space_url = create_or_update_space(initial_content, images=images) |
| if not space_url: |
| return "Failed to create space", initial_content, "Error" |
|
|
| return space_url, initial_content, "Blog generated successfully" |
|
|
| |
| with gr.Blocks(theme=gr.themes.Soft()) as app: |
| gr.Markdown("# 📝 Blog Editor") |
| gr.Markdown("Generate and edit professional blog posts with an intuitive interface") |
| |
| with gr.Row(): |
| with gr.Column(): |
| username = gr.Textbox(label="Username", placeholder="admin") |
| password = gr.Textbox(label="Password", type="password", placeholder="password123") |
| topic_input = gr.Textbox(label="Blog Topic", placeholder="e.g., Future of AI") |
| generate_btn = gr.Button("Generate & Edit", variant="primary") |
| |
| with gr.Column(): |
| status = gr.Textbox(label="Status", interactive=False) |
| blog_link = gr.Markdown("Blog link will appear here...") |
| blog_preview = gr.Markdown(label="Preview", value="Content preview will appear here...") |
| |
| generate_btn.click( |
| fn=generate_and_edit, |
| inputs=[topic_input, username, password], |
| outputs=[blog_link, blog_preview, status] |
| ) |
|
|
| if __name__ == "__main__": |
| app.launch(share=True, debug=True) |
| |
|
|