
Куда только уже этот ChatGPT не прикрутили с момента его появления. Возможно я изобрету велосипед, но мне показалось удобным сделать бота в Телеграм, который бы поддерживал голосовой ввод и управлял моим календарем в Google.
Итак, что мы будем делать?
Создадим нейро-сотрудника на моей платформе
Зарегистрируем Телеграм-бот и подключим его к нашему сотруднику
Напишем API для интеграция с Google календарем
Дадим функцию нашему сотруднику для работы с API
Шаг №1: Создаем нейро-сотрудника

Дабы не нарушать правила хабра я не буду писать название платформы по созданию нейро-сотрудников и дам только сам системный промпт на базе которого будет работать наш бот:
Цель: Помогать пользователю вести его Google календарь. Роль:йр Ты - женщина. Тебя зовут - Жанна Ты работаешь в должности - Личный секретарь Твоя задача помогать управлять календарем Google используя функцию "google_calendar". Поведение: Для твоей работы необходим ID календаря, который ты будешь передавать в функцию "google_calendar". ID календаря может быть предоставлен и в виде Email адреса. Без него ты не можешь отвечать ни на какие вопросы пользователя. При показе запланированных событий после названия события указывай его "event_id". Перед удалением событий запроси согласие пользователя на удаление событий и после подтверждения запусти "google_calendar" на удаление событий по интервалу дат или по списку "event_id". Не используй в ответах никакие эмоджи, кроме: "✅" и "?️".
Возможно пока не очень ясны некоторые инструкции в промпте, но позже вы все поймете, а пока важно отметить что промпт очень небольшой и по сути всем полностью будет управлять интеллект ChatGPT.
Шаг №2: Регистрируем Telegram-bot и прикручиваем его к нашему нейро-сотруднику
Тут все очень просто:
Зайдите в вашем Телеграме в бот @BotFather
Выберите в меню бота /newbot и следуйте указаниям
После регистрации бота скопируйте токен бота, он нужен для интеграции с нашим нейро-сотрудником


Шаг №3: Напишем API для интеграция с Google календарем
Для получения необходимого файла с ключами 'credentials.json' доступа прочитайте статью: «Настройка синхронизации google calendar с web приложением».
Вот класс, описывающий интеграцию с Google Calendar API:
from __future__ import print_function import datetime import googleapiclient from google.oauth2 import service_account from googleapiclient.discovery import build import uuid import json import codecs class GoogleCalendar(object): SCOPES = ['<https://www.googleapis.com/auth/calendar>'] CREDS_FILE = 'credentials.json' def __init__(self, calendarId): credentials = service_account.Credentials.from_service_account_file(CREDS_FILE, scopes=GoogleCalendar.SCOPES) self.service = googleapiclient.discovery.build('calendar', 'v3', credentials=credentials) self.calendarId = calendarId def create_event(self, event): e = self.service.events().insert(calendarId=self.calendarId, body=event).execute() print('Event created: %s' % (e.get('id'))) return e def get_events_list(self, start_date=None, end_date=None): now = datetime.datetime.utcnow().isoformat() + 'Z' if start_date is None and end_date is None: events_result = self.service.events().list(calendarId=self.calendarId, timeMin=now, maxResults=100, singleEvents=True, orderBy='startTime').execute() else: events_result = self.service.events().list(calendarId=self.calendarId, timeMin=start_date, timeMax=end_date, singleEvents=True).execute() events = events_result.get('items', []) if not events: print('No upcoming events found.') return json.dumps('No upcoming events found.') events_list = self.encode_events_list(events) return events_list def encode_events_list(self, events): events_list = [] for event in events: start = event['start'].get('dateTime', event['start'].get('date')) end = event['end'].get('endTime', event['end'].get('date')) events_list.append({ 'event_id' : event['id'], 'event_summary' : event['summary'], 'event_start' : start, 'event_end' : end, }) return events_list def update_event(self, event_id, updated_event): current_event = self.service.events().get(calendarId=self.calendarId, eventId=event_id).execute() updated_title = updated_event.get('summary', current_event['summary']) updated_start = updated_event.get('start', current_event['start']) updated_end = updated_event.get('end', current_event['end']) updated_event = { 'summary': updated_title, 'start': updated_start, 'end': updated_end } event = self.service.events().update(calendarId=self.calendarId, eventId=event_id, body=updated_event).execute() print('Event updated: %s' % event.get('id')) return json.dumps('Event updated.') def delete_event(self, event_id): res = self.service.events().delete(calendarId=self.calendarId, eventId=event_id).execute() print('Event deleted: %s' % event_id) return json.dumps('Event deleted.') def delete_events_in_range(self, start_date, end_date): events_result = self.service.events().list(calendarId=self.calendarId, timeMin=start_date, timeMax=end_date, singleEvents=True).execute() events = events_result.get('items', []) for event in events: self.delete_event(event['id']) events_list = self.encode_events_list(events) return json.dumps('Events deleted.')
А вот сам код API на базе Flask:
from flask import Flask, Response, render_template, redirect, url_for, request, session, jsonify from flask_cors import CORS from flask import send_from_directory import google.calendar # !!! это наш класс, описанный в блоке выше app = Flask(__name__) app.static_folder = 'static' CORS(app) def GetJsonFromRequest(request): data = request.get_json(force=True) if type(data) is not dict: data = request.get_json() data = json.loads(data) return data @app.route('/api/v1.0/google_calendar', methods=['POST']) def google_calendar(): data = GetJsonFromRequest(request) try: calendar = google.calendar.GoogleCalendar(data['calendarId']) if data['action'] == '+': res = calendar.create_event(data['event']) if data['action'] == '?': res = calendar.get_events_list(data['start_date'], data['end_date']) if data['action'] == '-': if data['start_date'] is None: res = calendar.delete_event(data['event_id']) else: res = calendar.delete_events_in_range(data['start_date'], data['end_date']) if data['action'] == '.': res = calendar.update_event(data['event_id'], data['event']) print('[END - google_calendar res]', res) return res except Exception as e: print('[END - google_calendar ERROR]', str(e)) return 'Error' if __name__ == "__main__": app.run(debug=False, host='0.0.0.0', port=5000)
Шаг №4: Напишем функцию для связи ChatGPT и нашего Google Calendar API
Для вызова функций в ChatGPT нам нужно дать описание всех переменных функции и сам код функции.
Вот описание параметров нашей функции:
{ "name": "google_calendar", "description": "Управление календарем Google", "parameters": { "type": "object", "properties": { "calendarId": { "type": "string", "description": "ID календаря", }, "action": { "type": "string", "enum": ["+", "?", '-', '.'], "description": "Тип действия. `+` - означает добавление события. `?` - означает получение всех событий календаря.. `-` - удалить событие в календаре. `.` - редактировать событие в календаре.", }, "event_ids": { "type": "string", "description": "Список ID событый в календаре в формате json: ```[{\\"event_id\\": \\"3lsvlor3hjlgpgmv7er7e5juov\\"}]```. Передается при типах действия `-` или '.'", }, "events": { "type": "string", "description": "Список событий в формате json: ```[{\\"summary\\": \\"test event\\", \\"description\\": \\"some info\\", \\"start\\": {\\"dateTime\\": \\"2024-09-04T03:00:00+03:00\\"}, \\"end\\": {\\"dateTime\\": \\"2024-09-04T05:30:00+03:00\\"}}]```. Передается при типах действия `+` или '.'", }, "start_date": { "type": "string", "description": "Дата начала периода в формате `2024-09-04T03:00:00+03:00`. Передается при типах действия `?` или '-'", }, "end_date": { "type": "string", "description": "Дата окончания периода в формате `2024-09-04T03:00:00+03:00`. Передается при типах действия `?` или '-'", }, }, "required": ["calendarId", "action"], }, },
А вот сам код функции:
def google_calendar(arguments): import requests import json data = { "sa_data" : None, "calendarId" : arguments['calendarId'], "action" : arguments['action'], 'start_date' : None, 'end_date' : None, } if 'start_date' in arguments.keys(): data['start_date'] = arguments['start_date'] if 'end_date' in arguments.keys(): data['end_date'] = arguments['end_date'] if arguments['action'] == '?': response = requests.post('https://___АДРЕС_АПИ_СЕРВИСА___/api/v1.0/google_calendar', data=json.dumps(data)) return response.text else: responses = [] if arguments['action'] == '+' or arguments['action'] == '.': if 'events' in arguments.keys(): events = json.loads(arguments['events']) for i in range(len(events)): e = events[i] data['event'] = e if 'event_ids' in arguments.keys(): event_ids = json.loads(arguments['event_ids']) data['event_id'] = event_ids[i] response = requests.post('https://___АДРЕС_АПИ_СЕРВИСА___/api/v1.0/google_calendar', data=json.dumps(data)) responses.append(response.text) if arguments['action'] == '-': if 'event_ids' in arguments.keys(): event_ids = json.loads(arguments['event_ids']) for i in range(len(event_ids)): data['event_id'] = event_ids[i]['event_id'] response = requests.post('https://___АДРЕС_АПИ_СЕРВИСА___/api/v1.0/google_calendar', data=json.dumps(data)) responses.append(response.text) if 'start_date' in arguments.keys(): response = requests.post('https://___АДРЕС_АПИ_СЕРВИСА___/api/v1.0/google_calendar', data=json.dumps(data)) responses.append(response.text) return json.dumps(str(responses))
Тестирование бота
Поскольку в промпте у нашего нейро-сотрудника есть такая инструкция:
Поведение: 1. Для твоей работы необходим ID календаря, который ты будешь передавать в функцию "google_calendar". ID календаря может быть предоставлен и в виде Email адреса. Без него ты не можешь отвечать ни на какие вопросы пользователя.
При старте общения с нашим ботом мы видим следующий диалог:

Если мы укажем наш ID календаря, то бот ответит примерно так:

Давайте для примера запланируем отпуск в Рио в нашем боте. Для начала спросим:

Поскольку у нас ничего пока нет в календаре, то попросим спланировать посещение достопримечательностей в Рио на этот период:

Посмотрим теперь в наш календарь Google:

Отлично! Получилось! Давайте немного посложнее попросим бота:

Как мы видим бот спросил подтверждение при удалении события из календаря, это было в его инструкции:
Поведение: ... 3. Перед удалением событий запроси согласие пользователя на удаление событий и после подтверждения запусти "google_calendar" на удаление событий по интервалу дат или по списку "event_id". ...
Проверяем календарь и видим, что событие было удалено:

Думаю идею вы уже уловили. Бота можно просить корректировать название событий, переносить события на нужную дату и время и т.д.
Да, и самое важное - боту можно отправлять голосовые и он так же будет помогать вам вести Google календарь.

Итоги
В целом мозгов у ChatGPT 4 вполне хватает на управление календарем.
Что можно еще попробовать?
Разбиение сложных задач на подзадачи
Помощь с распределением задач
Ежедневное уведомление о важных делах на сегодня/неделю/месяц
Просить бота фокусировать внимание пользователя на важных событиях и говорить об этом при постановке задач
Дать боту Яндекс.Календарь и предлагать в начале выбрать с каким календарем работать
Сам бот можно протестировать тут.
Идеи и вопросы пишите мне в телеграм.
