Рубрика: DataLens

  • Editor API

    Вводная

    Использовать API Connector в DataLens можно для множества вещей, на этой странице разберем основные подходы, как делать базовые запросы через API и разберем интересные примеры использования.

    Основные шаги подключения API

    Простое видео, как сделать запрос к API внутри DataLens

    То есть, основные шаги

    • Создать API или получить информацию по адресу и формату работы с некоторым API
    • Создать подключение к API
    • Создать чарт Editor
    • Написать и настроить код на Sources для интерактивной работы с API
    • Обработать результат на Prepare

    Пример: простой чат внутри DataLens

    Python Код для API

    import psycopg2
    import os
    import csv
    import io
    
    def handler(event, context):
        params = event.get('multiValueQueryStringParameters', {})
        chat_id   = params.get('chat_id',   [None])[0]
        message   = params.get('message',   [None])[0]
        author    = params.get('author',    [None])[0]
        message_key = params.get('message_key', [None])[0]
    
        if not chat_id:
            return {
                'statusCode': 400,
                'body': "Ошибка: параметр 'chat_id' является обязательным.",
                'headers': {'Content-Type': 'text/csv; charset=UTF-8'},
            }
    
        pg_pass = os.environ.get('PG_PASS')
        try:
            conn = psycopg2.connect(
                user="user1",
                password=pg_pass,
                host="rc1a-***.mdb.yandexcloud.net",
                port="6432",
                database="db1"
            )
            cur = conn.cursor()
    
            # 1. Обработка message_key: проверка и вставка
            if message_key is not None:
                cur.execute(
                    "SELECT 1 FROM chat_messages WHERE chat_id = %s AND message_key = %s",
                    (chat_id, message_key)
                )
                if not cur.fetchone():
                    # ключ не найден — вставляем полную строку
                    cur.execute(
                        "INSERT INTO chat_messages (chat_id, author, message, message_key, dttm) "
                        "VALUES (%s, %s, %s, %s, NOW())",
                        (chat_id, author, message, message_key)
                    )
                    conn.commit()
    
            # 2. Обычная логика добавления сообщения (если нет message_key)
            elif message and author:
                stop_words = ['политика', 'религия', 'другие чувствительные темы']
                if not any(w in message.lower() for w in stop_words):
                    cur.execute(
                        "SELECT 1 FROM chat_messages "
                        "WHERE author = %s AND message = %s AND chat_id = %s "
                        "AND dttm > NOW() - INTERVAL '1 minute'",
                        (author, message, chat_id)
                    )
                    if not cur.fetchone():
                        cur.execute(
                            "INSERT INTO chat_messages (chat_id, author, message, dttm) "
                            "VALUES (%s, %s, %s, NOW())",
                            (chat_id, author, message)
                        )
                        conn.commit()
    
            # 3. Получение последних 30 сообщений
            cur.execute("""
                SELECT author, message, dttm
                FROM (
                    SELECT author, message, dttm
                    FROM chat_messages
                    WHERE chat_id = %s
                    ORDER BY dttm DESC
                    LIMIT 30
                ) AS last_30
                ORDER BY dttm ASC;
            """, (chat_id,))
            rows = cur.fetchall()
    
            output = io.StringIO()
            w = csv.writer(output)
            w.writerow(['author', 'message', 'dttm'])
            if not rows:
                w.writerow(['-', '-', '-'])
            else:
                for r in rows:
                    w.writerow([r[0], r[1], r[2].isoformat()])
    
            return {
                'statusCode': 200,
                'body': output.getvalue(),
                'headers': {'Content-Type': 'text/csv; charset=UTF-8'},
            }
    
        except psycopg2.Error as e:
            return {
                'statusCode': 500,
                'body': f"Ошибка базы данных: {e}",
                'headers': {'Content-Type': 'text/csv; charset=UTF-8'},
            }
        finally:
            if 'cur' in locals():
                cur.close()
            if 'conn' in locals():
                conn.close()
    

    API Editor Chart

    var params = Editor.getParams();
    
    var author = params.user[0] != '' ? params.user[0]:Editor.getUserLogin();
    var message = params.message_to_send[0];
    var chat_id = params.chat_id[0];
    
    var message_key = author + params.send_dttm[0];
    
    if (message != '') {
    module.exports = {
        'myApiDataSource': {
            apiConnectionId: 'mu751arjzpn88',
            path: encodeURI(`?chat_id=${chat_id}&author=${author}&message=${message}&message_key=${message_key}`),
            method: 'GET'
            
            
        }
    }
    }
    else {
        module.exports = {
        'myApiDataSource': {
            apiConnectionId: 'mu751arjzpn88',
            path: `?chat_id=${chat_id}`,
            method: 'GET'
            
        }
    }
    }
    Editor.updateParams({"send_it":[""]});
    
    function print(mess) {
      console.log(mess);
    }
    
    
    function parseCsvToObjects(csvString) {
      const lines = csvString.trim().split('\n');
    
      // Функция, которая разбивает строку на значения с учётом кавычек
      function parseCsvLine(line) {
        const result = [];
        let current = '';
        let inQuotes = false;
    
        for (let i = 0; i < line.length; i++) {
          const char = line[i];
    
          if (char === '"') {
            // Если текущий символ кавычка, проверяем следующий чтобы определить если это экранирование
            if (inQuotes && line[i + 1] === '"') {
              // Экранированная кавычка двойным двойным
              current += '"';
              i++; // пропускаем следующий символ
            } else {
              inQuotes = !inQuotes; // переключаем состояние в/из кавычек
            }
          } else if (char === ',' && !inQuotes) {
            // Разделитель поля только если не внутри кавычек
            result.push(current);
            current = '';
          } else {
            current += char;
          }
        }
        result.push(current);
        return result;
      }
    
      const headers = parseCsvLine(lines[0]).map(h => h.trim());
    
      return lines.slice(1).map(line => {
        const values = parseCsvLine(line);
        const obj = {};
    
        headers.forEach((header, index) => {
          obj[header] = values[index] ? values[index].trim() : '';
        });
    
        return obj;
      });
    }
    
    
    var params = Editor.getParams();
    var current_user = params.user[0] != '' ? params.user[0]:Editor.getUserLogin();
    
    
    function csvToMarkdownChat(csvString) {
      const data = parseCsvToObjects(csvString);
      return data.map(({ author, message, dttm }) => {
        const isCurrentUser = author === current_user;
        const time = new Date(dttm).toLocaleTimeString([], { 
          hour: '2-digit', 
          minute: '2-digit',
          hour12: false // 24-часовой формат
        });
        
        // Иконка пользователя
        const userIcon = isCurrentUser ? '👤' : '👥';
        
        // Строка автора и времени
        const authorTimeLine = isCurrentUser 
          ? `> **${userIcon} Вы (${time})**` 
          : `**${userIcon} ${author} (${time})**`;
        
        // Сообщение с правильным выравниванием
        const messageLine = isCurrentUser 
          ? `{blue}(${message.replace(/\n/g, '\n> ')})` // Сохраняем переносы строк в цитате
          : message.replace(/\n/g, '\n'); // Обычное сообщение
        
        return `${authorTimeLine}\n${messageLine}`;
      }).join('\n\n');
    }
    
    
    
    const response = Editor.getLoadedData();
    print(response['myApiDataSource'].data.body.result);
    print(parseCsvToObjects(response['myApiDataSource'].data.body.result));
    const markdown = csvToMarkdownChat(response['myApiDataSource'].data.body.result);
    
    
    module.exports = {
        markdown
    };

    JS SELECTOR for message

    // Controls Tab
    
    var controls = [];
    var params = Editor.getParams();
    var message = params.message[0];
    
    var key = new Date().getTime() / 1000;
    
    if (message != '') {
    
        controls.push(
        {
            type: 'input',
            param: 'message',
            width:'85%',
            postUpdateOnChange: true
        })
            controls.push(
        {
            type: 'input',
            param: 'message_to_send',
            hidden:true
        })
        controls.push(
        {
            type: 'button',
            label: '💬',
            theme: 'action',
            updateOnChange: true,
            onClick: {
            action: 'setParams',
            args: {
                message_to_send:message,
                message: '',
                send_dttm:key
            }
            
        }
        }
        )
    } 
    else {
        controls.push(
        {
            type: 'input',
            param: 'message',
            width:'85%',
            updateOnChange: true
        })
         controls.push(
        {
            type: 'input',
            param: 'message_to_send',
            hidden:true
        })
    }
    
    module.exports = controls;