File size: 5,520 Bytes
d343201
 
 
 
06d3276
86368f8
6b7bfdd
06d3276
83c8c73
d343201
83c8c73
d343201
 
83c8c73
d343201
83c8c73
06d3276
 
 
 
 
 
f9e7cf4
06d3276
 
 
 
 
 
 
d465b34
06d3276
 
 
 
d465b34
06d3276
 
 
 
 
 
 
d465b34
06d3276
 
 
d465b34
06d3276
 
 
 
 
d465b34
d24e71f
06d3276
 
 
 
d24e71f
06d3276
d24e71f
2f38435
d343201
 
d24e71f
 
 
 
 
6b7bfdd
 
d24e71f
06d3276
d465b34
06d3276
 
 
 
d465b34
 
 
 
 
 
 
 
 
 
 
06d3276
83c8c73
d343201
fa7a61e
86368f8
1606dca
 
 
 
 
f9e7cf4
 
 
 
 
 
 
 
 
 
 
 
 
 
86368f8
f9e7cf4
1606dca
86368f8
61c4d2f
83c8c73
d343201
 
83c8c73
d343201
 
 
 
06d3276
 
 
 
 
 
 
 
 
 
d343201
 
83c8c73
d343201
 
 
 
83c8c73
d343201
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
from shiny import reactive, render, ui
import os
import requests
from dotenv import load_dotenv
from bs4 import BeautifulSoup
import subprocess
import time
from llm_connect import get_response

load_dotenv()

PAGE_ID = os.getenv("FB_PAGE_ID")
ACCESS_TOKEN = os.getenv("FB_PAGE_ACCESS_TOKEN")

generated_fb_post = reactive.Value("")

def scrape_shopify_blog(url: str) -> str:
    try:
        resp = requests.get(url, timeout=10)
        soup = BeautifulSoup(resp.content, 'html.parser')
        section = soup.find(
            'div',
            class_='w940 align-center size-content'
        )
        return section.get_text(strip=True, separator=' ') if section else ""
    except Exception as e:
        return f"❌ Error scraping blog: {e}"

def generate_facebook_post(topic: str = "", url: str = "", min_len: int = 500, max_len: int = 1000) -> str:
    # Handle blog scraping
    if url:
        scraped = scrape_shopify_blog(url)
        if scraped.startswith("❌") or not scraped.strip():
            return f"⚠️ Failed to extract blog content from URL: {url}"
        prompt = (
            f"You are a social media manager for a hobby e-commerce company called 'Ultima Supply'.\n"
            f"Write a detailed, engaging Facebook post (min {min_len} characters, max {max_len} characters) summarizing the following Shopify blog:\n\n"
            f"{scraped}\n\n"
            f"The post MUST include this exact URL: {url}\n"
            f"Use a casual, friendly tone with emojis.\n"
            f"VERY IMPORTANT: The post MUST include exactly 5 to 10 SEO-relevant hashtags at the end.\n"
            f"Do not include hashtags inline — list them as a group at the end of the post.\n"
            f"Keep everything under {max_len} characters total."
        )

    elif topic:
        prompt = (
            f"You are a social media manager for a hobby e-commerce company called 'Ultima Supply'.\n"
            f"Write a short, engaging Facebook post (min {min_len} characters, max {max_len} characters) about: '{topic}'.\n"
            f"Use a casual, friendly tone with fun emojis.\n"
            f"VERY IMPORTANT: Include exactly 5 to 10 SEO-relevant hashtags grouped at the end of the post.\n"
            f"Do NOT place hashtags inline — they must be in a clean list at the end.\n"
            f"The entire post must be under {max_len} characters total."
        )

    else:
        return "⚠️ Provide either a topic or a Shopify blog URL."

    # Step 1: Generate initial post
    post = get_response(
        input=prompt,
        template=lambda x: x.strip(),
        llm="gemini",
        md=False,
        temperature=0.9,
        max_tokens=250
    ).strip()

    if len(post) <= max_len:
        return post
    
    time.sleep(5)

    # Step 2: Shorten if needed
    shorten_prompt = (
        f"Shorten this Facebook post to {max_len} characters or fewer.\n"
        f"You MUST keep the Shopify blog link ({url}) and all original hashtags:\n\n{post}"
        if url else
        f"Shorten this Facebook post to {max_len} characters or fewer, keeping the tone, emojis, and all original hashtags:\n\n{post}"
    )

    shortened = get_response(
        input=shorten_prompt,
        template=lambda x: x.strip(),
        llm="gemini",
        md=False,
        temperature=0.7,
        max_tokens=200
    ).strip()

    return shortened[:max_len]

def post_to_facebook(message: str) -> str:
    proxy_url = "https://facebook-proxy.onrender.com/post-to-facebook"  # your actual deployed Render URL

    try:
        res = requests.post(proxy_url, json={"message": message}, timeout=10)
        res.raise_for_status()
        data = res.json()

        # Safely handle both proxy success and raw Facebook responses
        if isinstance(data, dict):
            if "status" in data and data["status"] == "success":
                return f"✅ Post successful! Facebook Post ID: {data.get('post_id', 'unknown')}"
            elif "id" in data or "post_id" in data:
                post_id = data.get("post_id") or data.get("id")
                return f"✅ Post successful! Facebook Post ID: {post_id}"
            elif "error" in data:
                return f"❌ Facebook error: {data['error']}"
        
        return f"⚠️ Unexpected response: {data}"

    except requests.RequestException as e:
        return f"❌ Network or proxy error: {e}"
    except Exception as e:
        return f"❌ Unexpected error: {e}"




def server(input, output, session):
    post_status = reactive.Value("")

    @output
    @render.ui
    @reactive.event(input.gen_btn_fb)
    def fb_post_draft():
        topic = input.fb_topic().strip()
        url = input.fb_url().strip()

        if not topic and not url:
            return ui.HTML("<p><strong>⚠️ Enter a topic or a blog URL.</strong></p>")
        
        post = generate_facebook_post(topic=topic, url=url)
        if post.startswith("⚠️") or post.startswith("❌"):
            return ui.HTML(f"<p><strong>{post}</strong></p>")

        generated_fb_post.set(post)
        return ui.HTML(f"<p><strong>Generated Facebook Post:</strong><br>{post}</p>")

    @output
    @render.text
    def fb_post_status():
        return post_status()

    @reactive.effect
    @reactive.event(input.post_btn_fb)
    def _():
        post = generated_fb_post()
        if not post:
            post_status.set("⚠️ No post generated yet.")
        else:
            result = post_to_facebook(post)
            post_status.set(result)