mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 07:48:37 +01:00
Add advanced ai
This commit is contained in:
30
dashboard/server/ai/Plugin.ts
Normal file
30
dashboard/server/ai/Plugin.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
import type OpenAI from 'openai'
|
||||
|
||||
|
||||
export type AIPlugin_TTool<T extends string> = (OpenAI.Chat.Completions.ChatCompletionTool & { function: { name: T } });
|
||||
export type AIPlugin_TFunction<T extends string> = (...args: any[]) => any;
|
||||
|
||||
type AIPlugin_Constructor<Items extends string[]> = {
|
||||
[Key in Items[number]]: {
|
||||
tool: AIPlugin_TTool<Key>,
|
||||
handler: AIPlugin_TFunction<Key>
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class AIPlugin<Items extends string[] = []> {
|
||||
constructor(public functions: AIPlugin_Constructor<Items>) { }
|
||||
|
||||
getTools() {
|
||||
const keys = Object.keys(this.functions) as Items;
|
||||
return keys.map((key: Items[number]) => { return this.functions[key].tool });
|
||||
}
|
||||
getHandlers() {
|
||||
const keys = Object.keys(this.functions) as Items;
|
||||
const result: Record<string, any> = {};
|
||||
keys.forEach((key: Items[number]) => {
|
||||
result[key] = this.functions[key].handler;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
67
dashboard/server/ai/functions/AI_ComposableChart.ts
Normal file
67
dashboard/server/ai/functions/AI_ComposableChart.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
|
||||
import { AIPlugin } from "../Plugin";
|
||||
|
||||
export class AiComposableChart extends AIPlugin<['createComposableChart']> {
|
||||
constructor() {
|
||||
super({
|
||||
'createComposableChart': {
|
||||
handler: (data: { labels: string, points: number[] }) => {
|
||||
return { ok: true };
|
||||
},
|
||||
tool: {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'createComposableChart',
|
||||
description: 'Creates a chart based on the provided datasets',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
labels: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
description: 'Labels for each data point in the chart'
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Title of the chart to let user understand what is displaying, not include dates'
|
||||
},
|
||||
datasets: {
|
||||
type: 'array',
|
||||
description: 'List of datasets',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
chartType: {
|
||||
type: 'string',
|
||||
enum: ['line', 'bar'],
|
||||
description: 'The type of chart to display the dataset, either "line" or "bar"'
|
||||
},
|
||||
points: {
|
||||
type: 'array',
|
||||
items: { type: 'number' },
|
||||
description: 'Numerical values for each data point in the chart'
|
||||
},
|
||||
color: {
|
||||
type: 'string',
|
||||
description: 'Color used to represent the dataset'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Name of the dataset'
|
||||
}
|
||||
},
|
||||
required: ['points', 'color', 'chartType', 'name'],
|
||||
description: 'Data points and style information for the dataset'
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['labels', 'datasets', 'title']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const AiComposableChartInstance = new AiComposableChart();
|
||||
80
dashboard/server/ai/functions/AI_Events.ts
Normal file
80
dashboard/server/ai/functions/AI_Events.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { EventModel } from "@schema/metrics/EventSchema";
|
||||
import { executeTimelineAggregation, fillAndMergeTimelineAggregationV2 } from "~/server/services/TimelineService";
|
||||
import { Types } from "mongoose";
|
||||
import { AIPlugin, AIPlugin_TTool } from "../Plugin";
|
||||
|
||||
|
||||
const getEventsCountTool: AIPlugin_TTool<'getEventsCount'> = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'getEventsCount',
|
||||
description: 'Gets the number of events received on a date range, can also specify the event name and the metadata associated',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' },
|
||||
name: { type: 'string', description: 'Name of the events to get' },
|
||||
metadata: { type: 'object', description: 'Metadata of events to get' },
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getEventsTimelineTool: AIPlugin_TTool<'getEventsTimeline'> = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'getEventsTimeline',
|
||||
description: 'Gets an array of date and count for events received on a date range. Should be used to create charts.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' },
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AiEvents extends AIPlugin<['getEventsCount', 'getEventsTimeline']> {
|
||||
|
||||
constructor() {
|
||||
|
||||
super({
|
||||
'getEventsCount': {
|
||||
handler: async (data: { project_id: string, from?: string, to?: string, name?: string, metadata?: string }) => {
|
||||
const query: any = {
|
||||
project_id: data.project_id,
|
||||
created_at: {
|
||||
$gt: data.from ? new Date(data.from).getTime() : new Date(2023).getTime(),
|
||||
$lt: data.to ? new Date(data.to).getTime() : new Date().getTime(),
|
||||
}
|
||||
}
|
||||
if (data.metadata) query.metadata = data.metadata;
|
||||
if (data.name) query.name = data.name;
|
||||
const result = await EventModel.countDocuments(query);
|
||||
return { count: result };
|
||||
},
|
||||
tool: getEventsCountTool
|
||||
},
|
||||
'getEventsTimeline': {
|
||||
handler: async (data: { project_id: string, from: string, to: string }) => {
|
||||
const timelineData = await executeTimelineAggregation({
|
||||
projectId: new Types.ObjectId(data.project_id) as any,
|
||||
model: EventModel,
|
||||
from: data.from, to: data.to, slice: 'day'
|
||||
});
|
||||
const timelineFilledMerged = fillAndMergeTimelineAggregationV2(timelineData, 'day', data.from, data.to);
|
||||
return { data: timelineFilledMerged };
|
||||
},
|
||||
tool: getEventsTimelineTool
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const AiEventsInstance = new AiEvents();
|
||||
|
||||
87
dashboard/server/ai/functions/AI_Visits.ts
Normal file
87
dashboard/server/ai/functions/AI_Visits.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { VisitModel } from "@schema/metrics/VisitSchema";
|
||||
import { AdvancedTimelineAggregationOptions, executeAdvancedTimelineAggregation, executeTimelineAggregation, fillAndMergeTimelineAggregationV2 } from "~/server/services/TimelineService";
|
||||
import { Types } from "mongoose";
|
||||
import { AIPlugin, AIPlugin_TTool } from "../Plugin";
|
||||
|
||||
|
||||
const getVisitsCountsTool: AIPlugin_TTool<'getVisitsCount'> = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'getVisitsCount',
|
||||
description: 'Gets the number of visits received on a date range',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' },
|
||||
website: { type: 'string', description: 'The website of the visits' },
|
||||
page: { type: 'string', description: 'The page of the visit' }
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getVisitsTimelineTool: AIPlugin_TTool<'getVisitsTimeline'> = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'getVisitsTimeline',
|
||||
description: 'Gets an array of date and count for events received on a date range. Should be used to create charts.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' },
|
||||
website: { type: 'string', description: 'The website of the visits' },
|
||||
page: { type: 'string', description: 'The page of the visit' }
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AiVisits extends AIPlugin<['getVisitsCount', 'getVisitsTimeline']> {
|
||||
|
||||
constructor() {
|
||||
|
||||
super({
|
||||
'getVisitsCount': {
|
||||
handler: async (data: { project_id: string, from?: string, to?: string, website?: string, page?: string }) => {
|
||||
const query: any = {
|
||||
project_id: data.project_id,
|
||||
created_at: {
|
||||
$gt: data.from ? new Date(data.from).getTime() : new Date(2023).getTime(),
|
||||
$lt: data.to ? new Date(data.to).getTime() : new Date().getTime(),
|
||||
}
|
||||
}
|
||||
if (data.website) query.website = data.website;
|
||||
if (data.page) query.page = data.page;
|
||||
const result = await VisitModel.countDocuments(query);
|
||||
return { count: result };
|
||||
},
|
||||
tool: getVisitsCountsTool
|
||||
},
|
||||
'getVisitsTimeline': {
|
||||
handler: async (data: { project_id: string, from: string, to: string, website?: string, page?: string }) => {
|
||||
const query: AdvancedTimelineAggregationOptions & { customMatch: Record<string, any> } = {
|
||||
projectId: new Types.ObjectId(data.project_id) as any,
|
||||
model: VisitModel,
|
||||
from: data.from, to: data.to, slice: 'day',
|
||||
customMatch: {}
|
||||
}
|
||||
|
||||
if (data.website) query.customMatch.website = data.website;
|
||||
if (data.page) query.customMatch.page = data.page;
|
||||
|
||||
const timelineData = await executeAdvancedTimelineAggregation(query);
|
||||
const timelineFilledMerged = fillAndMergeTimelineAggregationV2(timelineData, 'day', data.from, data.to);
|
||||
return { data: timelineFilledMerged };
|
||||
},
|
||||
tool: getVisitsTimelineTool
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export const AiVisitsInstance = new AiVisits();
|
||||
@@ -1,8 +1,5 @@
|
||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||
import { AiChatModel } from "@schema/ai/AiChatSchema";
|
||||
import { sendMessageOnChat } from "~/server/services/AiService";
|
||||
|
||||
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||
import { AiChatModel } from "@schema/ai/AiChatSchema";
|
||||
import { sendMessageOnChat } from "~/server/services/AiService";
|
||||
|
||||
|
||||
import type OpenAI from "openai";
|
||||
import { getChartsInMessage } from "~/server/services/AiService";
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
@@ -19,11 +18,14 @@ export default defineEventHandler(async event => {
|
||||
const chat = await AiChatModel.findOne({ _id: chat_id, project_id });
|
||||
if (!chat) return;
|
||||
|
||||
const messages = chat.messages.filter(e => {
|
||||
return (e.role == 'user' || (e.role == 'assistant' && e.content != undefined))
|
||||
}).map(e => {
|
||||
return { role: e.role, content: e.content }
|
||||
});
|
||||
|
||||
return messages;
|
||||
return (chat.messages as OpenAI.Chat.Completions.ChatCompletionMessageParam[])
|
||||
.filter(e => e.role === 'assistant' || e.role === 'user')
|
||||
.map(e => {
|
||||
const charts = getChartsInMessage(e);
|
||||
const content = e.content;
|
||||
return { role: e.role, content, charts }
|
||||
})
|
||||
.filter(e=>{
|
||||
return e.charts.length > 0 || e.content
|
||||
})
|
||||
});
|
||||
@@ -23,5 +23,6 @@ export default defineEventHandler(async event => {
|
||||
if (chatsRemaining <= 0) return setResponseStatus(event, 400, 'CHAT_LIMIT_REACHED');
|
||||
|
||||
const response = await sendMessageOnChat(text, project._id.toString(), chat_id);
|
||||
return response || 'Error getting response';
|
||||
|
||||
return response;
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
import OpenAI from "openai";
|
||||
import { EventModel } from "@schema/metrics/EventSchema";
|
||||
|
||||
|
||||
export const AI_EventsFunctions = {
|
||||
getEventsCount: ({ pid, from, to, name, metadata }: any) => {
|
||||
return getEventsCountForAI(pid, from, to, name, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const getEventsCountForAIDeclaration: OpenAI.Chat.Completions.ChatCompletionTool = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'getEventsCount',
|
||||
description: 'Gets the number of events received on a date range, can also specify the event name and the metadata associated',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' },
|
||||
name: { type: 'string', description: 'Name of the events to get' },
|
||||
metadata: { type: 'object', description: 'Metadata of events to get' },
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const AI_EventsTools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
|
||||
getEventsCountForAIDeclaration
|
||||
]
|
||||
|
||||
export async function getEventsCountForAI(project_id: string, from?: string, to?: string, name?: string, metadata?: string) {
|
||||
|
||||
const query: any = {
|
||||
project_id,
|
||||
created_at: {
|
||||
$gt: from ? new Date(from).getTime() : new Date(2023).getTime(),
|
||||
$lt: to ? new Date(to).getTime() : new Date().getTime(),
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata) query.metadata = metadata;
|
||||
if (name) query.name = name;
|
||||
|
||||
const result = await EventModel.countDocuments(query);
|
||||
|
||||
return { count: result };
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { VisitModel } from "@schema/metrics/VisitSchema";
|
||||
|
||||
|
||||
|
||||
export async function getVisitsCountFromDateRange(project_id: string, from?: string, to?: string) {
|
||||
const result = await VisitModel.countDocuments({
|
||||
project_id,
|
||||
created_at: {
|
||||
$gt: from ? new Date(from).getTime() : new Date(2023).getTime(),
|
||||
$lt: to ? new Date(to).getTime() : new Date().getTime(),
|
||||
}
|
||||
});
|
||||
return { count: result };
|
||||
}
|
||||
@@ -8,11 +8,6 @@ const config = useRuntimeConfig();
|
||||
let connection: mongoose.Mongoose;
|
||||
|
||||
|
||||
let anomalyMinutesCount = 0;
|
||||
function anomalyCheck() {
|
||||
|
||||
}
|
||||
|
||||
export default async () => {
|
||||
|
||||
console.log('[SERVER] Initializing');
|
||||
|
||||
@@ -1,59 +1,35 @@
|
||||
|
||||
import { getVisitsCountFromDateRange } from '~/server/api/ai/functions/AI_Visits';
|
||||
|
||||
import OpenAI from "openai";
|
||||
import { AiChatModel } from '@schema/ai/AiChatSchema';
|
||||
import { AI_EventsFunctions, AI_EventsTools } from '../api/ai/functions/AI_Events';
|
||||
import { ProjectCountModel } from '@schema/ProjectsCounts';
|
||||
import { ProjectLimitModel } from '@schema/ProjectsLimits';
|
||||
|
||||
import { AiEventsInstance } from '../ai/functions/AI_Events';
|
||||
import { AiVisitsInstance } from '../ai/functions/AI_Visits';
|
||||
import { AiComposableChartInstance } from '../ai/functions/AI_ComposableChart';
|
||||
|
||||
const { AI_ORG, AI_PROJECT, AI_KEY } = useRuntimeConfig();
|
||||
|
||||
const OPENAI_MODEL: OpenAI.Chat.ChatModel = 'gpt-4o-mini';
|
||||
|
||||
const openai = new OpenAI({
|
||||
organization: AI_ORG,
|
||||
project: AI_PROJECT,
|
||||
apiKey: AI_KEY
|
||||
});
|
||||
|
||||
|
||||
// const get_current_date: OpenAI.Chat.Completions.ChatCompletionTool = {
|
||||
// type: 'function',
|
||||
// function: {
|
||||
// name: 'get_current_date',
|
||||
// description: 'Gets the current date as ISO string',
|
||||
// }
|
||||
// }
|
||||
|
||||
const get_visits_count_Schema: OpenAI.Chat.Completions.ChatCompletionTool = {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'get_visits_count',
|
||||
description: 'Gets the number of visits received on a date range',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
from: { type: 'string', description: 'ISO string of start date including hours' },
|
||||
to: { type: 'string', description: 'ISO string of end date including hours' }
|
||||
},
|
||||
required: ['from', 'to']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
|
||||
get_visits_count_Schema,
|
||||
...AI_EventsTools
|
||||
...AiVisitsInstance.getTools(),
|
||||
...AiEventsInstance.getTools(),
|
||||
...AiComposableChartInstance.getTools()
|
||||
]
|
||||
|
||||
|
||||
const functions: any = {
|
||||
get_current_date: async ({ }) => {
|
||||
return new Date().toISOString();
|
||||
},
|
||||
get_visits_count: async ({ pid, from, to }: any) => {
|
||||
return await getVisitsCountFromDateRange(pid, from, to);
|
||||
},
|
||||
...AI_EventsFunctions
|
||||
...AiVisitsInstance.getHandlers(),
|
||||
...AiEventsInstance.getHandlers(),
|
||||
...AiComposableChartInstance.getHandlers()
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +57,14 @@ async function setChatTitle(title: string, chat_id?: string) {
|
||||
await AiChatModel.updateOne({ _id: chat_id }, { title });
|
||||
}
|
||||
|
||||
|
||||
export function getChartsInMessage(message: OpenAI.Chat.Completions.ChatCompletionMessageParam) {
|
||||
if (message.role != 'assistant') return [];
|
||||
if (!message.tool_calls) return [];
|
||||
if (message.tool_calls.length == 0) return [];
|
||||
return message.tool_calls.filter(e => e.function.name === 'createComposableChart').map(e => e.function.arguments);
|
||||
}
|
||||
|
||||
export async function sendMessageOnChat(text: string, pid: string, initial_chat_id?: string) {
|
||||
|
||||
|
||||
@@ -100,43 +84,36 @@ export async function sendMessageOnChat(text: string, pid: string, initial_chat_
|
||||
await setChatTitle(text.substring(0, 110), chat_id);
|
||||
}
|
||||
|
||||
const userMessage: OpenAI.Chat.Completions.ChatCompletionMessageParam = {
|
||||
role: 'user', content: text
|
||||
}
|
||||
const userMessage: OpenAI.Chat.Completions.ChatCompletionMessageParam = { role: 'user', content: text }
|
||||
messages.push(userMessage);
|
||||
await addMessageToChat(userMessage, chat_id);
|
||||
|
||||
let response = await openai.chat.completions.create({ model: 'gpt-3.5-turbo', messages, n: 1, tools });
|
||||
let response = await openai.chat.completions.create({ model: OPENAI_MODEL, messages, n: 1, tools });
|
||||
|
||||
let responseMessage = response.choices[0].message;
|
||||
let toolCalls = responseMessage.tool_calls;
|
||||
const chartsData: string[][] = [];
|
||||
|
||||
await addMessageToChat(responseMessage, chat_id);
|
||||
messages.push(responseMessage);
|
||||
while ((response.choices[0].message.tool_calls?.length || 0) > 0) {
|
||||
await addMessageToChat(response.choices[0].message, chat_id);
|
||||
messages.push(response.choices[0].message);
|
||||
if (response.choices[0].message.tool_calls) {
|
||||
|
||||
console.log('Tools to call', response.choices[0].message.tool_calls.length);
|
||||
chartsData.push(getChartsInMessage(response.choices[0].message));
|
||||
|
||||
if (toolCalls) {
|
||||
console.log({ toolCalls: toolCalls.length });
|
||||
for (const toolCall of toolCalls) {
|
||||
const functionName = toolCall.function.name;
|
||||
const functionToCall = functions[functionName];
|
||||
const functionArgs = JSON.parse(toolCall.function.arguments);
|
||||
console.log('CALLING FUNCTION', functionName, 'WITH PARAMS', functionArgs);
|
||||
const functionResponse = await functionToCall({ pid, ...functionArgs });
|
||||
console.log('RESPONSE FUNCTION', functionName, 'WITH VALUE', functionResponse);
|
||||
messages.push({ tool_call_id: toolCall.id, role: "tool", content: JSON.stringify(functionResponse) });
|
||||
await addMessageToChat({ tool_call_id: toolCall.id, role: "tool", content: JSON.stringify(functionResponse) }, chat_id);
|
||||
for (const toolCall of response.choices[0].message.tool_calls) {
|
||||
const functionName = toolCall.function.name;
|
||||
console.log('Calling tool function', functionName);
|
||||
const functionToCall = functions[functionName];
|
||||
const functionArgs = JSON.parse(toolCall.function.arguments);
|
||||
const functionResponse = await functionToCall({ project_id: pid, ...functionArgs });
|
||||
messages.push({ tool_call_id: toolCall.id, role: "tool", content: JSON.stringify(functionResponse) });
|
||||
await addMessageToChat({ tool_call_id: toolCall.id, role: "tool", content: JSON.stringify(functionResponse) }, chat_id);
|
||||
}
|
||||
}
|
||||
response = await openai.chat.completions.create({ model: 'gpt-4o', messages, n: 1, tools });
|
||||
responseMessage = response.choices[0].message;
|
||||
toolCalls = responseMessage.tool_calls;
|
||||
|
||||
await addMessageToChat(responseMessage, chat_id);
|
||||
|
||||
response = await openai.chat.completions.create({ model: OPENAI_MODEL, messages, n: 1, tools });
|
||||
}
|
||||
|
||||
await addMessageToChat(response.choices[0].message, chat_id);
|
||||
await ProjectLimitModel.updateOne({ project_id: pid }, { $inc: { ai_messages: 1 } })
|
||||
|
||||
return responseMessage.content;
|
||||
return { content: response.choices[0].message.content, charts: chartsData.filter(e => e.length > 0).flat() };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getPlanFromId, getPlanFromTag } from '@data/PREMIUM';
|
||||
import { getPlanFromId, getPlanFromTag, PREMIUM_TAG } from '@data/PREMIUM';
|
||||
import Stripe from 'stripe';
|
||||
|
||||
class StripeService {
|
||||
@@ -133,9 +133,23 @@ class StripeService {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
async createOneTimeCoupon() {
|
||||
async createStripeCode(plan: PREMIUM_TAG) {
|
||||
if (this.disabledMode) return;
|
||||
if (!this.stripe) throw Error('Stripe not initialized');
|
||||
|
||||
const INCUBATION_COUPON = 'sDD7Weh3';
|
||||
|
||||
if (plan === 'INCUBATION') {
|
||||
await this.stripe.promotionCodes.create({
|
||||
coupon: INCUBATION_COUPON,
|
||||
active: true,
|
||||
code: 'TESTCACCA1',
|
||||
max_redemptions: 1,
|
||||
})
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async createOneTimeSubscriptionDummy(customer_id: string, planId: number) {
|
||||
|
||||
Reference in New Issue
Block a user