Формирование реестров документов для указанных папках с нужными параметрами (такими как название статьи, краткое описание и т.п.) с использованием API Gemini.
Я храню на Google Диске статьи и разные документы по тематическим подпапкам. Несмотря на удобный поиск по контексту, разобраться в самой структуре документов со временем становится невозможным. Хочется иметь удобный реестр, который автоматически обновляется и выводит информацию, необходимую для конкретного каталога.
Простое решение
В этой статье я расскажу, как с помощью цепочки архитектурных хитростей удалось создать полностью автономный инструмент, который:
Рекурсивно обходит гигабайты файлов во вложенных папках на Google Диске.
Бесплатно распознает текст из файлов PDF, DOC, DOCX через встроенный скрытый движок OCR от Google.
Анализирует, например, научные статьи с помощью бесплатной модели Gemini 3.1 Flash Lite.
Обходит ограничения квот (429 errors) за счет динамической ротации API-ключей.
Не боится зависаний и параллельных запусков благодаря блокировкам LockService.
Работает часами в фоновом режиме, перезапускаясь по триггерам без создания дублей в таблице. Автоматически добавляет информацию о новых файлах
Я практически не привожу тексты скриптов, так как Gemini легко сформирует вам требуемый Apps Script под ваши потребности, если вы пропишите ему указанные ниже подходы.
Проблема: папка на 200 файлов, PDF-сканы и 6-минутное ограничение
Задача решалась трудоемкая: систематизировать большой архив научных работ, вытащить из каждого документа точное название, аннотацию и проверить ключевое условие - является соавтором работы конкретный ученый или нет.
Вручную это делать нереально. Но есть же AI. Однако первый простой скрипт на Google Apps Script, собирал кучку проблем:
Лимит времени: Обработка одного сложного PDF-файла (OCR + запрос к LLM) занимает от 15 до 40 секунд. На 20-м файле скрипт падает по таймауту в 6 минут.
Бинарные форматы: GAS не умеет «из коробки» читать текст из PDF или DOCX. Подключать платные внешние API для парсинга - дорого и сложно.
Лимиты API Gemini: На бесплатном тарифе Google AI Studio действуют ограничения. Например, у Gemini 2.5 Flash лимит составляет всего 15 запросов в минуту (RPM) и всего 20 запросов в день (RPD!). Если слать файлы один за другим, квота сгорает мгновенно, возвращая ошибку HTTP 429 Too Many Requests.
Ниже - детальный разбор того, как мы обошли каждое из этих ограничений.
Архитектурные хитрости. Не костыли, а фичи
Бесплатный OCR «на коленке» без сторонних сервисов
Открытием стало, что мощный встроенный движок GDrive OCR (распознавания текста), который используется при ручном открытии PDF через Google Документы, можно вызвать программно через Drive API.
Движок корректно обрабатывает любые PDF: со сканами, с битой кодировкой…
Код копирует бинарный файл (PDF или DOCX) во временный документ Google Docs, принудительно включая параметр ocr: true. Google сам распознает текст, парсит структуру документа и сохраняет ее. Мы забираем текст через DocumentApp и удаляем временный файл.
Для работы этого метода в левой панели редактора Apps Script нужно обязательно добавить службу Drive API в разделе “Сервисы”.
Конструкцию создания/удаления файла стоит оборачивать в try...catch...finally, чтобы удаление происходило в любом случае, иначе в случае сбоя можно забить свой GDrive кучей временных файлов, например:
try { let resource = { title: 'temp_convert_' + fileId, mimeType: MimeType.GOOGLE_DOCS }; let options = { ocr: true, ocrLanguage: "ru" }; tempFile = Drive.Files.copy(resource, fileId, options); const doc = DocumentApp.openById(tempFile.id); text = doc.getBody().getText(); Drive.Files.remove(tempFile.id); } catch (e) { Logger.log("Ошибка OCR для файла ID " + fileId + ": " + e.toString()); if (tempFile) { try { Drive.Files.remove(tempFile.id); } catch(i) {} } }
Обход лимита в 6 минут с помощью триггеров времени
Поскольку за один запуск обработать все файлы невозможно, мы использовали нашу Google Таблицу как простейшую базу данных.
Перед началом обхода папок скрипт сканирует таблицу и кэширует имена уже обработанных файлов.
А в цикле обработки мы просто делаем проверку: if (existingFiles[fileName]) { continue; }.
Теперь настраиваем триггер времени (например минутный или на 10 минут) в панели Apps Script (знак “часы”). Скрипт запускается, работает свои 5-6 минут, падает. Через минуту триггер запускает его снова. Новый процесс сканирует таблицу, видит, что первые 15 файлов уже обработаны, мгновенно их пропускает и переходит к 16-му файлу. Процесс идет абсолютно автономно до тех пор, пока не обработает всю структуру папок. После этого скрипт должен программно удалять свои временные триггеры (чтобы избежать получения ошибки полного исчерпания суточного лимита).
Проблема Race Condition и защита через LockService
Когда мы настроили триггер, всплыл опасный баг. Извлечение текста из тяжелого PDF через OCR может занимать больше минуты.
Поток №1 берет файл paper_new.pdf и начинает его распознавать.
Проходит минута. Поток №2 запускается по триггеру. Он сканирует таблицу, но Поток №1 еще не записал результат для paper_new.pdf (он все еще парсится!).
Поток №2 решает, что файл не обработан, и тоже берет его в работу.
На выходе мы получаем дублирующиеся строки в таблице и впустую сожженные лимиты API. В реестр может добавляться и временный файл от OCR.
Решение - использование встроенной службы взаимных исключений LockService. Например:
try { let resource = { title: 'temp_convert_' + fileId, mimeType: MimeType.GOOGLE_DOCS }; let options = { ocr: true, ocrLanguage: "ru" }; tempFile = Drive.Files.copy(resource, fileId, options); const doc = DocumentApp.openById(tempFile.id); text = doc.getBody().getText(); Drive.Files.remove(tempFile.id); } catch (e) { Logger.log("Ошибка OCR для файла ID " + fileId + ": " + e.toString()); if (tempFile) { try { Drive.Files.remove(tempFile.id); } catch(i) {} } }
Ротация API-ключей и борьба с ошибкой HTTP 429 (Too Many Requests)
Бесплатные лимиты Google AI Studio привязаны к API-ключу. Чтобы не утыкаться в суточный потолок одного ключа, мы реализовали ротацию пула ключей. Скрипт принимает массив ключей API и циклически переключается между ними, если ловит статус 429. Например:
let currentKeyIndex = 0; //... внутри цикла отправки запроса... if (responseCode === 429) { let oldIndex = currentKeyIndex; currentKeyIndex = (currentKeyIndex + 1)% GEMINI_API_KEYS.length; Logger.log(«Ключ №» + (oldIndex + 1) + “ временно исчерпан. Переключаемся на Ключ №“ + (currentKeyIndex + 1)); if (currentKeyIndex === 0) { // Если по кругу вернулись к первому ключу — значит, исчерпан минутный лимит (RPM) у всех ключей. // Спим 30 секунд для сброса квоты. Utilities.sleep(30000); } continue; // Повторяем запрос с новым ключом }
Структурированный JSON-ответ от LLM в одно действие
Нам нужно вытащить два разных параметра: оригинальное название статьи и ее краткую аннотацию. Делать два отдельных запроса к AI - расточительство лимитов.
Мы использовали возможность Gemini API - принудительный режим вывода JSON (responseMimeType: "application/json"). Мы передаем промт, требующий вернуть JSON-объект с полями title и summary. API гарантирует, что на выходе будет чистый JSON-код без markdown-разметки типа ```json или лишнего сопроводительного текста:
const payload = { "contents": [{ "parts": [{ "text": prompt }] }], "generationConfig": { "responseMimeType": "application/json" } };
Скрипт парсит этот JSON и аккуратно раскладывает название и аннотацию в соответствующие колонки таблицы.
Итоговый рабочий пайплайн

В результате получилась гибкая и отказоустойчивая система. Если файл не является текстовым (например, это презентация .pptx или таблица .xlsx), скрипт мгновенно заносит его в реестр со стандартной заглушкой («Презентация (содержимое не запрашивалось)»), не расходуя токены AI.
Если же это текстовый файл, происходит глубокий анализ:
Извлекается до 50 000 символов текста.
Происходит обращение к модели gemini-3.1-flash-lite (у нее шикарный лимит - 15 запросов в минуту в бесплатном тарифе).
В промте жестко задано условие: «Проверь, есть ли среди соавторов или в тексте фамилия… Если нет - сделай явную пометку в поле summary».
Данные структурированно заносятся в таблицу.
Если суточный лимит по всем ключам исчерпан полностью (что бывает при обработке очень больших папок за один день), скрипт просто прекращает запись текущего файла в таблицу. Он остается «необработанным» и будет бесшовно подхвачен триггером на следующий день, когда обновятся лимиты квот. Дневной лимит у gemini-3.1-flash-lite 500 запросов. Если использовать 3 API ключа, то можно качественно обработать 1.500 файлов. С учетом RPM (запросов в минуту)- 15, на 1.500 файлов уйдет около 2 часов.
Бесплатный API получаем на aistudio.google.com. Там же (в Gemini API Usage) - графики по своим запросам. Текущие лимиты можно посмотреть в Gemini API Rate Limit, а все доступные лимиты- там же, с переключателем “All model”
Заключение
Используя эту связку решений, можно абсолютно бесплатно и удобно каталогизировать архивы документов, формировать разные реестры для всевозможных целей и автоматизировать учет документов внутри Google Drive. Google Apps Script превращается из «игрушечного» макрос-языка в мощную платформу, способную переваривать огромные массивы данных в связке с современными AI.
