postiz/libraries/nestjs-libraries/src/chat/tools/integration.schedule.post.ts

144 lines
5.0 KiB
TypeScript

import { AgentToolInterface } from '@gitroom/nestjs-libraries/chat/agent.tool.interface';
import { createTool } from '@mastra/core/tools';
import { z } from 'zod';
import { Injectable } from '@nestjs/common';
import {
IntegrationManager,
socialIntegrationList,
} from '@gitroom/nestjs-libraries/integrations/integration.manager';
import { validationMetadatasToSchemas } from 'class-validator-jsonschema';
import { IntegrationService } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.service';
import { RefreshToken } from '@gitroom/nestjs-libraries/integrations/social.abstract';
import { timer } from '@gitroom/helpers/utils/timer';
import { PostsService } from '@gitroom/nestjs-libraries/database/prisma/posts/posts.service';
import { makeId } from '@gitroom/nestjs-libraries/services/make.is';
import { AllProvidersSettings } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/all.providers.settings';
@Injectable()
export class IntegrationSchedulePostTool implements AgentToolInterface {
constructor(
private _postsService: PostsService,
private _integrationService: IntegrationService
) {}
name = 'integrationSchedulePostTool';
async run(): Promise<any> {
return createTool({
id: 'schedulePostTool',
description: `
This tool allows you to schedule a post to a social media platform, based on integrationSchema tool.
So for example:
If the user want to post a post to LinkedIn with one comment
- socialPost array length will be one
- postsAndComments array length will be two (one for the post, one for the comment)
If the user want to post 20 posts for facebook each in individual days without comments
- socialPost array length will be 20
- postsAndComments array length will be one
`,
requireApproval: true,
inputSchema: z.object({
socialPost: z.array(
z.object({
integrationId: z
.string()
.describe('The id of the integration (not internal id)'),
date: z.string().describe('The date of the post in UTC time'),
shortLink: z
.boolean()
.describe(
'If the post has a link inside, we can ask the user if they want to add a short link'
),
type: z
.enum(['draft', 'schedule', 'now'])
.describe(
'The type of the post, if we pass now, we should pass the current date also'
),
postsAndComments: z
.array(
z.object({
content: z.string().describe('The content of the post'),
image: z
.array(z.string())
.describe('The image of the post (URLS)'),
})
)
.describe(
'first item is the post, every other item is the comments'
),
settings: z
.array(
z.object({
key: z.string().describe('Name of the settings key to pass'),
value: z.string().describe('Value of the key'),
})
)
.describe(
'This relies on the integrationSchema tool to get the settings [input:settings]'
),
})
).describe('Individual post')
}),
outputSchema: z.object({
output: z.array(
z.object({
id: z.string(),
postId: z.string(),
releaseURL: z.string(),
status: z.string(),
})
),
}),
execute: async ({ runtimeContext, context }) => {
// @ts-ignore
const organizationId = runtimeContext.get('organization') as string;
const finalOutput = [];
for (const post of context.socialPost) {
const integration = await this._integrationService.getIntegrationById(
organizationId,
post.integrationId
);
if (!integration) {
throw new Error('Integration not found');
}
const output = await this._postsService.createPost(organizationId, {
date: post.date,
type: post.type as 'draft' | 'schedule' | 'now',
shortLink: post.shortLink,
tags: [],
posts: [
{
integration,
group: makeId(10),
settings: post.settings.reduce(
(acc, s) => ({
...acc,
[s.key]: s.value,
}),
{} as AllProvidersSettings
),
value: post.postsAndComments.map((p) => ({
content: p.content,
id: makeId(10),
image: p.image.map((p) => ({
id: makeId(10),
path: p,
})),
})),
},
],
});
finalOutput.push(...output);
}
return {
output: finalOutput,
};
},
});
}
}