Skip to content

Commit

Permalink
neurocalls fix
Browse files Browse the repository at this point in the history
  • Loading branch information
katsuhira02 committed Sep 8, 2024
1 parent 685150a commit 339997f
Show file tree
Hide file tree
Showing 5 changed files with 543 additions and 137 deletions.
268 changes: 268 additions & 0 deletions docs/neurocoder07.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# Создание Telegram-бота для управления списком задач с использованием Supabase и grammY

В этой статье мы рассмотрим, как создать Telegram-бота для управления списком задач (CRUD: Create, Read, Update, Delete) с использованием Supabase и библиотеки grammY. Мы будем использовать два файла: `index.ts` и `todo-list.ts`.

## Установка и настройка

### Установка зависимостей
Для начала установим необходимые зависимости:
```
npm install grammy @grammyjs/storage-free supabase
```
### Настройка Supabase

Создайте проект в [Supabase](https://supabase.com/) и настройте таблицу `todo_list` со следующими полями:

- `id` (integer, primary key)
- `telegram_id` (text)
- `task` (text)

### Настройка grammY

Создайте бота в Telegram с помощью [BotFather](https://t.me/BotFather) и получите токен.

## Файл `todo-list.ts`

Этот файл содержит функции для работы с базой данных Supabase.

```typescript:supabase/functions/_shared/supabase/todo-list.ts
import { supabase } from "./index.ts";

export async function readTask(id: number) {
const { data, error } = await supabase
.from('todo_list')
.select('*')
.eq('id', id)

if (error) {
throw error
}
return data
}

export async function createTask(telegram_id: string, task: string) {
const { data, error } = await supabase
.from('todo_list')
.insert({
telegram_id,
task,
})

if (error) {
throw error
}
return data
}

export async function updateTask(id: number, task: string) {
const { data, error } = await supabase
.from('todo_list')
.update({ task })
.eq('id', id)

if (error) {
throw error
}
return data
}

export async function deleteTask(id: number) {
const { data, error } = await supabase
.from('todo_list')
.delete()
.eq('id', id)

if (error) {
throw error
}
return data
}

export async function readTasks(telegram_id: string) {
const { data, error } = await supabase
.from('todo_list')
.select('*')
.eq('telegram_id', telegram_id)

if (error) {
throw error
}
return data
}
```

## Файл `index.ts`

Этот файл содержит логику бота на основе библиотеки grammY.

```typescript:supabase/functions/todo-list/index.ts
import { createTask, readTask, readTasks, updateTask, deleteTask } from "../_shared/supabase/todo-list.ts";
import { botNeuroCoder, handleUpdateNeuroCoder } from "../_shared/telegram/bots.ts";

console.log(`Function "telegram-bot" up and running!`)

botNeuroCoder.command('start', async (ctx) => {
await ctx.reply("Welcome! Вы попали в ToDo List Bot.", {
reply_markup: {
inline_keyboard: [
[{ text: 'Открыть меню', callback_data: 'open_menu' }]
]
}
})
return
})

botNeuroCoder.on('message:text', async (ctx) => {
const message = ctx.message.text
const telegram_id = ctx.from?.id.toString()

if (message.startsWith('/')) return
console.log(message)

if (ctx.message.reply_to_message) {
if (ctx.message.reply_to_message.text?.includes('Отправьте задачу.')) {
await createTask(telegram_id, message)
await ctx.reply('Задача создана')
return
}
if (ctx.message.reply_to_message.text?.includes('Напишите новую задачу.')) {
const tasks = await readTasks(telegram_id)
console.log(tasks)
await ctx.reply("Выберите задачу для изменения", {
reply_markup: {
inline_keyboard: tasks.map((task: any) => [
{ text: task.task, callback_data: `task_update_${task.id}_${message}`
}
])
}
})
return
}
}
})

botNeuroCoder.on('callback_query:data', async (ctx) => {
const callbackData = ctx.callbackQuery.data

console.log(callbackData, "callbackData")
const telegram_id = ctx.from?.id.toString()

if (callbackData === 'open_menu') {
await ctx.reply("Вы открыли меню", {
reply_markup: {
inline_keyboard: [
[{ text: 'Create', callback_data: 'create_task' }],
[{ text: 'Read', callback_data: 'read_tasks' }],
[{ text: 'Update', callback_data: 'update_task' }],
]
}
})
return
}
if (callbackData.includes('task')) {
if (callbackData.includes('create')) {
try {
await ctx.reply("Отправьте задачу.", {
reply_markup: {
force_reply: true
}
})
return
} catch (e) {
await ctx.reply('Ошибка при создании задачи')
throw new Error('Ошибка при создании задачи', e)
}
}
if (callbackData.includes('read')) {
try {
if (callbackData.split("_").length === 3) {
const task_id = callbackData.split("_")[2]
const task = await readTask(Number(task_id))
await ctx.reply(task[0].task, {
reply_markup: {
inline_keyboard: [
[{ text: 'Delete', callback_data: `delete_task_${task_id}` }]
]
}
})
return
} else {
const tasks = await readTasks(telegram_id)
console.log(tasks)
await ctx.reply("Выберите задачу", {
reply_markup: {
inline_keyboard: tasks.map((task: any) => [
{ text: task.task, callback_data: `task_read_${task.id}`
}
])
}
})
}
return
} catch (e) {
await ctx.reply('Ошибка при чтении задач')
throw new Error('Ошибка при чтении задач', e)
}
}
if (callbackData.includes('update')) {
if (callbackData.split("_").length > 3) {
const task_id = callbackData.split("_")[2]
const new_task = callbackData.split("_")[3]
await updateTask(Number(task_id), new_task)
await ctx.reply("Задача обновлена")
return
}
await ctx.reply("Напишите новую задачу.", {
reply_markup: {
force_reply: true
}
})
return
}
if (callbackData.includes('delete')) {
const task_id = callbackData.split("_")[2]
await deleteTask(Number(task_id))
await ctx.reply("Задача удалена.")
return
}
}
return
})

Deno.serve(async (req) => {
try {
const url = new URL(req.url)
if (url.searchParams.get('secret') !== Deno.env.get('FUNCTION_SECRET')) {
return new Response('not allowed', { status: 405 })
}

return await handleUpdateNeuroCoder(req)
} catch (err) {
console.error(err)
}
})
```

## Объяснение кода

### Функции для работы с базой данных

В файле `todo-list.ts` определены функции для работы с таблицей `todo_list` в Supabase:

- `createTask`: Создает новую задачу.
- `readTask`: Читает задачу по ID.
- `readTasks`: Читает все задачи для конкретного пользователя.
- `updateTask`: Обновляет задачу по ID.
- `deleteTask`: Удаляет задачу по ID.

### Логика бота

В файле `index.ts` реализована логика бота с использованием библиотеки grammY:

- Команда `/start` отправляет приветственное сообщение и предлагает открыть меню.
- Обработчик текстовых сообщений создает или обновляет задачи в зависимости от контекста.
- Обработчик `callback_query` обрабатывает нажатия на кнопки меню и выполняет соответствующие действия (создание, чтение, обновление, удаление задач).

## Заключение

В этой статье мы рассмотрели, как создать Telegram-бота для управления списком задач с использованием Supabase и библиотеки grammY. Мы определили функции для работы с базой данных и реализовали логику бота для выполнения операций CRUD.
102 changes: 102 additions & 0 deletions docs/neurocoder08.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Добавление команды для склейки нескольких видео в одно в Telegram-боте

В этом руководстве мы рассмотрим, как добавить команду в Telegram-бота для склейки нескольких видео в одно с использованием библиотеки `grammy` и `ffmpeg`. Мы будем использовать файл `index.ts` в качестве примера.

## Шаг 1: Установка зависимостей

Для начала установим необходимые зависимости:

```bash
npm install grammy fluent-ffmpeg @ffmpeg-installer/ffmpeg
```

## Шаг 2: Импорт необходимых модулей

В файле `index.ts` импортируем необходимые модули:

```typescript
import { Context } from "grammy";
import ffmpeg from "fluent-ffmpeg";
import ffmpegInstaller from "@ffmpeg-installer/ffmpeg";
import path from "path";
import fs from "fs";

ffmpeg.setFfmpegPath(ffmpegInstaller.path);
```

## Шаг 3: Проверка доступа к файлам

Создадим функцию для проверки доступа к файлам:

```typescript
const checkAccess = (filePath: string, mode: number) => {
return new Promise<void>((resolve, reject) => {
fs.access(filePath, mode, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
};
```

## Шаг 4: Создание команды для склейки видео

Создадим асинхронную функцию `short`, которая будет обрабатывать команду для склейки видео:

```typescript
const short = async (ctx: Context): Promise<void> => {
try {
await ctx.reply("Video creation started");

const inputFilePath = path.resolve(__dirname, "./assets/input/");
const outputFilePath = path.resolve(__dirname, "./assets/output/output.mp4");

try {
await checkAccess(inputFilePath, fs.constants.R_OK); // Проверка прав на чтение
await checkAccess(path.dirname(outputFilePath), fs.constants.W_OK); // Проверка прав на запись в директорию
console.log("Access check passed");
} catch (err) {
console.error("Access check failed:", err);
throw err;
}

const createShortVideo = async () => {
console.log(inputFilePath, outputFilePath);
console.log("Merging started");
return new Promise<void>((resolve, reject) => {
ffmpeg()
.input(`${inputFilePath}/input.txt`)
.output(outputFilePath)
.inputOptions(["-f concat", "-safe 0"])
.outputOptions(["-c copy"])
.on("end", () => {
console.log("Merging complete!");
resolve();
})
.on("error", (err) => {
console.error("Error:", err);
reject(err);
})
.on("progress", (progress) => {
console.log("Progress:", progress.percent);
})
.run();
});
};

await createShortVideo();
return;
} catch (error) {
throw error;
}
};

export default short;
```

## Заключение

Теперь у вас есть команда для склейки нескольких видео в одно в вашем Telegram-боте. Эта команда проверяет доступ к файлам, а затем использует `ffmpeg` для объединения видео. Не забудьте настроить пути к входным и выходным файлам в соответствии с вашими требованиями.
4 changes: 3 additions & 1 deletion supabase/functions/_shared/supabase/passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
UserPassport,
} from "../types/index.ts";
import { supabase } from "./index.ts";
import { getUid } from "./users.ts";

export async function setPassport(
passport: PassportUser,
Expand Down Expand Up @@ -181,9 +182,10 @@ export async function getPassportsTasksByUsername(
username: string,
): Promise<string[]> {
try {
const uid = await getUid(username);
const { data, error } = await supabase.from("user_passport")
.select("*")
.eq("username", username)
.eq("user_id", uid)
.eq("type", "task");

if (error) {
Expand Down
Loading

0 comments on commit 339997f

Please sign in to comment.