From 64970a574620192fdc52740c1a384ffcefe0cda7 Mon Sep 17 00:00:00 2001
From: Pascal Gula <pascal.gula@gmail.com>
Date: Tue, 12 Mar 2024 18:30:40 +0100
Subject: [PATCH] Google readers integrations doc and drive updates (#11724)

---
 .../llama-index-readers-google/CHANGELOG.md   |   6 +
 .../readers/google/calendar/README.md         |  35 ++++
 .../llama_index/readers/google/docs/README.md |  36 +++++
 .../readers/google/drive/README.md            |  51 ++++++
 .../llama_index/readers/google/drive/base.py  | 149 ++++++++++++------
 .../readers/google/gmail/README.md            |  22 +++
 .../llama_index/readers/google/keep/README.md |  39 +++++
 .../readers/google/sheets/README.md           |  35 ++++
 .../llama-index-readers-google/pyproject.toml |  13 +-
 9 files changed, 339 insertions(+), 47 deletions(-)
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/calendar/README.md
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/docs/README.md
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/README.md
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/gmail/README.md
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/keep/README.md
 create mode 100644 llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/sheets/README.md

diff --git a/llama-index-integrations/readers/llama-index-readers-google/CHANGELOG.md b/llama-index-integrations/readers/llama-index-readers-google/CHANGELOG.md
index 36bff877ab..a9f026fb6d 100644
--- a/llama-index-integrations/readers/llama-index-readers-google/CHANGELOG.md
+++ b/llama-index-integrations/readers/llama-index-readers-google/CHANGELOG.md
@@ -1,5 +1,11 @@
 # CHANGELOG
 
+## [0.1.5] - 2024-03-06
+
+- Add missing README.md for all readers folder lost during the last migration from llamahub
+- Add `query_string` in Google Drive Reader
+- Some others minor fixes
+
 ## [0.1.2] - 2024-02-13
 
 - Add maintainers and keywords from library.json (llamahub)
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/calendar/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/calendar/README.md
new file mode 100644
index 0000000000..1b815ad4b5
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/calendar/README.md
@@ -0,0 +1,35 @@
+# Google Calendar Loader
+
+`pip install llama-index-readers-google`
+
+This loader reads your upcoming Google Calendar events and parses the relevant info into `Documents`.
+
+As a prerequisite, you will need to register with Google and generate a `credentials.json` file in the directory where you run this loader. See [here](https://developers.google.com/workspace/guides/create-credentials) for instructions.
+
+## Usage
+
+Here's an example usage of the GoogleCalendar. It will retrieve up to 100 future events, unless an optional `number_of_results` argument is passed. It will also retrieve only future events, unless an optional `start_date` argument is passed.
+
+```python
+from llama_index.readers.google import GoogleCalendarReader
+
+loader = GoogleCalendarReader()
+documents = loader.load_data()
+```
+
+## Example
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
+
+### LlamaIndex
+
+```python
+from llama_index.readers.google import GoogleCalendarReader
+from llama_index.core import VectorStoreIndex
+
+loader = GoogleCalendarReader()
+documents = loader.load_data()
+
+index = VectorStoreIndex.from_documents(documents)
+index.query("When am I meeting Gordon?")
+```
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/docs/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/docs/README.md
new file mode 100644
index 0000000000..2ec267fa7b
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/docs/README.md
@@ -0,0 +1,36 @@
+# Google Doc Loader
+
+`pip install llama-index-readers-google`
+
+This loader takes in IDs of Google Docs and parses their text into `Document`s. You can extract a Google Doc's ID directly from its URL. For example, the ID of `https://docs.google.com/document/d/1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec/edit` is `1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec`.
+
+As a prerequisite, you will need to register with Google and generate a `credentials.json` file in the directory where you run this loader. See [here](https://developers.google.com/workspace/guides/create-credentials) for instructions.
+
+## Usage
+
+To use this loader, you simply need to pass in an array of Google Doc IDs.
+
+```python
+from llama_index.readers.google import GoogleDocsReader
+
+gdoc_ids = ["1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec"]
+loader = GoogleDocsReader()
+documents = loader.load_data(document_ids=gdoc_ids)
+```
+
+## Examples
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
+
+### LlamaIndex
+
+```python
+from llama_index.readers.google import GoogleDocsReader
+from llama_index.core import VectorStoreIndex, download_loader
+
+gdoc_ids = ["1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec"]
+loader = GoogleDocsReader()
+documents = loader.load_data(document_ids=gdoc_ids)
+index = VectorStoreIndex.from_documents(documents)
+index.query("Where did the author go to school?")
+```
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/README.md
new file mode 100644
index 0000000000..c721310924
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/README.md
@@ -0,0 +1,51 @@
+# Google Drive Loader
+
+`pip install llama-index-readers-google`
+
+This loader reads files from Google Drive using folder or file ids. To use this loader, you need to pass in a list of file id's or folder id.
+
+### folder_id
+
+You can extract a folder_id directly from its drive URL.
+
+For example, the folder_id of `https://drive.google.com/drive/folders/1w7XryYu6mL9VLmfyqUkA4_fRnDbsCqV-` is `1w7XryYu6mL9VLmfyqUkA4_fRnDbsCqV-`.
+
+### file_id
+
+You can extract a file_id directly from its sharable drive URL.
+
+For example, the file_id of `https://drive.google.com/file/d/1LEqD_zQiOizKrBKZYKJtER_h6i49wE-y/view?usp=sharing` is `1LEqD_zQiOizKrBKZYKJtER_h6i49wE-y`.
+
+### mime_types
+
+DEPRECATED: You can also filter the files by the mimeType e.g.: `mime_types=["application/vnd.google-apps.document"]`
+
+### query_string
+
+You can also filter the files by the query string e.g.: `query_string="name contains 'test'"`
+It gives more flexibility to filter the documents. More info: https://developers.google.com/drive/api/v3/search-files
+
+## Usage
+
+We need `credentials.json` file to use this reader.
+
+1. You need to create a service account following the steps mentioned [here](https://cloud.google.com/iam/docs/keys-create-delete)
+2. Get your json file and rename to `credentials.json` and move to the project root
+
+> Note: If you are not using Google Workspaces (formerly GSuite), You'll need to share your document making it public, or inviting your service account as an reader/editor of the folder or file.
+
+Finally, make sure you enable "Google Drive API" in the console of your Google App.
+
+```python
+from llama_index.readers.google import GoogleDriveReader
+
+loader = GoogleDriveReader()
+
+#### Using folder id
+documents = loader.load_data(folder_id="folderid")
+
+#### Using file ids
+documents = loader.load_data(file_ids=["fileid1", "fileid2"])
+```
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/base.py b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/base.py
index 6528b4acb1..4a34da5be6 100644
--- a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/base.py
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/drive/base.py
@@ -4,7 +4,12 @@ import logging
 import os
 import tempfile
 from pathlib import Path
-from typing import Any, List, Optional
+from typing import List, Optional, Tuple
+
+from google.auth.transport.requests import Request
+from google.oauth2 import service_account
+from google.oauth2.credentials import Credentials
+from pydrive.drive import GoogleDrive
 
 from llama_index.core.readers import SimpleDirectoryReader
 from llama_index.core.readers.base import BaseReader
@@ -52,7 +57,7 @@ class GoogleDriveReader(BaseReader):
             },
         }
 
-    def _get_credentials(self) -> Any:
+    def _get_credentials(self) -> Tuple[Credentials, GoogleDrive]:
         """Authenticate with Google and save credentials.
         Download the credentials.json file with these instructions: https://developers.google.com/drive/api/v3/quickstart/python.
             Copy credentials.json file and rename it to client_secrets.json file which will be used by pydrive for downloading files.
@@ -66,17 +71,13 @@ class GoogleDriveReader(BaseReader):
         """
         from google_auth_oauthlib.flow import InstalledAppFlow
         from pydrive.auth import GoogleAuth
-        from pydrive.drive import GoogleDrive
-
-        from google.auth.transport.requests import Request
-        from google.oauth2 import service_account
-        from google.oauth2.credentials import Credentials
 
         # First, we need the Google API credentials for the app
         creds = None
-        if os.path.exists(self.token_path):
+
+        if Path(self.token_path).exists():
             creds = Credentials.from_authorized_user_file(self.token_path, SCOPES)
-        elif os.path.exists(self.credentials_path):
+        elif Path(self.credentials_path).exists():
             creds = service_account.Credentials.from_service_account_file(
                 self.credentials_path, scopes=SCOPES
             )
@@ -84,6 +85,7 @@ class GoogleDriveReader(BaseReader):
             gauth.credentials = creds
             drive = GoogleDrive(gauth)
             return creds, drive
+
         # If there are no (valid) credentials available, let the user log in.
         if not creds or not creds.valid:
             if creds and creds.expired and creds.refresh_token:
@@ -94,7 +96,7 @@ class GoogleDriveReader(BaseReader):
                 )
                 creds = flow.run_local_server(port=0)
             # Save the credentials for the next run
-            with open(self.token_path, "w") as token:
+            with open(self.token_path, "w", encoding="utf-8") as token:
                 token.write(creds.to_json())
 
         # Next, we need user authentication to download files (via pydrive)
@@ -122,13 +124,16 @@ class GoogleDriveReader(BaseReader):
         self,
         folder_id: Optional[str] = None,
         file_id: Optional[str] = None,
-        mime_types: Optional[list] = None,
+        mime_types: Optional[List[str]] = None,
+        query_string: Optional[str] = None,
     ) -> List[List[str]]:
         """Get file ids present in folder/ file id
         Args:
             folder_id: folder id of the folder in google drive.
             file_id: file id of the file in google drive
-            mime_types: the mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            mime_types: The mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            query_string: A more generic query string to filter the documents, e.g. "name contains 'test'".
+
         Returns:
             metadata: List of metadata of filde ids.
         """
@@ -139,7 +144,7 @@ class GoogleDriveReader(BaseReader):
             fileids_meta = []
             if folder_id:
                 folder_mime_type = "application/vnd.google-apps.folder"
-                query = "'" + folder_id + "' in parents"
+                query = "('" + folder_id + "' in parents)"
 
                 # Add mimeType filter to query
                 if mime_types:
@@ -150,22 +155,38 @@ class GoogleDriveReader(BaseReader):
                     )
                     query += f" and ({mime_query})"
 
-                results = (
-                    service.files()
-                    .list(
-                        q=query,
-                        includeItemsFromAllDrives=True,
-                        supportsAllDrives=True,
-                        fields="*",
+                # Add query string filter
+                if query_string:
+                    # to keep the recursiveness, we need to add folder_mime_type to the mime_types
+                    query += (
+                        f" and ((mimeType='{folder_mime_type}') or ({query_string}))"
                     )
-                    .execute()
-                )
-                items = results.get("files", [])
+
+                items = []
+                # get files taking into account that the results are paginated
+                while True:
+                    results = (
+                        service.files()
+                        .list(
+                            q=query,
+                            includeItemsFromAllDrives=True,
+                            supportsAllDrives=True,
+                            fields="*",
+                        )
+                        .execute()
+                    )
+                    items.extend(results.get("files", []))
+                    page_token = results.get("nextPageToken", None)
+                    if page_token is None:
+                        break
+
                 for item in items:
                     if item["mimeType"] == folder_mime_type:
                         fileids_meta.extend(
                             self._get_fileids_meta(
-                                folder_id=item["id"], mime_types=mime_types
+                                folder_id=item["id"],
+                                mime_types=mime_types,
+                                query_string=query_string,
                             )
                         )
                     else:
@@ -187,7 +208,6 @@ class GoogleDriveReader(BaseReader):
                                 item["modifiedTime"],
                             )
                         )
-
             else:
                 # Get the file details
                 file = (
@@ -217,7 +237,9 @@ class GoogleDriveReader(BaseReader):
             return fileids_meta
 
         except Exception as e:
-            logger.error(f"An error occurred while getting fileids metadata: {e}")
+            logger.error(
+                f"An error occurred while getting fileids metadata: {e}", exc_info=True
+            )
 
     def _download_file(self, fileid: str, filename: str) -> str:
         """Download the file with fileid and filename
@@ -266,7 +288,9 @@ class GoogleDriveReader(BaseReader):
 
             return new_file_name
         except Exception as e:
-            logger.error(f"An error occurred while downloading file: {e}")
+            logger.error(
+                f"An error occurred while downloading file: {e}", exc_info=True
+            )
 
     def _load_data_fileids_meta(self, fileids_meta: List[List[str]]) -> List[Document]:
         """Load data from fileids metadata
@@ -306,14 +330,22 @@ class GoogleDriveReader(BaseReader):
 
             return documents
         except Exception as e:
-            logger.error(f"An error occurred while loading data from fileids meta: {e}")
+            logger.error(
+                f"An error occurred while loading data from fileids meta: {e}",
+                exc_info=True,
+            )
 
     def _load_from_file_ids(
-        self, file_ids: List[str], mime_types: list
+        self,
+        file_ids: List[str],
+        mime_types: Optional[List[str]],
+        query_string: Optional[str],
     ) -> List[Document]:
         """Load data from file ids
         Args:
-            file_ids: file ids of the files in google drive.
+            file_ids: File ids of the files in google drive.
+            mime_types: The mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            query_string: List of query strings to filter the documents, e.g. "name contains 'test'".
 
         Returns:
             Document: List of Documents of text.
@@ -322,46 +354,71 @@ class GoogleDriveReader(BaseReader):
             fileids_meta = []
             for file_id in file_ids:
                 fileids_meta.extend(
-                    self._get_fileids_meta(file_id=file_id, mime_types=mime_types)
+                    self._get_fileids_meta(
+                        file_id=file_id,
+                        mime_types=mime_types,
+                        query_string=query_string,
+                    )
                 )
             return self._load_data_fileids_meta(fileids_meta)
         except Exception as e:
-            logger.error(f"An error occurred while loading with fileid: {e}")
+            logger.error(
+                f"An error occurred while loading with fileid: {e}", exc_info=True
+            )
+
+    def _load_from_folder(
+        self,
+        folder_id: str,
+        mime_types: Optional[List[str]],
+        query_string: Optional[str],
+    ) -> List[Document]:
+        """Load data from folder_id.
 
-    def _load_from_folder(self, folder_id: str, mime_types: list) -> List[Document]:
-        """Load data from folder_id
         Args:
             folder_id: folder id of the folder in google drive.
-            mime_types: the mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            mime_types: The mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            query_string: A more generic query string to filter the documents, e.g. "name contains 'test'".
+
         Returns:
             Document: List of Documents of text.
         """
         try:
             fileids_meta = self._get_fileids_meta(
-                folder_id=folder_id, mime_types=mime_types
+                folder_id=folder_id,
+                mime_types=mime_types,
+                query_string=query_string,
             )
             return self._load_data_fileids_meta(fileids_meta)
         except Exception as e:
-            logger.error(f"An error occurred while loading from folder: {e}")
+            logger.error(
+                f"An error occurred while loading from folder: {e}", exc_info=True
+            )
 
     def load_data(
         self,
-        folder_id: str = None,
-        file_ids: List[str] = None,
-        mime_types: List[str] = None,
+        folder_id: Optional[str] = None,
+        file_ids: Optional[List[str]] = None,
+        mime_types: Optional[List[str]] = None,  # Deprecated
+        query_string: Optional[str] = None,
     ) -> List[Document]:
-        """Load data from the folder id and file ids.
+        """Load data from the folder id or file ids.
 
         Args:
-            folder_id: folder id of the folder in google drive.
-            file_ids: file ids of the files in google drive.
-            mime_types: the mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            folder_id: Folder id of the folder in google drive.
+            file_ids: File ids of the files in google drive.
+            mime_types: The mimeTypes you want to allow e.g.: "application/vnd.google-apps.document"
+            query_string: A more generic query string to filter the documents, e.g. "name contains 'test'".
+                It gives more flexibility to filter the documents. More info: https://developers.google.com/drive/api/v3/search-files
+
         Returns:
             List[Document]: A list of documents.
         """
         self._creds, self._drive = self._get_credentials()
 
         if folder_id:
-            return self._load_from_folder(folder_id, mime_types)
+            return self._load_from_folder(folder_id, mime_types, query_string)
+        elif file_ids:
+            return self._load_from_file_ids(file_ids, mime_types, query_string)
         else:
-            return self._load_from_file_ids(file_ids, mime_types)
+            logger.warning("Either 'folder_id' or 'file_ids' must be provided.")
+            return []
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/gmail/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/gmail/README.md
new file mode 100644
index 0000000000..27f2f0dad2
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/gmail/README.md
@@ -0,0 +1,22 @@
+# Gmail Loader
+
+`pip install llama-index-readers-google`
+
+This loader searches your Gmail account and parses the resulting emails into `Document`s. The search query can include normal query params, like `from: email@example.com label:inbox`.
+
+As a prerequisite, you will need to register with Google and generate a `credentials.json` file in the directory where you run this loader. See [here](https://developers.google.com/workspace/guides/create-credentials) for instructions.
+
+## Usage
+
+To use this loader, you simply need to pass in a search query string.
+
+```python
+from llama_index.readers.google import GmailReader
+
+loader = GmailReader(query="from: me label:inbox")
+documents = loader.load_data()
+```
+
+## Examples
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/keep/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/keep/README.md
new file mode 100644
index 0000000000..b432bb340a
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/keep/README.md
@@ -0,0 +1,39 @@
+# Google Keep Loader
+
+`pip install llama-index-readers-google`
+
+This loader takes in IDs of Google Keep and parses their text into `Document`s. You can extract a Google Keep's ID directly from its URL. For example, the ID of `https://keep.google.com/u/6/#NOTE/1OySsaIrx_pvQaJJk3VPQfYQvSuxTQuPndEEGl7qvrhFaN8VnO4K8Bti0SL2YklU` is `1OySsaIrx_pvQaJJk3VPQfYQvSuxTQuPndEEGl7qvrhFaN8VnO4K8Bti0SL2YklU`.
+
+This loader uses the (unofficial) gkeepapi library. Google Keep does provide an official API, however in order to use it, (1) your account has to be an Enterprise (Google Workspace) account (2) you will need to generate a service account to authenticate with Google Keep API (3) you will need to enable Domain-wide Delegation to enable the service account with Google Read API scopes. See [here](https://issuetracker.google.com/issues/210500028) for details. Thus I believe gkeepapi is actually more practical and useful for the majority of the users.
+
+To use gkeepapi, you will need to login with username and a password. I highly recommend using a (one-off) App Password over using your own password. You can find how to generate App Password at [here](https://support.google.com/accounts/answer/185833?hl=en). The username and password should be saved at a `keep_credentials.json` file, with `username` and `password` being keys. It's recommended you delete the App Password once you no longer need it.
+
+## Usage
+
+To use this loader, you simply need to pass in an array of Google Keep IDs.
+
+```python
+from llama_index.readers.google import GoogleKeepReader
+
+gkeep_ids = ["1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec"]
+loader = GoogleKeepReader()
+documents = loader.load_data(document_ids=gkeep_ids)
+```
+
+## Examples
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
+
+### LlamaIndex
+
+```python
+from llama_index import VectorStoreIndex
+from llama_hub.google_keep import GoogleKeepReader
+
+gkeep_ids = ["1wf-y2pd9C878Oh-FmLH7Q_BQkljdm6TQal-c1pUfrec"]
+loader = GoogleKeepReader()
+notes = loader.load_data(document_ids=gkeep_ids)
+index = VectorStoreIndex.from_documents(notes)
+query_engine = index.as_query_engine()
+query_engine.query("What are my current TODOs?")
+```
diff --git a/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/sheets/README.md b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/sheets/README.md
new file mode 100644
index 0000000000..9ceff1e473
--- /dev/null
+++ b/llama-index-integrations/readers/llama-index-readers-google/llama_index/readers/google/sheets/README.md
@@ -0,0 +1,35 @@
+# Google Sheets Loader
+
+`pip install llama-index-readers-google`
+
+This loader reads your upcoming Google Sheets and parses the relevant info into `Documents`.
+
+As a prerequisite, you will need to register with Google and generate a `credentials.json` file in the directory where you run this loader. See [here](https://developers.google.com/workspace/guides/create-credentials) for instructions.
+
+## Usage
+
+Here's an example usage of the GoogleSheetsReader.
+
+```python
+from llama_index.readers.google import GoogleSheetsReader
+
+loader = GoogleSheetsReader()
+documents = loader.load_data()
+```
+
+## Example
+
+This loader is designed to be used as a way to load data into [LlamaIndex](https://github.com/run-llama/llama_index/tree/main/llama_index).
+
+### LlamaIndex
+
+```python
+from llama_index.readers.google import GoogleSheetsReader
+from llama_index.core import VectorStoreIndex, download_loader
+
+loader = GoogleSheetsReader()
+documents = loader.load_data()
+
+index = VectorStoreIndex.from_documents(documents)
+index.query("When am I meeting Gordon?")
+```
diff --git a/llama-index-integrations/readers/llama-index-readers-google/pyproject.toml b/llama-index-integrations/readers/llama-index-readers-google/pyproject.toml
index c962ed7937..d82a94e1a4 100644
--- a/llama-index-integrations/readers/llama-index-readers-google/pyproject.toml
+++ b/llama-index-integrations/readers/llama-index-readers-google/pyproject.toml
@@ -19,6 +19,9 @@ GoogleDriveReader = "ravi03071991"
 GoogleKeepReader = "pycui"
 GoogleSheetsReader = "piroz"
 
+[tool.llamahub.class_contributors]
+GoogleDriveReader = ["metanov"]
+
 [tool.mypy]
 disallow_untyped_defs = true
 exclude = ["_static", "build", "examples", "notebooks", "venv"]
@@ -31,7 +34,15 @@ description = "llama-index readers google integration"
 exclude = ["**/BUILD"]
 keywords = ["email", "gmail", "google keep", "google notes"]
 license = "MIT"
-maintainers = ["bbornsztein", "jerryjliu", "ong", "piroz", "pycui", "ravi03071991"]
+maintainers = [
+    "bbornsztein",
+    "jerryjliu",
+    "metanov",
+    "ong",
+    "piroz",
+    "pycui",
+    "ravi03071991",
+]
 name = "llama-index-readers-google"
 readme = "README.md"
 version = "0.1.5"
-- 
GitLab