chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import rootConfig from '../../eslint.config.mjs'
|
||||
|
||||
export default [
|
||||
...rootConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@botpresshub/personality",
|
||||
"scripts": {
|
||||
"check:type": "tsc --noEmit",
|
||||
"build": "bp add -y && bp build",
|
||||
"test": "vitest --run"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@botpress/client": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"dedent": "^1.6.0",
|
||||
"json5": "^2.2.3",
|
||||
"jsonrepair": "^3.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@botpress/cli": "workspace:*",
|
||||
"@botpress/common": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"@botpresshub/llm": "workspace:*",
|
||||
"@bpinternal/genenv": "0.0.1",
|
||||
"@types/semver": "^7.3.11",
|
||||
"semver": "^7.3.8"
|
||||
},
|
||||
"bpDependencies": {
|
||||
"llm": "../../interfaces/llm"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import * as sdk from '@botpress/sdk'
|
||||
import llm from './bp_modules/llm'
|
||||
|
||||
export default new sdk.PluginDefinition({
|
||||
name: 'personality',
|
||||
version: '1.0.0',
|
||||
configuration: {
|
||||
schema: sdk.z.object({
|
||||
model: sdk.z.string().describe('Model to use to handle bot personality'),
|
||||
personality: sdk.z
|
||||
.string()
|
||||
.max(1000)
|
||||
.describe(
|
||||
'Describe what your chatbot is meant to do and how it should behave. You can include some personality traits here as well to influence how the chatbot will respond. Expressions are supported.'
|
||||
),
|
||||
}),
|
||||
},
|
||||
interfaces: {
|
||||
llm: sdk.version.allWithinMajorOf(llm),
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import JSON5 from 'json5'
|
||||
import { jsonrepair } from 'jsonrepair'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
export type LLMInput = bp.interfaces.llm.actions.generateContent.input.Input
|
||||
export type LLMOutput = bp.interfaces.llm.actions.generateContent.output.Output
|
||||
|
||||
type LLMChoice = LLMOutput['choices'][number]
|
||||
type PredictResponse = {
|
||||
success: boolean
|
||||
json: object
|
||||
}
|
||||
|
||||
const tryParseJson = (str: string) => {
|
||||
try {
|
||||
return JSON5.parse(jsonrepair(str))
|
||||
} catch {
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
export const parseLLMOutput = (output: LLMOutput): PredictResponse => {
|
||||
const mappedChoices: LLMChoice['content'][] = output.choices.map((choice) => choice.content)
|
||||
const firstChoice = mappedChoices[0]!
|
||||
return {
|
||||
success: true,
|
||||
json: tryParseJson(firstChoice as string),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import * as gen from './generate-content'
|
||||
import * as rewrite from './rewrite-prompt'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
const plugin = new bp.Plugin({
|
||||
actions: {},
|
||||
})
|
||||
|
||||
plugin.on.beforeOutgoingMessage('*', async ({ data: message, configuration, actions }) => {
|
||||
if (message.type !== 'text') {
|
||||
console.debug('Ignoring non-text message')
|
||||
return
|
||||
}
|
||||
|
||||
console.debug('Rewriting message:', message.payload.text)
|
||||
|
||||
const text = message.payload.text as string
|
||||
|
||||
const { model, personality } = configuration
|
||||
|
||||
const input = rewrite.prompt({
|
||||
model,
|
||||
personality,
|
||||
payload: text,
|
||||
})
|
||||
const output = await actions.llm.generateContent(input)
|
||||
|
||||
const { success, json } = gen.parseLLMOutput(output)
|
||||
|
||||
const parseResult = rewrite.responseSchema.safeParse(json)
|
||||
if (!success || !parseResult.success) {
|
||||
console.debug('Failed to rewrite message')
|
||||
return { data: message }
|
||||
}
|
||||
|
||||
message.payload.text = parseResult.data.payload
|
||||
return { data: message }
|
||||
})
|
||||
|
||||
export default plugin
|
||||
@@ -0,0 +1,48 @@
|
||||
import { z } from '@botpress/sdk'
|
||||
import dedent from 'dedent'
|
||||
import { LLMInput } from './generate-content'
|
||||
|
||||
export const responseSchema = z.object({
|
||||
payload: z.string(),
|
||||
})
|
||||
|
||||
type PromptArgs = {
|
||||
model: string
|
||||
personality: string
|
||||
payload: string
|
||||
}
|
||||
|
||||
const systemPrompt = (args: PromptArgs): string => dedent`
|
||||
Please rewrite the below JSON messages in your own voice and personality.
|
||||
Do NOT CHANGE the nature and meaning of any of the messages.
|
||||
Do not add additional greetings, introduction or personality traits in the below messages.
|
||||
Just change the writing style.
|
||||
Preserve the numbering, ordering, meaning, casing and spacing.
|
||||
Only rewrite the main message text, keep buttons and choices as-is.
|
||||
|
||||
Your personality is as follows:
|
||||
---
|
||||
${args.personality}
|
||||
---
|
||||
`
|
||||
|
||||
const userPrompt = (args: PromptArgs): string => dedent`
|
||||
\`\`\`json
|
||||
{ "payload": ${args.payload} }
|
||||
\`\`\`
|
||||
|
||||
type OutputFormat = ${responseSchema.toTypescriptType({ treatDefaultAsOptional: true })}
|
||||
`
|
||||
|
||||
export const prompt = (args: PromptArgs): LLMInput => ({
|
||||
model: { id: args.model },
|
||||
responseFormat: 'json_object',
|
||||
temperature: 0,
|
||||
systemPrompt: systemPrompt(args),
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: userPrompt(args),
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": { "*": ["./*"] },
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [".botpress/**/*", "definitions/**/*", "src/**/*", "*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import config from '../../vitest.config'
|
||||
export default config
|
||||
Reference in New Issue
Block a user