Google Drive APIで新規フォルダ作成

Google Drive API を使い、my drive のなかに Schoolフォルダを作成したい
さらにSchoolフォルダのなかにReadフォルダを作成したい

ここへPDFファイルを置いて
このなかにファイルがあるならOCRしてカレンダーに予定を書き込み
処理終了したら ReadフォルダにPDFファイルを移動する

この時に同じフォルダがあると同じフォルダが複数できるらしいので
チェック機能を追加する

なので
Google Drive API を使用して My Drive 内に「School」フォルダを作成(または既存のものを使用)し、その中に「Read」フォルダを作成する

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

で必要なライブラリを入れる

Google Cloud Console でプロジェクトを作成し、Google Drive API を有効化も忘れずに

from __future__ import print_function
import os.path
from google.oauth2 import credentials
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# 認証と API クライアントのセットアップ
SCOPES = ['https://www.googleapis.com/auth/drive']

def main():
    """Google Drive API に接続し、フォルダを作成または取得します。"""
    creds = None
    # token.json はユーザーのアクセストークンとリフレッシュトークンを保存します。初回実行時に自動的に作成されます。
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # 資格情報がないか、無効または期限切れの場合は再ログインします。
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            # ユーザーにブラウザで認証してもらいます。
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # 認証情報を保存します。
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    # Drive API クライアントを作成
    service = build('drive', 'v3', credentials=creds)

    # 1. "School" フォルダを取得または作成
    school_folder_id = get_or_create_folder(service, 'School', parent_id=None)

    # 2. "Read" フォルダを "School" フォルダ内に作成
    read_folder_id = get_or_create_folder(service, 'Read', parent_id=school_folder_id)

    print('School フォルダの ID: %s' % school_folder_id)
    print('Read フォルダの ID: %s' % read_folder_id)

def get_or_create_folder(service, folder_name, parent_id=None):
    """
    フォルダを取得または作成します。

    Parameters:
        service: Drive API サービス インスタンス。
        folder_name (str): フォルダの名前。
        parent_id (str): 親フォルダの ID(省略可能)。

    Returns:
        str: フォルダの ID。
    """
    # フォルダを検索
    query = "name='{}' and mimeType='application/vnd.google-apps.folder' and trashed=false".format(folder_name)
    if parent_id:
        query += " and '{}' in parents".format(parent_id)

    response = service.files().list(
        q=query,
        spaces='drive',
        fields='files(id, name)',
    ).execute()
    files = response.get('files', [])

    if files:
        # 既存のフォルダが見つかった場合
        folder_id = files[0]['id']
        print('既存の "{}" フォルダの ID を使用します: {}'.format(folder_name, folder_id))
    else:
        # フォルダが存在しない場合、新規作成
        file_metadata = {
            'name': folder_name,
            'mimeType': 'application/vnd.google-apps.folder',
        }
        if parent_id:
            file_metadata['parents'] = [parent_id]

        file = service.files().create(body=file_metadata, fields='id').execute()
        folder_id = file.get('id')
        print('新規に "{}" フォルダを作成しました。ID: {}'.format(folder_name, folder_id))

    return folder_id

if __name__ == '__main__':
    main()

を実行したが

Traceback (most recent call last):
  File "/Users/snowpool/aw10s/week_calendar_voice/quickstart.py", line 59, in <module>
    main()
  File "/Users/snowpool/aw10s/week_calendar_voice/quickstart.py", line 26, in main
    creds.refresh(Request())
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/google/oauth2/credentials.py", line 335, in refresh
    ) = reauth.refresh_grant(
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/google/oauth2/reauth.py", line 351, in refresh_grant
    _client._handle_error_response(response_data, retryable_error)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/google/oauth2/_client.py", line 73, in _handle_error_response
    raise exceptions.RefreshError(
google.auth.exceptions.RefreshError: ('invalid_scope: Bad Request', {'error': 'invalid_scope', 'error_description': 'Bad Request'})

となる

認証関連でエラーになるので
一度検証

mkdir g_drive
cd g_drive 
cp ../credentials.json .
cp ../create_folder.py .

python create_folder.py 

で実行すると
認証画面になるので進めていく

これで Google Drive APIが使えて
新規フォルダ作成までできた

次はPDFファイルを読み込んでテキストを抽出する

それができたら
抽出した内容をollamaに渡してカレンダーに入れる

一度テキストファイルに書き出すかGPTで調べたが
内容の多さを基準にする場合、以下の点を目安に考えると良いでしょう。

### 1. **APIの入力制限**
– Ollama APIや多くのテキスト処理APIは、入力テキストの長さに制限があります。
一般的に**数千文字以内**であれば直接渡しても問題ないことが多いです。
– 確認しているAPIの制限が**4,000〜8,000文字**程度であれば、
1〜2ページ程度の短めのPDFであれば直接渡せます。
内容がこの文字数を超える場合は、分割するかファイルで管理した方が良いでしょう。

### 2. **テキストの内容**
– **数百文字〜数千文字程度**であれば、直接渡してもスムーズに処理できます。
一般的には、A4サイズのPDF1〜2ページ程度です。
– 内容が**5ページ以上**ある場合や、**10,000文字以上の大量のテキスト**になる場合は、
テキストファイルに保存し分割しながら処理した方が管理が簡単です。

### 3. **利用シナリオ**
– **リアルタイム性が重要**な場合:数千文字までで、
可能であれば直接APIに渡す方がシンプルです。
– **大規模なドキュメントや長文の内容を確認しながら処理したい**場合:
ファイルに書き出して保存し、分割して処理する方が確認がしやすくなります。

### 具体的な基準
– **3,000文字以下**:直接Ollamaに渡す
– **3,000〜10,000文字程度**:可能であれば直接渡すが、ファイルに書き出して保存も検討
– **10,000文字以上**:テキストファイルに書き出し、必要に応じて分割して処理

例えば、10,000文字はおおよそA4サイズのPDFファイルで5ページ前後に相当します。
この文字数を基準に、リアルタイム性や内容の確認のしやすさに応じて直接渡すか、
ファイルに保存してから渡すかを判断すると良いでしょう。

ということなので
PDFの処理結果を直接渡すことにする