""" Wix Blog Publisher for Alwrity This module integrates the Wix API with the Alwrity AI Writer platform, allowing users to publish generated blog content directly to their Wix site. """ import os import logging import tempfile import streamlit as st from typing import Dict, List, Optional, Union, Any, Tuple from pathlib import Path from .wix_integration import WixIntegration # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger('wix_blog_publisher') def publish_to_wix( title: str, content: str, is_markdown: bool = True, featured_image_path: Optional[str] = None, featured_image_url: Optional[str] = None, excerpt: Optional[str] = None, tags: Optional[List[str]] = None, categories: Optional[List[str]] = None, seo_title: Optional[str] = None, seo_description: Optional[str] = None, seo_keywords: Optional[List[str]] = None, author_name: Optional[str] = None, publisher_name: Optional[str] = None, publisher_logo_url: Optional[str] = None, publish: bool = True, update_if_exists: bool = True, api_key: Optional[str] = None, refresh_token: Optional[str] = None, site_id: Optional[str] = None ) -> Dict: """ Publish a blog post to Wix. Args: title: Post title content: Post content (markdown or HTML) is_markdown: Whether the content is in markdown format featured_image_path: Local path to featured image (optional) featured_image_url: URL of featured image to download (optional) excerpt: Post excerpt/summary (optional) tags: List of tags (optional) categories: List of category names (optional) seo_title: SEO title (optional) seo_description: SEO description (optional) seo_keywords: SEO keywords (optional) author_name: Name of the author (optional) publisher_name: Name of the publisher (optional) publisher_logo_url: URL of the publisher's logo (optional) publish: Whether to publish the post immediately (optional) update_if_exists: Whether to update an existing post with the same title (optional) api_key: Wix API key (optional if using refresh token) refresh_token: Wix refresh token for OAuth authentication site_id: Wix site ID Returns: Published blog post data """ # Initialize Wix integration wix = WixIntegration(api_key, refresh_token, site_id) # Publish the blog post return wix.publish_blog_post( title=title, content=content, is_markdown=is_markdown, featured_image_path=featured_image_path, featured_image_url=featured_image_url, excerpt=excerpt, tags=tags, categories=categories, seo_title=seo_title, seo_description=seo_description, seo_keywords=seo_keywords, author_name=author_name, publisher_name=publisher_name, publisher_logo_url=publisher_logo_url, publish=publish, update_if_exists=update_if_exists ) def wix_blog_publisher_ui(): """ Streamlit UI for publishing blog posts to Wix. """ st.title("Publish to Wix") st.write("Publish your blog content directly to your Wix site.") # Authentication settings st.header("Wix Authentication") # Check for saved credentials if "wix_refresh_token" in st.session_state and "wix_site_id" in st.session_state: st.success("✅ Wix credentials are saved in this session.") show_saved = st.checkbox("Show saved credentials") if show_saved: st.text_input("Refresh Token", value=st.session_state.wix_refresh_token, type="password", disabled=True) st.text_input("Site ID", value=st.session_state.wix_site_id, disabled=True) clear_creds = st.button("Clear saved credentials") if clear_creds: if "wix_refresh_token" in st.session_state: del st.session_state.wix_refresh_token if "wix_site_id" in st.session_state: del st.session_state.wix_site_id st.rerun() else: col1, col2 = st.columns(2) with col1: refresh_token = st.text_input("Wix Refresh Token", type="password", help="Your Wix refresh token for API authentication") with col2: site_id = st.text_input("Wix Site ID", help="Your Wix site ID") save_creds = st.checkbox("Save credentials for this session", value=True) if st.button("Validate Credentials"): if not refresh_token: st.error("Refresh token is required.") return if not site_id: st.error("Site ID is required.") return # Try to initialize Wix integration to validate credentials try: wix = WixIntegration(refresh_token=refresh_token, site_id=site_id) # Test API call site_info = wix.get_site_info() if site_info.get("status") == "connected": st.success(f"✅ Credentials validated successfully! Found {site_info.get('post_count', 0)} posts and {site_info.get('category_count', 0)} categories.") # Save credentials if requested if save_creds: st.session_state.wix_refresh_token = refresh_token st.session_state.wix_site_id = site_id st.rerun() else: st.error(f"❌ Failed to validate credentials: {site_info.get('error', 'Unknown error')}") except Exception as e: st.error(f"❌ Failed to validate credentials: {str(e)}") return # Blog content section st.header("Blog Content") # Check if we have content in session state (from other parts of the app) blog_title = st.text_input( "Blog Title", value=st.session_state.get("blog_title", ""), help="The title of your blog post" ) content_type = st.radio( "Content Format", ["Markdown", "HTML"], horizontal=True, help="The format of your blog content" ) is_markdown = content_type == "Markdown" blog_content = st.text_area( "Blog Content", value=st.session_state.get("blog_content", ""), height=300, help="The content of your blog post" ) # Featured image st.subheader("Featured Image") image_source = st.radio( "Image Source", ["None", "Upload", "URL"], horizontal=True, help="How to provide the featured image" ) featured_image_path = None featured_image_url = None if image_source == "Upload": uploaded_file = st.file_uploader("Upload Featured Image", type=["jpg", "jpeg", "png", "gif"]) if uploaded_file: # Save the uploaded file to a temporary location with tempfile.NamedTemporaryFile(delete=False, suffix=f".{uploaded_file.name.split('.')[-1]}") as tmp: tmp.write(uploaded_file.getvalue()) featured_image_path = tmp.name elif image_source == "URL": featured_image_url = st.text_input("Featured Image URL", help="URL of the featured image") # Blog metadata st.header("Blog Metadata") col1, col2 = st.columns(2) with col1: excerpt = st.text_area( "Excerpt", value=st.session_state.get("blog_excerpt", ""), help="A short summary of your blog post" ) tags_input = st.text_input( "Tags (comma-separated)", value=", ".join(st.session_state.get("blog_tags", [])) if isinstance(st.session_state.get("blog_tags", []), list) else st.session_state.get("blog_tags", ""), help="Tags for your blog post, separated by commas" ) tags = [tag.strip() for tag in tags_input.split(",")] if tags_input else None categories_input = st.text_input( "Categories (comma-separated)", value=", ".join(st.session_state.get("blog_categories", [])) if isinstance(st.session_state.get("blog_categories", []), list) else st.session_state.get("blog_categories", ""), help="Categories for your blog post, separated by commas" ) categories = [cat.strip() for cat in categories_input.split(",")] if categories_input else None with col2: author_name = st.text_input("Author Name", help="Name of the blog post author") publisher_name = st.text_input("Publisher Name", help="Name of the blog publisher (usually your site name)") publisher_logo_url = st.text_input("Publisher Logo URL", help="URL of the publisher's logo") # SEO settings with st.expander("SEO Settings"): seo_title = st.text_input("SEO Title", value=blog_title, help="Title for search engines (defaults to blog title)") seo_description = st.text_area("SEO Description", value=excerpt, help="Description for search engines (defaults to excerpt)") seo_keywords_input = st.text_input("SEO Keywords (comma-separated)", value=tags_input, help="Keywords for search engines (defaults to tags)") seo_keywords = [kw.strip() for kw in seo_keywords_input.split(",")] if seo_keywords_input else None # Publishing options st.header("Publishing Options") col1, col2 = st.columns(2) with col1: publish = not st.checkbox("Save as draft", help="If checked, the post will be saved as a draft instead of being published") with col2: update_if_exists = st.checkbox("Update if exists", value=True, help="If checked, an existing post with the same title will be updated") # Publish button if st.button("Publish to Wix", type="primary"): if not blog_title: st.error("Blog title is required.") return if not blog_content: st.error("Blog content is required.") return # Get credentials refresh_token = st.session_state.get("wix_refresh_token") site_id = st.session_state.get("wix_site_id") if not refresh_token or not site_id: st.error("Wix credentials are required. Please enter them in the authentication section.") return # Show progress with st.spinner("Publishing to Wix..."): try: # Publish to Wix result = publish_to_wix( title=blog_title, content=blog_content, is_markdown=is_markdown, featured_image_path=featured_image_path, featured_image_url=featured_image_url, excerpt=excerpt, tags=tags, categories=categories, seo_title=seo_title, seo_description=seo_description, seo_keywords=seo_keywords, author_name=author_name, publisher_name=publisher_name, publisher_logo_url=publisher_logo_url, publish=publish, update_if_exists=update_if_exists, refresh_token=refresh_token, site_id=site_id ) # Clean up temporary file if created if featured_image_path and os.path.exists(featured_image_path) and featured_image_path.startswith(tempfile.gettempdir()): try: os.remove(featured_image_path) except: pass # Show success message st.success("✅ Blog post published successfully!") # Show post details post = result.get("post", {}) st.subheader("Published Post Details") col1, col2 = st.columns(2) with col1: st.write(f"**Title:** {post.get('title', 'N/A')}") st.write(f"**Status:** {post.get('status', 'N/A')}") st.write(f"**ID:** {post.get('id', 'N/A')}") with col2: st.write(f"**Published Date:** {post.get('publishedDate', 'N/A')}") st.write(f"**URL:** {post.get('url', 'N/A')}") st.write(f"**Tags:** {', '.join(post.get('tags', []))}") # Add a view button if URL is available if post.get("url"): st.markdown(f"[View Post]({post.get('url')})") # Add SEO report button if st.button("Generate SEO Report"): with st.spinner("Generating SEO report..."): try: wix = WixIntegration(refresh_token=refresh_token, site_id=site_id) seo_report = wix.get_seo_report(post.get("id"), seo_keywords or tags or []) st.subheader("SEO Report") st.write(f"**SEO Score:** {seo_report.get('seo_score', 0):.1f}/100") st.write("**Recommendations:**") for i, rec in enumerate(seo_report.get("recommendations", [])): st.write(f"{i+1}. {rec}") except Exception as e: st.error(f"Failed to generate SEO report: {str(e)}") except Exception as e: st.error(f"❌ Failed to publish blog post: {str(e)}") logger.error(f"Failed to publish blog post: {str(e)}") # For testing the UI directly if __name__ == "__main__": wix_blog_publisher_ui()