Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(integration seed): script added #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integrationsSeed/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OPENAI_API_KEY=your_new_placeholder
2 changes: 2 additions & 0 deletions integrationsSeed/IntegrationsList.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
title,logoPng
Ferrari,
50 changes: 50 additions & 0 deletions integrationsSeed/PromptManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
type PromptType = "description" | "readme";

export class PromptManager {
private templates: Record<PromptType, (title: string) => string> = {
description: (title) => `
Provide a brief, keyword-optimized and SEO friendly description of the ${title} integration with Botpress. It needs to be 30 words or less. It must not use single quotes (') or double quotes ("). Very importatnt: no single or double quotes used.
Here's an example of a good description: Learn how to integrate Slack with AI and unlock advanced automation, productivity, and communication capabilities with generative AI.`,
readme: (title) => `
Generate an SEO-optimized README for the ${title} integration with Botpress. It must not use single quotes (') or double quotes ("). Very importatnt: no single or double quotes used. The first line always needs to be: "# Integrate ${title} with AI". Here is an example of a good README:
# Integrate Slack with AI
Unlock the full potential of Slack by integrating it with generative AI technologies. With AI, you can automate routine tasks, generate intelligent responses, analyze conversations in real time, and enhance team collaboration. From improving customer support with AI-powered bots to using natural language processing for more intuitive interactions, the possibilities are endless.
## What is Slack?
Slack is a cloud-based communication platform designed to streamline team collaboration. It offers real-time messaging, organized channels, and a wide range of integrations, making it a popular tool for businesses of all sizes. By integrating AI into Slack, you can enhance its core functionalities with advanced automation and data-driven insights.
## Benefits of Integrating Slack with AI
By integrating generative AI into Slack, your team can:
- **Automate responses**: Use AI to generate automatic responses to frequently asked questions, allowing your team to focus on more complex tasks.
- **Generate content**: Leverage generative AI to draft messages, reports, or summaries directly within Slack, speeding up content creation.
- **Real-time language translation**: With AI, you can instantly translate messages into multiple languages, making cross-border communication seamless.
- **Sentiment analysis**: Analyze team conversations with AI to gauge sentiment, track engagement, and improve team dynamics.
- **Task automation**: Integrate AI-powered task management to automatically assign, update, and track tasks based on conversation context.
## How to Set Up Slack AI Integrations
### 1. Slack AI Integration for Workflow Automation
Integrate Slack with AI to automate repetitive tasks. AI-powered bots can help with task management, reminders, and more, allowing your team to stay focused on high-priority work.
### 2. Using Slack AI Integration for Natural Language Processing (NLP)
With AI-driven NLP tools, Slack becomes even more intuitive. Your team can interact with bots in natural language, generating more accurate and conversational responses.
### 3. Boost Productivity with Slack AI Integration
AI-powered tools in Slack can help draft messages, reports, and summaries, drastically improving productivity by reducing the time spent on manual writing tasks.
### 4. Enhance Customer Support with Slack AI Integration
Integrate AI chatbots into your Slack channels to streamline customer support. AI can handle common queries, freeing up human agents to focus on more complex issues.
### 5. Real-time Analytics and Insights via Slack AI Integration
Generative AI can analyze conversations in real time, providing valuable insights on team dynamics, customer sentiment, and overall communication effectiveness. Use these insights to make data-driven decisions that improve productivity and collaboration.
## Explore More Slack AI Integration Use Cases
Integrating Slack with generative AI opens up a world of possibilities, from automating workflows to enhancing communication with AI-generated content. Here’s how other businesses are leveraging AI in Slack:
- Automating meeting notes and summaries.
- Generating creative ideas and brainstorming sessions with AI.
- Using AI-powered translation for global teams.
---
**Related Integrations:**
- [Google AI Integrations](https://botpress.com/integrations/google)
- [Microsoft Teams AI Integrations](https://botpress.com/integrations/microsoft-teams)
---
`,
};

constructor(private integrationTitle: string) {}

public getPrompt(type: PromptType): string {
return this.templates[type](this.integrationTitle);
}
}
28 changes: 28 additions & 0 deletions integrationsSeed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Integrations Seeding Script

This script allows you to seed integration data into your system with titles and logos. It uses OpenAI to assist in generating descriptions or other relevant metadata for each integration. If integration already exists, it will not be overwritten

## Prerequisites

Before starting, ensure that:

1. You are logged into the correct workspace. Your workspace should have both the handler and about information set up.

## Setup

Follow these steps to set up and use the project:

1. Clone this repository.
2. Add your OpenAI API key to the `.env` file:
```bash
OPENAI_API_KEY=your_openai_api_key
```
3. Populate the integrationsList.csv file with the integration titles and links to their PNG logos.
4. Install dependencies:
```bash
npm install
```
5. Run the seeding script
```bash
npm run seed
```
67 changes: 67 additions & 0 deletions integrationsSeed/handleLogo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import fs from "fs";
import { exec } from "child_process";
import { promisify } from "util";
import axios from "axios";
import sharp from "sharp";

const execAsync = promisify(exec);

async function downloadLogo(
url: string,
integrationPath: string
): Promise<void> {
console.log(`Attempting to download logo from ${url}`);

const response = await axios({
method: "get",
url: url,
responseType: "stream",
});

const contentType = response.headers["content-type"];
if (!contentType || !contentType.startsWith("image/")) {
throw new Error(
`Invalid content-type. Expected image/* but received ${contentType}`
);
}

const writer = fs.createWriteStream(`${integrationPath}/logo.png`);

response.data.pipe(writer);

return new Promise((resolve, reject) => {
writer.on("finish", resolve);
writer.on("error", reject);
});
}

async function convertLogoToSvg(integrationPath: string) {
console.log(`Attempting to convert logo to SVG`);

const pngPath = `${integrationPath}/logo.png`;
const svgPath = `${integrationPath}/logo.svg`;

const pngBuffer = await sharp(pngPath).png().toBuffer();
const base64Png = pngBuffer.toString("base64");

const svgContent = `
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<image href="data:image/png;base64,${base64Png}" width="200" height="200"/>
</svg>
`;

fs.writeFileSync(svgPath, svgContent);

await execAsync(`rm ${pngPath}`);
await execAsync(`mv ${svgPath} ${integrationPath}/icon.svg`);
console.log(`SVG file created at ${svgPath}`);
}

export async function handleLogo(integrationPath: string, logoUrl: string) {
console.log(`Handling logo for integration at ${integrationPath}`);
await downloadLogo(logoUrl, integrationPath);
await convertLogoToSvg(integrationPath);
console.log(
`Logo successfully handled for integration at ${integrationPath}`
);
}
64 changes: 64 additions & 0 deletions integrationsSeed/handleSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import "dotenv/config";
import { exec } from "child_process";
import { promisify } from "util";
import { OpenAI } from "openai";
import { PromptManager } from "PromptManager";

const execAsync = promisify(exec);

async function generateAiContent(prompt: string): Promise<string> {
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});

const chatCompletion = await client.chat.completions.create({
messages: [{ role: "user", content: prompt }],
model: "gpt-4o",
});

const description = chatCompletion.choices[0]?.message.content;

return description ?? "";
}

export async function handleSetup(
integrationPath: string,
title: string,
dashedTitle: string
): Promise<void> {
console.log(`Setting up ${title} integration`);
const promptManager = new PromptManager(title);

const descriptionPrompt = promptManager.getPrompt("description");
const description = await generateAiContent(descriptionPrompt);

console.log(`Successfully generated description for ${title} integration`);

await execAsync(`
sed -i '' $'6i\\
title: \\"${title}\\",\\
description: \\"${description}\\",\\
' ${integrationPath}/integration.definition.ts
`);

console.log(`Successfully inserted description for ${title} integration`);

const readmePrompt = promptManager.getPrompt("readme");
const readme = await generateAiContent(readmePrompt);

console.log(`Successfully generated README for ${title} integration`);

await execAsync(`echo "${readme}" > ${integrationPath}/hub.md`);

console.log(`Successfully inserted README for ${title} integration`);

await execAsync(
`
sed -i '' \
-e 's/"name": "placeholder_integration"/"name": "${dashedTitle}"/g' \
-e 's/"integrationName": "placeholder-integration"/"integrationName": "${dashedTitle}"/g' \
${integrationPath}/package.json
`
);
console.log(`Successfully inserted definitions into ${title} integration`);
}
72 changes: 72 additions & 0 deletions integrationsSeed/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import fs from "fs";
import csv from "csv-parser";
import { exec } from "child_process";
import { promisify } from "util";
import { handleLogo } from "./handleLogo";
import { handleSetup } from "./handleSetup";
const execAsync = promisify(exec);

interface CsvRow {
title: string;
logoPng: string;
}

function getDashedString(input: string): string {
return input
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^a-z0-9-]/g, "");
}

async function seedIntegrations() {
const csvRows: CsvRow[] = [];

const errors: string[] = [];

await new Promise((resolve, reject) => {
fs.createReadStream("./integrationsList.csv")
.pipe(csv())
.on("data", (data: CsvRow) => csvRows.push(data))
.on("end", resolve)
.on("error", reject);
});

for (const { title, logoPng } of csvRows) {
try {
console.log("=======================");
console.log("Seeding integration", title);

const dashedTitle = getDashedString(title);
const newPath = "../integrations/" + dashedTitle;

await execAsync(`cp -R ./placeholder-integration ${newPath}`);

await handleLogo(
newPath,
logoPng || `https://logo.clearbit.com/${title}.com`
);

await handleSetup(newPath, title, dashedTitle);

console.log(`Attempting to publicly deploy ${title} integration`);

await execAsync(`cd ${newPath} && npm i && bp deploy -y --public`);

console.log(
"\x1b[1m\x1b[32m%s\x1b[0m",
`Successfully publicly deployed ${title} integration`
);
} catch (e) {
console.log(e);
if (e instanceof Error) {
errors.push(`Error seeding ${title}: ${e.message}`);
} else {
errors.push(`Unknown error seeding ${title}`);
}
}
}
console.log("Finished processing with the following errors:");
errors.forEach((error) => console.error(error));
}

seedIntegrations();
Loading