Now I am an adept of the Depth, but the money issue is still relevant

And again I welcome all my readers! In my last article, I started talking about how I became a Depth cadet. The continuation of the immersion into the Depth will begin here and now, so I strongly recommend that you still turn to the origins in order to be aware of all the events that happened to me during this period.

So, let's go. As a newly minted cadet, I can’t go anywhere, but in this status you can’t go far, so I was looking for an assignment for myself. A task that will be tough for me and quite interesting. After all, I didn’t want to get burnout and a twitchy eye from the start – this is a rather sad and common situation when guys, with powerful enthusiasm, grab onto projects that they are not yet capable of. And then I come across a channel with the promising name “Witcher Contracts”.

And there are puzzles there... in general, there is plenty to choose from. Choose a puzzle here

And there are contracts there… that is, there are a lot of interesting tasks, you could choose more. I wandered among all these proposals and saw the following: “import audio from Telegram to Deep.” “This is quite a curious thing,” I thought, and the gears immediately began to work in my head, how and what I would write for the bot. I wasn’t even interested in when or in what volumes I would receive the reward. I saw the goal and ignored all sorts of obstacles that could await me.

Literally 5 minutes later, without even blinking an eye, I am already receiving advice from Soniroot about what this package should be and what functions it should perform. Yes, as I thought, a bot on Telegram… pumping out audio… Sounds quite logical and expected. You can get to work. But only then did the realization come that not everything is so simple…

You can talk about the Deep Case itself for a long time and admire the beauty of the connections. We admire it here

You can talk about the Deep Case itself for a long time and admire the beauty of connections
We admire here

How the package works

The principle of the package is a balance of simplicity and complexity. In my understanding, problems could not be avoided. If we keep the explanations to a minimum, then first the file is sent, Deep downloads it and adds it to the space. But the eyes are afraid, but the hands are doing the work, so I’ll tell you about the whole sequence of my actions.

In my first article, I mentioned the value of consulting. So, without exaggeration, I will note that Foksha provided me with incredible help at the start. More precisely, he provided me with a ready-made package for Telegram.

By the way, this package. Take a look here

Of course, at that moment it was not entirely clear to me what I had to do as a result. What are these tokens, what does port 3050 have to do with it, and how can I connect THIS to the bot? Foksha did not doze off and promptly provided all the necessary information, which helped me a lot. We needed to create a webhook that would react when the bot received a message, and then collect all the information about the message and create connections in space.

That’s when the puzzle began to come together, and it became much easier and clearer for me to figure out what was what. On the plus side, I took on this project already with a base of necessary knowledge obtained through consultations. Therefore, with a certain knowledge base, it’s not so scary to dig deeper into the code to understand how everything works.

And this is what my bag looks like when receiving messages.

And this is what mine looks like bag while receiving messages.

And the principle of operation is as follows: after the user sends a message to the bot, connections begin to appear in space: who sent it, when, the content of what was sent, in what language, and so on. This is the basis that someday someone might need. It’s better to have more data than less. The excess can always be cut out.

However, this package has not yet accepted audio. You'll have to tinker with this. If all the data about the message came simply as an array of information, then we get the audio through the method Telegram API “getFile”. With all this, before receiving the file you need to find out its name on the server. And then download it… And the file can be voice, music, recording – anything.

Here it is, the confrontation between ogg and mp3. And then if appears on the scene. The simplest, but at the same time ingenious solution. Either audio or voice.

You probably guessed it: I just made two variations with identical code. Only in one case for regular recordings, and the second for voice recordings.

I am attaching the code of the handler that is responsible for this here. In case it comes in handy for someone.

async (req, res, next, { deep, require, gql }) => {
    console.log(req.body);  // Выводит тело запроса в консоль
    const body = req.body;  // Сохраняет тело запроса в переменную body

    // Получает идентификаторы типов для различных элементов данных
    const typeIds = {
        contain: await deep.id("@deep-foundation/core", 'Contain'),
        updateId: await deep.id("@deep-foundation/telegram_save_audio", 'update_id'),
        message: await deep.id("@deep-foundation/telegram_save_audio", 'message'),
        messageId: await deep.id("@deep-foundation/telegram_save_audio", 'message_id'),
        from: await deep.id("@deep-foundation/telegram_save_audio", 'from'),
        chat: await deep.id("@deep-foundation/telegram_save_audio", 'chat'),
        id: await deep.id("@deep-foundation/telegram_save_audio", 'id'),
        isBot: await deep.id("@deep-foundation/telegram_save_audio", 'is_bot'),
        firstName: await deep.id("@deep-foundation/telegram_save_audio", 'first_name'),
        lastName: await deep.id("@deep-foundation/telegram_save_audio", 'last_name'),
        username: await deep.id("@deep-foundation/telegram_save_audio", 'username'),
        languageCode: await deep.id("@deep-foundation/telegram_save_audio", 'language_code'),
        type: await deep.id("@deep-foundation/telegram_save_audio", 'type'),
        date: await deep.id("@deep-foundation/telegram_save_audio", 'date'),
        text: await deep.id("@deep-foundation/telegram_save_audio", 'text'),
        audio: await deep.id("@deep-foundation/telegram_save_audio", 'Audio'),
        voice: await deep.id("@deep-foundation/telegram_save_audio", 'Voice'),
        duration: await deep.id("@deep-foundation/telegram_save_audio", 'Duration'),
        fileName: await deep.id("@deep-foundation/telegram_save_audio", 'File_name'),
        mimeType: await deep.id("@deep-foundation/telegram_save_audio", 'Mime_type'),
        title: await deep.id("@deep-foundation/telegram_save_audio", 'Title'),
        performer: await deep.id("@deep-foundation/telegram_save_audio", 'Performer'),
        fileId: await deep.id("@deep-foundation/telegram_save_audio", 'File_id'),
        fileUniqueId: await deep.id("@deep-foundation/telegram_save_audio", 'File_unique_id'),
        fileSize: await deep.id("@deep-foundation/telegram_save_audio", 'File_size'),
        telegram: await deep.id("@deep-foundation/telegram_save_audio", "Token"),
        insertLinksTo: await deep.id("@deep-foundation/telegram_save_audio", 'InsertLinksTo')
    };

    // Получает токен для связи с Telegram
    const { data: telegramLinkToken } = await deep.select({ type_id: typeIds.telegram });
    const [{ value: { value: tokenValue } }] = telegramLinkToken;

    // Выбирает ссылку для вставки
    const selectInsertLinksToLinkId = await deep.select({ type_id: typeIds.insertLinksTo });
    console.log(selectInsertLinksToLinkId);

    // Если ссылка для вставки не найдена, выбрасывает ошибку
    if (!selectInsertLinksToLinkId.data.length) {
        throw new Error(`${typeIds.insertLinksTo} link type not found`);
    }

    const { data: [{ id: insertLinksToLinkId, to_id: insertLinksToObjectLinkId }] } = selectInsertLinksToLinkId;

    // Вставляет сообщение в базу данных
    const { data: [{ id: messageLinkId }] } = await deep.insert({
        type_id: typeIds.message,
        in: {
            data: {
                type_id: typeIds.contain,
                from_id: insertLinksToObjectLinkId,
            },
        },
    });

    // Вставляет ID обновления в базу данных
    const { data: [{ id: updateIdLinkId }] } = await deep.insert({
        type_id: typeIds.updateId,
        number: { data: { value: body.update_id } },
        in: {
            data: {
                type_id: typeIds.contain,
                from_id: messageLinkId,
            },
        },
    });

    // Вставляет ID сообщения в базу данных
    await deep.insert({
        type_id: typeIds.messageId,
        number: { data: { value: body.message.message_id } },
        in: {
            data: {
                type_id: typeIds.contain,
                from_id: messageLinkId,
            },
        },
    });

    // Вставляет отправителя сообщения в базу данных
    const { data: [{ id: fromLinkId }] } = await deep.insert({
        type_id: typeIds.from,
        in: {
            data: {
                type_id: typeIds.contain,
                from_id: messageLinkId,
            },
        },
    });

    // Функция для вставки данных отправителя в базу данных
    async function insertData_from(items_from) {
        for (let i = 0; i < items_from.length; i++) {
            const { type_id, value, value_type } = items_from[i];

            await deep.insert({
                type_id,
                [value_type]: { data: { value } },
                in: {
                    data: {
                        type_id: typeIds.contain,
                        from_id: fromLinkId,
                    },
                },
            });
        }
    }

    // Данные отправителя
    const items_from = [
        { type_id: typeIds.id, value: body.message.from.id, value_type: 'number' },
        { type_id: typeIds.firstName, value: body.message.from.first_name, value_type: 'string' },
        { type_id: typeIds.lastName, value: body.message.from.last_name, value_type: 'string' },
        { type_id: typeIds.username, value: body.message.from.username, value_type: 'string' },
        { type_id: typeIds.languageCode, value: body.message.from.language_code, value_type: 'string' },
        { type_id: typeIds.isBot, value: +body.message.from.is_bot, value_type: 'number' },
    ];

    // Вставка данных отправителя в базу данных
    await insertData_from(items_from);

    // Вставка чата в базу данных
    const { data: [{ id: chatLinkId }] } = await deep.insert({
        type_id: typeIds.chat,
        in: {
            data: {
                type_id: typeIds.contain,
                from_id: messageLinkId,
            },
        },
    });

    // Функция для вставки данных чата в базу данных
    async function insertData_chat(items_chat) {
        for (let i = 0; i < items_chat.length; i++) {
            const { type_id, value, value_type } = items_chat[i];

            await deep.insert({
                type_id,
                [value_type]: { data: { value } },
                in: {
                    data: {
                        type_id: typeIds.contain,
                        from_id: chatLinkId,
                    },
                },
            });
        }
    }

    // Данные чата
    const items_chat = [
        { type_id: typeIds.id, value: body.message.chat.id, value_type: 'number' },
        { type_id: typeIds.firstName, value: body.message.chat.first_name, value_type: 'string' },
        { type_id: typeIds.lastName, value: body.message.chat.last_name, value_type: 'string' },
        { type_id: typeIds.username, value: body.message.chat.username, value_type: 'string' },
        { type_id: typeIds.type, value: body.message.chat.type, value_type: 'string' },
        { type_id: typeIds.date, value: body.message.date, value_type: 'number' },
        { type_id: typeIds.text, value: body.message.text, value_type: 'string' },
    ];

    // Вставка данных чата в базу данных
    await insertData_chat(items_chat);

    // Если в сообщении есть аудио
    if (body.message.audio) {
        // Вставка аудио в базу данных
        const { data: [{ id: audioLinkId }] } = await deep.insert({
            type_id: typeIds.audio,
            in: {
                data: {
                    type_id: typeIds.contain,
                    from_id: messageLinkId,
                },
            },
        });

        // Функция для вставки данных аудио в базу данных
        async function insertData(items) {
            for (let i = 0; i < items.length; i++) {
                const { type_id, value, value_type } = items[i];

                await deep.insert({
                    type_id,
                    [value_type]: { data: { value } },
                    in: {
                        data: {
                            type_id: typeIds.contain,
                            from_id: audioLinkId,
                        },
                    },
                });
            }
        }

        // Данные аудио
        const items = [
            { type_id: typeIds.duration, value: body.message.audio.duration, value_type: 'number' },
            { type_id: typeIds.mimeType, value: body.message.audio.mime_type, value_type: 'string' },
            { type_id: typeIds.fileId, value: body.message.audio.file_id, value_type: 'string'
            },
            { type_id: typeIds.fileUniqueId, value: body.message.audio.file_unique_id, value_type: 'string' },
            { type_id: typeIds.fileSize, value: body.message.audio.file_size, value_type: 'number' },
            { type_id: typeIds.fileName, value: body.message.audio.file_name, value_type: 'string' },
            { type_id: typeIds.title, value: body.message.audio.title, value_type: 'string' },
            { type_id: typeIds.performer, value: body.message.audio.performer, value_type: 'string' },
        ];

        // Вставка данных аудио в базу данных
        await insertData(items);

        // Получение файла аудио из Telegram
        const axios = require('axios');
        const FormData = require('form-data');
        const axiosInstance = axios.create({ maxBodyLength: Infinity });
        const getinfo_file = await axiosInstance.get("https://api.telegram.org/bot" + tokenValue + "/getFile?file_id=" + body.message.audio.file_id);
        const file = await axiosInstance.get("https://api.telegram.org/file/bot" + tokenValue + "/" + getinfo_file.data.result.file_path, {
            responseType: 'arraybuffer'
        });

        let buffer = Buffer.from(file.data);

        // Создание формы для отправки файла
        const formData = new FormData();
        formData.append('file', buffer, { filename: 'example.mp3', contentType: 'audio/mpeg' });
        const { data: [{ id }] } = await deep.insert({
            type_id: deep.idLocal('@deep-foundation/core', 'AsyncFile'),
            in: {
                data: [
                    {
                        type_id: deep.idLocal('@deep-foundation/core', 'Contain'),
                        from_id: audioLinkId,
                    },
                ]
            },
        });

        // Отправка файла на сервер
        const ssl = deep.apolloClient.ssl;
        const path = deep.apolloClient.path.slice(0, -4);
        const url = `${ssl ? "https://" : "http://"}${path}/file`;

        await axiosInstance.post(url, formData, {
            headers: {
                'linkId': id,
                "Authorization": `Bearer ${deep.token}`,
            },
        });
    } else if (body.message.voice) {
        // Если в сообщении есть голосовое сообщение
        const { data: [{ id: voiceLinkId }] } = await deep.insert({
            type_id: typeIds.voice,
            in: {
                data: {
                    type_id: typeIds.contain,
                    from_id: messageLinkId,
                },
            },
        });

        // Функция для вставки данных голосового сообщения в базу данных
        async function insertData(items) {
            for (let i = 0; i < items.length; i++) {
                const { type_id, value, value_type } = items[i];

                await deep.insert({
                    type_id,
                    [value_type]: { data: { value } },
                    in: {
                        data: {
                            type_id: typeIds.contain,
                            from_id: voiceLinkId,
                        },
                    },
                });
            }
        }

        // Данные голосового сообщения
        const items = [
            { type_id: typeIds.duration, value: body.message.voice.duration, value_type: 'number' },
            { type_id: typeIds.mimeType, value: body.message.voice.mime_type, value_type: 'string' },
            { type_id: typeIds.fileId, value: body.message.voice.file_id, value_type: 'string' },
            { type_id: typeIds.fileUniqueId, value: body.message.voice.file_unique_id, value_type: 'string' },
            { type_id: typeIds.fileSize, value: body.message.voice.file_size, value_type: 'number' },
        ];

        // Вставка данных голосового сообщения в базу данных
        await insertData(items);

        // Получение файла голосового сообщения из Telegram
        const axios = require('axios');
        const FormData = require('form-data');

        const axiosInstance = axios.create({ maxBodyLength: Infinity });
        const getinfo_file = await axiosInstance.get("https://api.telegram.org/bot" + tokenValue + "/getFile?file_id=" + body.message.voice.file_id);
        console.log(getinfo_file);
        const file = await axiosInstance.get("https://api.telegram.org/file/bot" + tokenValue + "/" + getinfo_file.data.result.file_path, {
            responseType: 'arraybuffer'
        });

        console.log(file);

        let buffer = Buffer.from(file.data);

        // Создание формы для отправки файла
        const formData = new FormData();
        formData.append('file', buffer, { filename: 'example.ogg', contentType: 'audio/ogg' });
        const { data: [{ id }] } = await deep.insert({
            type_id: deep.idLocal('@deep-foundation/core', 'AsyncFile'),
            in: {
                data: [
                    {
                        type_id: deep.idLocal('@deep-foundation/core', 'Contain'),
                        from_id: voiceLinkId,
                    },
                ]
            },
        });

        console.log('drop-zone id file', id, file);
        console.log('drop-zone formData', formData);

        // Отправка файла на сервер
        const ssl = deep.apolloClient.ssl;
        const path = deep.apolloClient.path.slice(0, -4);
        const url = `${ssl ? "https://" : "http://"}${path}/file`;

        await axiosInstance.post(url, formData, {
            headers: {
                'linkId': id,
                "Authorization": `Bearer ${deep.token}`,
            },
        });
    }

    res.send('ok');  // Отправляет ответ 'ok' на запрос
}

After receiving the audio, Deep pulls out all the information: weight, title, duration, artist, type and name of the file in the system. This link to the file will be useful to us later, since it is substituted to obtain the file, as mentioned earlier. And if we use a regular browser, then this link will simply download the file.

Therefore, we have already seen the finish line, but there is just one “but”: files arrive in the Deep bit by bit. Or rather, the bits arrive in the form of text, and all this must be rewritten as a file. One unconscious evening, another consultation and yes, now the package creates a file. The whole system works and is pleasing to the eye. But you, the readers, may have a reasonable question: why bother so much? There are many possibilities and simpler options.

For example, you can use the package in conjunction with another package that converts speech to text and the ChatGPT package. Or use sent audio in conjunction with your own smart home system. There are actually a lot of options, I agree. And of course, it all depends on the user and the task at hand. But I wouldn’t like to rely simply on theories and assumptions when you can be part of something bigger and turn ideas into reality. Just recently SenchaPencha asked me to trim the package, leaving only the audio preservation. As it turned out, my package was for him the starting point for some grandiose plan.

This is what I'm getting at: you don't have to go far to find examples of reuse. Everything that we produce at Glubina will be used as an investment in a technological and modern future – either a small package or a large-scale project.

This is how you can poke around in my bag:

Step-by-step text instructions

  1. Launch Deep in the GitPod cloud

  2. Wait for the prebuild. After it is completed, 2 windows will open: ports 3007 and 4000. The second one can be closed. We will only work in the window of port 3007 (if the browser has blocked the opening of 2 windows, then you should open 3007 yourself – for this you should go to the bottom panel Ports and click on the link opposite port 3007)

  3. Login as Admin:

    1. Right-click on the link with the name User. A radial menu will appear.

    2. You need to select LMB traveler.

    3. After LMB select types+. New connections will appear. We need s type: Type name: User

    4. By analogy, go to the radial menu and select travelertyped+. There will be a connection with name: Admin.

    5. Go to the Administrator's communication radial menu and press the LMB button login

  4. Install package telegram-save-audio

    1. Click on the packager button in the upper right corner of the screen

    2. enter telegram-save-audio

    3. go to tab Not Install

    4. select the one we need by name and click install. We are waiting for installation and you can use the package.

    5. A link will appear with a box icon and name telegram-save-audio. Move it to a place convenient for you.

  5. Give the package admin rights

    1. We press RMB on an empty space. The radial menu appears. We need to create a connection.

    2. Choose insert. A window will appear ClientHandler.

    3. Select the hand with an eye icon in the upper left corner. An input field will appear.

    4. Enter “join” and click LMB on the item with the “handshake” icon and name Join

    5. Click on the checkmark in the lower right corner

    6. Click LMB to connect telegram-save-audio and hold down the left mouse button until the connection is made name: Admin. Release LMB.

    7. A connection will appear name: Join.

  6. Create a connection Host

    1. Similar to creating a connection Join create a connection with the type Hostbut now click LMB once on the empty space.

    2. Open communication radial menu Host and choose editor

    3. You also need to return to the tab gitpod. Go to the console tab below.

    4. Select tab Ports

    5. Select port 3050 and on the left side above the parameter State right click on open(private).

    6. Choose open(public)

    7. Click on the copy port 3050 button.

    8. Paste the copied value into the communication editor Host

    9. Ctrl+S and close the text editor window.

  7. Create a connection token

    1. By analogy with point c Host create a connection tokenbut now we insert the value of your bot’s token into it.

  8. Create a connection space and log in

    1. by analogy with the previous points of creating a connection. Features a purple glass ball icon.

    2. Enter the radial menu of the created connection and select the value space. You will appear in an empty space with one single connection space

  9. Create a connection InsertLinksTo similar to creating a connection joinbut now the beginning and end of the connection is one and also the connection – space(when searching in ClientHandler the connection will have a star icon)

  10. Open the top menu (3 arrows) and click on the cross next to the value space. We'll go back to Admin

  11. Now you need to create a connection SetWebHook (also with an asterisk) and draw it by analogy with the connection joinbut now from a previously created connection Host to our other connection token

  12. Your messages to the bot will appear within the connection space.

Video instruction

  1. Enter Deep.Case:

  1. Login to Admin:

  1. Use the sachet:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *