chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import * as sdk from '@botpress/sdk'
|
||||
import * as genenv from './.genenv'
|
||||
import gsheets from './bp_modules/gsheets'
|
||||
import telegram from './bp_modules/telegram'
|
||||
|
||||
export default new sdk.BotDefinition({
|
||||
events: {},
|
||||
recurringEvents: {},
|
||||
conversation: {
|
||||
tags: {
|
||||
downstream: {
|
||||
title: 'Downstream Conversation ID',
|
||||
description: 'ID of the downstream conversation binded to the upstream one',
|
||||
},
|
||||
upstream: {
|
||||
title: 'Upstream Conversation ID',
|
||||
description: 'ID of the upstream conversation binded to the downstream one',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.addIntegration(gsheets, {
|
||||
enabled: true,
|
||||
configurationType: 'serviceAccountKey',
|
||||
configuration: {
|
||||
clientEmail: genenv.SHEETZY_GSHEETS_CLIENT_EMAIL,
|
||||
privateKey: genenv.SHEETZY_GSHEETS_PRIVATE_KEY,
|
||||
spreadsheetId: genenv.SHEETZY_GSHEETS_SPREADSHEET_ID,
|
||||
},
|
||||
})
|
||||
.addIntegration(telegram, {
|
||||
enabled: true,
|
||||
configuration: {
|
||||
botToken: genenv.SHEETZY_TELEGRAM_BOT_TOKEN,
|
||||
typingIndicatorEmoji: true,
|
||||
},
|
||||
})
|
||||
@@ -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,26 @@
|
||||
{
|
||||
"name": "@bp-bots/sheetzy",
|
||||
"scripts": {
|
||||
"postinstall": "genenv -o ./.genenv/index.ts -e SHEETZY_TELEGRAM_BOT_TOKEN -e SHEETZY_GSHEETS_CLIENT_EMAIL -e SHEETZY_GSHEETS_PRIVATE_KEY -e SHEETZY_GSHEETS_SPREADSHEET_ID",
|
||||
"check:type": "tsc --noEmit",
|
||||
"check:bplint": "bp lint",
|
||||
"build": "bp add -y && bp build"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@botpress/client": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@botpress/cli": "workspace:*",
|
||||
"@botpress/common": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"@botpresshub/gsheets": "workspace:*",
|
||||
"@botpresshub/telegram": "workspace:*",
|
||||
"@bpinternal/genenv": "0.0.1"
|
||||
},
|
||||
"bpDependencies": {
|
||||
"telegram": "../../integrations/telegram",
|
||||
"gsheets": "../../integrations/gsheets"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# Sheetzy
|
||||
|
||||
## Description
|
||||
|
||||
This is a bot that allows you to read and write data to a Google Sheet while chatting on Telegram.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Create a new bot using the Botpress Dashboard or the Botpress CLI.
|
||||
2. Install the Telegram and GSheets integrations using the command `bp add telegram && bp add gsheets`.
|
||||
3. Build the bot using command `bp build`.
|
||||
4. Deploy the bot using command `bp deploy`.
|
||||
5. In the botpress Dashboard, enable and configure the integrations Telegram and Google Sheets.
|
||||
6. Talk to the bot in Telegram and send the message `/help`. You should receive a message with the list of available commands.
|
||||
@@ -0,0 +1,2 @@
|
||||
import * as bp from '.botpress'
|
||||
export const bot = new bp.Bot({ actions: {} })
|
||||
@@ -0,0 +1,177 @@
|
||||
import { z } from '@botpress/sdk'
|
||||
import { MessageHandlerProps } from './types'
|
||||
import { ApiUtils } from './utils'
|
||||
|
||||
const valuesSchema = z.array(z.array(z.union([z.string(), z.number()])))
|
||||
|
||||
export class CommandError extends Error {}
|
||||
export type Command = (props: MessageHandlerProps, args: string[]) => Promise<void>
|
||||
|
||||
const help: Command = async (props) => {
|
||||
const utils = new ApiUtils(props)
|
||||
const commandNames = Object.keys(commands)
|
||||
await utils.respond(`Available commands\n${commandNames.map((name) => `- ${name}`).join('\n')}`)
|
||||
}
|
||||
|
||||
const info: Command = async (props) => {
|
||||
const utils = new ApiUtils(props)
|
||||
const { output } = await props.client.callAction({
|
||||
type: 'gsheets:getInfoSpreadsheet',
|
||||
input: {
|
||||
fields: [
|
||||
'sheets.properties.sheetId',
|
||||
'sheets.properties.title',
|
||||
'sheets.properties.gridProperties.rowCount',
|
||||
'sheets.properties.gridProperties.columnCount',
|
||||
],
|
||||
},
|
||||
})
|
||||
await utils.respond(JSON.stringify(output, null, 2))
|
||||
}
|
||||
|
||||
const get: Command = async (props, args) => {
|
||||
const utils = new ApiUtils(props)
|
||||
|
||||
const [range] = args
|
||||
if (!range) {
|
||||
throw new CommandError('Missing range')
|
||||
}
|
||||
|
||||
const {
|
||||
output: { values },
|
||||
} = await props.client.callAction({
|
||||
type: 'gsheets:getValues',
|
||||
input: {
|
||||
range,
|
||||
},
|
||||
})
|
||||
|
||||
await utils.respond(JSON.stringify(values, null, 2))
|
||||
}
|
||||
|
||||
const set: Command = async (props, args) => {
|
||||
const utils = new ApiUtils(props)
|
||||
|
||||
const [range, ...body] = args
|
||||
const jsonValues = body.join(' ')
|
||||
|
||||
if (!range) {
|
||||
throw new CommandError('Missing range')
|
||||
}
|
||||
|
||||
const parseResult = valuesSchema.safeParse(JSON.parse(jsonValues))
|
||||
if (!parseResult.success) {
|
||||
throw new CommandError('Invalid values')
|
||||
}
|
||||
|
||||
const values = parseResult.data
|
||||
|
||||
await props.client.callAction({
|
||||
type: 'gsheets:setValues',
|
||||
input: {
|
||||
range,
|
||||
values: _stringifyValues(values),
|
||||
},
|
||||
})
|
||||
|
||||
await utils.respond('Done')
|
||||
}
|
||||
|
||||
const append: Command = async (props, args) => {
|
||||
const utils = new ApiUtils(props)
|
||||
|
||||
const [firstArg, secondArg, ...body] = args
|
||||
const jsonValues = body.join(' ')
|
||||
|
||||
if (!firstArg) {
|
||||
throw new CommandError('Missing startColumn')
|
||||
}
|
||||
|
||||
let sheetName: string | undefined
|
||||
let startColumn: string
|
||||
|
||||
if (secondArg && !secondArg.startsWith('[') && !secondArg.startsWith('{')) {
|
||||
sheetName = firstArg
|
||||
startColumn = secondArg
|
||||
} else {
|
||||
startColumn = firstArg
|
||||
if (firstArg.includes('!')) {
|
||||
const parts = firstArg.split('!')
|
||||
if (parts.length > 1 && parts[1]) {
|
||||
sheetName = parts[0]
|
||||
startColumn = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!startColumn) {
|
||||
throw new CommandError('Missing startColumn')
|
||||
}
|
||||
|
||||
const parseResult = valuesSchema.safeParse(JSON.parse(jsonValues))
|
||||
if (!parseResult.success) {
|
||||
throw new CommandError('Invalid values')
|
||||
}
|
||||
|
||||
const values = parseResult.data
|
||||
|
||||
await props.client.callAction({
|
||||
type: 'gsheets:appendValues',
|
||||
input: {
|
||||
sheetName,
|
||||
startColumn,
|
||||
values: _stringifyValues(values),
|
||||
},
|
||||
})
|
||||
|
||||
await utils.respond('Done')
|
||||
}
|
||||
|
||||
const clear: Command = async (props, args) => {
|
||||
const utils = new ApiUtils(props)
|
||||
const [range] = args
|
||||
if (!range) {
|
||||
throw new CommandError('Missing range')
|
||||
}
|
||||
|
||||
await props.client.callAction({
|
||||
type: 'gsheets:clearValues',
|
||||
input: {
|
||||
range,
|
||||
},
|
||||
})
|
||||
|
||||
await utils.respond('Done')
|
||||
}
|
||||
|
||||
const addSheet: Command = async (props, args) => {
|
||||
const utils = new ApiUtils(props)
|
||||
|
||||
const [title] = args
|
||||
|
||||
if (!title) {
|
||||
throw new CommandError('Missing title')
|
||||
}
|
||||
|
||||
await props.client.callAction({
|
||||
type: 'gsheets:addSheet',
|
||||
input: {
|
||||
title,
|
||||
},
|
||||
})
|
||||
|
||||
await utils.respond('Done')
|
||||
}
|
||||
|
||||
const _stringifyValues = (values: any[][]): string[][] =>
|
||||
values.map((majorDimension) => majorDimension.map((cell) => cell.toString()))
|
||||
|
||||
export const commands = {
|
||||
'/help': help,
|
||||
'/info': info,
|
||||
'/get': get,
|
||||
'/set': set,
|
||||
'/append': append,
|
||||
'/clear': clear,
|
||||
'/addSheet': addSheet,
|
||||
} satisfies Record<`/${string}`, Command>
|
||||
@@ -0,0 +1,39 @@
|
||||
import { bot } from './bot'
|
||||
import { CommandError, commands } from './commands'
|
||||
import { ApiUtils } from './utils'
|
||||
|
||||
bot.on.message('*', async (props) => {
|
||||
const utils = new ApiUtils(props)
|
||||
|
||||
if (props.message.type !== 'text') {
|
||||
await utils.respond('I only understand text messages')
|
||||
return
|
||||
}
|
||||
|
||||
const text = props.message.payload.text as string
|
||||
const [command, ...args] = text.split(' ')
|
||||
if (!command) {
|
||||
await utils.respond('Please provide a command')
|
||||
await commands['/help'](props, [])
|
||||
return
|
||||
}
|
||||
|
||||
const commandHandler = commands[command as keyof typeof commands]
|
||||
if (!commandHandler) {
|
||||
await utils.respond('Unknown command')
|
||||
await commands['/help'](props, [])
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await commandHandler(props, args)
|
||||
} catch (error) {
|
||||
if (error instanceof CommandError) {
|
||||
await utils.respond(error.message)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default bot
|
||||
@@ -0,0 +1 @@
|
||||
export * from '.botpress'
|
||||
@@ -0,0 +1,16 @@
|
||||
import { MessageHandlerProps } from './types'
|
||||
|
||||
export class ApiUtils {
|
||||
public constructor(private readonly _props: MessageHandlerProps) {}
|
||||
public readonly respond = async (text: string) => {
|
||||
await this._props.client.createMessage({
|
||||
type: 'text',
|
||||
conversationId: this._props.message.conversationId,
|
||||
userId: this._props.ctx.botId,
|
||||
tags: {},
|
||||
payload: {
|
||||
text,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": { "*": ["./*"] },
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [".botpress/**/*", "src/**/*", "*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user