Даём нейро-сотруднику на ChatGPT управлять календарем Google через Telegram бот

от автора

Фото сгенерировано в OpenAI по запросу: "сгенери фото для статьи "ChatGPT управляет вашим календарем Google через персональный бот в Telegram"

Фото сгенерировано в OpenAI по запросу: «сгенери фото для статьи «ChatGPT управляет вашим календарем Google через персональный бот в Telegram»

Куда только уже этот ChatGPT не прикрутили с момента его появления. Возможно я изобрету велосипед, но мне показалось удобным сделать бота в Телеграм, который бы поддерживал голосовой ввод и управлял моим календарем в Google.

Итак, что мы будем делать?

  1. Создадим нейро-сотрудника на моей платформе

  2. Зарегистрируем Телеграм-бот и подключим его к нашему сотруднику

  3. Напишем API для интеграция с Google календарем

  4. Дадим функцию нашему сотруднику для работы с API

Шаг №1: Создаем нейро-сотрудника

На скриншоте начало квиза по созданию нейро-сотрудника

На скриншоте начало квиза по созданию нейро-сотрудника

Дабы не нарушать правила хабра я не буду писать название платформы по созданию нейро-сотрудников и дам только сам системный промпт на базе которого будет работать наш бот:

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

Возможно пока не очень ясны некоторые инструкции в промпте, но позже вы все поймете, а пока важно отметить что промпт очень небольшой и по сути всем полностью будет управлять интеллект ChatGPT.

Шаг №2: Регистрируем Telegram-bot и прикручиваем его к нашему нейро-сотруднику

Тут все очень просто:

  1. Зайдите в вашем Телеграме в бот @BotFather

  2. Выберите в меню бота /newbot и следуйте указаниям

  3. После регистрации бота скопируйте токен бота, он нужен для интеграции с нашим нейро-сотрудником

На скриншоте блок по настройке бота в Телеграм для работы нашего нейро-сотрудника

На скриншоте блок по настройке бота в Телеграм для работы нашего нейро-сотрудника
Так же вы можете сделать бота условно бесплатным и ограничить количество бесплатных токенов

Так же вы можете сделать бота условно бесплатным и ограничить количество бесплатных токенов

Шаг №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 адреса. Без него ты не можешь отвечать ни на какие вопросы пользователя. 

При старте общения с нашим ботом мы видим следующий диалог:

На скрине начало диалога с нейро-сотрудником, управляющим Google календарем

На скрине начало диалога с нейро-сотрудником, управляющим Google календарем

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

После получения ID Google календаря наш нейро-сотрудник готов им управлять

После получения ID Google календаря наш нейро-сотрудник готов им управлять

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

Просим нейро-сотрудника проверить события за заданный период

Просим нейро-сотрудника проверить события за заданный период

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

Просим нашего бота с помощью ChatGPT придумать интересные для посещения места в Рио и сформировать наш план посещения их во время отпуска

Просим нашего бота с помощью ChatGPT придумать интересные для посещения места в Рио и сформировать наш план посещения их во время отпуска

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

Проверяем как события опубликовались в Google календаре

Проверяем как события опубликовались в Google календаре

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

Просим бота удалить одно из событий

Просим бота удалить одно из событий

Как мы видим бот спросил подтверждение при удалении события из календаря, это было в его инструкции:

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

Проверяем календарь и видим, что событие было удалено:

Видно, что нужное событие было удалено

Видно, что нужное событие было удалено

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

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

Наш получившийся бот/сотрудник понимает команды голосом и даже озвучивает свой ответ

Наш получившийся бот/сотрудник понимает команды голосом и даже озвучивает свой ответ

Итоги

В целом мозгов у ChatGPT 4 вполне хватает на управление календарем.

Что можно еще попробовать?

  1. Разбиение сложных задач на подзадачи

  2. Помощь с распределением задач

  3. Ежедневное уведомление о важных делах на сегодня/неделю/месяц

  4. Просить бота фокусировать внимание пользователя на важных событиях и говорить об этом при постановке задач

  5. Дать боту Яндекс.Календарь и предлагать в начале выбрать с каким календарем работать

Сам бот можно протестировать тут.

Идеи и вопросы пишите мне в телеграм.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Каким облачным календарем Вы пользуетесь?

70.21% Google33
6.38% Яндекс3
10.64% Microsoft Outlook5
12.77% Другой6

Проголосовали 47 пользователей. Воздержались 6 пользователей.

ссылка на оригинал статьи https://habr.com/ru/articles/785346/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *