Update app.py
Browse files
app.py
CHANGED
|
@@ -467,6 +467,9 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
| 467 |
if __name__ == "__main__":
|
| 468 |
app.launch(share=True)'''
|
| 469 |
|
|
|
|
|
|
|
|
|
|
| 470 |
import gradio as gr
|
| 471 |
import os
|
| 472 |
import time
|
|
@@ -479,15 +482,22 @@ from dotenv import load_dotenv
|
|
| 479 |
from huggingface_hub import HfApi, upload_file
|
| 480 |
import json
|
| 481 |
from functools import partial
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
|
| 483 |
load_dotenv()
|
| 484 |
|
| 485 |
# Configuration
|
| 486 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
|
|
|
|
|
|
| 487 |
HF_USERNAME = "jsakshi"
|
| 488 |
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"}
|
| 489 |
|
| 490 |
-
# Simulated user authentication (
|
| 491 |
AUTHORIZED_USERS = {"admin": "password123"} # username: password
|
| 492 |
|
| 493 |
# Store edit history for undo/redo
|
|
@@ -495,49 +505,79 @@ edit_history = []
|
|
| 495 |
current_history_index = -1
|
| 496 |
|
| 497 |
def generate_initial_content(topic):
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
"
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 506 |
return response.json()[0]['generated_text']
|
| 507 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 508 |
|
| 509 |
def create_or_update_space(content_data, space_name=None, images=[]):
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
if part.
|
| 525 |
-
if
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
|
|
|
|
|
|
|
|
|
| 541 |
<head>
|
| 542 |
<meta charset="UTF-8">
|
| 543 |
<title>Editable Blog</title>
|
|
@@ -548,8 +588,9 @@ def create_or_update_space(content_data, space_name=None, images=[]):
|
|
| 548 |
.image-container {{ position: relative; margin: 20px 0; }}
|
| 549 |
.editable-image {{ width: 100%; max-width: 500px; cursor: move; }}
|
| 550 |
.delete-image {{ position: absolute; top: 5px; right: 5px; }}
|
| 551 |
-
.editing-tools {{ position: fixed; top: 10px; left: 10px; background: white; padding: 10px; border: 1px solid #ccc; }}
|
| 552 |
[contenteditable]:focus {{ outline: 2px solid #2D68C4; }}
|
|
|
|
| 553 |
</style>
|
| 554 |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
| 555 |
</head>
|
|
@@ -569,6 +610,7 @@ def create_or_update_space(content_data, space_name=None, images=[]):
|
|
| 569 |
<button onclick="redo()">Redo</button>
|
| 570 |
</div>
|
| 571 |
{html_content}
|
|
|
|
| 572 |
<script>
|
| 573 |
let currentSpace = "{space_name}";
|
| 574 |
let images = {json.dumps(images)};
|
|
@@ -618,7 +660,7 @@ def create_or_update_space(content_data, space_name=None, images=[]):
|
|
| 618 |
}}
|
| 619 |
}}
|
| 620 |
|
| 621 |
-
// Drag and drop
|
| 622 |
document.querySelectorAll('.image-container').forEach(container => {{
|
| 623 |
container.addEventListener('dragstart', e => {{
|
| 624 |
e.dataTransfer.setData('text/plain', container.dataset.index);
|
|
@@ -658,30 +700,76 @@ def create_or_update_space(content_data, space_name=None, images=[]):
|
|
| 658 |
</script>
|
| 659 |
</body>
|
| 660 |
</html>"""
|
| 661 |
-
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
|
| 667 |
-
|
| 668 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 669 |
|
| 670 |
def authenticate(username, password):
|
| 671 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
|
| 673 |
def generate_and_edit(topic, username, password):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 674 |
if not authenticate(username, password):
|
| 675 |
-
return "Authentication failed", "", ""
|
| 676 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
initial_content = generate_initial_content(topic)
|
| 678 |
-
|
| 679 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
|
| 681 |
-
#
|
| 682 |
-
|
| 683 |
-
|
| 684 |
-
|
|
|
|
|
|
|
| 685 |
|
| 686 |
# Gradio interface
|
| 687 |
with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
@@ -691,7 +779,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
| 691 |
with gr.Row():
|
| 692 |
with gr.Column():
|
| 693 |
username = gr.Textbox(label="Username", placeholder="admin")
|
| 694 |
-
password = gr.Textbox(label="Password", type="password")
|
| 695 |
topic_input = gr.Textbox(label="Blog Topic", placeholder="e.g., Future of AI")
|
| 696 |
generate_btn = gr.Button("Generate & Edit", variant="primary")
|
| 697 |
|
|
@@ -700,9 +788,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
| 700 |
blog_link = gr.Markdown("Blog link will appear here...")
|
| 701 |
blog_preview = gr.Markdown(label="Preview", value="Content preview will appear here...")
|
| 702 |
|
| 703 |
-
# Update function (simulated)
|
| 704 |
-
update_btn = gr.Button("Update Content", visible=False)
|
| 705 |
-
|
| 706 |
generate_btn.click(
|
| 707 |
fn=generate_and_edit,
|
| 708 |
inputs=[topic_input, username, password],
|
|
@@ -710,4 +795,5 @@ with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
| 710 |
)
|
| 711 |
|
| 712 |
if __name__ == "__main__":
|
| 713 |
-
app.launch(share=True)
|
|
|
|
|
|
| 467 |
if __name__ == "__main__":
|
| 468 |
app.launch(share=True)'''
|
| 469 |
|
| 470 |
+
|
| 471 |
+
|
| 472 |
+
|
| 473 |
import gradio as gr
|
| 474 |
import os
|
| 475 |
import time
|
|
|
|
| 482 |
from huggingface_hub import HfApi, upload_file
|
| 483 |
import json
|
| 484 |
from functools import partial
|
| 485 |
+
import logging
|
| 486 |
+
|
| 487 |
+
# Set up logging
|
| 488 |
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
| 489 |
+
logger = logging.getLogger(__name__)
|
| 490 |
|
| 491 |
load_dotenv()
|
| 492 |
|
| 493 |
# Configuration
|
| 494 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 495 |
+
if not HF_TOKEN:
|
| 496 |
+
logger.error("HF_TOKEN not found in .env file")
|
| 497 |
HF_USERNAME = "jsakshi"
|
| 498 |
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"}
|
| 499 |
|
| 500 |
+
# Simulated user authentication (replace with proper auth in production)
|
| 501 |
AUTHORIZED_USERS = {"admin": "password123"} # username: password
|
| 502 |
|
| 503 |
# Store edit history for undo/redo
|
|
|
|
| 505 |
current_history_index = -1
|
| 506 |
|
| 507 |
def generate_initial_content(topic):
|
| 508 |
+
"""Generate initial blog content using Hugging Face API."""
|
| 509 |
+
logger.info(f"Generating content for topic: {topic}")
|
| 510 |
+
try:
|
| 511 |
+
prompt = f"""Create a detailed blog post about {topic} including:
|
| 512 |
+
- A compelling title and subtitle
|
| 513 |
+
- An introduction
|
| 514 |
+
- 3 main sections with descriptive headings
|
| 515 |
+
- A conclusion
|
| 516 |
+
Use an informative tone."""
|
| 517 |
+
response = requests.post(
|
| 518 |
+
"https://api-inference.huggingface.co/models/mistralai/Mistral-7B-Instruct-v0.2",
|
| 519 |
+
headers=HEADERS,
|
| 520 |
+
json={"inputs": prompt, "parameters": {"max_length": 2000}}
|
| 521 |
+
)
|
| 522 |
+
if response.status_code != 200:
|
| 523 |
+
logger.error(f"API request failed: {response.status_code} - {response.text}")
|
| 524 |
+
return f"Error: API request failed with status {response.status_code}"
|
| 525 |
return response.json()[0]['generated_text']
|
| 526 |
+
except Exception as e:
|
| 527 |
+
logger.error(f"Error generating content: {str(e)}")
|
| 528 |
+
return f"Error generating content: {str(e)}"
|
| 529 |
+
|
| 530 |
+
def generate_image(prompt):
|
| 531 |
+
"""Generate an image using Stable Diffusion API."""
|
| 532 |
+
try:
|
| 533 |
+
response = requests.post(
|
| 534 |
+
"https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-xl-base-1.0",
|
| 535 |
+
headers=HEADERS,
|
| 536 |
+
json={"inputs": prompt}
|
| 537 |
+
)
|
| 538 |
+
if response.status_code == 200:
|
| 539 |
+
return response.content
|
| 540 |
+
logger.error(f"Image generation failed: {response.status_code} - {response.text}")
|
| 541 |
+
return None
|
| 542 |
+
except Exception as e:
|
| 543 |
+
logger.error(f"Error generating image: {str(e)}")
|
| 544 |
+
return None
|
| 545 |
|
| 546 |
def create_or_update_space(content_data, space_name=None, images=[]):
|
| 547 |
+
"""Create or update a Hugging Face Space with editable content."""
|
| 548 |
+
try:
|
| 549 |
+
api = HfApi(token=HF_TOKEN)
|
| 550 |
+
if not space_name:
|
| 551 |
+
space_id = f"blog-{uuid.uuid4().hex[:8]}"
|
| 552 |
+
space_name = f"{HF_USERNAME}/{space_id}"
|
| 553 |
+
api.create_repo(repo_id=space_name, repo_type="space", space_sdk="static", private=False)
|
| 554 |
+
logger.info(f"Created new space: {space_name}")
|
| 555 |
+
|
| 556 |
+
# Process content into editable sections
|
| 557 |
+
sections = re.split(r'(## .+)', content_data)
|
| 558 |
+
html_content = '<div class="editable-container">'
|
| 559 |
+
current_section = ""
|
| 560 |
+
for part in sections:
|
| 561 |
+
if part.strip():
|
| 562 |
+
if part.startswith('## '):
|
| 563 |
+
if current_section:
|
| 564 |
+
html_content += f'<div class="section-content" contenteditable="true">{markdown.markdown(current_section)}</div></div>'
|
| 565 |
+
html_content += f'<div class="section"><h2 class="editable-header" contenteditable="true">{part[3:]}</h2>'
|
| 566 |
+
current_section = ""
|
| 567 |
+
else:
|
| 568 |
+
current_section += part
|
| 569 |
+
if current_section:
|
| 570 |
+
html_content += f'<div class="section-content" contenteditable="true">{markdown.markdown(current_section)}</div></div>'
|
| 571 |
+
html_content += '</div>'
|
| 572 |
+
|
| 573 |
+
# Add images
|
| 574 |
+
image_html = ""
|
| 575 |
+
for i, img_path in enumerate(images):
|
| 576 |
+
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>'
|
| 577 |
+
|
| 578 |
+
# Complete HTML with editing features
|
| 579 |
+
complete_html = f"""<!DOCTYPE html>
|
| 580 |
+
<html lang="en">
|
| 581 |
<head>
|
| 582 |
<meta charset="UTF-8">
|
| 583 |
<title>Editable Blog</title>
|
|
|
|
| 588 |
.image-container {{ position: relative; margin: 20px 0; }}
|
| 589 |
.editable-image {{ width: 100%; max-width: 500px; cursor: move; }}
|
| 590 |
.delete-image {{ position: absolute; top: 5px; right: 5px; }}
|
| 591 |
+
.editing-tools {{ position: fixed; top: 10px; left: 10px; background: white; padding: 10px; border: 1px solid #ccc; z-index: 1000; }}
|
| 592 |
[contenteditable]:focus {{ outline: 2px solid #2D68C4; }}
|
| 593 |
+
body {{ font-family: Arial, sans-serif; line-height: 1.6; }}
|
| 594 |
</style>
|
| 595 |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
| 596 |
</head>
|
|
|
|
| 610 |
<button onclick="redo()">Redo</button>
|
| 611 |
</div>
|
| 612 |
{html_content}
|
| 613 |
+
{image_html}
|
| 614 |
<script>
|
| 615 |
let currentSpace = "{space_name}";
|
| 616 |
let images = {json.dumps(images)};
|
|
|
|
| 660 |
}}
|
| 661 |
}}
|
| 662 |
|
| 663 |
+
// Drag and drop images
|
| 664 |
document.querySelectorAll('.image-container').forEach(container => {{
|
| 665 |
container.addEventListener('dragstart', e => {{
|
| 666 |
e.dataTransfer.setData('text/plain', container.dataset.index);
|
|
|
|
| 700 |
</script>
|
| 701 |
</body>
|
| 702 |
</html>"""
|
| 703 |
+
|
| 704 |
+
# Upload HTML
|
| 705 |
+
upload_file(
|
| 706 |
+
path_or_fileobj=complete_html.encode(),
|
| 707 |
+
path_in_repo="index.html",
|
| 708 |
+
repo_id=space_name,
|
| 709 |
+
repo_type="space"
|
| 710 |
+
)
|
| 711 |
+
|
| 712 |
+
# Upload images if provided as bytes
|
| 713 |
+
for i, img in enumerate(images):
|
| 714 |
+
if isinstance(img, bytes):
|
| 715 |
+
upload_file(
|
| 716 |
+
path_or_fileobj=img,
|
| 717 |
+
path_in_repo=f"image_{i}.png",
|
| 718 |
+
repo_id=space_name,
|
| 719 |
+
repo_type="space"
|
| 720 |
+
)
|
| 721 |
+
images[i] = f"image_{i}.png"
|
| 722 |
+
|
| 723 |
+
logger.info(f"Updated space: {space_name}")
|
| 724 |
+
return f"https://huggingface.co/spaces/{space_name}"
|
| 725 |
+
except Exception as e:
|
| 726 |
+
logger.error(f"Error creating/updating space: {str(e)}")
|
| 727 |
+
return None
|
| 728 |
|
| 729 |
def authenticate(username, password):
|
| 730 |
+
"""Authenticate user against hardcoded credentials."""
|
| 731 |
+
if not username or not password:
|
| 732 |
+
logger.warning("Empty username or password provided")
|
| 733 |
+
return False
|
| 734 |
+
is_valid = username in AUTHORIZED_USERS and AUTHORIZED_USERS[username] == password
|
| 735 |
+
logger.info(f"Authentication attempt for {username}: {'Success' if is_valid else 'Failed'}")
|
| 736 |
+
return is_valid
|
| 737 |
|
| 738 |
def generate_and_edit(topic, username, password):
|
| 739 |
+
"""Generate blog and create editable space."""
|
| 740 |
+
logger.info(f"Starting generate_and_edit for topic: {topic}")
|
| 741 |
+
|
| 742 |
+
# Check authentication
|
| 743 |
if not authenticate(username, password):
|
| 744 |
+
return "Authentication failed: Incorrect username or password", "", "Error"
|
| 745 |
|
| 746 |
+
# Check HF_TOKEN
|
| 747 |
+
if not HF_TOKEN:
|
| 748 |
+
return "Authentication failed: HF_TOKEN not set in .env", "", "Error"
|
| 749 |
+
|
| 750 |
+
# Generate content
|
| 751 |
initial_content = generate_initial_content(topic)
|
| 752 |
+
if "Error" in initial_content:
|
| 753 |
+
return "Failed to generate content", initial_content, "Error"
|
| 754 |
+
|
| 755 |
+
# Generate images
|
| 756 |
+
image_prompts = [
|
| 757 |
+
f"Professional illustration about {topic}, clean design, minimalist style.",
|
| 758 |
+
f"Data visualization related to {topic}, infographic style."
|
| 759 |
+
]
|
| 760 |
+
images = []
|
| 761 |
+
for prompt in image_prompts:
|
| 762 |
+
img_data = generate_image(prompt)
|
| 763 |
+
if img_data:
|
| 764 |
+
images.append(img_data)
|
| 765 |
+
time.sleep(2) # Prevent rate limiting
|
| 766 |
|
| 767 |
+
# Create space
|
| 768 |
+
space_url = create_or_update_space(initial_content, images=images)
|
| 769 |
+
if not space_url:
|
| 770 |
+
return "Failed to create space", initial_content, "Error"
|
| 771 |
+
|
| 772 |
+
return space_url, initial_content, "Blog generated successfully"
|
| 773 |
|
| 774 |
# Gradio interface
|
| 775 |
with gr.Blocks(theme=gr.themes.Soft()) as app:
|
|
|
|
| 779 |
with gr.Row():
|
| 780 |
with gr.Column():
|
| 781 |
username = gr.Textbox(label="Username", placeholder="admin")
|
| 782 |
+
password = gr.Textbox(label="Password", type="password", placeholder="password123")
|
| 783 |
topic_input = gr.Textbox(label="Blog Topic", placeholder="e.g., Future of AI")
|
| 784 |
generate_btn = gr.Button("Generate & Edit", variant="primary")
|
| 785 |
|
|
|
|
| 788 |
blog_link = gr.Markdown("Blog link will appear here...")
|
| 789 |
blog_preview = gr.Markdown(label="Preview", value="Content preview will appear here...")
|
| 790 |
|
|
|
|
|
|
|
|
|
|
| 791 |
generate_btn.click(
|
| 792 |
fn=generate_and_edit,
|
| 793 |
inputs=[topic_input, username, password],
|
|
|
|
| 795 |
)
|
| 796 |
|
| 797 |
if __name__ == "__main__":
|
| 798 |
+
app.launch(share=True, debug=True)
|
| 799 |
+
|