feat: add prompt service (#6241)

fix CLOUD-19
This commit is contained in:
darkskygit
2024-04-02 07:04:54 +00:00
parent 593161dccb
commit 3c01d944fb
8 changed files with 246 additions and 8 deletions

View File

@@ -1,10 +1,11 @@
import { ServerFeature } from '../../core/config';
import { Plugin } from '../registry';
import { assertProvidersConfigs, CopilotProviderService } from './provider';
import { PromptService } from './prompt';
import { assertProvidersConfigs, CopilotProviderService } from './providers';
@Plugin({
name: 'copilot',
providers: [CopilotProviderService],
providers: [PromptService, CopilotProviderService],
contributesTo: ServerFeature.Copilot,
if: config => {
if (config.flavor.graphql) {

View File

@@ -0,0 +1,72 @@
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { ChatMessage } from './types';
@Injectable()
export class PromptService {
constructor(private readonly db: PrismaClient) {}
/**
* list prompt names
* @returns prompt names
*/
async list() {
return this.db.aiPrompt
.findMany({ select: { name: true } })
.then(prompts => Array.from(new Set(prompts.map(p => p.name))));
}
/**
* get prompt messages by prompt name
* @param name prompt name
* @returns prompt messages
*/
async get(name: string): Promise<ChatMessage[]> {
return this.db.aiPrompt.findMany({
where: {
name,
},
select: {
role: true,
content: true,
},
orderBy: {
idx: 'asc',
},
});
}
async set(name: string, messages: ChatMessage[]) {
return this.db.$transaction(async tx => {
const prompts = await tx.aiPrompt.count({ where: { name } });
if (prompts > 0) {
return 0;
}
return tx.aiPrompt
.createMany({
data: messages.map((m, idx) => ({ name, idx, ...m })),
})
.then(ret => ret.count);
});
}
async update(name: string, messages: ChatMessage[]) {
return this.db.$transaction(async tx => {
await tx.aiPrompt.deleteMany({ where: { name } });
return tx.aiPrompt
.createMany({
data: messages.map((m, idx) => ({ name, idx, ...m })),
})
.then(ret => ret.count);
});
}
async delete(name: string) {
return this.db.aiPrompt
.deleteMany({
where: { name },
})
.then(ret => ret.count);
}
}

View File

@@ -2,14 +2,14 @@ import assert from 'node:assert';
import { Injectable, Logger } from '@nestjs/common';
import { Config } from '../../fundamentals';
import { Config } from '../../../fundamentals';
import {
CapabilityToCopilotProvider,
CopilotConfig,
CopilotProvider,
CopilotProviderCapability,
CopilotProviderType,
} from './types';
} from '../types';
type CopilotProviderConfig = CopilotConfig[keyof CopilotConfig];

View File

@@ -1,4 +1,6 @@
import { AiPromptRole } from '@prisma/client';
import type { ClientOptions as OpenAIClientOptions } from 'openai';
import { z } from 'zod';
export interface CopilotConfig {
openai: OpenAIClientOptions;
@@ -23,10 +25,18 @@ export interface CopilotProvider {
getCapabilities(): CopilotProviderCapability[];
}
export type ChatMessage = {
role: 'system' | 'assistant' | 'user';
content: string;
};
export const ChatMessageSchema = z
.object({
role: z.enum(
Array.from(Object.values(AiPromptRole)) as [
'system' | 'assistant' | 'user',
]
),
content: z.string(),
})
.strict();
export type ChatMessage = z.infer<typeof ChatMessageSchema>;
export interface CopilotTextToTextProvider extends CopilotProvider {
generateText(messages: ChatMessage[], model: string): Promise<string>;