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
" +
+ "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 ?
+ "" + 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"""
+
+ """
+ })
+
+ 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"""
+
+ """
+ })
+
+ 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}
"""