Spaces:
Sleeping
Sleeping
| import requests | |
| import time | |
| import logging | |
| import gradio as gr | |
| from config import config | |
| logger = logging.getLogger(__name__) | |
| def post_to_linkedin(name, job_post): | |
| """ | |
| Post to LinkedIn via their API with improved UX feedback | |
| Args: | |
| name (str): Name of the person posting | |
| job_post (str): Content of the job post | |
| Yields: | |
| tuple: (status_message, success_link_update) | |
| """ | |
| logger.info(f"Starting LinkedIn post process for user: {name}") | |
| yield "Verifying inputs...", gr.update(value="", visible=False) | |
| # Validate configuration | |
| if not config.organisation_number or not config.token or not config.post_api_url: | |
| error_msg = "Configuration Error: Missing LinkedIn API variables. Please check Spaces Secrets." | |
| logger.error(error_msg) | |
| yield f"β {error_msg}", gr.update(visible=False) | |
| return | |
| # Check for ServiceTrigger | |
| if not config.service_trigger: | |
| warning_msg = "Configuration Error: Missing ServiceTrigger variable. FeedHire update will be manual." | |
| logger.warning(warning_msg) | |
| yield f"β {warning_msg}", gr.update(visible=False) | |
| # Validate inputs | |
| if not name.strip() or not job_post.strip(): | |
| error_msg = "Please fill in all fields (Name and Job Post)." | |
| logger.warning(f"Validation failed: {error_msg}") | |
| yield f"β {error_msg}", gr.update(visible=False) | |
| return | |
| # Prepare API request | |
| headers_dict = { | |
| 'Authorization': f'Bearer {config.token}', | |
| 'Content-Type': 'application/json', | |
| 'X-Restli-Protocol-Version': '2.0.0', | |
| 'LinkedIn-Version': '202510' | |
| } | |
| data = { | |
| "author": f"urn:li:organization:{config.organisation_number}", | |
| "commentary": f"{name}\n\n{job_post}", | |
| "visibility": "PUBLIC", | |
| "lifecycleState": "PUBLISHED", | |
| "distribution": { | |
| "feedDistribution": "MAIN_FEED", | |
| "targetEntities": [], | |
| "thirdPartyDistributionChannels": [] | |
| }, | |
| "isReshareDisabledByAuthor": False | |
| } | |
| try: | |
| logger.info("Sending post to LinkedIn API") | |
| yield "π Posting to LinkedIn...", gr.update(visible=False) | |
| response = requests.post( | |
| config.post_api_url, | |
| headers=headers_dict, | |
| json=data, | |
| timeout=30 | |
| ) | |
| if response.status_code == 201: | |
| logger.info("LinkedIn post created successfully") | |
| # Wait for LinkedIn API to update | |
| for i in range(10, 0, -1): | |
| yield f"β Post successful! Waiting for LinkedIn API update... ({i} seconds remaining)", gr.update(visible=False) | |
| time.sleep(1) | |
| # Trigger FeedHire backend update | |
| if config.service_trigger: | |
| try: | |
| logger.info("Triggering FeedHire backend update") | |
| trigger_resp = requests.post(f"{config.service_trigger}", timeout=10) | |
| yield "π FeedHire website triggered, waiting for job listing update...", gr.update(visible=False) | |
| if trigger_resp.status_code == 200: | |
| logger.info("FeedHire backend triggered successfully") | |
| yield "β Backend triggered successfully! FeedHire will update the listing shortly.", gr.update(visible=False) | |
| else: | |
| logger.warning(f"Backend trigger failed with status {trigger_resp.status_code}") | |
| yield f"β οΈ Backend trigger failed (Status: {trigger_resp.status_code}). FeedHire update may be delayed.", gr.update(visible=False) | |
| except Exception as trigger_error: | |
| logger.error(f"Error triggering async fetch: {trigger_error}") | |
| yield f"β οΈ Error triggering FeedHire backend: {trigger_error}", gr.update(visible=False) | |
| yield "β Post live! π Retrieving your post link...", gr.update(visible=False) | |
| # Fetch post URL | |
| try: | |
| logger.info("Fetching LinkedIn post URL") | |
| post_api_url = "https://api.linkedin.com/rest/posts" | |
| headers = { | |
| "Authorization": f"Bearer {config.token}", | |
| "LinkedIn-Version": "202510", | |
| "X-Restli-Protocol-Version": "2.0.0" | |
| } | |
| params = { | |
| "q": "author", | |
| "author": f"urn:li:organization:{config.organisation_number}", | |
| "count": 1 | |
| } | |
| fetch_response = requests.get(post_api_url, headers=headers, params=params, timeout=30) | |
| if fetch_response.status_code == 200: | |
| fetch_data = fetch_response.json() | |
| if fetch_data.get("elements") and len(fetch_data["elements"]) > 0: | |
| post_id_urn = fetch_data["elements"][0]["id"] | |
| if "share" in post_id_urn: | |
| post_id = post_id_urn.split(":")[-1] | |
| post_url = f"https://www.linkedin.com/feed/update/urn:li:share:{post_id}/" | |
| elif "activity" in post_id_urn: | |
| post_id = post_id_urn.split(":")[-1] | |
| post_url = f"https://www.linkedin.com/feed/update/urn:li:activity:{post_id}/" | |
| else: | |
| raise Exception("Unknown post URN format") | |
| logger.info(f"Post URL retrieved: {post_url}") | |
| print(f"Post URL: {post_url}") | |
| yield "β Post published successfully!", gr.update(value=f"### π [Click here to view your post on LinkedIn β]({post_url})", visible=True) | |
| return | |
| # Fallback if URL retrieval fails | |
| logger.warning("Could not retrieve post URL, using fallback") | |
| yield "β Post published! (Could not auto-retrieve post link. Please check the LinkedIn page.)", gr.update(visible=False) | |
| except Exception as fetch_error: | |
| logger.error(f"Error fetching post: {fetch_error}") | |
| yield f"β Post published! (Error retrieving link: {fetch_error})", gr.update(visible=False) | |
| else: | |
| # Handle API errors | |
| try: | |
| error_data = response.json() | |
| error_message = error_data.get('message', response.text) | |
| except requests.exceptions.JSONDecodeError: | |
| error_message = response.text | |
| error_msg = f"Error {response.status_code}: {error_message}" | |
| logger.error(f"LinkedIn API error: {error_msg}") | |
| print(f"β {error_msg}") | |
| yield f"β {error_msg}", gr.update(visible=False) | |
| except requests.exceptions.Timeout: | |
| error_msg = "Request timed out. Please try again." | |
| logger.error(error_msg) | |
| yield f"β Error: {error_msg}", gr.update(visible=False) | |
| except requests.exceptions.RequestException as e: | |
| error_msg = f"Network Error: {str(e)}" | |
| logger.error(error_msg) | |
| yield f"β {error_msg}", gr.update(visible=False) | |
| except Exception as e: | |
| error_msg = f"Error: {str(e)}" | |
| logger.exception("Unexpected error in post_to_linkedin") | |
| yield f"β {error_msg}", gr.update(visible=False) |