diff --git a/workflows/Generate LinkedIn Activity Reports via Slack Commands with GPT-4.1 and Email-11052/readme-11052.md b/workflows/Generate LinkedIn Activity Reports via Slack Commands with GPT-4.1 and Email-11052/readme-11052.md new file mode 100644 index 000000000..76b3d3423 --- /dev/null +++ b/workflows/Generate LinkedIn Activity Reports via Slack Commands with GPT-4.1 and Email-11052/readme-11052.md @@ -0,0 +1,415 @@ +Generate LinkedIn Activity Reports via Slack Commands with GPT-4.1 and Email + +https://n8nworkflows.xyz/workflows/generate-linkedin-activity-reports-via-slack-commands-with-gpt-4-1-and-email-11052 + + +# Generate LinkedIn Activity Reports via Slack Commands with GPT-4.1 and Email + +### 1. Workflow Overview + +This n8n workflow enables users to generate detailed LinkedIn activity reports by invoking a Slack slash command. When a user types `/check-linkedin [firstName lastName]` in Slack, the workflow extracts the name, finds the corresponding LinkedIn profile using Apify actors, scrapes recent posts, and uses GPT-4.1 AI models to analyze posting frequency, topics, and highlights. Finally, it composes a formatted HTML report and sends it via email to a designated recipient. + +The workflow is logically divided into these blocks: + +- **1.1 Slack Command Intake & Validation:** Receive Slack slash command input, validate if it contains a full name. +- **1.2 Name Extraction:** Use GPT to extract first and last names from the input. +- **1.3 LinkedIn Profile Lookup:** Use Apify actors to find the LinkedIn profile URL for the extracted name. +- **1.4 LinkedIn Posts Scraping:** Scrape recent LinkedIn posts of the profile. +- **1.5 Posts Aggregation:** Aggregate and structure the scraped posts for analysis. +- **1.6 AI Analysis & Summarization:** Use GPT-4.1 and a Langchain structured output parser to analyze posts and generate a detailed summary. +- **1.7 HTML Report Generation & Email Delivery:** Format the AI summary into an HTML report and email it to the requester. +- **1.8 Error Handling & Slack Feedback:** Notify Slack if the input name is invalid. + +--- + +### 2. Block-by-Block Analysis + +--- + +#### 1.1 Slack Command Intake & Validation + +**Overview:** +This block receives the Slack slash command POST request, checks if the input text is a full name, branching to error messaging if not. + +**Nodes Involved:** +- Webhook +- GPT 4.1-mini for classification +- Do we have a full name ? (text classifier) +- Tell on slack that no full name was found + +**Node Details:** +- **Webhook** + - Type: HTTP Webhook (POST) + - Configuration: Receives Slack slash command at a defined path (placeholder to be replaced) + - Input: Slack slash command payload (JSON) + - Output: Passes the raw Slack command data downstream + - Edge cases: Invalid HTTP method or malformed requests + +- **GPT 4.1-mini for classification** + - Type: OpenAI GPT chat model (GPT 4.1-mini) + - Role: Classify if input text is a full name or not + - Input: `{{ $json.body.text }}` (text entered in Slack command) + - Output: Prediction used for branching + - Edge cases: API errors, rate limiting, classification uncertainty + +- **Do we have a full name ?** + - Type: Text Classifier node (Langchain) + - Role: Categorize input as "full-name" or "not-full-name" + - InputText: `{{ $json.body.text }}` + - Categories: "full-name", "not-full-name" + - Output: Branches workflow based on category + - Edge cases: Misclassification, expression evaluation failures + +- **Tell on slack that no full name was found** + - Type: Slack node (chat message) + - Role: Sends a message back to the Slack channel notifying the user that the input was not a full name + - Configuration: Uses OAuth2 Slack credential, posts to the originating channel `{{ $json.body.channel_id }}` + - Input: Triggered if name classification is negative + - Edge cases: Slack API auth failures, invalid channel IDs + +--- + +#### 1.2 Name Extraction + +**Overview:** +Extract first name and last name explicitly from the validated input text using GPT. + +**Nodes Involved:** +- GPT 4.1-mini to extract firstName + lastName +- Extract firstName and lastName (Information Extractor node) + +**Node Details:** +- **GPT 4.1-mini to extract firstName + lastName** + - Type: OpenAI GPT chat model (GPT 4.1-mini) + - Role: Refine and normalize the name extraction process + - Input: Raw Slack command text + - Output: Passes text to the information extractor node + - Edge cases: API errors, ambiguous names + +- **Extract firstName and lastName** + - Type: Langchain Information Extractor + - Role: Identifies and extracts structured attributes: `firstName` and `lastName` + - Input: Text from previous GPT node + - Output: JSON with `firstName` and `lastName` fields (both required) + - Edge cases: Missing attributes, parsing failures + +--- + +#### 1.3 LinkedIn Profile Lookup + +**Overview:** +Find the LinkedIn profile URL for the extracted person using Apify actor. + +**Nodes Involved:** +- Find Linkedin Profile (Apify actor) +- Get Linkedin Profile URL (Apify dataset query) + +**Node Details:** +- **Find Linkedin Profile** + - Type: Apify actor call + - Role: Runs an Apify actor (configured via URL) that searches LinkedIn based on the first and last name + - Input: JSON body with `firstName` and `lastName` + - Output: Returns datasetId for collected profile data + - Edge cases: Actor timeout, invalid input, no profile found + +- **Get Linkedin Profile URL** + - Type: Apify dataset query + - Role: Retrieves profile URL from Apify dataset using the datasetId from previous node + - Input: Uses `defaultDatasetId` from previous node + - Output: Extracted LinkedIn profile URL (`linkedinProfileUrl`) + - Edge cases: Dataset empty, API errors + +--- + +#### 1.4 LinkedIn Posts Scraping + +**Overview:** +Scrape recent posts of the found LinkedIn profile via another Apify actor. + +**Nodes Involved:** +- Scrap what this person posted recently (Apify actor) +- Structure recent posts (Apify dataset query) +- Aggregate (Aggregate node) + +**Node Details:** +- **Scrap what this person posted recently** + - Type: Apify actor call + - Role: Runs Apify actor to scrape LinkedIn posts for the given profile URL + - Input: JSON body with `usernames` array containing the LinkedIn profile URL + - Output: Dataset id for scraped posts + - Edge cases: Actor failure, rate limits, empty posts + +- **Structure recent posts** + - Type: Apify dataset query + - Role: Retrieves up to 20 recent posts from Apify dataset + - Input: Dataset ID from scraping node + - Output: List of post objects with text and posted_at.date properties + - Edge cases: Empty dataset, partial data + +- **Aggregate** + - Type: Aggregate node (standard n8n) + - Role: Collects and merges fields `posted_at.date` and `text` from the posts into a single object + - Input: List of recent posts + - Output: Aggregated JSON data for analysis + - Edge cases: Empty input array, aggregation errors + +--- + +#### 1.5 AI Analysis & Summarization + +**Overview:** +Analyze aggregated LinkedIn posts data with GPT 4.1 to generate a detailed analytical summary following a strict JSON schema. + +**Nodes Involved:** +- Summer McBriefing (Langchain Agent) +- Structured Output Parser (Langchain Output Parser) +- GPT 4.1 (OpenAI chat model) + +**Node Details:** +- **Summer McBriefing** + - Type: Langchain Agent (AI language model with custom prompt) + - Role: Receives aggregated post dates and text, generates a JSON report including posting frequency, topics, highlights, and data quality stats + - Prompt: Detailed instructions to produce exactly the required JSON schema, no extra fields or prose + - Input: Aggregated dates and texts from previous nodes + - Output: JSON object matching LinkedInPostsAnalysis schema + - Edge cases: Parsing ambiguity, incomplete input data, GPT API errors + +- **Structured Output Parser** + - Type: Langchain Output Parser + - Role: Validates and enforces JSON structure according to the provided JSON schema + - Input: Raw JSON from Summer McBriefing + - Output: Structured, validated JSON for further processing + - Edge cases: Schema validation failures, parser errors + +- **GPT 4.1** + - Type: OpenAI GPT chat model (GPT 4.1) + - Role: Connected as AI languageModel input to Summer McBriefing (used internally) + - Edge cases: API failures, rate limits + +--- + +#### 1.6 HTML Report Generation & Email Delivery + +**Overview:** +Generate an HTML report from the structured AI output and send it by email to a configured recipient. + +**Nodes Involved:** +- HTML (HTML generation) +- Send report via Email (Gmail node) +- Sticky Note12 (Contact info) + +**Node Details:** +- **HTML** + - Type: HTML node (n8n built-in) + - Role: Formats the JSON report into a styled, professional HTML email + - Uses Mustache-style expressions to inject AI output and extracted names into the template + - Includes summary, posting frequency, topics, and highlights in a visually clear layout + - Edge cases: Missing JSON fields, malformed HTML + +- **Send report via Email** + - Type: Gmail node (OAuth2) + - Role: Sends the generated HTML email to a fixed recipient (`admin@example.com`) + - Subject includes person’s name dynamically: `Recent LinkedIn Activity about [personName]` + - Requires Gmail OAuth2 credentials + - Edge cases: Email sending failures, auth errors, invalid recipient + +- **Sticky Note12** + - Type: Sticky Note + - Role: Contains contact information for questions or feedback (email and LinkedIn) + - No direct functional role in automation + +--- + +#### 1.7 Error Handling & Slack Feedback + +**Overview:** +If the input text is not a full name, this block provides user feedback on Slack. + +**Nodes Involved:** +- Tell on slack that no full name was found +- Sticky Note1 (Error handling explanation) + +**Node Details:** +- **Tell on slack that no full name was found** + - As described in 1.1 +- **Sticky Note1** + - Provides a note reminding the user about error handling for no full name found input + +--- + +### 3. Summary Table + +| Node Name | Node Type | Functional Role | Input Node(s) | Output Node(s) | Sticky Note | +|-----------------------------------|--------------------------------------|----------------------------------------------|-------------------------------|--------------------------------|---------------------------------------------------------------| +| Webhook | Webhook | Receive Slack slash command request | — | GPT 4.1-mini for classification | | +| GPT 4.1-mini for classification | OpenAI GPT chat model | Classify if input is a full name | Webhook | Do we have a full name ? | | +| Do we have a full name ? | Text classifier (Langchain) | Branch workflow on full name check | GPT 4.1-mini for classification | Extract firstName and lastName / Tell on slack no full name | Sticky Note1: No full name found error handling | +| Tell on slack that no full name was found | Slack message node | Notify user on Slack of invalid input | Do we have a full name ? | — | Sticky Note1: No full name found error handling | +| GPT 4.1-mini to extract firstName + lastName | OpenAI GPT chat model | Extract first and last name from input | Do we have a full name ? | Extract firstName and lastName | | +| Extract firstName and lastName | Langchain Information Extractor | Extract structured firstName and lastName | GPT 4.1-mini to extract names | Find Linkedin Profile | | +| Find Linkedin Profile | Apify actor | Find LinkedIn profile URL from name | Extract firstName and lastName | Get Linkedin Profile URL | Sticky Note3: Data gathering via Apify | +| Get Linkedin Profile URL | Apify dataset query | Retrieve LinkedIn profile URL | Find Linkedin Profile | Scrap what this person posted recently | Sticky Note3: Data gathering via Apify | +| Scrap what this person posted recently | Apify actor | Scrape recent LinkedIn posts | Get Linkedin Profile URL | Structure recent posts | Sticky Note3: Data gathering via Apify | +| Structure recent posts | Apify dataset query | Retrieve structured posts (limit 20) | Scrap what this person posted recently | Aggregate | Sticky Note3: Data gathering via Apify | +| Aggregate | Aggregate node | Aggregate post dates and texts | Structure recent posts | Summer McBriefing | Sticky Note4: Summarization & Intelligence Layer | +| Summer McBriefing | Langchain Agent | Analyze posts and generate JSON report | Aggregate | HTML | Sticky Note4: Summarization & Intelligence Layer | +| Structured Output Parser | Langchain Output Parser | Validate and structure AI output JSON | Summer McBriefing | Summer McBriefing (loop back) | | +| HTML | HTML node | Format JSON summary into styled HTML email | Summer McBriefing | Send report via Email | Sticky Note5: HTML Output & Email | +| Send report via Email | Gmail node | Email the report to recipient | HTML | — | | +| Sticky Note12 | Sticky Note | Contact info for questions and feedback | — | — | | +| Sticky Note | Sticky Note | Workflow overview and instructions | — | — | | +| Sticky Note2 | Sticky Note | Slack intake and parsing explanation | — | — | | +| Sticky Note3 | Sticky Note | Notes on Apify data gathering | — | — | Sticky Note3: Data gathering via Apify | +| Sticky Note4 | Sticky Note | Summarization and AI layer explanation | — | — | Sticky Note4: Summarization & Intelligence Layer | +| Sticky Note5 | Sticky Note | HTML output and email explanation | — | — | Sticky Note5: HTML Output & Response via Email | +| Sticky Note9 | Sticky Note | Video walkthrough link | — | — | # 🎙️ Video Walkthrough @[youtube](-4VwNYsOIPc) | + +--- + +### 4. Reproducing the Workflow from Scratch + +1. **Create Webhook Node** + - Type: Webhook + - HTTP Method: POST + - Path: `/path-placeholder-to-be-replaced-by-your-webhook` (replace with your actual path) + - Purpose: Receive Slack slash command payloads + +2. **Add GPT 4.1-mini for Classification Node** + - Type: OpenAI GPT chat model + - Model: `gpt-4.1-mini` + - Input: Text from `Webhook` node — `{{$json.body.text}}` + - Purpose: Classify if input is a full name or not + +3. **Add Text Classifier Node "Do we have a full name ?"** + - Type: Langchain Text Classifier + - Input Text: `{{$json.body.text}}` + - Categories: + - `full-name` (input is a full name) + - `not-full-name` (otherwise) + - Connect from GPT classification node + - Purpose: Branch the workflow + +4. **Add Slack Node for Invalid Name Feedback** + - Type: Slack + - Action: Send Message to Channel + - Channel: `{{$json.body.channel_id}}` (from Webhook) + - Text: `"{{$json.body.text}} is not a full name. Please send a full name to get information."` + - Authentication: OAuth2 (Slack credentials) + - Connect from classifier node on `not-full-name` branch + +5. **Add GPT 4.1-mini to Extract First and Last Name** + - Model: `gpt-4.1-mini` + - Input: Slack command text `{{$json.body.text}}` + - Connect from classifier node on `full-name` branch + +6. **Add Information Extractor Node** + - Type: Langchain Information Extractor + - Input Text: Output text from previous GPT node + - Attributes: + - `firstName` (required) + - `lastName` (required) + - Connect from GPT extraction node + +7. **Add Apify Actor Node "Find Linkedin Profile"** + - Actor URL: `https://console.apify.com/actors/FbqC9BRstFBddhUqj/input` + - Input JSON Body: + ```json + { + "firstName": "{{ $json.output.firstName }}", + "lastName": "{{ $json.output.lastName }}" + } + ``` + - Connect from Information Extractor node + - Credentials: Apify API key + +8. **Add Apify Dataset Query Node "Get Linkedin Profile URL"** + - Resource: Datasets + - Dataset ID: `={{ $json.defaultDatasetId }}` (from previous node) + - Connect from "Find Linkedin Profile" + +9. **Add Apify Actor Node "Scrap what this person posted recently"** + - Actor URL: `https://console.apify.com/actors/r4oNX7IHlW4RQAjKP` + - Input JSON Body: + ```json + { + "usernames": ["{{ $json.linkedinProfileUrl }}"] + } + ``` + - Connect from "Get Linkedin Profile URL" + - Credentials: Apify API key + +10. **Add Apify Dataset Query Node "Structure recent posts"** + - Resource: Datasets + - Dataset ID: `={{ $json.defaultDatasetId }}` (from previous node) + - Limit: 20 + - Connect from "Scrap what this person posted recently" + +11. **Add Aggregate Node** + - Fields to Aggregate: + - `posted_at.date` + - `text` + - Connect from "Structure recent posts" + +12. **Add Langchain Agent Node "Summer McBriefing"** + - Text Input Template: + ``` + Dates: + {{ $json.date }} + + Posts: + {{ $json.text }} + ``` + - System Message: Detailed analytical instructions to produce JSON summary with posting frequency, topics, highlights, and data quality + - Input: Connect from Aggregate node + - Built-in Tools: GPT 4.1 model (configured) + - Credentials: OpenAI API key + +13. **Add Langchain Output Parser Node "Structured Output Parser"** + - Schema: Use the detailed LinkedInPostsAnalysis JSON schema embedded in the workflow + - Connect as AI output parser to "Summer McBriefing" node + +14. **Add HTML Node** + - Paste the provided HTML template from the workflow, including placeholders for dynamic data injection using n8n expressions, e.g., `{{ $json.output.latest_post_date }}` + - Connect from "Summer McBriefing" node output + +15. **Add Gmail Node "Send report via Email"** + - Send To: `admin@example.com` (replace with desired recipient) + - Subject: `Recent LinkedIn Activity about {{ $('Get Linkedin Profile URL').item.json.personName }}` + - Message: `={{ $json.html }}` (HTML output from previous node) + - Credentials: Gmail OAuth2 credentials configured in n8n + - Connect from HTML node + +16. **Set up Slack App and Slash Command** + - Create Slack App with `/check-linkedin` slash command + - Set Request URL to your n8n webhook URL path + - Ensure Slack OAuth2 credentials have `chat:write` and `commands` scopes + +17. **Configure Credentials** + - Apify API key with access to required actors + - OpenAI API key with GPT 4.1 and GPT 4.1-mini + - Slack OAuth2 token with required scopes + - Gmail OAuth2 account for sending emails + +18. **Testing & Validation** + - Test slash command with valid full names to verify end-to-end functionality + - Test with invalid inputs to verify error handling messages in Slack + - Monitor Apify actor usage and costs + - Monitor OpenAI API usage and costs + +--- + +### 5. General Notes & Resources + +| Note Content | Context or Link | +|----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------| +| Slack Slash Command: Run `/check-linkedin [firstName lastName]` in Slack to get LinkedIn activity. | Sticky Note overview at the start of the workflow | +| Workflow requires two Apify actors for LinkedIn profile lookup and post scraping. | Sticky Note3: Data gathering via Apify | +| Summarization and intelligence layer uses GPT 4.1 with a detailed JSON schema for output format. | Sticky Note4: Summarization & Intelligence Layer | +| HTML email format includes profile name, activity stats, topics, and highlights. | Sticky Note5: HTML Output & Response via Email | +| Video walkthrough available on YouTube: `@[youtube](-4VwNYsOIPc)` | Sticky Note9: Video Walkthrough | +| Contact for feedback: Emir Belkahia, email: emir.belkahia@gmail.com, LinkedIn: linkedin.com/in/emirbelkahia | Sticky Note12 | +| Cost considerations: Apify actors and GPT calls incur usage costs; optimize parameters accordingly. | Sticky Note3 and Sticky Note4 | + +--- + +This document comprehensively covers the workflow logic, node configurations, integration points, and reproduction steps to facilitate thorough understanding, modification, and deployment by advanced users or automation agents. \ No newline at end of file