From 0bf70616eaa8cb17cfb157fc80d000c643a64833 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Sat, 27 Jul 2024 15:38:19 +0330 Subject: [PATCH 1/7] Add LinkedIn create post product in Python --- .../linkedin-post-gen/lambda_function.py | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 post-master-ai/linkedin-post-gen/lambda_function.py diff --git a/post-master-ai/linkedin-post-gen/lambda_function.py b/post-master-ai/linkedin-post-gen/lambda_function.py new file mode 100644 index 0000000..821f97d --- /dev/null +++ b/post-master-ai/linkedin-post-gen/lambda_function.py @@ -0,0 +1,176 @@ +import json +import boto3 +import os +import requests +import feedparser +import markdown +import re + +lambda_client = boto3.client('lambda') +s3_client = boto3.client('s3') + +RSS_FEED_URL = 'https://rss.nytimes.com/services/xml/rss/nyt/World.xml' + +def get_latest_news(rss_feed_url): + """ + Fetches the latest news articles from the RSS feed. + """ + feed = feedparser.parse(rss_feed_url) + return feed.entries + +def filter_news(articles, keywords): + """ + Filters news articles based on user-required keywords. + """ + filtered_articles = [] + for article in articles: + for keyword in keywords: + if keyword.lower() in article.title.lower() or keyword.lower() in article.description.lower(): + filtered_articles.append(article) + break + return filtered_articles + +def invoke_openai_lambda(execution_id, user_id, product_id, prompt, openai_function): + """ + Invokes the OpenAI Lambda function to generate a LinkedIn post. + """ + openai_payload = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "service": "chat-gpt-4o", + "size": "1x", + "prompt": prompt + } + + response = lambda_client.invoke( + FunctionName=openai_function, + InvocationType='RequestResponse', + Payload=json.dumps(openai_payload) + ) + + response_payload = json.load(response['Payload']) + status_code = response_payload.get('status_code') + if status_code != 200: + raise Exception(f"OpenAI Lambda function returned status code {status_code} with body {response_payload.get('body')}") + + return response_payload.get('body') + +def decode_unicode(input_str): + """Decodes Unicode-escaped string.""" + return re.sub(r'\\u([0-9A-Fa-f]{4})', lambda match: chr(int(match.group(1), 16)), input_str) + +def generate_html_message(execution_id, user_id, product_id, result): + markdown_string = result['choices'][0]['message']['content'] + + # Decode the Unicode string + decoded_string = decode_unicode(markdown_string) + + # Convert the decoded Markdown string to HTML + html_content = markdown.markdown(decoded_string) + + # formatted_response = json.dumps(result, indent=4) + + return f""" +
+

Task Execution Result

+

Execution ID: {execution_id}

+

User ID: {user_id}

+

Product ID: {product_id}

+ Response:
+
+ {html_content} +
+
+ """ + +def send_result_to_wordpress(result): + post_data = json.dumps(result) + wordpress_url = 'https://promptintellect.com/wp-json/product-extension/v1/lambda-results' + + headers = { + 'Content-Type': 'application/json', + 'Content-Length': str(len(post_data)) + } + + response = requests.post(wordpress_url, headers=headers, data=post_data) + if response.status_code != 200: + raise Exception(f"Unexpected status code: {response.status_code}, {response.text}") + +def handler(event, context): + try: + # Extract environment variables + bucket_name = os.environ['PI_EXECUTION_S3_BUCKET_NAME'] + result_folder = os.environ['PI_RESULTS_FOLDER'] + openai_function = os.environ['PI_OPENAI_FUNCTION'] + + # Extract event data + execution_id = event['execution_id'] + user_id = event['user_id'] + product_id = event['product_id'] + token = event['token'] + custom_inputs = event['custom_inputs'] + keywords = [keyword.strip() for keyword in custom_inputs.get('keywords', '').replace('-', ',').split(',')] + + # Fetch and filter news articles + feed_url = RSS_FEED_URL + articles = get_latest_news(feed_url) + filtered_articles = filter_news(articles, keywords) + + if not filtered_articles: + raise Exception("No articles found matching the keywords") + + # Generate a LinkedIn post prompt + news_summary = "\n\n".join([f"Title: {article.title}\nLink: {article.link}" for article in filtered_articles]) + prompt = f"Write a LinkedIn post based on the following news articles:\n\n{news_summary}" + + # Invoke OpenAI Lambda function + openai_result = invoke_openai_lambda(execution_id, user_id, product_id, prompt, openai_function) + + # Save the result to S3 + result_key = f"{result_folder}/{execution_id}/result.json" + s3_client.put_object(Bucket=bucket_name, Key=result_key, Body=json.dumps(openai_result, indent=4)) + + # Prepare the result + html_message = generate_html_message(execution_id, user_id, product_id, openai_result) + + result = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "successful", + "results": html_message + } + + # Send the result to the endpoint + send_result_to_wordpress(result) + + return { + 'statusCode': 200, + 'body': json.dumps({'message': 'Task executed successfully'}) + } + + except Exception as e: + error_message = str(e) + print(f"Error: {error_message}") + + error_result = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "failed", + "results": f""" +
+

Error: {error_message}

+
+ """ + } + + send_result_to_wordpress(error_result) + + return { + 'statusCode': 500, + 'body': json.dumps({'message': error_message}) + } From ae2abe7e0825f9b226ed05a1b807e33c5c7f27cf Mon Sep 17 00:00:00 2001 From: Hojjat Date: Sun, 28 Jul 2024 04:11:07 +0330 Subject: [PATCH 2/7] Add new service in Java --- .../instagram-post-gen-py/lambda_function.py | 150 +++++++++++++ post-master-ai/instagram-post-gen/pom.xml | 75 +++++++ .../com/example/InstagramPostHandler.java | 201 ++++++++++++++++++ 3 files changed, 426 insertions(+) create mode 100644 post-master-ai/instagram-post-gen-py/lambda_function.py create mode 100644 post-master-ai/instagram-post-gen/pom.xml create mode 100644 post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java diff --git a/post-master-ai/instagram-post-gen-py/lambda_function.py b/post-master-ai/instagram-post-gen-py/lambda_function.py new file mode 100644 index 0000000..bdc59d1 --- /dev/null +++ b/post-master-ai/instagram-post-gen-py/lambda_function.py @@ -0,0 +1,150 @@ +import json +import boto3 +import os +import requests +import markdown +import re + +s3_client = boto3.client('s3') +lambda_client = boto3.client('lambda') + +def invoke_openai_lambda(execution_id, user_id, product_id, prompt, service, size, openai_function): + """ + Invokes the OpenAI Lambda function to generate content. + """ + openai_payload = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "service": service, + "size": size, + "prompt": prompt + } + + response = lambda_client.invoke( + FunctionName=openai_function, + InvocationType='RequestResponse', + Payload=json.dumps(openai_payload) + ) + + response_payload = json.load(response['Payload']) + status_code = response_payload.get('status_code') + if status_code != 200: + raise Exception(f"OpenAI Lambda function returned status code {status_code} with body {response_payload.get('body')}") + + return response_payload.get('body') + +def download_and_upload_to_s3(url, bucket_name, folder_path): + """ + Downloads an image from a URL and uploads it to an S3 bucket. + """ + base_url = url.split('?')[0] + file_name = folder_path + "/" + base_url.split('/')[-1] + + response = requests.get(url, stream=True) + s3_client.put_object(Body=response.content, Bucket=bucket_name, Key=file_name) + + print(f"File {file_name} uploaded to S3 bucket {bucket_name}") + return file_name + +def decode_unicode(input_str): + """Decodes Unicode-escaped string.""" + return re.sub(r'\\u([0-9A-Fa-f]{4})', lambda match: chr(int(match.group(1), 16)), input_str) + +def generate_html_message(execution_id, user_id, product_id, caption): + return f""" +
+

Instagram Post Creation Result

+

Execution ID: {execution_id}

+

User ID: {user_id}

+

Product ID: {product_id}

+

Caption:
+

{markdown.markdown(decode_unicode(caption))}
+

+
+ """ + +def send_result_to_wordpress(result): + post_data = json.dumps(result) + wordpress_url = 'https://promptintellect.com/wp-json/product-extension/v1/lambda-results' + + headers = { + 'Content-Type': 'application/json', + 'Content-Length': str(len(post_data)) + } + + response = requests.post(wordpress_url, headers=headers, data=post_data) + if response.status_code != 200: + raise Exception(f"Unexpected status code: {response.status_code}, {response.text}") + +def handler(event, context): + try: + # Extract environment variables + bucket_name = os.environ['PI_EXECUTION_S3_BUCKET_NAME'] + result_folder = os.environ['PI_RESULTS_FOLDER'] + openai_function = os.environ['PI_OPENAI_FUNCTION'] + + # Extract event data + execution_id = event['execution_id'] + user_id = event['user_id'] + product_id = event['product_id'] + token = event['token'] + custom_inputs = event['custom_inputs'] + explanation = custom_inputs.get('explanation', '') + + # Generate Instagram post caption + caption_prompt = f"Create an Instagram post caption based on the following explanation:\n\n{explanation}" + openai_caption_result = invoke_openai_lambda(execution_id, user_id, product_id, caption_prompt, "chat-gpt-4o", "1x", openai_function) + caption = openai_caption_result['choices'][0]['message']['content'] + + # Generate Instagram post image + image_prompt = f"Generate an image based on the following explanation:\n\n{explanation}" + openai_image_result = invoke_openai_lambda(execution_id, user_id, product_id, image_prompt, "image-dall-e-3", "1x", openai_function) + image_url = openai_image_result["data"][0]["url"] + + # Upload the image to S3 + uploaded_image_key = download_and_upload_to_s3(image_url, bucket_name, f"{result_folder}/{execution_id}") + + # Prepare the result + html_message = generate_html_message(execution_id, user_id, product_id, caption) + + result = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "successful", + "results": html_message + } + + # Send the result to the endpoint + send_result_to_wordpress(result) + + return { + 'statusCode': 200, + 'body': json.dumps({'message': 'Task executed successfully'}) + } + + except Exception as e: + error_message = str(e) + print(f"Error: {error_message}") + + error_result = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "failed", + "results": f""" +
+

Error: {error_message}

+
+ """ + } + + send_result_to_wordpress(error_result) + + return { + 'statusCode': 500, + 'body': json.dumps({'message': error_message}) + } diff --git a/post-master-ai/instagram-post-gen/pom.xml b/post-master-ai/instagram-post-gen/pom.xml new file mode 100644 index 0000000..9700cda --- /dev/null +++ b/post-master-ai/instagram-post-gen/pom.xml @@ -0,0 +1,75 @@ + + 4.0.0 + com.example + instagram-post-gen + jar + 1.0-SNAPSHOT + instagram-post-gen + http://maven.apache.org + + + 1.8 + 1.8 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.1.0 + + false + + + + package + + shade + + + + + + + + + + junit + junit + 3.8.1 + test + + + com.amazonaws + aws-lambda-java-core + 1.2.1 + + + com.amazonaws + aws-lambda-java-events + 3.11.0 + + + com.amazonaws + aws-java-sdk-s3 + 1.11.1016 + + + com.amazonaws + aws-java-sdk-lambda + 1.11.1016 + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + com.fasterxml.jackson.core + jackson-databind + 2.12.3 + + + diff --git a/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java new file mode 100644 index 0000000..c692351 --- /dev/null +++ b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java @@ -0,0 +1,201 @@ +package com.example; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.LambdaLogger; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.lambda.AWSLambda; +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.nio.charset.StandardCharsets; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.function.Function; +import java.util.regex.MatchResult; +import java.util.HashMap; +import java.util.List; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class InstagramPostHandler implements RequestHandler, Map> { + + private final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient(); + private final AWSLambda lambdaClient = AWSLambdaClientBuilder.defaultClient(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public Map handleRequest(Map event, Context context) { + LambdaLogger logger = context.getLogger(); + Map response = new HashMap<>(); + + try { + // Extract environment variables + String bucketName = System.getenv("PI_EXECUTION_S3_BUCKET_NAME"); + String resultFolder = System.getenv("PI_RESULTS_FOLDER"); + String openaiFunction = System.getenv("PI_OPENAI_FUNCTION"); + + // Extract event data + String executionId = (String) event.get("execution_id"); + Integer userId = (Integer) event.get("user_id"); + Integer productId = (Integer) event.get("product_id"); + String token = (String) event.get("token"); + Map customInputs = (Map) event.get("custom_inputs"); + String explanation = customInputs.getOrDefault("explanation", ""); + + // Generate Instagram post caption + String captionPrompt = "Create an Instagram post caption based on the following explanation:\n\n" + explanation; + String openaiCaptionResult = invokeOpenaiLambda(executionId, userId, productId, captionPrompt, "chat-gpt-4o", "1x", openaiFunction, logger); + Map openaiCaptionMap = objectMapper.readValue(openaiCaptionResult, new TypeReference>() {}); + String caption = (String) ((Map) ((Map) ((List) openaiCaptionMap.get("choices")).get(0)).get("message")).get("content"); + + // Generate Instagram post image + String imagePrompt = "Generate an image based on the following explanation:\n\n" + explanation; + String openaiImageResult = invokeOpenaiLambda(executionId, userId, productId, imagePrompt, "image-dall-e-3", "1x", openaiFunction, logger); + Map openaiImageMap = objectMapper.readValue(openaiImageResult, new TypeReference>() {}); + String imageUrl = (String) ((Map) ((Map) openaiImageMap.get("data")).get(0)).get("url"); + + // Upload the image to S3 + String uploadedImageKey = downloadAndUploadToS3(imageUrl, bucketName, resultFolder + "/" + executionId, logger); + + // Prepare the result + String htmlMessage = generateHtmlMessage(executionId, userId, productId, caption); + + Map result = new HashMap<>(); + result.put("execution_id", executionId); + result.put("user_id", userId); + result.put("product_id", productId); + result.put("token", token); + result.put("status", "successful"); + result.put("results", htmlMessage); + + // Send the result to the endpoint + sendResultToWordpress(result, logger); + + response.put("statusCode", 200); + response.put("body", "{\"message\": \"Task executed successfully\"}"); + } catch (Exception e) { + logger.log("Error: " + e.getMessage()); + + Map errorResult = new HashMap<>(); + errorResult.put("execution_id", event.get("execution_id")); + errorResult.put("user_id", event.get("user_id")); + errorResult.put("product_id", event.get("product_id")); + errorResult.put("token", event.get("token")); + errorResult.put("status", "failed"); + errorResult.put("results", "

Error: " + e.getMessage() + "

"); + + try { + sendResultToWordpress(errorResult, logger); + } catch (IOException ioException) { + context.getLogger().log("Failed to send result to WordPress: " + ioException.getMessage()); + } + + response.put("statusCode", 500); + response.put("body", "{\"message\": \"" + e.getMessage() + "\"}"); + } + + return response; + } + + private String invokeOpenaiLambda(String executionId, Integer userId, Integer productId, String prompt, String service, String size, String openaiFunction, LambdaLogger logger) throws IOException { + Map openaiPayload = new HashMap<>(); + openaiPayload.put("execution_id", executionId); + openaiPayload.put("user_id", userId); + openaiPayload.put("product_id", productId); + openaiPayload.put("service", service); + openaiPayload.put("size", size); + openaiPayload.put("prompt", prompt); + + InvokeRequest invokeRequest = new InvokeRequest() + .withFunctionName(openaiFunction) + .withPayload(objectMapper.writeValueAsString(openaiPayload)); + InvokeResult invokeResult = lambdaClient.invoke(invokeRequest); + + String responsePayload = new String(invokeResult.getPayload().array(), StandardCharsets.UTF_8); + Map responseMap = objectMapper.readValue(responsePayload, new TypeReference>() {}); + int statusCode = (int) responseMap.get("status_code"); + if (statusCode != 200) { + throw new RuntimeException("OpenAI Lambda function returned status code " + statusCode + " with body " + responseMap.get("body")); + } + + return objectMapper.writeValueAsString(responseMap.get("body")); + } + + private String downloadAndUploadToS3(String url, String bucketName, String folderPath, LambdaLogger logger) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpGet httpGet = new HttpGet(url); + CloseableHttpResponse response = httpClient.execute(httpGet); + + try { + HttpEntity entity = response.getEntity(); + if (entity != null) { + String fileName = folderPath + "/" + url.substring(url.lastIndexOf('/') + 1, url.indexOf('?')); + s3Client.putObject(bucketName, fileName, entity.getContent(), null); + logger.log("File " + fileName + " uploaded to S3 bucket " + bucketName); + return fileName; + } else { + throw new RuntimeException("Failed to download image from URL"); + } + } finally { + response.close(); + } + } + + private String generateHtmlMessage(String executionId, Integer userId, Integer productId, String caption) { + return "
" + + "

Instagram Post Creation Result

" + + "

Execution ID: " + executionId + "

" + + "

User ID: " + userId + "

" + + "

Product ID: " + productId + "

" + + "

Caption:

" + markdownToHtml(decodeUnicode(caption)) + "

" + + "
"; + } + + private String decodeUnicode(String inputStr) { + Pattern pattern = Pattern.compile("\\\\u([0-9A-Fa-f]{4})"); + Matcher matcher = pattern.matcher(inputStr); + StringBuffer result = new StringBuffer(); + while (matcher.find()) { + String unicodeChar = String.valueOf((char) Integer.parseInt(matcher.group(1), 16)); + matcher.appendReplacement(result, unicodeChar); + } + matcher.appendTail(result); + return result.toString(); + } + + private String markdownToHtml(String markdown) { + // Simple replacement for the sake of this example, consider using a library for more complex conversions + return markdown.replaceAll("\n", "
"); + } + + private void sendResultToWordpress(Map result, LambdaLogger logger) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost("https://promptintellect.com/wp-json/product-extension/v1/lambda-results"); + httpPost.setHeader("Content-Type", "application/json"); + httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(result))); + + CloseableHttpResponse response = httpClient.execute(httpPost); + if (response.getStatusLine().getStatusCode() != 200) { + throw new RuntimeException("Unexpected status code: " + response.getStatusLine().getStatusCode()); + } + + response.close(); + } +} From 7d8d8f94d888201b3f2b616675dc444460cbe6b9 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 1 Aug 2024 01:49:04 +0330 Subject: [PATCH 3/7] Fix some bugs --- post-master-ai/instagram-post-gen/pom.xml | 5 ++ .../com/example/InstagramPostHandler.java | 54 ++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/post-master-ai/instagram-post-gen/pom.xml b/post-master-ai/instagram-post-gen/pom.xml index 9700cda..2c176bb 100644 --- a/post-master-ai/instagram-post-gen/pom.xml +++ b/post-master-ai/instagram-post-gen/pom.xml @@ -71,5 +71,10 @@ jackson-databind 2.12.3 + + org.commonmark + commonmark + 0.22.0 + diff --git a/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java index c692351..a253e60 100644 --- a/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java +++ b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java @@ -33,6 +33,11 @@ import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.commonmark.node.*; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.html.HtmlRenderer; public class InstagramPostHandler implements RequestHandler, Map> { @@ -59,6 +64,10 @@ public Map handleRequest(Map event, Context cont Map customInputs = (Map) event.get("custom_inputs"); String explanation = customInputs.getOrDefault("explanation", ""); + // just for debugging + logger.log("customInputs: " + customInputs); + logger.log("explanation: " + explanation); + // Generate Instagram post caption String captionPrompt = "Create an Instagram post caption based on the following explanation:\n\n" + explanation; String openaiCaptionResult = invokeOpenaiLambda(executionId, userId, productId, captionPrompt, "chat-gpt-4o", "1x", openaiFunction, logger); @@ -66,10 +75,15 @@ public Map handleRequest(Map event, Context cont String caption = (String) ((Map) ((Map) ((List) openaiCaptionMap.get("choices")).get(0)).get("message")).get("content"); // Generate Instagram post image - String imagePrompt = "Generate an image based on the following explanation:\n\n" + explanation; + String imagePrompt = "Generate an image based on the following explanation, this image will be used for non-commercial purposes:\n\n" + explanation; + + // just for debugging + logger.log("imagePrompt: " + imagePrompt); + logger.log("caption: " + caption); + String openaiImageResult = invokeOpenaiLambda(executionId, userId, productId, imagePrompt, "image-dall-e-3", "1x", openaiFunction, logger); Map openaiImageMap = objectMapper.readValue(openaiImageResult, new TypeReference>() {}); - String imageUrl = (String) ((Map) ((Map) openaiImageMap.get("data")).get(0)).get("url"); + String imageUrl = (String) ((Map) ((List) openaiImageMap.get("data")).get(0)).get("url"); // Upload the image to S3 String uploadedImageKey = downloadAndUploadToS3(imageUrl, bucketName, resultFolder + "/" + executionId, logger); @@ -146,10 +160,13 @@ private String downloadAndUploadToS3(String url, String bucketName, String folde try { HttpEntity entity = response.getEntity(); if (entity != null) { - String fileName = folderPath + "/" + url.substring(url.lastIndexOf('/') + 1, url.indexOf('?')); - s3Client.putObject(bucketName, fileName, entity.getContent(), null); - logger.log("File " + fileName + " uploaded to S3 bucket " + bucketName); - return fileName; + String baseUrl = url.split("\\?")[0]; + String[] urlParts = baseUrl.split("/"); + String fileName = urlParts[urlParts.length - 1]; + String fullPath = folderPath + "/" + fileName; + s3Client.putObject(bucketName, fullPath, entity.getContent(), null); + logger.log("File " + fullPath + " uploaded to S3 bucket " + bucketName); + return fullPath; } else { throw new RuntimeException("Failed to download image from URL"); } @@ -164,25 +181,24 @@ private String generateHtmlMessage(String executionId, Integer userId, Integer p "

Execution ID: " + executionId + "

" + "

User ID: " + userId + "

" + "

Product ID: " + productId + "

" + - "

Caption:

" + markdownToHtml(decodeUnicode(caption)) + "

" + + "

Caption:

" + markdownToHtml(escape(caption)) + "

" + ""; } - private String decodeUnicode(String inputStr) { - Pattern pattern = Pattern.compile("\\\\u([0-9A-Fa-f]{4})"); - Matcher matcher = pattern.matcher(inputStr); - StringBuffer result = new StringBuffer(); - while (matcher.find()) { - String unicodeChar = String.valueOf((char) Integer.parseInt(matcher.group(1), 16)); - matcher.appendReplacement(result, unicodeChar); - } - matcher.appendTail(result); - return result.toString(); + private String escape(String s) { + return s.codePoints() + .mapToObj(codePoint -> codePoint > 127 ? + "&#x" + Integer.toHexString(codePoint) + ";" : + new String(Character.toChars(codePoint))) + .collect(Collectors.joining()); } private String markdownToHtml(String markdown) { - // Simple replacement for the sake of this example, consider using a library for more complex conversions - return markdown.replaceAll("\n", "
"); + HtmlRenderer renderer = HtmlRenderer.builder().build(); + Parser parser = Parser.builder().build(); + Node document = parser.parse(markdown); + + return renderer.render(document); } private void sendResultToWordpress(Map result, LambdaLogger logger) throws IOException { From 222d421238f473a80beec23912f3472539aa7066 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 1 Aug 2024 04:10:42 +0330 Subject: [PATCH 4/7] Fix some bugs --- post-master-ai/instagram-post-gen/pom.xml | 5 +++++ .../java/com/example/InstagramPostHandler.java | 17 ++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/post-master-ai/instagram-post-gen/pom.xml b/post-master-ai/instagram-post-gen/pom.xml index 2c176bb..cefb6a9 100644 --- a/post-master-ai/instagram-post-gen/pom.xml +++ b/post-master-ai/instagram-post-gen/pom.xml @@ -76,5 +76,10 @@ commonmark 0.22.0 + + com.kcthota + emoji4j + 6.0 + diff --git a/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java index a253e60..2292740 100644 --- a/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java +++ b/post-master-ai/instagram-post-gen/src/main/java/com/example/InstagramPostHandler.java @@ -39,6 +39,8 @@ import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; +import emoji4j.EmojiUtils; + public class InstagramPostHandler implements RequestHandler, Map> { private final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient(); @@ -64,10 +66,6 @@ public Map handleRequest(Map event, Context cont Map customInputs = (Map) event.get("custom_inputs"); String explanation = customInputs.getOrDefault("explanation", ""); - // just for debugging - logger.log("customInputs: " + customInputs); - logger.log("explanation: " + explanation); - // Generate Instagram post caption String captionPrompt = "Create an Instagram post caption based on the following explanation:\n\n" + explanation; String openaiCaptionResult = invokeOpenaiLambda(executionId, userId, productId, captionPrompt, "chat-gpt-4o", "1x", openaiFunction, logger); @@ -76,11 +74,6 @@ public Map handleRequest(Map event, Context cont // Generate Instagram post image String imagePrompt = "Generate an image based on the following explanation, this image will be used for non-commercial purposes:\n\n" + explanation; - - // just for debugging - logger.log("imagePrompt: " + imagePrompt); - logger.log("caption: " + caption); - String openaiImageResult = invokeOpenaiLambda(executionId, userId, productId, imagePrompt, "image-dall-e-3", "1x", openaiFunction, logger); Map openaiImageMap = objectMapper.readValue(openaiImageResult, new TypeReference>() {}); String imageUrl = (String) ((Map) ((List) openaiImageMap.get("data")).get(0)).get("url"); @@ -176,12 +169,14 @@ private String downloadAndUploadToS3(String url, String bucketName, String folde } private String generateHtmlMessage(String executionId, Integer userId, Integer productId, String caption) { + String markdownHtml = markdownToHtml(caption); + String finalHtml = EmojiUtils.hexHtmlify(markdownHtml); return "
" + "

Instagram Post Creation Result

" + "

Execution ID: " + executionId + "

" + "

User ID: " + userId + "

" + "

Product ID: " + productId + "

" + - "

Caption:

" + markdownToHtml(escape(caption)) + "

" + + "

Caption:

" + finalHtml + "

" + "
"; } @@ -197,7 +192,7 @@ private String markdownToHtml(String markdown) { HtmlRenderer renderer = HtmlRenderer.builder().build(); Parser parser = Parser.builder().build(); Node document = parser.parse(markdown); - + return renderer.render(document); } From ee67fb28e1790efa9e6a5a4baa5d69ce25e809fb Mon Sep 17 00:00:00 2001 From: Hojjat Date: Thu, 1 Aug 2024 04:14:01 +0330 Subject: [PATCH 5/7] Remove some unuseful files --- .../instagram-post-gen-py/lambda_function.py | 150 ------------------ 1 file changed, 150 deletions(-) delete mode 100644 post-master-ai/instagram-post-gen-py/lambda_function.py diff --git a/post-master-ai/instagram-post-gen-py/lambda_function.py b/post-master-ai/instagram-post-gen-py/lambda_function.py deleted file mode 100644 index bdc59d1..0000000 --- a/post-master-ai/instagram-post-gen-py/lambda_function.py +++ /dev/null @@ -1,150 +0,0 @@ -import json -import boto3 -import os -import requests -import markdown -import re - -s3_client = boto3.client('s3') -lambda_client = boto3.client('lambda') - -def invoke_openai_lambda(execution_id, user_id, product_id, prompt, service, size, openai_function): - """ - Invokes the OpenAI Lambda function to generate content. - """ - openai_payload = { - "execution_id": execution_id, - "user_id": user_id, - "product_id": product_id, - "service": service, - "size": size, - "prompt": prompt - } - - response = lambda_client.invoke( - FunctionName=openai_function, - InvocationType='RequestResponse', - Payload=json.dumps(openai_payload) - ) - - response_payload = json.load(response['Payload']) - status_code = response_payload.get('status_code') - if status_code != 200: - raise Exception(f"OpenAI Lambda function returned status code {status_code} with body {response_payload.get('body')}") - - return response_payload.get('body') - -def download_and_upload_to_s3(url, bucket_name, folder_path): - """ - Downloads an image from a URL and uploads it to an S3 bucket. - """ - base_url = url.split('?')[0] - file_name = folder_path + "/" + base_url.split('/')[-1] - - response = requests.get(url, stream=True) - s3_client.put_object(Body=response.content, Bucket=bucket_name, Key=file_name) - - print(f"File {file_name} uploaded to S3 bucket {bucket_name}") - return file_name - -def decode_unicode(input_str): - """Decodes Unicode-escaped string.""" - return re.sub(r'\\u([0-9A-Fa-f]{4})', lambda match: chr(int(match.group(1), 16)), input_str) - -def generate_html_message(execution_id, user_id, product_id, caption): - return f""" -
-

Instagram Post Creation Result

-

Execution ID: {execution_id}

-

User ID: {user_id}

-

Product ID: {product_id}

-

Caption:
-

{markdown.markdown(decode_unicode(caption))}
-

-
- """ - -def send_result_to_wordpress(result): - post_data = json.dumps(result) - wordpress_url = 'https://promptintellect.com/wp-json/product-extension/v1/lambda-results' - - headers = { - 'Content-Type': 'application/json', - 'Content-Length': str(len(post_data)) - } - - response = requests.post(wordpress_url, headers=headers, data=post_data) - if response.status_code != 200: - raise Exception(f"Unexpected status code: {response.status_code}, {response.text}") - -def handler(event, context): - try: - # Extract environment variables - bucket_name = os.environ['PI_EXECUTION_S3_BUCKET_NAME'] - result_folder = os.environ['PI_RESULTS_FOLDER'] - openai_function = os.environ['PI_OPENAI_FUNCTION'] - - # Extract event data - execution_id = event['execution_id'] - user_id = event['user_id'] - product_id = event['product_id'] - token = event['token'] - custom_inputs = event['custom_inputs'] - explanation = custom_inputs.get('explanation', '') - - # Generate Instagram post caption - caption_prompt = f"Create an Instagram post caption based on the following explanation:\n\n{explanation}" - openai_caption_result = invoke_openai_lambda(execution_id, user_id, product_id, caption_prompt, "chat-gpt-4o", "1x", openai_function) - caption = openai_caption_result['choices'][0]['message']['content'] - - # Generate Instagram post image - image_prompt = f"Generate an image based on the following explanation:\n\n{explanation}" - openai_image_result = invoke_openai_lambda(execution_id, user_id, product_id, image_prompt, "image-dall-e-3", "1x", openai_function) - image_url = openai_image_result["data"][0]["url"] - - # Upload the image to S3 - uploaded_image_key = download_and_upload_to_s3(image_url, bucket_name, f"{result_folder}/{execution_id}") - - # Prepare the result - html_message = generate_html_message(execution_id, user_id, product_id, caption) - - result = { - "execution_id": execution_id, - "user_id": user_id, - "product_id": product_id, - "token": token, - "status": "successful", - "results": html_message - } - - # Send the result to the endpoint - send_result_to_wordpress(result) - - return { - 'statusCode': 200, - 'body': json.dumps({'message': 'Task executed successfully'}) - } - - except Exception as e: - error_message = str(e) - print(f"Error: {error_message}") - - error_result = { - "execution_id": execution_id, - "user_id": user_id, - "product_id": product_id, - "token": token, - "status": "failed", - "results": f""" -
-

Error: {error_message}

-
- """ - } - - send_result_to_wordpress(error_result) - - return { - 'statusCode': 500, - 'body': json.dumps({'message': error_message}) - } From 82918602b6486b8a7a248223a2e3af46e921017d Mon Sep 17 00:00:00 2001 From: Hojjat Date: Wed, 14 Aug 2024 15:11:22 +0330 Subject: [PATCH 6/7] Add new service for analyzing SEO of a website using its URL --- .../URL-SEO-analyzer/lambda_function.py | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 site-sleuth/URL-SEO-analyzer/lambda_function.py diff --git a/site-sleuth/URL-SEO-analyzer/lambda_function.py b/site-sleuth/URL-SEO-analyzer/lambda_function.py new file mode 100644 index 0000000..034d789 --- /dev/null +++ b/site-sleuth/URL-SEO-analyzer/lambda_function.py @@ -0,0 +1,229 @@ +import json +import boto3 +import os +import requests +import emoji +import markdown +from bs4 import BeautifulSoup, Comment # Import Comment +from urllib.request import urlopen + +s3_client = boto3.client('s3') +lambda_client = boto3.client('lambda') + +HEADERS = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate", + "Connection": "keep-alive", + "Upgrade-Insecure-Requests": "1", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "none", + "Sec-Fetch-User": "?1", + "Cache-Control": "max-age=0", +} + +def handler(event, context): + try: + # Extract environment variables + bucket_name = os.environ['PI_EXECUTION_S3_BUCKET_NAME'] + result_folder = os.environ['PI_RESULTS_FOLDER'] + openai_function = os.environ['PI_OPENAI_FUNCTION'] + + # Extract event data + execution_id = event['execution_id'] + user_id = event['user_id'] + product_id = event['product_id'] + token = event['token'] + custom_inputs = event['custom_inputs'] + website_url = custom_inputs['website_url'] + + # Crawl and extract website content + crawled_data = crawl_website(website_url) + + # Generate a detailed prompt for OpenAI + prompt = generate_seo_analysis_prompt(crawled_data, website_url) + + # Invoke the OpenAI function for SEO analysis + openai_payload = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "service": "chat-gpt-4o-mini", + "size": "9x", + "prompt": prompt + } + + response = lambda_client.invoke( + FunctionName=openai_function, + InvocationType='RequestResponse', + Payload=json.dumps(openai_payload) + ) + + response_payload = json.load(response['Payload']) + status_code = response_payload.get('status_code') + if status_code != 200: + raise Exception(f"OpenAI chat function returns {status_code} as status code with body {str(response_payload.get('body'))}") + function_result = response_payload.get('body') + + if function_result is None: + raise Exception("No result from OpenAI chat function") + + # Save the result to S3 + result_key = f"{result_folder}/{execution_id}/seo_result.json" + s3_client.put_object(Bucket=bucket_name, Key=result_key, Body=json.dumps(function_result, indent=4)) + + # Send the result as HTML to the endpoint + html_message = generate_html_message(execution_id, user_id, product_id, function_result) + + send_result_to_wordpress({ + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "successful", + "results": html_message + }) + + return { + 'statusCode': 200, + 'body': json.dumps({ + 'message': 'Task executed successfully' + }) + } + + except Exception as e: + print(f"Error: {str(e)}") + + send_result_to_wordpress({ + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "failed", + "results": f""" +
+

Error: {str(e)}

+
+ """ + }) + + return { + 'statusCode': 500, + 'body': json.dumps({ + 'message': str(e) + }) + } + +def crawl_website(url): + response = requests.get(url, headers=HEADERS) + html = response.text + + # Parse HTML using BeautifulSoup + soup = BeautifulSoup(html, 'html.parser') + + # Extract relevant SEO elements + title = soup.title.string if soup.title else "No title found" + description = soup.find("meta", {"name": "description"})['content'] if soup.find("meta", {"name": "description"}) else "No description found" + keywords = soup.find("meta", {"name": "keywords"})['content'] if soup.find("meta", {"name": "keywords"}) else "No keywords found" + h1_tags = [h1.get_text() for h1 in soup.find_all('h1')] + h2_tags = [h2.get_text() for h2 in soup.find_all('h2')] + h3_tags = [h3.get_text() for h3 in soup.find_all('h3')] + alt_texts = [img['alt'] for img in soup.find_all('img') if img.has_attr('alt')] + links = [a['href'] for a in soup.find_all('a') if a.has_attr('href')] + + # Removing unnecessary parts of the HTML + # Remove script, style, and comments + for script in soup(["script", "style"]): + script.extract() + comments = soup.findAll(text=lambda text: isinstance(text, Comment)) + [comment.extract() for comment in comments] + + # Remove unnecessary attributes from tags + for tag in soup.find_all(True): + # Only keep certain attributes for tags + if tag.name == 'a': + attrs = {key: tag.attrs[key] for key in ['href'] if key in tag.attrs} + tag.attrs = attrs + # Remove all attributes for other tags + else: + tag.attrs = {} + + # Cleaned HTML content + cleaned_html = soup.prettify() + + crawled_data = { + "title": title, + "description": description, + "keywords": keywords, + "h1_tags": h1_tags, + "h2_tags": h2_tags, + "h3_tags": h3_tags, + "alt_texts": alt_texts, + "links": links, + "cleaned_html": cleaned_html # Reduced HTML content for analysis + } + + return crawled_data + +def generate_seo_analysis_prompt(crawled_data, website_url): + return f""" + You are an expert in SEO analysis. I have provided you with the relevant crawled data from the website: {website_url}. + Here is the information: + + - Title: {crawled_data['title']} + - Description: {crawled_data['description']} + - Keywords: {crawled_data['keywords']} + - H1 Tags: {', '.join(crawled_data['h1_tags'])} + - H2 Tags: {', '.join(crawled_data['h2_tags'])} + - H3 Tags: {', '.join(crawled_data['h3_tags'])} + - Alt Texts: {', '.join(crawled_data['alt_texts'])} + - Links: {', '.join(crawled_data['links'])} + + Here is the cleaned HTML content of the webpage (unnecessary tags and scripts removed): + {crawled_data['cleaned_html']} + + Please analyze this website in terms of SEO and provide detailed insights and recommendations. Your analysis should include, but not be limited to, the following: + + 1. Overall SEO performance of the website. + 2. Issues with meta tags, titles, and descriptions. + 3. Use of headings (H1, H2, H3, etc.) and their effectiveness. + 4. Keyword optimization and suggestions for improvement. + 5. Use of alt texts for images and suggestions for improvement. + 6. Analysis of internal and external links. + 7. Any missing critical SEO elements. + 8. Recommendations for improving the website's SEO. + + Provide your analysis in a structured format with actionable insights. + """ + +def generate_html_message(execution_id, user_id, product_id, response): + response_text = response['choices'][0]['message']['content'] + emojized_text = emoji.emojize(response_text) + html_str = markdown.markdown(emojized_text) + return f""" +
+

SEO Analysis Result

+

Execution ID: {execution_id}

+

User ID: {user_id}

+

Product ID: {product_id}

+

Analysis Results:
+

{html_str}
+

+
+ """ + +def send_result_to_wordpress(result): + post_data = json.dumps(result) + wordpress_url = 'https://promptintellect.com/wp-json/product-extension/v1/lambda-results' + + headers = { + 'Content-Type': 'application/json', + 'Content-Length': str(len(post_data)) + } + + response = requests.post(wordpress_url, headers=headers, data=post_data) + + if response.status_code != 200: + raise Exception(f"Unexpected status code: {response.status_code}, {response.text}") From 34eac50f20e1f87bc8342fad897535337f938ce0 Mon Sep 17 00:00:00 2001 From: Hojjat Date: Sat, 17 Aug 2024 16:22:28 +0330 Subject: [PATCH 7/7] Add new service for SEO competitor analysis --- .../SEO-rival-insights/lambda_function.py | 238 ++++++++++++++++++ .../URL-SEO-analyzer/lambda_function.py | 2 +- 2 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 site-sleuth/SEO-rival-insights/lambda_function.py diff --git a/site-sleuth/SEO-rival-insights/lambda_function.py b/site-sleuth/SEO-rival-insights/lambda_function.py new file mode 100644 index 0000000..4cf612a --- /dev/null +++ b/site-sleuth/SEO-rival-insights/lambda_function.py @@ -0,0 +1,238 @@ +import json +import boto3 +import os +import requests +import emoji +import markdown +from bs4 import BeautifulSoup, Comment + +s3_client = boto3.client('s3') +lambda_client = boto3.client('lambda') + +HEADERS = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate", + "Connection": "keep-alive", + "Upgrade-Insecure-Requests": "1", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "none", + "Sec-Fetch-User": "?1", + "Cache-Control": "max-age=0", +} + +def handler(event, context): + try: + # Extract environment variables + bucket_name = os.environ['PI_EXECUTION_S3_BUCKET_NAME'] + result_folder = os.environ['PI_RESULTS_FOLDER'] + openai_function = os.environ['PI_OPENAI_FUNCTION'] + + # Extract event data + execution_id = event['execution_id'] + user_id = event['user_id'] + product_id = event['product_id'] + token = event['token'] + custom_inputs = event['custom_inputs'] + competitor_url = custom_inputs['competitor_url'] + user_website_url = custom_inputs['user_website_url'] + + # Crawl and extract website content for both the user and competitor websites + user_data = crawl_website(user_website_url) + competitor_data = crawl_website(competitor_url) + + # Generate a detailed prompt for OpenAI to analyze the competitor + prompt = generate_competitor_analysis_prompt(user_data, competitor_data, user_website_url, competitor_url) + + # Invoke the OpenAI function for competitor SEO analysis + openai_payload = { + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "service": "chat-gpt-4o-mini", + "size": "11x", + "prompt": prompt + } + + response = lambda_client.invoke( + FunctionName=openai_function, + InvocationType='RequestResponse', + Payload=json.dumps(openai_payload) + ) + + response_payload = json.load(response['Payload']) + status_code = response_payload.get('status_code') + if status_code != 200: + raise Exception(f"OpenAI chat function returned {status_code} as status code with body {str(response_payload.get('body'))}") + function_result = response_payload.get('body') + + if function_result is None: + raise Exception("No result from OpenAI chat function") + + # Save the result to S3 + result_key = f"{result_folder}/{execution_id}/competitor_seo_result.json" + s3_client.put_object(Bucket=bucket_name, Key=result_key, Body=json.dumps(function_result, indent=4)) + + # Send the result as HTML to the endpoint + html_message = generate_html_message(execution_id, user_id, product_id, function_result) + + send_result_to_wordpress({ + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "successful", + "results": html_message + }) + + return { + 'statusCode': 200, + 'body': json.dumps({ + 'message': 'Task executed successfully' + }) + } + + except Exception as e: + print(f"Error: {str(e)}") + + send_result_to_wordpress({ + "execution_id": execution_id, + "user_id": user_id, + "product_id": product_id, + "token": token, + "status": "failed", + "results": f""" +
+

Error: {str(e)}

+
+ """ + }) + + return { + 'statusCode': 500, + 'body': json.dumps({ + 'message': str(e) + }) + } + +def crawl_website(url): + response = requests.get(url, headers=HEADERS) + html = response.text + + # Parse HTML using BeautifulSoup + soup = BeautifulSoup(html, 'html.parser') + + # Extract relevant SEO elements + title = soup.title.string if soup.title else "No title found" + description = soup.find("meta", {"name": "description"})['content'] if soup.find("meta", {"name": "description"}) else "No description found" + keywords = soup.find("meta", {"name": "keywords"})['content'] if soup.find("meta", {"name": "keywords"}) else "No keywords found" + h1_tags = [h1.get_text() for h1 in soup.find_all('h1')] + h2_tags = [h2.get_text() for h2 in soup.find_all('h2')] + h3_tags = [h3.get_text() for h3 in soup.find_all('h3')] + alt_texts = [img['alt'] for img in soup.find_all('img') if img.has_attr('alt')] + links = [a['href'] for a in soup.find_all('a') if a.has_attr('href')] + + # Removing unnecessary parts of the HTML + # Remove script, style, and comments + for script in soup(["script", "style"]): + script.extract() + comments = soup.findAll(text=lambda text: isinstance(text, Comment)) + [comment.extract() for comment in comments] + + # Remove unnecessary attributes from tags + for tag in soup.find_all(True): + # Only keep certain attributes for
tags + if tag.name == 'a': + attrs = {key: tag.attrs[key] for key in ['href'] if key in tag.attrs} + tag.attrs = attrs + # Remove all attributes for other tags + else: + tag.attrs = {} + + # Cleaned HTML content + cleaned_html = soup.prettify() + + crawled_data = { + "title": title, + "description": description, + "keywords": keywords, + "h1_tags": h1_tags, + "h2_tags": h2_tags, + "h3_tags": h3_tags, + "alt_texts": alt_texts, + "links": links, + "cleaned_html": cleaned_html # Reduced HTML content for analysis + } + + return crawled_data + +def generate_competitor_analysis_prompt(user_data, competitor_data, user_website_url, competitor_url): + return f""" + You are an expert in SEO analysis. I have provided you with the relevant crawled data from two websites: the user's website ({user_website_url}) and a competitor's website ({competitor_url}). + Here is the information for the user's website: + + - Title: {user_data['title']} + - Description: {user_data['description']} + - Keywords: {user_data['keywords']} + - H1 Tags: {', '.join(user_data['h1_tags'])} + - H2 Tags: {', '.join(user_data['h2_tags'])} + - H3 Tags: {', '.join(user_data['h3_tags'])} + - Alt Texts: {', '.join(user_data['alt_texts'])} + - Links: {', '.join(user_data['links'])} + - Cleaned HTML: ``` {user_data['cleaned_html']} ``` + + And here is the information for the competitor's website: + + - Title: {competitor_data['title']} + - Description: {competitor_data['description']} + - Keywords: {competitor_data['keywords']} + - H1 Tags: {', '.join(competitor_data['h1_tags'])} + - H2 Tags: {', '.join(competitor_data['h2_tags'])} + - H3 Tags: {', '.join(competitor_data['h3_tags'])} + - Alt Texts: {', '.join(competitor_data['alt_texts'])} + - Links: {', '.join(competitor_data['links'])} + - Cleaned HTML: ``` {competitor_data['cleaned_html']} ``` + + Please perform a detailed SEO competitor analysis, focusing on the following aspects: + + 1. Comparative SEO performance of the user's website and the competitor's website. + 2. Strengths and weaknesses of both websites in terms of SEO. + 3. Opportunities for the user to improve and outperform the competitor in SEO. + 4. Specific recommendations for improving the user's website SEO to gain an edge over the competitor. + + Provide your analysis in a structured format with actionable insights. + """ + +def generate_html_message(execution_id, user_id, product_id, response): + response_text = response['choices'][0]['message']['content'] + emojized_text = emoji.emojize(response_text) + html_str = markdown.markdown(emojized_text) + return f""" +
+

SEO Competitor Analysis Result

+

Execution ID: {execution_id}

+

User ID: {user_id}

+

Product ID: {product_id}

+

Analysis Results:
+

{html_str}
+

+
+ """ + +def send_result_to_wordpress(result): + post_data = json.dumps(result) + wordpress_url = 'https://promptintellect.com/wp-json/product-extension/v1/lambda-results' + + headers = { + 'Content-Type': 'application/json', + 'Content-Length': str(len(post_data)) + } + + response = requests.post(wordpress_url, data=post_data, headers=headers) + + if response.status_code != 200: + raise Exception(f"Failed to send result to WordPress. Status code: {response.status_code}, Response: {response.text}") + + return response.text diff --git a/site-sleuth/URL-SEO-analyzer/lambda_function.py b/site-sleuth/URL-SEO-analyzer/lambda_function.py index 034d789..ee1ed95 100644 --- a/site-sleuth/URL-SEO-analyzer/lambda_function.py +++ b/site-sleuth/URL-SEO-analyzer/lambda_function.py @@ -209,7 +209,7 @@ def generate_html_message(execution_id, user_id, product_id, response):

User ID: {user_id}

Product ID: {product_id}

Analysis Results:
-

{html_str}
+
{html_str}

"""