Course
Ручной ввод данных — враг продуктивности. Если ваша команда извлекает данные из операционных писем, таких как счета, подтверждения бронирований или формы обратной связи, вам наверняка знаком кошмар традиционных методов парсинга.
Исторически разработчики полагались на регулярные выражения (Regex), чтобы вытащить детали вроде номера счета или суммы к оплате. Но Regex крайне хрупок: стоит поставщику изменить шаблон письма или добавить случайный разрыв строки — и весь парсер тихо ломается.
В этом руководстве я покажу, как собрать полностью автоматизированный, безголовый конвейер, решающий эту проблему с помощью генеративного ИИ. Мы напишем легковесный скрипт, который читает непрочитанные письма в Gmail, передает неструктурированный текст в API Gemini для интеллектуального извлечения и записывает идеально структурированные данные JSON прямо в Google Sheet.
Предварительные требования:
- Учетная запись Google
- Базовое знакомство с JavaScript (Google Apps Script)
- Ключ API Gemini
Что такое Google Apps Script?
Google Apps Script — это облачная платформа быстрой разработки приложений на базе JavaScript, позволяющая автоматизировать, настраивать и расширять приложения Google Workspace, такие как Документы, Таблицы, Презентации и другие.
Поскольку платформа работает непосредственно на серверах Google, нет необходимости устанавливать ПО, настраивать локальные среды или управлять инфраструктурой.
Apps Script дает разработчикам и low-code‑разработчикам возможность программно взаимодействовать с инструментами Google Workspace, такими как Docs, Sheets, Slides, Drive и др. Вы можете создавать и запускать автоматизации через пользовательские меню, нажатия кнопок или по расписанию, а также использовать сервис для создания и публикации аддонов в Google Workspace Marketplace.
Как работает Google Apps Script
Google Apps Script снимает с вас тяжесть настройки бэкенда и аутентификации API, позволяя сосредоточиться на логике и данных. Это достигается за счет следующих возможностей:
- Облачный редактор: вы пишете, отлаживаете и разворачиваете JavaScript‑код полностью в веб‑IDE прямо в браузере.
- Встроенные сервисы: вместо борьбы с OAuth и сложными вызовами API вы используете готовые глобальные объекты (такие как SpreadsheetApp, MailApp или DriveApp) для нативного взаимодействия с сервисами Google.
- Событийные триггеры: скрипты можно выполнять вручную через пользовательские кнопки меню или запускать автоматически по времени (например, каждую полночь) и по событиям (например, при отправке пользователем формы Google).
Архитектура Google Apps Script: конвейер от Gmail к Sheets
Прежде чем писать скрипт, давайте опишем, как данные проходят через конвейер. Архитектура опирается на четыре компонента, работающих вместе:
- Gmail (источник): процесс начинается с запроса к вашему инбоксу с использованием стандартных операторов поиска (например, is:unread label:invoices). Скрипт выделяет нужные треды и извлекает как текстовое тело, так и все прикрепленные PDF‑файлы.
- Apps Script (вычисления): выступает в роли оркестрационного слоя. Он проходит по непрочитанным тредам, преобразует вложения в данные base64 и отвечает за логику отчетов об ошибках и пакетную обработку.
- API Gemini (движок преобразования): Apps Script отправляет мультимодальный полезный груз (текст письма плюс PDF) в модель Gemini 2.5 Flash. Передавая в вызове API строгую схему JSON‑ответа, мы заставляем модель извлекать точные значения — поставщика, сумму и валюту — вместо генерации разговорного текста.
- Google Sheets (назначение): когда Gemini возвращает структурированный JSON, Apps Script парсит результаты, собирает их в единый массив и пакетно вставляет данные в следующую пустую строку активной таблицы с помощью setValues().

Зачем использовать Google Apps Script в качестве вычислительного слоя для этой сборки?
Главное преимущество — полное отсутствие инфраструктурных накладных расходов. Не требуется никаких серверов, вам не нужно настраивать Docker‑контейнеры или организовывать сложные потоки OAuth только ради чтения писем или записи в таблицу.
Поскольку Apps Script нативно интегрируется с сервисами GmailApp и SpreadsheetApp, за аутентификацию отвечает Google. Вам остается написать код и связать конечные точки.
Шаг 1. Подготовьте среду Google Apps Script
Прежде чем писать код, подготовим внешние зависимости. Это включает получение доступа к API Gemini, создание целевой таблицы и настройку инбокса Gmail для корректной маркировки входящих счетов.
Генерация ключа API Gemini
Чтобы обеспечить интеллектуальное извлечение данных, нам нужен доступ к API Gemini.
- Перейдите в Google AI Studio и войдите под своей учетной записью Google.
- В левом меню нажмите Get API key.
- Нажмите кнопку Create API key. Вы можете создать ключ в существующем проекте Google Cloud или позволить AI Studio создать новый.
- Скопируйте сгенерированную строку.
Рекомендация по безопасности: не теряйте этот ключ и, главное, не планируйте хранить его в открытом виде в коде. Оставьте его в буфере обмена или сохраните в защищенном заметнике — на следующем шаге мы надежно поместим его в среду Apps Script.

Подготовка Google Sheet и защита ключа
Нужно место для хранения извлеченных данных. Этот лист также послужит точкой запуска нашего скрипта автоматизации.
1. Задайте заголовки «базы данных» Создайте новую пустую таблицу Google. В первой строке добавьте следующие заголовки столбцов, соответствующие JSON‑схеме, которую мы определим в скрипте:
- Date
- Vendor
- Invoice Number
- Total Amount
- Currency
- Items Summary
- Email Link
Закрепите верхнюю строку, чтобы заголовки оставались видимыми по мере роста объема данных.

2. Откройте Apps Script и сохраните ключ API Теперь, когда лист создан, откроем редактор Apps Script прямо из него. Это автоматически свяжет наш код с данной таблицей.
- В вашей таблице нажмите Extensions > Apps Script в верхнем меню.

- Когда откроется редактор, в левой боковой панели нажмите на значок шестеренки, чтобы открыть Project Settings.

- Прокрутите вниз до блока Script Properties.
- Нажмите Add script property.
- В поле Property введите точно
GEMINI_API_KEY. - В поле Value вставьте ключ API, который вы скопировали ранее из AI Studio.
- Нажмите Save script properties.

Написанный далее код теперь будет безопасно получать это значение во время выполнения, не раскрывая ваши учетные данные.
Шаг 2. Напишите код Google Apps Script
Находясь в редакторе Apps Script, удалите любой код по умолчанию. Мы построим наш движок автоматизации по блокам.
1. Конфигурация и настройка интерфейса
Начнем с определения глобального объекта конфигурации. Это хорошая практика «чистого кода»: все жестко заданные переменные собраны в одном месте, и вам нужно править только верхний блок.
Также добавим функцию onOpen(). Этот встроенный триггер Apps Script автоматически создает пользовательское меню в Google Sheets, позволяя нетехническим пользователям запускать скрипт вручную, не открывая редактор кода.
const CONFIG = {
searchQuery: "is:unread label:invoices",
model: "gemini-2.5-flash",
adminEmail: Session.getActiveUser().getEmail() // Automatically emails the script owner if it crashes
};
/**
* Creates a custom menu in Google Sheets so non-technical users can run the script manually.
*/
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('🤖 AI Automations')
.addItem('Fetch New Invoices', 'processInvoices')
.addToUi();
}
2. Оркестрация
Функция processInvoices() выступает главным оркестратором. Она начинает с безопасного получения ключа API из Script Properties, настроенных ранее.
Затем использует встроенный сервис GmailApp для запроса инбокса.
Вызвав GmailApp.search(CONFIG.searchQuery), скрипт получает массив тредов, соответствующих правилу is:unread label:invoices.
Если есть совпадения, он перебирает каждый тред, берет последнее сообщение, извлекает текстовое тело и выделяет все вложенные PDF‑файлы.
function processInvoices() {
const apiKey = PropertiesService.getScriptProperties().getProperty("GEMINI_API_KEY");
if (!apiKey) {
throw new Error("GEMINI_API_KEY is missing! Please set it in Script Properties.");
}
const threads = GmailApp.search(CONFIG.searchQuery);
if (threads.length === 0) return;
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const batchData = [];
const processedThreads = [];
3. Обработка писем и мультимодальных PDF
Перебирая треды, мы берем последнее сообщение. Однако счета редко приходят в виде простого текста — почти всегда они во вложениях как PDF.
Используя Gemini 2.5 Flash, который нативно мультимодален, наш скрипт проходит по latestMessage.getAttachments(), берет все PDF, конвертирует их в строку Base64 и передает непосредственно в полезную нагрузку API как inlineData.
Gemini «читает» PDF визуально и извлекает данные так же легко, как и текст.
for (let i = 0; i < threads.length; i++) {
const thread = threads[i];
const latestMessage = thread.getMessages().pop();
const emailBody = latestMessage.getPlainBody();
const emailDate = latestMessage.getDate();
const emailLink = https://mail.google.com/mail/u/0/#inbox/${thread.getId()};
const attachments = latestMessage.getAttachments();
try {
const geminiParts = [];
geminiParts.push({ text: "Extract invoice details from this email and any attached documents:\n\n" + emailBody });
// Add PDF attachments as base64 to the prompt
for (const attachment of attachments) {
if (attachment.getContentType() === "application/pdf") {
geminiParts.push({
inlineData: {
mimeType: "application/pdf",
data: Utilities.base64Encode(attachment.getBytes())
}
});
}
}
// Invoke Gemini API
const extractedData = callGeminiAPI(apiKey, geminiParts);
4. Пакетная вставка и обработка ошибок
Для оптимизации производительности мы не записываем строки по одной в таблицу.
Вместо этого мы помещаем извлеченные данные JSON в массив (batchData) и записываем все сразу в конце с помощью setValues().
Обратите внимание на блок try...catch.
Если Gemini «галлюцинирует» или дает сбой на конкретном письме, скрипт не падает целиком. Он аккуратно перехватывает ошибку и с помощью MailApp.sendEmail() немедленно уведомляет администратора, обеспечивая высокую наблюдаемость.
// Push to batch array instead of writing one-by-one
batchData.push([
emailDate,
extractedData.vendor || "Unknown Vendor",
extractedData.invoiceNumber || "N/A",
extractedData.totalAmount || 0.00,
extractedData.currency || "USD",
extractedData.itemsSummary || "N/A",
emailLink
]);
processedThreads.push(thread);
} catch (error) {
MailApp.sendEmail(CONFIG.adminEmail, "🚨 Invoice Pipeline Error", error.toString());
}
}
// Batch Write to Sheets
if (batchData.length > 0) {
const lastRow = Math.max(sheet.getLastRow(), 1);
sheet.getRange(lastRow + 1, 1, batchData.length, batchData[0].length).setValues(batchData);
}
// Mark all processed threads as read so they aren't parsed again
processedThreads.forEach(t => t.markRead());
}
Наконец, скрипт вызывает thread.markRead() для каждого обработанного письма. Это гарантирует, что при следующем запуске скрипта он проигнорирует эти письма и найдет только новые.
5. Вспомогательная функция API Gemini (JSON‑режим)
При обращении к LLM разработчики часто используют приемы промт‑инжиниринга вроде «Верни блок JSON». Однако модели нередко отвечают разговорной «обвязкой» (например: «Конечно, вот ваши данные: [JSON]»), что ломает последующий парсинг.
Задав responseMimeType: "application/json" и указав строгую responseSchema, мы заставляем REST API Gemini отвечать только гарантированным JSON‑объектом с нашими точными заголовками столбцов для таблицы.
function callGeminiAPI(apiKey, partsArray) {
const url = https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.model}:generateContent?key=${apiKey};
const responseSchema = {
type: "OBJECT",
properties: {
vendor: { type: "STRING" },
invoiceNumber: { type: "STRING" },
totalAmount: { type: "NUMBER" },
currency: { type: "STRING" },
itemsSummary: { type: "STRING" }
},
required: ["vendor", "totalAmount"]
};
const payload = {
contents: [{ parts: partsArray }],
generationConfig: {
responseMimeType: "application/json",
responseSchema: responseSchema
}
};
const options = {
method: "POST",
contentType: "application/json",
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
const jsonResponse = JSON.parse(response.getContentText());
return JSON.parse(jsonResponse.candidates[0].content.parts[0].text);
}
Шаг 3. Автоматизируйте конвейер Google Apps Script
Код ценен только тогда, когда упрощает вам жизнь.
Google Apps Script предоставляет мощные среды выполнения — от интерактивных кнопок до полностью безголовых фоновых «кронов».
Метод 1: Запуск через интерфейс таблицы
Если вы создаете этот инструмент для нетехнической бухгалтерской команды, они вряд ли захотят открывать редактор кода Apps Script, чтобы обработать сегодняшние счета.
Поскольку мы включили функцию onOpen() в наш код, Apps Script автоматически добавляет пользовательское меню прямо в интерфейс Google Sheets при каждом открытии таблицы.
- Вернитесь в таблицу и обновите страницу.
- Через несколько секунд в верхней панели меню появится новый пункт 🤖 AI Automations.
- Нажмите его и выберите Fetch New Invoices.

- При первом запуске Google попросит авторизовать скрипт (для чтения вашей почты Gmail и отправки писем от вашего имени). После авторизации скрипт выполнится в реальном времени. Вы увидите, как извлеченные данные JSON заполняют строки прямо на глазах!
Метод 2: Безголовая автоматизация через триггеры по времени
Если вам нужна настоящая автоматизация по принципу «настроил — и забыл», используйте встроенные триггеры по времени, чтобы конвейер работал автономно в фоне.
- В редакторе Apps Script нажмите Триггеры (значок часов) в левой панели.

- Нажмите Add Trigger в правом нижнем углу.

- Выберите функцию processInvoices.
- Измените источник события на Time‑driven и настройте запуск по часам (например, каждые 6 часов).
- Нажмите Save.

Теперь ваш безголовый ИИ‑конвейер полностью автономен.
Даже если ваш компьютер полностью выключен, серверы Google будут каждые шесть часов «просыпаться», сканировать инбокс, разбирать счета через Gemini, записывать данные в Sheets и снова «засыпать».
Вы можете отслеживать успех или неудачи фоновых запусков, нажав вкладку Executions в редакторе Apps Script и посмотрев логи.
Шаг 4. Тестирование ИИ‑извлечения данных
Теперь, когда код готов, нужно протестировать его, чтобы убедиться, что конвейер извлечения работает как ожидается.
Рассмотрим две практические ситуации, чтобы увидеть, как API Gemini справляется с разными форматами данных и какие ответы фактически возвращает.
Тест 1: Извлечение из письма с простым текстом
Сначала проверим счет, встроенный прямо в тело письма.
- Отправьте себе письмо с темой «Invoice INV-2023-88493».
- В теле напишите неструктурированный текст, например: «Hi Team, please pay Acme Corp $450.00 USD for the Q3 software license.»
- Присвойте письму метку invoices и убедитесь, что оно остается непрочитанным.

- Запустите скрипт через пользовательское меню.

За кулисами Gemini получает этот неструктурированный текст и строго следует нашей JSON‑схеме.
Вместо разговорной «обвязки» он возвращает «сырой» полезный груз.
Поскольку ответ — идеально структурированный JSON, наш массив batchData.push() беспрепятственно читает extractedData.totalAmount и записывает 6550 прямо в Google Sheet без какой‑либо сложной логики Regex.

Тест 2: Извлечение из PDF‑вложения
Теперь проверим настоящую мощь Gemini 2.5 Flash, передав ему PDF‑документ.
- Сгенерируйте или скачайте пример счета в PDF (например, на $20,700.00 от ProTech Cloud Services).
- Отправьте себе письмо с этим PDF. Тело письма можно оставить пустым!
- Присвойте метку invoices и оставьте письмо непрочитанным.

- Запустите скрипт. Конвейер обнаружит вложение, конвертирует его в Base64, а Gemini визуально прочитает документ и извлечет поставщика и сумму.

Здесь архитектура демонстрирует свою ценность.
Вам не пришлось писать собственный OCR (оптическое распознавание символов), подключать отдельную библиотеку для парсинга PDF или составлять регулярные выражения для поиска итоговой суммы.
LLM нативно обработала неструктурированные визуальные данные.
Заключение
Автоматизация бизнес‑процессов не требует тяжелой инфраструктуры или борьбы со сложными контурами авторизации.
Комбинируя Google Apps Script и API Gemini, мы построили интеллектуальный бессерверный конвейер данных, полностью работающий в облачной экосистеме, которой вы уже пользуетесь ежедневно.
Сила этой архитектуры — в простоте. Вместо развертывания серверов, настройки вебхуков или управления защищенными файлами учетных данных на внешнем сервере Apps Script нативно берет на себя контекст, аутентификацию и выполнение.
Тем временем Gemini устраняет необходимость в хрупких регулярных выражениях или дорогом OCR‑ПО, превращая «шумные» письма и неструктурированные PDF в предсказуемые строки базы данных одним вызовом API.
Чтобы продвинуться дальше и узнать, что еще можно построить с программным доступом к LLM, рекомендую курс DataCamp Introduction to APIs in Python или углубиться в проектирование интеллектуальных рабочих процессов в курсе AI Agent Fundamentals .