LINEBotの設定

LINEBotの設定

udemyの講習
ChatGPTを用いたLINEBot開発入門-基本的な機能からPDFを用いたQ&Aまで、クラウド上での開発方法を徹底解説
これによれば
LINEから cloud functionsのURLにリクエスト送信

これはトリガーとしてcloud functions で関数が実行される

今回はLINEからのhttpリクエストをトリガーとして実行される

LINEではユーザがメッセージを送ると
指定したURLにリクエストを送信するwebhookという機能がある

このwebhookを使うことで
Lineから CFにリクエスト送信できる

CFを実行すると
返答文章が生成されるので
それをLINEサーバーに返すことで
ユーザのトークルームに返答が表示される

この場合CFで行っているのは2つ
LINEからのリクエストを受け取る
文章を生成してLINEに返答文を送信

CF側では
リクエストがLINEから来てるのか認証する
あと
返答文を返す時に
LINEのトークルームにメッセージを送る権限があるかを認証する

CFとLINE連携には認証が必要

これは
Channel secret
LINEからのメッセージの証明
Channel access token
LINEに権限を持っている証明
が必要

これらの認証関連は
MessaginAPIを使う

https://developers.line.biz/ja/
にログイン

プロバイダを作成するので
任意の名前を入力

会社・事業者の所在国・地域
を日本にして

チャネル名を設定

チャネル説明

音声入力でLINEを行い、返信も音声で行う

大業種

個人でOK

小業種

個人(ITコンピュータ)
とした

次に
MessagingAPI 設定をクリック

webhookは後でfirebaseを設定してURLを取得する

チャンネルアクセストークンを発行する

チャネル基本設定で
チャネルシークレットの取得ができる

Faster-whisperマイクのコード解説

Faster-whisperマイクのコード解説

コードを読むのにChatGPTを使用
これによりコードの解説が得られることで理解しやすくなる

git clone https://github.com/personabb/colab_AI_sample.git

でリポジトリクローン

cd colab_AI_sample 
cd colab_fasterwhisper_sample

そして
main.pyの中の

    while True:
        audio_data = recorder.speech2audio()
        text = fasterWhispermodel.audio2text(audio_data)
        print(text)

これで
recorder.speech2audio()メソッドで音声を録音して、録音データをaudio_dataに格納し、fasterWhispermodel.audio2text()メソッドにて、音声ファイルを文字起こしして、textとして表示

つまり
printではなく
文字を送信するメソッドを作成すれば処理は完成するはず

module_recoder.py
発話の録音用モジュール

import numpy as np
import sounddevice as sd

import os
import configparser
# ファイルの存在チェック用モジュール
import errno

class Recorderconfig:
    def __init__(self, config_ini_path = './configs/config.ini'):
        # iniファイルの読み込み
        self.config_ini = configparser.ConfigParser()
        
        # 指定したiniファイルが存在しない場合、エラー発生
        if not os.path.exists(config_ini_path):
            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)
        
        self.config_ini.read(config_ini_path, encoding='utf-8')
        Recorder_items = self.config_ini.items('Recorder')
        self.Recorder_config_dict = dict(Recorder_items)

class Recorder:
    def __init__(self, config_ini_path = './configs/config.ini'):
            
            Recorder_config = Recorderconfig(config_ini_path = config_ini_path)
            config_dict = Recorder_config.Recorder_config_dict
            
            self.fs = int(config_dict["fs"])
            self.silence_threshold = float(config_dict["silence_threshold"])
            self.min_duration = float(config_dict["min_duration"])
            self.amplitude_threshold = float(config_dict["amplitude_threshold"])
            self.start_threshold = float(config_dict["start_threshold"])

    def speech2audio(self):
        record_Flag = False

        non_recorded_data = []
        recorded_audio = []
        silent_time = 0
        input_time = 0
        start_threshold = 0.3
        all_time = 0
        
        with sd.InputStream(samplerate=self.fs, channels=1) as stream:
            while True:
                data, overflowed = stream.read(int(self.fs * self.min_duration))
                all_time += 1
                if all_time == 10:
                    print("stand by ready OK")
                elif all_time >=10:
                    if np.max(np.abs(data) > self.amplitude_threshold) and not record_Flag:
                        input_time += self.min_duration
                        if input_time >= start_threshold:
                            record_Flag = True
                            print("recording...")
                            recorded_audio=non_recorded_data[int(-1*start_threshold*10)-2:]  

                    else:
                        input_time = 0

                    if overflowed:
                        print("Overflow occurred. Some samples might have been lost.")
                    if record_Flag:
                        recorded_audio.append(data)

                    else:
                        non_recorded_data.append(data)

                    if np.all(np.abs(data) < self.amplitude_threshold):
                        silent_time += self.min_duration
                        if (silent_time >= self.silence_threshold) and record_Flag:
                            print("finished")
                            record_Flag = False
                            break
                    else:
                        silent_time = 0

        audio_data = np.concatenate(recorded_audio, axis=0)

        return audio_data

が全文

class Recorderconfig:
    def __init__(self, config_ini_path = './configs/config.ini'):
        # iniファイルの読み込み
        self.config_ini = configparser.ConfigParser()
        
        # 指定したiniファイルが存在しない場合、エラー発生
        if not os.path.exists(config_ini_path):
            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)
        
        self.config_ini.read(config_ini_path, encoding='utf-8')
        Recorder_items = self.config_ini.items('Recorder')
        self.Recorder_config_dict = dict(Recorder_items)

この中で

config_ini_path = './configs/config.ini'

で指定されている設定ファイルをRecorder_config_dictとして読み込む

辞書型で読み込んでいるため、設定ファイルの中身をpythonの辞書として読み込むことが可能

self.Recorder_config_dict = dict(Recorder_items)

読み込んでいるのは

[Recorder]

fs=16000
silence_threshold=0.5
min_duration=0.1
amplitude_threshold=0.05
start_threshold = 0.3

の部分
それが

Recorder_items = self.config_ini.items('Recorder')

次に
Recorderクラスのinitメソッド

class Recorder:
    def __init__(self, config_ini_path = './configs/config.ini'):
            
            Recorder_config = Recorderconfig(config_ini_path = config_ini_path)
            config_dict = Recorder_config.Recorder_config_dict
            
            self.fs = int(config_dict["fs"])
            self.silence_threshold = float(config_dict["silence_threshold"])
            self.min_duration = float(config_dict["min_duration"])
            self.amplitude_threshold = float(config_dict["amplitude_threshold"])
            self.start_threshold = float(config_dict["start_threshold"])

まず、設定ファイルの内容をconfig_dictに格納
これは辞書型のため、config_dict[“device”]のような形で設定ファイルの内容を文字列として取得
すべての文字を文字列として取得するため、int型やbool型にしたい場合は、適宜型変更をする必要があることに注意

self.fs = int(config_dict["fs"]):

ではサンプリングレート fsの設定

fs=16000

がその対象
この時文字列として読み込んでいるので
Int でキャストしている

つまり

            self.silence_threshold = float(config_dict["silence_threshold"])
            self.min_duration = float(config_dict["min_duration"])
            self.amplitude_threshold = float(config_dict["amplitude_threshold"])
            self.start_threshold = float(config_dict["start_threshold"])

の部分で

config_dict[]

で設定値を読み込んで
それぞれfloat int などにキャストして値を設定している

続いて、設定ファイルから各種値をインスタンス変数に格納する

Recorderクラスのspeech2audioメソッド

class Recorder:
   ・・・
    def speech2audio(self):
        record_Flag = False

        non_recorded_data = []
        recorded_audio = []
        silent_time = 0
        input_time = 0
        start_threshold = 0.3
        all_time = 0
        
        with sd.InputStream(samplerate=self.fs, channels=1) as stream:
            while True:
                data, overflowed = stream.read(int(self.fs * self.min_duration))
                all_time += 1
                if all_time == 10:
                    print("stand by ready OK")
                elif all_time >=10:
                    if np.max(np.abs(data) > self.amplitude_threshold) and not record_Flag:
                        input_time += self.min_duration
                        if input_time >= start_threshold:
                            record_Flag = True
                            print("recording...")
                            recorded_audio=non_recorded_data[int(-1*start_threshold*10)-2:]  

                    else:
                        input_time = 0

                    if overflowed:
                        print("Overflow occurred. Some samples might have been lost.")
                    if record_Flag:
                        recorded_audio.append(data)

                    else:
                        non_recorded_data.append(data)

                    if np.all(np.abs(data) < self.amplitude_threshold):
                        silent_time += self.min_duration
                        if (silent_time >= self.silence_threshold) and record_Flag:
                            print("finished")
                            record_Flag = False
                            break
                    else:
                        silent_time = 0

        audio_data = np.concatenate(recorded_audio, axis=0)

        return audio_data

上記の部分では,ユーザの発話をマイクを通して取得

「stand by ready OK」と表示されてから,マイクに入力された音声の大きさが閾値(self.amplitude_threshold)以上だった場合に,録音が開始
録音が開始されたら、「recording…」と表示

その後、マイクに入力された音声の大きさが閾値以下になって0.5秒(self.silence_threshold)経過したら録音が停止する

録音が停止したら、「finished」と表示

初期設定:
* record_Flag : 録音中かどうかを示すフラグ。初期値は False(録音していない)。
* non_recorded_data : 録音を開始する前に収集したデータを保持するリスト。
* recorded_audio : 録音中の音声データを保持するリスト。
* silent_time : 無音が続いた時間をカウントする変数。
* input_time : 入力が続いた時間をカウントする変数。
* start_threshold : 録音を開始するためのしきい値。
* all_time : 全体の時間をカウントする変数

with sd.InputStream(samplerate=self.fs, channels=1) as stream:: 

サンプリングレート self.fs とチャンネル数 1(モノラル)で音声入力ストリームを開始

            while True:

でループで音声を取得する

データの読み取り: data, overflowed = stream.read(int(self.fs * self.min_duration))
* self.min_duration に基づいて、一定時間分の音声データを読み取ります。
* overflowed はバッファがオーバーフローしたかどうかを示します。
スタンバイメッセージの表示:
* 最初の10回のループで “stand by ready OK” を表示します(初期化期間を意味するようです)。

                data, overflowed = stream.read(int(self.fs * self.min_duration))
                all_time += 1
                if all_time == 10:
                    print("stand by ready OK")

の部分

if np.max(np.abs(data) > self.amplitude_threshold) and not record_Flag:
    input_time += self.min_duration
    if input_time >= start_threshold:
        record_Flag = True
        print("recording...")
        recorded_audio = non_recorded_data[int(-1 * start_threshold * 10) - 2:]
else:
    input_time = 0

では

np.max(np.abs(data) > self.amplitude_threshold):

* これは、現在の音声データの振幅が self.amplitude_threshold(振幅のしきい値)を超えているかどうかをチェックします。np.abs(data) は音声データの絶対値(振幅)を計算し、np.max() はその最大値を取得します。
not record_Flag:
* record_Flag が False の場合、つまりまだ録音が開始されていない場合にこの条件が真になります。

次に入力時間の追加

input_time += self.min_duration

上記の条件が真の場合、input_time に self.min_duration を加算します。これにより、音声がしきい値を超えた時間がカウントされます。

if input_time >= start_threshold:

input_time が start_threshold を超えた場合、録音を開始する条件が満たされたとみなされます。start_threshold は録音開始のためのしきい値です。

録音の開始

record_Flag = True
print("recording...")
recorded_audio = non_recorded_data[int(-1 * start_threshold * 10) - 2:]

record_Flag = True に設定することで、録音が開始されます。

recorded_audio = non_recorded_data[int(-1 * start_threshold * 10) - 2:]:

* 録音の開始時に、直前の音声データを recorded_audio に追加します。これは、しきい値を超える前の短い期間の音声も記録するためです。int(-1 * start_threshold * 10) – 2 は、start_threshold 秒間のデータを遡って取得するインデックスを計算しています。-2 の部分は余裕を持たせるために追加されている可能性があります

module_whisper.py
音声の文字起こし用のモジュール

from faster_whisper import WhisperModel
import numpy as np
import torch

import os
import configparser
# ファイルの存在チェック用モジュール
import errno

class FasterWhisperconfig:
    def __init__(self, config_ini_path = './configs/config.ini'):
        # iniファイルの読み込み
        self.config_ini = configparser.ConfigParser()
        
        # 指定したiniファイルが存在しない場合、エラー発生
        if not os.path.exists(config_ini_path):
            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)
        
        self.config_ini.read(config_ini_path, encoding='utf-8')
        FasterWhisper_items = self.config_ini.items('FasterWhisper')
        self.FasterWhisper_config_dict = dict(FasterWhisper_items)

class FasterWhisperModel:
    def __init__(self,device = None, config_ini_path = './configs/config.ini'):
        FasterWhisper_config = FasterWhisperconfig(config_ini_path = config_ini_path)
        config_dict = FasterWhisper_config.FasterWhisper_config_dict

        if device is not None:
            self.DEVICE = device
        else:
            device = config_dict["device"]

            self.DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
            if device != "auto":
                self.DEVICE = device
            
        self.BEAM_SIZE = int(config_dict["gpu_beam_size"]) if self.DEVICE == "cuda" else int(config_dict["cpu_beam_size"])
        self.language = config_dict["language"]
        self.COMPUTE_TYPE = config_dict["gpu_compute_type"] if self.DEVICE == "cuda" else config_dict["cpu_compute_type"]
        self.MODEL_TYPE = config_dict["gpu_model_type"] if self.DEVICE == "cuda" else config_dict["cpu_model_type"]
        self.kotoba_chunk_length = int(config_dict["chunk_length"])
        self.kotoba_condition_on_previous_text = config_dict["condition_on_previous_text"]
        if self.kotoba_condition_on_previous_text == "True":
            self.kotoba_condition_on_previous_text = True
        else:
            self.kotoba_condition_on_previous_text = False

        if config_dict["use_kotoba"] == "True":
            self.use_kotoba = True
        else:
            self.use_kotoba = False

        if not self.use_kotoba:
            self.model = WhisperModel(self.MODEL_TYPE, device=self.DEVICE, compute_type=self.COMPUTE_TYPE)
        else:
            self.MODEL_TYPE = config_dict["kotoba_model_type"]
            #self.model = WhisperModel(self.MODEL_TYPE, device=self.DEVICE, compute_type=self.cotoba_compute_type)
            self.model = WhisperModel(self.MODEL_TYPE)


    def audio2text(self, data):
        result = ""
        data = data.flatten().astype(np.float32)
        if not self.use_kotoba:
            segments, _ = self.model.transcribe(data, beam_size=self.BEAM_SIZE,language=self.language)
        else:
            segments, _ = self.model.transcribe(data, beam_size=self.BEAM_SIZE,language=self.language, chunk_length=self.kotoba_chunk_length, condition_on_previous_text=self.kotoba_condition_on_previous_text)
        
        for segment in segments:
            result += segment.text
        
        return result
            
    def audioFile2text(self, file_path):
        result = ""
        if not self.use_kotoba:
            segments, _ = self.model.transcribe(file_path, beam_size=self.BEAM_SIZE,language=self.language)
        else:
            segments, _ = self.model.transcribe(file_path, beam_size=self.BEAM_SIZE,language=self.language, chunk_length=self.kotoba_chunk_length, condition_on_previous_text=self.kotoba_condition_on_previous_text)
        
        for segment in segments:
            result += segment.text

        return result
FasterWhisperconfigクラス

class FasterWhisperconfig:
    def __init__(self, config_ini_path = './configs/config.ini'):
        # iniファイルの読み込み
        self.config_ini = configparser.ConfigParser()
        
        # 指定したiniファイルが存在しない場合、エラー発生
        if not os.path.exists(config_ini_path):
            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)
        
        self.config_ini.read(config_ini_path, encoding='utf-8')
        FasterWhisper_items = self.config_ini.items('FasterWhisper')
        self.FasterWhisper_config_dict = dict(FasterWhisper_items)

ここではconfig_ini_path = ‘./configs/config.ini’で指定されている設定ファイルをFasterWhisper_config_dictとして読み込んでいます。
辞書型で読み込んでいるため、設定ファイルの中身をpythonの辞書として読み込むことが可能

これにより

[FasterWhisper]
device = auto
language = ja

gpu_model_type = large-v3
gpu_beam_size = 1
gpu_compute_type = float16

cpu_model_type = small
cpu_beam_size = 1
cpu_compute_type = int8

use_kotoba = True
kotoba_model_type = kotoba-tech/kotoba-whisper-v1.0-faster
chunk_length = 15
condition_on_previous_text = False

の部分を読み込んで辞書にしている

FasterWhisperModelクラスのinitメソッド

class FasterWhisperModel:
    def __init__(self,device = None, config_ini_path = './configs/config.ini'):
        FasterWhisper_config = FasterWhisperconfig(config_ini_path = config_ini_path)
        config_dict = FasterWhisper_config.FasterWhisper_config_dict

        if device is not None:
            self.DEVICE = device
        else:
            device = config_dict["device"]

            self.DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
            if device != "auto":
                self.DEVICE = device
            
        self.BEAM_SIZE = int(config_dict["gpu_beam_size"]) if self.DEVICE == "cuda" else int(config_dict["cpu_beam_size"])
        self.language = config_dict["language"]
        self.COMPUTE_TYPE = config_dict["gpu_compute_type"] if self.DEVICE == "cuda" else config_dict["cpu_compute_type"]
        self.MODEL_TYPE = config_dict["gpu_model_type"] if self.DEVICE == "cuda" else config_dict["cpu_model_type"]
        self.kotoba_chunk_length = int(config_dict["chunk_length"])
        self.kotoba_condition_on_previous_text = config_dict["condition_on_previous_text"]
        if self.kotoba_condition_on_previous_text == "True":
            self.kotoba_condition_on_previous_text = True
        else:
            self.kotoba_condition_on_previous_text = False

        if config_dict["use_kotoba"] == "True":
            self.use_kotoba = True
        else:
            self.use_kotoba = False

        if not self.use_kotoba:
            self.model = WhisperModel(self.MODEL_TYPE, device=self.DEVICE, compute_type=self.COMPUTE_TYPE)
        else:
            self.MODEL_TYPE = config_dict["kotoba_model_type"]
            #self.model = WhisperModel(self.MODEL_TYPE, device=self.DEVICE, compute_type=self.cotoba_compute_type)
            self.model = WhisperModel(self.MODEL_TYPE)

これは

        FasterWhisper_config = FasterWhisperconfig(config_ini_path = config_ini_path)
        config_dict = FasterWhisper_config.FasterWhisper_config_dict


まず、設定ファイルの内容をconfig_dictに格納しています。これは辞書型のため、config_dict[“device”]のような形で設定ファイルの内容を文字列として取得することができます。
あくまで、すべての文字を文字列として取得するため、int型やbool型にしたい場合は、適宜型変更をする必要があることに注意

続いて下記の順番で処理を行います。
* モデルを動作させるdeviceを指定する
* 設定ファイルの各種設定を取得する
* モデルを定義する。
* 設定ファイルに合わせて、適切なモデルを定義する

FasterWhisperModelクラスのaudioFile2textメソッド

class FasterWhisperModel:
    ・・・
    def audio2text(self, data):
        result = ""
        data = data.flatten().astype(np.float32)
        if not self.use_kotoba:
            segments, _ = self.model.transcribe(data, beam_size=self.BEAM_SIZE,language=self.language)
        else:
            segments, _ = self.model.transcribe(data, beam_size=self.BEAM_SIZE,language=self.language, chunk_length=self.kotoba_chunk_length, condition_on_previous_text=self.kotoba_condition_on_previous_text)
        
        for segment in segments:
            result += segment.text
        
        return result

faster-whisperモデルのtranscribeメソッドを呼び出して、音声認識をしています。
faster-whisperモデルのtranscribeメソッドは、ファイル名を引数にした場合は、そのファイルを読み込んで処理を行い。numpyデータやbinaryデータを引数にした場合は、そのデータをそのまま利用してくれます

設定ファイルで指定したモデルに合わせて、適切な引数を使っています。
faster-whisperは30秒以上の音声に関しては、音声を分割して処理をするため、分割されて生成されたテキストをresult変数に格納して、return

data = data.flatten().astype(np.float32)

音声データをfaster-whisperモデルに入力するために、データを整形

roboflow Workspaceでアノテーション

roboflow Workspaceでアノテーション

https://axross-recipe.com/recipes/1469
を参考に行う

https://blog.roboflow.com/train-yolov8-obb-model/
のチュートリアルも参考にする

https://blog.roboflow.com
へアクセスし
GoogleIDなどで、Sign InすればOK

その場合
Continue with Google をクリック

ユーザ名を入力すると
プランが2つ出る
Free の無料か
Starter traialの月額249$
のどっちかになるので

とりあえずはFree にする

これでCreate workspace をクリック

次に
Invite teammates.
Add collaborators to help with labeling, upload data, train models, and more.
チームメイトを招待します。
ラベル付け、データのアップロード、モデルのトレーニングなどを支援するコラボレーターを追加します。

とあるけど
とりあえずSkipでOK

これでプロジェクトの作成画面になるが
デフォルトだとライセンスが
CC BY 4.0
になっている

Project Name は
anotation_test
とした

Annotation Group
注釈グループ
が識別のため必要らしい

とりあえずバスクリンなので
Baskulin

Project Typeには
Object Detection
を選択

これで
Create Project をクリック

次に画像ファイル
もしくは画像フォルダを選択する

ここでバスクリンを撮影したフォルダを指定するが
せっかくなので
画像の水増しをする

まず
Pixcel 8 で撮影したバスクリンの画像を
Google Photo からダウンロード

4枚の写真になっているので
これを水増しする

なお複数の写真をダウンロードすると
圧縮ファイルになっているのでこれを解凍する

vim generate_images.py

で内容を

import sys
import os
from PIL import Image

# コマンドライン引数から画像ファイル名を取得
if len(sys.argv) != 2:
    print("Usage: python generate_images.py imagefile.png")
    sys.exit(1)

image_file = sys.argv[1]

# 画像を読み込む
try:
    image = Image.open(image_file)
except IOError:
    print(f"Could not open the image file {image_file}")
    sys.exit(1)

# ファイル名と拡張子を分離し、ディレクトリ名を決定
file_name, file_extension = os.path.splitext(os.path.basename(image_file))
directory_name = file_name

# ディレクトリが存在しない場合は作成
if not os.path.exists(directory_name):
    os.makedirs(directory_name)

# 画像の変形と保存を行う関数
def save_images(image, prefix, transform, count=100):
    for i in range(count):
        filename = f'{prefix}{i+1:03}{file_extension}'
        filepath = os.path.join(directory_name, filename)
        transformed_image = image.transpose(transform)
        transformed_image.save(filepath)

# 各変換を適用して画像を保存
save_images(image, f'{file_name}_', Image.FLIP_TOP_BOTTOM, 100)
save_images(image, f'{file_name}_rot90_', Image.ROTATE_90, 100)
save_images(image, f'{file_name}_rot270_', Image.ROTATE_270, 100)

という画像を回転させてコピーするスクリプトを作成

次に写真をコピーしておく

cp ~/Downloads/Photos-001\ \(1\)/PXL_20240504_1732* .

ファイル名を変えた方が楽なので
ターミナルで

i=1
for file in PXL_20240504_173232354.jpg PXL_20240504_173242547.jpg PXL_20240504_173237123.jpg PXL_20240504_173253414.jpg; do
  mv "$file" "basclin$i.jpg"
  i=$((i + 1))
done

を実行

すると

basclin1.jpg
basclin2.jpg
basclin3.jpg
basclin4.jpg
というようにファイル名が変わる

よくみたらスペルミスなので

i=1
for file in basclin*.jpg; do
  mv "$file" "Baskulin$i.jpg"
  i=$((i + 1))
done

で修正

これでファイル名が
Baskulin1.jpg
Baskulin2.jpg
Baskulin3.jpg
Baskulin4.jpg
となったので

python generate_images.py Baskulin1.jpg
python generate_images.py Baskulin2.jpg
python generate_images.py Baskulin3.jpg
python generate_images.py Baskulin4.jpg

でファイルを量産

これで各ファイルごとのフォルダができたので
これを1つのフォルダにまとめる

ls -d */ | grep Bas


Basと書かれたディレクトリのみ表示できるので

move_files.sh

というスクリプトを作成

#!/bin/bash

# 移動先のディレクトリを作成(存在しない場合)
mkdir -p baskulin

# Baskulinで始まる全ディレクトリのファイルを baskulin ディレクトリに移動
for dir in Baskulin*/; do
    # ディレクトリ内のファイルを baskulin に移動
    mv "$dir"* baskulin/
done

echo "All files have been moved to the 'baskulin' directory."

として保存

chmod +x move_files.sh

で実行権限付与

./move_files.sh

で実行すれば全てのファイルが
1つのフォルダに移動される

そしてこのフォルダをアップロード

これでsave and continueをクリック

なお100枚以上に増やしたけど
同じ画像の場合は全て1つのものとしてみなすため
意味がなかった

回転させたりした場合は
異なる画像としてカウントされる

これでデータがアップできたので
次はアノテーション

Firebase の設定

Firebase の設定

実行環境
M1 MacbookAir 16GB

ゼロから始めるFirebase入門
を参考に
Firebaseの設定をしていく

まず
https://console.firebase.google.com/
にアクセスし

新規プロジェクトを作成する

_とかはプロジェクト名に使えない

自身の取引、ビジネス、仕事、または職業のみを目的として Firebase を利用することを正式に認めます。
にチェックを入れる

Google アナリティクス
はとりあえず有効にしておく

Google アナリスティクスアカウントの選択は
Default Account For Firebase
でよいらしい

Vue.js/vue-cli を Google Firebase にデプロイする
を参考にした

これで準備ができました
とでたら
続行をクリック

これでFirebaseプロジェクトのダッシュボードが憑依される

次にFirebase CLI のインストール

npm install -g firebase-tools

を実行したが

zsh: command not found: npm

となる

【初心者向け】zsh: command not found: npm がでた時の対処法
を参考に

brew -v

でバージョン確認

Homebrew 4.3.15

次に
nodebrewのインストール

実行すると

==> Auto-updating Homebrew...
Adjust how often this is run with HOMEBREW_AUTO_UPDATE_SECS or disable with
HOMEBREW_NO_AUTO_UPDATE. Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
asm6809                    go@1.22                    packcc
boost@1.85                 gql                        pcaudiolib
crow                       http-server-rs             pgcopydb
dwarfs                     kea                        tevent
fast_float                 kubernetes-cli@1.30        tmpmail
flexiblas                  ldb                        truetree
gabo                       mariadb@11.4               ufbt
==> New Casks
kindle-create              localcan                   nrf-connect

You have 27 outdated formulae installed.

Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
    arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.

となるので

arch -arm64 brew install nodebrew

で再度実行

==> Downloading https://ghcr.io/v2/homebrew/core/nodebrew/manifests/1.2.0-1
######################################################################### 100.0%
==> Fetching nodebrew
==> Downloading https://ghcr.io/v2/homebrew/core/nodebrew/blobs/sha256:bd835b02e
######################################################################### 100.0%
==> Pouring nodebrew--1.2.0.all.bottle.1.tar.gz
==> Caveats
You need to manually run setup_dirs to create directories required by nodebrew:
  /opt/homebrew/opt/nodebrew/bin/nodebrew setup_dirs

Add path:
  export PATH=$HOME/.nodebrew/current/bin:$PATH

To use Homebrew's directories rather than ~/.nodebrew add to your profile:
  export NODEBREW_ROOT=/opt/homebrew/var/nodebrew

zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions
==> Summary
🍺  /opt/homebrew/Cellar/nodebrew/1.2.0: 9 files, 43.2KB
==> Running `brew cleanup nodebrew`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

と表示される
パスを通す必要があるので

echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
source ~/.zshrc

次に

nodebrew ls-remote

でインストールできるnode.jsのバージョンを確認

v0.0.1    v0.0.2    v0.0.3    v0.0.4    v0.0.5    v0.0.6    

v0.1.0    v0.1.1    v0.1.2    v0.1.3    v0.1.4    v0.1.5    v0.1.6    v0.1.7
v0.1.8    v0.1.9    v0.1.10   v0.1.11   v0.1.12   v0.1.13   v0.1.14   v0.1.15
v0.1.16   v0.1.17   v0.1.18   v0.1.19   v0.1.20   v0.1.21   v0.1.22   v0.1.23
v0.1.24   v0.1.25   v0.1.26   v0.1.27   v0.1.28   v0.1.29   v0.1.30   v0.1.31
v0.1.32   v0.1.33   v0.1.90   v0.1.91   v0.1.92   v0.1.93   v0.1.94   v0.1.95
v0.1.96   v0.1.97   v0.1.98   v0.1.99   v0.1.100  v0.1.101  v0.1.102  v0.1.103
v0.1.104  

v0.2.0    v0.2.1    v0.2.2    v0.2.3    v0.2.4    v0.2.5    v0.2.6    

v0.3.0    v0.3.1    v0.3.2    v0.3.3    v0.3.4    v0.3.5    v0.3.6    v0.3.7
v0.3.8    

v0.4.0    v0.4.1    v0.4.2    v0.4.3    v0.4.4    v0.4.5    v0.4.6    v0.4.7
v0.4.8    v0.4.9    v0.4.10   v0.4.11   v0.4.12   

v0.5.0    v0.5.1    v0.5.2    v0.5.3    v0.5.4    v0.5.5    v0.5.6    v0.5.7
v0.5.8    v0.5.9    v0.5.10   

v0.6.0    v0.6.1    v0.6.2    v0.6.3    v0.6.4    v0.6.5    v0.6.6    v0.6.7
v0.6.8    v0.6.9    v0.6.10   v0.6.11   v0.6.12   v0.6.13   v0.6.14   v0.6.15
v0.6.16   v0.6.17   v0.6.18   v0.6.19   v0.6.20   v0.6.21   

v0.7.0    v0.7.1    v0.7.2    v0.7.3    v0.7.4    v0.7.5    v0.7.6    v0.7.7
v0.7.8    v0.7.9    v0.7.10   v0.7.11   v0.7.12   

v0.8.0    v0.8.1    v0.8.2    v0.8.3    v0.8.4    v0.8.5    v0.8.6    v0.8.7
v0.8.8    v0.8.9    v0.8.10   v0.8.11   v0.8.12   v0.8.13   v0.8.14   v0.8.15
v0.8.16   v0.8.17   v0.8.18   v0.8.19   v0.8.20   v0.8.21   v0.8.22   v0.8.23
v0.8.24   v0.8.25   v0.8.26   v0.8.27   v0.8.28   

v0.9.0    v0.9.1    v0.9.2    v0.9.3    v0.9.4    v0.9.5    v0.9.6    v0.9.7
v0.9.8    v0.9.9    v0.9.10   v0.9.11   v0.9.12   

v0.10.0   v0.10.1   v0.10.2   v0.10.3   v0.10.4   v0.10.5   v0.10.6   v0.10.7
v0.10.8   v0.10.9   v0.10.10  v0.10.11  v0.10.12  v0.10.13  v0.10.14  v0.10.15
v0.10.16  v0.10.17  v0.10.18  v0.10.19  v0.10.20  v0.10.21  v0.10.22  v0.10.23
v0.10.24  v0.10.25  v0.10.26  v0.10.27  v0.10.28  v0.10.29  v0.10.30  v0.10.31
v0.10.32  v0.10.33  v0.10.34  v0.10.35  v0.10.36  v0.10.37  v0.10.38  v0.10.39
v0.10.40  v0.10.41  v0.10.42  v0.10.43  v0.10.44  v0.10.45  v0.10.46  v0.10.47
v0.10.48  

v0.11.0   v0.11.1   v0.11.2   v0.11.3   v0.11.4   v0.11.5   v0.11.6   v0.11.7
v0.11.8   v0.11.9   v0.11.10  v0.11.11  v0.11.12  v0.11.13  v0.11.14  v0.11.15
v0.11.16  

v0.12.0   v0.12.1   v0.12.2   v0.12.3   v0.12.4   v0.12.5   v0.12.6   v0.12.7
v0.12.8   v0.12.9   v0.12.10  v0.12.11  v0.12.12  v0.12.13  v0.12.14  v0.12.15
v0.12.16  v0.12.17  v0.12.18  

v4.0.0    v4.1.0    v4.1.1    v4.1.2    v4.2.0    v4.2.1    v4.2.2    v4.2.3
v4.2.4    v4.2.5    v4.2.6    v4.3.0    v4.3.1    v4.3.2    v4.4.0    v4.4.1
v4.4.2    v4.4.3    v4.4.4    v4.4.5    v4.4.6    v4.4.7    v4.5.0    v4.6.0
v4.6.1    v4.6.2    v4.7.0    v4.7.1    v4.7.2    v4.7.3    v4.8.0    v4.8.1
v4.8.2    v4.8.3    v4.8.4    v4.8.5    v4.8.6    v4.8.7    v4.9.0    v4.9.1


v5.0.0    v5.1.0    v5.1.1    v5.2.0    v5.3.0    v5.4.0    v5.4.1    v5.5.0
v5.6.0    v5.7.0    v5.7.1    v5.8.0    v5.9.0    v5.9.1    v5.10.0   v5.10.1
v5.11.0   v5.11.1   v5.12.0   

v6.0.0    v6.1.0    v6.2.0    v6.2.1    v6.2.2    v6.3.0    v6.3.1    v6.4.0
v6.5.0    v6.6.0    v6.7.0    v6.8.0    v6.8.1    v6.9.0    v6.9.1    v6.9.2
v6.9.3    v6.9.4    v6.9.5    v6.10.0   v6.10.1   v6.10.2   v6.10.3   v6.11.0
v6.11.1   v6.11.2   v6.11.3   v6.11.4   v6.11.5   v6.12.0   v6.12.1   v6.12.2
v6.12.3   v6.13.0   v6.13.1   v6.14.0   v6.14.1   v6.14.2   v6.14.3   v6.14.4
v6.15.0   v6.15.1   v6.16.0   v6.17.0   v6.17.1   

v7.0.0    v7.1.0    v7.2.0    v7.2.1    v7.3.0    v7.4.0    v7.5.0    v7.6.0
v7.7.0    v7.7.1    v7.7.2    v7.7.3    v7.7.4    v7.8.0    v7.9.0    v7.10.0
v7.10.1   

v8.0.0    v8.1.0    v8.1.1    v8.1.2    v8.1.3    v8.1.4    v8.2.0    v8.2.1
v8.3.0    v8.4.0    v8.5.0    v8.6.0    v8.7.0    v8.8.0    v8.8.1    v8.9.0
v8.9.1    v8.9.2    v8.9.3    v8.9.4    v8.10.0   v8.11.0   v8.11.1   v8.11.2
v8.11.3   v8.11.4   v8.12.0   v8.13.0   v8.14.0   v8.14.1   v8.15.0   v8.15.1
v8.16.0   v8.16.1   v8.16.2   v8.17.0   

v9.0.0    v9.1.0    v9.2.0    v9.2.1    v9.3.0    v9.4.0    v9.5.0    v9.6.0
v9.6.1    v9.7.0    v9.7.1    v9.8.0    v9.9.0    v9.10.0   v9.10.1   v9.11.0
v9.11.1   v9.11.2   

v10.0.0   v10.1.0   v10.2.0   v10.2.1   v10.3.0   v10.4.0   v10.4.1   v10.5.0
v10.6.0   v10.7.0   v10.8.0   v10.9.0   v10.10.0  v10.11.0  v10.12.0  v10.13.0
v10.14.0  v10.14.1  v10.14.2  v10.15.0  v10.15.1  v10.15.2  v10.15.3  v10.16.0
v10.16.1  v10.16.2  v10.16.3  v10.17.0  v10.18.0  v10.18.1  v10.19.0  v10.20.0
v10.20.1  v10.21.0  v10.22.0  v10.22.1  v10.23.0  v10.23.1  v10.23.2  v10.23.3
v10.24.0  v10.24.1  

v11.0.0   v11.1.0   v11.2.0   v11.3.0   v11.4.0   v11.5.0   v11.6.0   v11.7.0
v11.8.0   v11.9.0   v11.10.0  v11.10.1  v11.11.0  v11.12.0  v11.13.0  v11.14.0
v11.15.0  

v12.0.0   v12.1.0   v12.2.0   v12.3.0   v12.3.1   v12.4.0   v12.5.0   v12.6.0
v12.7.0   v12.8.0   v12.8.1   v12.9.0   v12.9.1   v12.10.0  v12.11.0  v12.11.1
v12.12.0  v12.13.0  v12.13.1  v12.14.0  v12.14.1  v12.15.0  v12.16.0  v12.16.1
v12.16.2  v12.16.3  v12.17.0  v12.18.0  v12.18.1  v12.18.2  v12.18.3  v12.18.4
v12.19.0  v12.19.1  v12.20.0  v12.20.1  v12.20.2  v12.21.0  v12.22.0  v12.22.1
v12.22.2  v12.22.3  v12.22.4  v12.22.5  v12.22.6  v12.22.7  v12.22.8  v12.22.9
v12.22.10 v12.22.11 v12.22.12 

v13.0.0   v13.0.1   v13.1.0   v13.2.0   v13.3.0   v13.4.0   v13.5.0   v13.6.0
v13.7.0   v13.8.0   v13.9.0   v13.10.0  v13.10.1  v13.11.0  v13.12.0  v13.13.0
v13.14.0  

v14.0.0   v14.1.0   v14.2.0   v14.3.0   v14.4.0   v14.5.0   v14.6.0   v14.7.0
v14.8.0   v14.9.0   v14.10.0  v14.10.1  v14.11.0  v14.12.0  v14.13.0  v14.13.1
v14.14.0  v14.15.0  v14.15.1  v14.15.2  v14.15.3  v14.15.4  v14.15.5  v14.16.0
v14.16.1  v14.17.0  v14.17.1  v14.17.2  v14.17.3  v14.17.4  v14.17.5  v14.17.6
v14.18.0  v14.18.1  v14.18.2  v14.18.3  v14.19.0  v14.19.1  v14.19.2  v14.19.3
v14.20.0  v14.20.1  v14.21.0  v14.21.1  v14.21.2  v14.21.3  

v15.0.0   v15.0.1   v15.1.0   v15.2.0   v15.2.1   v15.3.0   v15.4.0   v15.5.0
v15.5.1   v15.6.0   v15.7.0   v15.8.0   v15.9.0   v15.10.0  v15.11.0  v15.12.0
v15.13.0  v15.14.0  

v16.0.0   v16.1.0   v16.2.0   v16.3.0   v16.4.0   v16.4.1   v16.4.2   v16.5.0
v16.6.0   v16.6.1   v16.6.2   v16.7.0   v16.8.0   v16.9.0   v16.9.1   v16.10.0
v16.11.0  v16.11.1  v16.12.0  v16.13.0  v16.13.1  v16.13.2  v16.14.0  v16.14.1
v16.14.2  v16.15.0  v16.15.1  v16.16.0  v16.17.0  v16.17.1  v16.18.0  v16.18.1
v16.19.0  v16.19.1  v16.20.0  v16.20.1  v16.20.2  

v17.0.0   v17.0.1   v17.1.0   v17.2.0   v17.3.0   v17.3.1   v17.4.0   v17.5.0
v17.6.0   v17.7.0   v17.7.1   v17.7.2   v17.8.0   v17.9.0   v17.9.1   

v18.0.0   v18.1.0   v18.2.0   v18.3.0   v18.4.0   v18.5.0   v18.6.0   v18.7.0
v18.8.0   v18.9.0   v18.9.1   v18.10.0  v18.11.0  v18.12.0  v18.12.1  v18.13.0
v18.14.0  v18.14.1  v18.14.2  v18.15.0  v18.16.0  v18.16.1  v18.17.0  v18.17.1
v18.18.0  v18.18.1  v18.18.2  v18.19.0  v18.19.1  v18.20.0  v18.20.1  v18.20.2
v18.20.3  v18.20.4  

v19.0.0   v19.0.1   v19.1.0   v19.2.0   v19.3.0   v19.4.0   v19.5.0   v19.6.0
v19.6.1   v19.7.0   v19.8.0   v19.8.1   v19.9.0   

v20.0.0   v20.1.0   v20.2.0   v20.3.0   v20.3.1   v20.4.0   v20.5.0   v20.5.1
v20.6.0   v20.6.1   v20.7.0   v20.8.0   v20.8.1   v20.9.0   v20.10.0  v20.11.0
v20.11.1  v20.12.0  v20.12.1  v20.12.2  v20.13.0  v20.13.1  v20.14.0  v20.15.0
v20.15.1  v20.16.0  v20.17.0  

v21.0.0   v21.1.0   v21.2.0   v21.3.0   v21.4.0   v21.5.0   v21.6.0   v21.6.1
v21.6.2   v21.7.0   v21.7.1   v21.7.2   v21.7.3   

v22.0.0   v22.1.0   v22.2.0   v22.3.0   v22.4.0   v22.4.1   v22.5.0   v22.5.1
v22.6.0   v22.7.0   

io@v1.0.0 io@v1.0.1 io@v1.0.2 io@v1.0.3 io@v1.0.4 io@v1.1.0 io@v1.2.0 io@v1.3.0
io@v1.4.1 io@v1.4.2 io@v1.4.3 io@v1.5.0 io@v1.5.1 io@v1.6.0 io@v1.6.1 io@v1.6.2
io@v1.6.3 io@v1.6.4 io@v1.7.1 io@v1.8.1 io@v1.8.2 io@v1.8.3 io@v1.8.4 

io@v2.0.0 io@v2.0.1 io@v2.0.2 io@v2.1.0 io@v2.2.0 io@v2.2.1 io@v2.3.0 io@v2.3.1
io@v2.3.2 io@v2.3.3 io@v2.3.4 io@v2.4.0 io@v2.5.0 

io@v3.0.0 io@v3.1.0 io@v3.2.0 io@v3.3.0 io@v3.3.1 

io@vX.X.X形式のバージョン

2014年にNode.jsの開発に関して意見の相違が生じた結果、io.jsが誕生し
その後、Node.jsとio.jsは再統合され、現在のNode.jsのプロジェクトに吸収された
とのこと
なので最新版を使えば問題なさそう

問題はfirebaseで使うので
どのバージョンをつけば良いかということ

GPTによれば最新のものであればOK
とのこと

【初心者向け】zsh: command not found: npm がでた時の対処法

を参考に

nodebrew install v22.7.0 

としたがエラー

Fetching: https://nodejs.org/dist/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz
Warning: Failed to open the file 
Warning: /Users/snowpool/.nodebrew/src/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz
Warning: : No such file or directory
curl: (23) Failure writing output to destination

download failed: https://nodejs.org/dist/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz

GPTで調べたらインストールコマンドが

nodebrew install-binary

となっていたので
これで検索

nodebrewによるNode.jsのインストール手順まとめ
を参考に

安定版をインストールしたいので

nodebrew install-binary stable

を実行

Fetching: https://nodejs.org/dist/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz
Warning: Failed to open the file 
Warning: /Users/snowpool/.nodebrew/src/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz
Warning: : No such file or directory
                                                                            0.0%curl: (23) Failure writing output to destination

download failed: https://nodejs.org/dist/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz

となる

原因は

nodebrew setup

が行われていないため

既にパスは通しているけど
念の為

source ~/.zshrc    

を実行しておく

再度

nodebrew install-binary stable

を実行すると

Fetching: https://nodejs.org/dist/v22.7.0/node-v22.7.0-darwin-arm64.tar.gz
######################################################################### 100.0%
Installed successfully

でインストールできた

ログから
v22.7.0
がインストールされているのがわかるので

nodebrew use v22.7.0

の後に

node -v

v22.7.0

と表示されればOK

npm -v
10.8.2

というように
Npmも一緒にインストールされる

とりあえずこれで準備できたので

npm install -g firebase-tools    

を実行すると

added 630 packages in 33s

69 packages are looking for funding
  run `npm fund` for details

となる

firebase --version
13.15.4

が前回インストールしたときのバージョンだった

irebase --version           
13.16.0

とバージョンが表示されていればOK

firebase login

を実行すると

i  Firebase optionally collects CLI and Emulator Suite usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you.

? Allow Firebase to collect CLI and Emulator Suite usage and error reporting 
information? (Y/n) 
i Firebase は、製品の改善に役立てるために、CLI およびエミュレータ スイートの使用状況およびエラー報告情報をオプションで収集します。データは Google のプライバシー ポリシー (https://policies.google.com/privacy) に従って収集され、お客様を特定するために使用されることはありません。

? Firebase が CLI とエミュレータ スイートの使用状況とエラー レポートを収集できるようにする 
情報? (はい/いいえ)

となるので
Y

これでブラウザが立ち上がり
認証画面になるのでそのまま進めていく

i  Firebase optionally collects CLI and Emulator Suite usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you.

? Allow Firebase to collect CLI and Emulator Suite usage and error reporting 
information? Yes
i  To change your data collection preference at any time, run `firebase logout` and log in again.

Visit this URL on this device to log in:ct_uri=http%3A%2F%2Flocalhost%3A9005

Waiting for authentication...

✔  Success! Logged in as snowpoollovely@gmail.com

となり認証が成功

次にプロジェクトの初期化
プロジェクトディレクトリは

/Users/snowpool/aw10s/linebot

ここで

firebase init

を実行

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /Users/snowpool/aw10s/linebot

? Which Firebase features do you want to set up for this directory? Press Space 
to select features, then Enter to confirm your choices. (Press <space> to 
select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
❯◯ Realtime Database: Configure a security rules file for Realtime Database and 
(optionally) provision default instance
 ◯ Firestore: Configure security rules and indexes files for Firestore
 ◯ Functions: Configure a Cloud Functions directory and its files
 ◯ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub 
Action deploys
 ◯ Storage: Configure a security rules file for Cloud Storage
(Move up and down to reveal more choices)

となるので

chatGPTで調べる

このプロンプトは、Firebaseプロジェクトを初期化する際に、どのFirebase機能を設定するかを選択する画面です。それぞれの選択肢がどのような役割を果たすのかについて説明し、今回のプロジェクトに適した選択について提案します。

### 選択肢の説明

1. **Realtime Database**:
– セキュリティルールと、オプションでデフォルトのインスタンスを設定します。リアルタイムでデータを読み書きできるNoSQLデータベースです。

2. **Firestore**:
– セキュリティルールとインデックスファイルを設定します。リアルタイムの更新やクエリが可能なドキュメントベースのNoSQLデータベースです。

3. **Functions**:
– Cloud Functionsのディレクトリと必要なファイルを設定します。サーバーレスなバックエンドロジックを実装するための選択肢です。Webhookサーバーを構築する際には、必須となります。

4. **Hosting**:
– Firebase Hosting用のファイルを設定し、オプションでGitHub Actionsを使用してデプロイを自動化する設定を行います。静的ウェブサイトやSPAをホスティングする場合に使用します。

5. **Storage**:
– Cloud Storage用のセキュリティルールファイルを設定します。画像やファイルのアップロードとストレージ管理に使用します。

### 今回のプロジェクトでの選択

あなたが取り組んでいるのは、LINE Botで音声の読み上げと入力、そしてOllamaでの文章修正を行い、FirebaseでWebhookサーバーとして動作させることです。したがって、以下の選択肢が関連性があります:

– **Functions**: これを選択してください。これは、Webhookサーバーを構築するためにCloud Functionsを使用するために必要です。Cloud FunctionsでLINE Botの処理や、Ollamaとの連携を行います。

### 選択の方法

1. **Functions**を選択するには、`Space`キーを押してチェックマークを付けます。
2. 他の選択肢は必要なければそのままにしておきます。
3. `Enter`キーを押して選択を確定します。

### 他のオプションについて

– **Firestore**: もし、修正されたテキストやログを保存するためにデータベースを使用したい場合は、Firestoreを選択するのも有効です。ただし、基本的なWebhookの処理のみであれば、必須ではありません。
– **Hosting**: 今回はWebコンテンツのホスティングが目的ではないため、選択する必要はありません。
– **Storage**: 音声ファイルのアップロードや保存が必要でない限り、これも選択する必要はありません。

このガイドラインに従って、Firebaseプロジェクトを初期化し、必要な機能を設定してください。`Functions`を選択することで、Webhookサーバーを構築する準備が整います。

とのことなので

❯◉ Functions: Configure a Cloud Functions directory and its files

にのみ spaceキーでチェックをいれEnter

? Which Firebase features do you want to set up for this directory? Press Space 
to select features, then Enter to confirm your choices. Functions: Configure a 
Cloud Functions directory and its files

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Please select an option: 
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

となる

意味は
このプロンプトでは、Firebaseプロジェクトをディレクトリに関連付ける方法を選択するオプションを提供しています。各オプションの意味を以下に説明し、適切な選択についても提案します。

### オプションの説明

1. **Use an existing project**:
– 既にFirebaseコンソールで作成したプロジェクトがある場合、このオプションを選択します。これにより、現在のディレクトリをその既存のFirebaseプロジェクトに関連付けることができます。
– これが最も一般的で推奨されるオプションです。

2. **Create a new project**:
– 新しいFirebaseプロジェクトを作成する場合にこのオプションを選択します。Firebaseコンソールに新しいプロジェクトが作成され、そのプロジェクトが現在のディレクトリに関連付けられます。
– まだFirebaseプロジェクトを作成していない場合や、新規のプロジェクトが必要な場合に有効です。

3. **Add Firebase to an existing Google Cloud Platform project**:
– 既存のGoogle Cloud Platform(GCP)プロジェクトがあり、それにFirebaseの機能を追加したい場合にこのオプションを選択します。
– GCPプロジェクトのリソースを有効に活用したい場合に便利です。

4. **Don’t set up a default project**:
– 既存のFirebaseプロジェクトや新しいプロジェクトを今すぐ設定したくない場合、このオプションを選択します。後でプロジェクトを設定することができますが、このディレクトリに対してFirebase機能をすぐに使用することはできません。
– 特定のプロジェクトにすぐに関連付けたくない場合にのみ選択します。

### おすすめの選択肢

– **Use an existing project**: 既にFirebaseプロジェクトがある場合、または特定のプロジェクトをこのディレクトリに関連付けたい場合はこのオプションを選びます。
– **Create a new project**: 新しいプロジェクトを作成したい場合、またはまだプロジェクトがない場合はこちらを選びます。

### 今回の状況に応じた選択

もし既にLINE BotやOllamaで使うために設定済みのFirebaseプロジェクトがある場合、**Use an existing project**を選択して、そのプロジェクトを選択するのが良いでしょう。まだプロジェクトを作成していない場合、または新規のプロジェクトが必要であれば、**Create a new project**を選択して新しいプロジェクトを作成します。

選択肢を決定したら、`Enter`キーを押して選択を確定してください。

既に firebase で
voicelinebot
というプロジェクトを作っているのでこれを使う

既に「voicelinebot」というFirebaseプロジェクトを作成しているので、そのプロジェクトを使用するのが最適です。そのために、以下の手順を実行します:

### 手順

1. **「Use an existing project」を選択**:
– `Use an existing project`オプションを選び、`Enter`キーを押します。

2. **「voicelinebot」を選択**:
– Firebase CLIがプロジェクトのリストを表示します。その中から「voicelinebot」を見つけて選択します。
– 矢印キーを使って「voicelinebot」を選択し、`Enter`キーを押します。

これにより、現在のディレクトリが「voicelinebot」プロジェクトに関連付けられます。これからFirebase Functionsのコードを実装し、`firebase deploy`コマンドを使用してデプロイすると、「voicelinebot」プロジェクト内で動作するようになります。

### 確認と次のステップ

– プロジェクトが正しく関連付けられると、Firebase CLIはディレクトリにプロジェクト関連の設定ファイル(`firebase.json`や`.firebaserc`)を生成します。
– 必要なCloud Functionsの実装を行った後、次のコマンドでデプロイできます:

“`bash
firebase deploy –only functions
“`

– デプロイが成功すると、Firebaseコンソールで「voicelinebot」プロジェクトのCloud Functionsセクションから関数の状態やログを確認できます。

これで、「voicelinebot」プロジェクトを使用してLINE Botの機能を実装するための準備が整いました。今後の開発作業に進んでください。

❯ Use an existing project 

でEnter

? Select a default Firebase project for this directory: 
  myfirebaseprojectapp-273fc (MyFirebaseProjectApp) 
  myportfolioproject-5e36a (MyPortfolioProject ) 
  mysecondsite-9c25e (MysecondSite) 
  raspberrypi-ea1b6 (raspberryPi) 
  raspberypi-293821 (raspberypi) 
❯ voicelinebot (voicelinebot) 

プロジェクトの一覧表示となるので

 voicelinebot (voicelinebot) 

を選択しEnter

? Which Firebase features do you want to set up for this directory? Press Space 
to select features, then Enter to confirm your choices. Functions: Configure a 
Cloud Functions directory and its files

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: voicelinebot 
(voicelinebot)
i  Using project voicelinebot (voicelinebot)

=== Functions Setup
Let's create a new codebase for your functions.
A directory corresponding to the codebase will be created in your project
with sample code pre-configured.

See https://firebase.google.com/docs/functions/organize-functions for
more information on organizing your functions using codebases.

Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? 
  JavaScript 
  TypeScript 
❯ Python 

となるので
chatGPTで調べてみた

Firebase FunctionsでPythonを使いたい場合、Firebase CLIの標準オプションでは直接サポートされていません(2024年現在、Firebase Functionsは主にJavaScriptとTypeScriptでの実装をサポートしています)。そのため、Firebase Functionsの選択肢にPythonが表示されるのは異例であり、通常はJavaScriptまたはTypeScriptを選択します。

### Pythonサポートの状況

– Firebase Functionsは、公式にはJavaScript/TypeScriptの実装をサポートしており、Pythonでの実装は公式サポート外です。
– Pythonでクラウド関数を実行する場合、通常はGoogle Cloud Functionsを直接使用し、Firebaseの認証やデータベースと統合します。

### 対応方法

#### 1. JavaScriptまたはTypeScriptで実装

公式のサポートに従い、Firebase Functionsの実装にはJavaScriptまたはTypeScriptを選択します。これにより、公式のドキュメントやサポートを最大限に活用できます。

– JavaScriptで実装する場合:
– シンプルに開始するにはJavaScriptを選びます。

– TypeScriptで実装する場合:
– 型の安全性を重視する場合、TypeScriptを選択します。

#### 2. Pythonを使用する場合の代替方法

Pythonを使用したい場合、以下の方法でFirebaseと連携することができます。

1. **Google Cloud FunctionsでPythonを使用**:
– Google Cloud FunctionsはPythonでの関数実装をサポートしています。Firebaseの機能(Firestore、Authenticationなど)を使用する場合、Google Cloud FunctionsのエンドポイントとしてPythonコードを実装し、それをFirebaseのイベント(データの変更や認証イベントなど)に関連付けます。

2. **Flaskなどのフレームワークを使用してWebhookを構築**:
– PythonでWebhookを構築し、Firebaseのデータやイベントを処理するWeb APIを作成することも可能です。これをFirebase HostingやCloud Runでホスティングし、Firebase Functionsの代わりに使用します。

### 次のステップ

1. **JavaScript/TypeScriptで実装する場合**:
– Pythonのオプションが表示された場合でも、`JavaScript`または`TypeScript`を選択してプロジェクトを設定します。
– Firebase Functions用に作成されたサンプルコードを基に開発を進めます。

2. **Pythonで実装する場合**:
– Firebase Functionsのプロジェクト設定はスキップし、代わりにGoogle Cloud Functionsや他のPython互換の環境での開発を検討します。

Firebase Functionsでの公式なサポートが必要な場合、現在のところJavaScript/TypeScriptを選ぶのが最も確実な方法です。これを踏まえて、プロジェクトの設定を進めてください。

と出るが

Cloud Functions for FirebaseをPythonで使ってみた

Firebase Functionsで新たにサポートされたPythonをSetupし、更にTypeScriptと共存させる
などの情報もあるので気にせずに
pythonnを選択する

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Please select an option: Use an existing project
? Select a default Firebase project for this directory: voicelinebot 
(voicelinebot)
i  Using project voicelinebot (voicelinebot)

=== Functions Setup
Let's create a new codebase for your functions.
A directory corresponding to the codebase will be created in your project
with sample code pre-configured.

See https://firebase.google.com/docs/functions/organize-functions for
more information on organizing your functions using codebases.

Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions? Python
✔  Wrote functions/requirements.txt
✔  Wrote functions/.gitignore
✔  Wrote functions/main.py
? Do you want to install dependencies now? (Y/n) 

となる
意味は

`Do you want to install dependencies now? (Y/n)` というプロンプトが表示された場合、`Y` を選択することで、Python環境に必要な依存関係が自動的にインストールされます。これにより、作成された`requirements.txt`にリストされているパッケージがインストールされ、PythonのCloud Functionsが正しく動作するようになります。

### 選択の推奨

– **`Y`を選択**:
– `Y`を選択することで、依存関係のインストールが自動で行われ、セットアップがスムーズに進みます。特に、すぐに開発を開始したい場合や、依存関係の管理に慣れていない場合に便利です。

### 次のステップ

1. **依存関係のインストール**:
– `Y`を選択すると、Firebase CLIがPythonのパッケージ管理システム(通常は`pip`)を使用して、`requirements.txt`に記載されたパッケージをインストールします。

2. **関数の実装**:
– `functions/main.py`というファイルが作成されているので、ここに必要な関数のロジックを実装します。このファイルに、LINE BotやOllamaとの連携機能を追加します。

3. **関数のデプロイ**:
– 必要な関数を実装した後、次のコマンドでFirebaseにデプロイします。

“`bash
firebase deploy –only functions
“`

### まとめ

– `Y`を選択して依存関係をインストールし、開発環境を整えましょう。
– `main.py`で関数の実装を行い、テストが終わったらFirebaseにデプロイして、LINE Botなどとの連携を実現します。

これで、Pythonを使用してFirebase Functionsをセットアップし、プロジェクトの開発を進める準備が整いました。

となるので
Y
でEnter

Requirement already satisfied: pip in ./venv/lib/python3.12/site-packages (24.0)
Collecting pip
  Downloading pip-24.2-py3-none-any.whl.metadata (3.6 kB)
Downloading pip-24.2-py3-none-any.whl (1.8 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 8.7 MB/s eta 0:00:00
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 24.0
    Uninstalling pip-24.0:
      Successfully uninstalled pip-24.0
Successfully installed pip-24.2
Collecting firebase_functions~=0.1.0 (from -r requirements.txt (line 1))
  Downloading firebase_functions-0.1.2-py3-none-any.whl.metadata (1.5 kB)
Collecting flask>=2.1.2 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading flask-3.0.3-py3-none-any.whl.metadata (3.2 kB)
Collecting functions-framework>=3.0.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading functions_framework-3.8.1-py3-none-any.whl.metadata (16 kB)
Collecting firebase-admin>=6.0.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading firebase_admin-6.5.0-py3-none-any.whl.metadata (1.5 kB)
Collecting pyyaml>=6.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl.metadata (2.1 kB)
Collecting typing-extensions>=4.4.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Using cached typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting cloudevents==1.9.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading cloudevents-1.9.0-py3-none-any.whl.metadata (6.5 kB)
Collecting flask-cors>=3.0.10 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading Flask_Cors-4.0.1-py2.py3-none-any.whl.metadata (5.5 kB)
Collecting pyjwt>=2.5.0 (from pyjwt[crypto]>=2.5.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading PyJWT-2.9.0-py3-none-any.whl.metadata (3.0 kB)
Collecting google-events>=0.5.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_events-0.12.0-py3-none-any.whl.metadata (1.9 kB)
Collecting google-cloud-firestore>=2.11.0 (from firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_cloud_firestore-2.18.0-py2.py3-none-any.whl.metadata (5.7 kB)
Collecting deprecation<3.0,>=2.0 (from cloudevents==1.9.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading deprecation-2.1.0-py2.py3-none-any.whl.metadata (4.6 kB)
Collecting cachecontrol>=0.12.6 (from firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading cachecontrol-0.14.0-py3-none-any.whl.metadata (3.1 kB)
Collecting google-api-python-client>=1.7.8 (from firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_api_python_client-2.143.0-py2.py3-none-any.whl.metadata (6.7 kB)
Collecting google-cloud-storage>=1.37.1 (from firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_cloud_storage-2.18.2-py2.py3-none-any.whl.metadata (9.1 kB)
Collecting google-api-core<3.0.0dev,>=1.22.1 (from google-api-core[grpc]<3.0.0dev,>=1.22.1; platform_python_implementation != "PyPy"->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_api_core-2.19.2-py3-none-any.whl.metadata (2.7 kB)
Collecting Werkzeug>=3.0.0 (from flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading werkzeug-3.0.4-py3-none-any.whl.metadata (3.7 kB)
Collecting Jinja2>=3.1.2 (from flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting itsdangerous>=2.1.2 (from flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading itsdangerous-2.2.0-py3-none-any.whl.metadata (1.9 kB)
Collecting click>=8.1.3 (from flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting blinker>=1.6.2 (from flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading blinker-1.8.2-py3-none-any.whl.metadata (1.6 kB)
Collecting watchdog>=1.0.0 (from functions-framework>=3.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl.metadata (40 kB)
Collecting gunicorn>=22.0.0 (from functions-framework>=3.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading gunicorn-23.0.0-py3-none-any.whl.metadata (4.4 kB)
Collecting google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1 (from google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_auth-2.34.0-py2.py3-none-any.whl.metadata (4.7 kB)
Collecting google-cloud-core<3.0.0dev,>=1.4.1 (from google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_cloud_core-2.4.1-py2.py3-none-any.whl.metadata (2.7 kB)
Collecting proto-plus<2.0.0dev,>=1.22.0 (from google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Using cached proto_plus-1.24.0-py3-none-any.whl.metadata (2.2 kB)
Collecting protobuf!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev,>=3.20.2 (from google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading protobuf-5.27.4-cp38-abi3-macosx_10_9_universal2.whl.metadata (592 bytes)
Collecting cryptography>=3.4.0 (from pyjwt[crypto]>=2.5.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl.metadata (5.4 kB)
Collecting requests>=2.16.0 (from cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Using cached requests-2.32.3-py3-none-any.whl.metadata (4.6 kB)
Collecting msgpack<2.0.0,>=0.5.2 (from cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl.metadata (9.1 kB)
Collecting cffi>=1.12 (from cryptography>=3.4.0->pyjwt[crypto]>=2.5.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl.metadata (1.5 kB)
Collecting packaging (from deprecation<3.0,>=2.0->cloudevents==1.9.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading packaging-24.1-py3-none-any.whl.metadata (3.2 kB)
Collecting googleapis-common-protos<2.0.dev0,>=1.56.2 (from google-api-core<3.0.0dev,>=1.22.1->google-api-core[grpc]<3.0.0dev,>=1.22.1; platform_python_implementation != "PyPy"->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading googleapis_common_protos-1.65.0-py2.py3-none-any.whl.metadata (1.5 kB)
Collecting grpcio<2.0dev,>=1.33.2 (from google-api-core[grpc]<3.0.0dev,>=1.22.1; platform_python_implementation != "PyPy"->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading grpcio-1.66.0-cp312-cp312-macosx_10_9_universal2.whl.metadata (3.9 kB)
Collecting grpcio-status<2.0.dev0,>=1.33.2 (from google-api-core[grpc]<3.0.0dev,>=1.22.1; platform_python_implementation != "PyPy"->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading grpcio_status-1.66.0-py3-none-any.whl.metadata (1.1 kB)
Collecting httplib2<1.dev0,>=0.19.0 (from google-api-python-client>=1.7.8->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading httplib2-0.22.0-py3-none-any.whl.metadata (2.6 kB)
Collecting google-auth-httplib2<1.0.0,>=0.2.0 (from google-api-python-client>=1.7.8->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_auth_httplib2-0.2.0-py2.py3-none-any.whl.metadata (2.2 kB)
Collecting uritemplate<5,>=3.0.1 (from google-api-python-client>=1.7.8->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading uritemplate-4.1.1-py2.py3-none-any.whl.metadata (2.9 kB)
Collecting cachetools<6.0,>=2.0.0 (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading cachetools-5.5.0-py3-none-any.whl.metadata (5.3 kB)
Collecting pyasn1-modules>=0.2.1 (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading pyasn1_modules-0.4.0-py3-none-any.whl.metadata (3.4 kB)
Collecting rsa<5,>=3.1.4 (from google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading rsa-4.9-py3-none-any.whl.metadata (4.2 kB)
Collecting google-resumable-media>=2.7.2 (from google-cloud-storage>=1.37.1->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google_resumable_media-2.7.2-py2.py3-none-any.whl.metadata (2.2 kB)
Collecting google-crc32c<2.0dev,>=1.0 (from google-cloud-storage>=1.37.1->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading google-crc32c-1.5.0.tar.gz (12 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting MarkupSafe>=2.0 (from Jinja2>=3.1.2->flask>=2.1.2->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl.metadata (3.0 kB)
Collecting pycparser (from cffi>=1.12->cryptography>=3.4.0->pyjwt[crypto]>=2.5.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Collecting pyparsing!=3.0.0,!=3.0.1,!=3.0.2,!=3.0.3,<4,>=2.4.2 (from httplib2<1.dev0,>=0.19.0->google-api-python-client>=1.7.8->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading pyparsing-3.1.4-py3-none-any.whl.metadata (5.1 kB)
Collecting pyasn1<0.7.0,>=0.4.6 (from pyasn1-modules>=0.2.1->google-auth!=2.24.0,!=2.25.0,<3.0.0dev,>=2.14.1->google-cloud-firestore>=2.11.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading pyasn1-0.6.0-py2.py3-none-any.whl.metadata (8.3 kB)
Collecting charset-normalizer<4,>=2 (from requests>=2.16.0->cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl.metadata (33 kB)
Collecting idna<4,>=2.5 (from requests>=2.16.0->cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading idna-3.8-py3-none-any.whl.metadata (9.9 kB)
Collecting urllib3<3,>=1.21.1 (from requests>=2.16.0->cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading urllib3-2.2.2-py3-none-any.whl.metadata (6.4 kB)
Collecting certifi>=2017.4.17 (from requests>=2.16.0->cachecontrol>=0.12.6->firebase-admin>=6.0.0->firebase_functions~=0.1.0->-r requirements.txt (line 1))
  Downloading certifi-2024.7.4-py3-none-any.whl.metadata (2.2 kB)
Downloading firebase_functions-0.1.2-py3-none-any.whl (76 kB)
Downloading cloudevents-1.9.0-py3-none-any.whl (47 kB)
Downloading firebase_admin-6.5.0-py3-none-any.whl (126 kB)
Downloading flask-3.0.3-py3-none-any.whl (101 kB)
Downloading Flask_Cors-4.0.1-py2.py3-none-any.whl (14 kB)
Downloading functions_framework-3.8.1-py3-none-any.whl (35 kB)
Downloading google_cloud_firestore-2.18.0-py2.py3-none-any.whl (326 kB)
Downloading google_events-0.12.0-py3-none-any.whl (504 kB)
Downloading PyJWT-2.9.0-py3-none-any.whl (22 kB)
Downloading PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl (173 kB)
Using cached typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Downloading blinker-1.8.2-py3-none-any.whl (9.5 kB)
Downloading cachecontrol-0.14.0-py3-none-any.whl (22 kB)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Downloading cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl (6.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.2/6.2 MB 6.7 MB/s eta 0:00:00
Downloading deprecation-2.1.0-py2.py3-none-any.whl (11 kB)
Downloading google_api_core-2.19.2-py3-none-any.whl (139 kB)
Downloading google_api_python_client-2.143.0-py2.py3-none-any.whl (12.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.2/12.2 MB 9.0 MB/s eta 0:00:00
Downloading google_auth-2.34.0-py2.py3-none-any.whl (200 kB)
Downloading google_cloud_core-2.4.1-py2.py3-none-any.whl (29 kB)
Downloading google_cloud_storage-2.18.2-py2.py3-none-any.whl (130 kB)
Downloading gunicorn-23.0.0-py3-none-any.whl (85 kB)
Downloading itsdangerous-2.2.0-py3-none-any.whl (16 kB)
Downloading jinja2-3.1.4-py3-none-any.whl (133 kB)
Using cached proto_plus-1.24.0-py3-none-any.whl (50 kB)
Downloading protobuf-5.27.4-cp38-abi3-macosx_10_9_universal2.whl (412 kB)
Downloading watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl (88 kB)
Downloading werkzeug-3.0.4-py3-none-any.whl (227 kB)
Downloading cachetools-5.5.0-py3-none-any.whl (9.5 kB)
Downloading cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl (178 kB)
Downloading google_auth_httplib2-0.2.0-py2.py3-none-any.whl (9.3 kB)
Downloading google_resumable_media-2.7.2-py2.py3-none-any.whl (81 kB)
Downloading googleapis_common_protos-1.65.0-py2.py3-none-any.whl (220 kB)
Downloading grpcio-1.66.0-cp312-cp312-macosx_10_9_universal2.whl (10.6 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10.6/10.6 MB 9.9 MB/s eta 0:00:00
Downloading grpcio_status-1.66.0-py3-none-any.whl (14 kB)
Using cached httplib2-0.22.0-py3-none-any.whl (96 kB)
Downloading MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl (18 kB)
Downloading msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl (85 kB)
Downloading pyasn1_modules-0.4.0-py3-none-any.whl (181 kB)
Using cached requests-2.32.3-py3-none-any.whl (64 kB)
Using cached rsa-4.9-py3-none-any.whl (34 kB)
Using cached uritemplate-4.1.1-py2.py3-none-any.whl (10 kB)
Downloading packaging-24.1-py3-none-any.whl (53 kB)
Downloading certifi-2024.7.4-py3-none-any.whl (162 kB)
Downloading charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl (119 kB)
Downloading idna-3.8-py3-none-any.whl (66 kB)
Downloading pyasn1-0.6.0-py2.py3-none-any.whl (85 kB)
Downloading pyparsing-3.1.4-py3-none-any.whl (104 kB)
Downloading urllib3-2.2.2-py3-none-any.whl (121 kB)
Downloading pycparser-2.22-py3-none-any.whl (117 kB)
Building wheels for collected packages: google-crc32c
  Building wheel for google-crc32c (pyproject.toml) ... done
  Created wheel for google-crc32c: filename=google_crc32c-1.5.0-py3-none-any.whl size=13027 sha256=139d975c4c5d667b2152b772b4daab531e73106a48b599ceaf2b867d8514ef6e
  Stored in directory: /Users/snowpool/Library/Caches/pip/wheels/40/b9/2e/089df51c5e6f7cda282c650457a1d9a7a55bf6386d8de8bf3d
Successfully built google-crc32c
Installing collected packages: watchdog, urllib3, uritemplate, typing-extensions, pyyaml, pyparsing, pyjwt, pycparser, pyasn1, protobuf, packaging, msgpack, MarkupSafe, itsdangerous, idna, grpcio, google-crc32c, click, charset-normalizer, certifi, cachetools, blinker, Werkzeug, rsa, requests, pyasn1-modules, proto-plus, Jinja2, httplib2, gunicorn, googleapis-common-protos, google-resumable-media, deprecation, cffi, grpcio-status, google-events, google-auth, flask, cryptography, cloudevents, cachecontrol, google-auth-httplib2, google-api-core, functions-framework, flask-cors, google-cloud-core, google-api-python-client, google-cloud-storage, google-cloud-firestore, firebase-admin, firebase_functions
Successfully installed Jinja2-3.1.4 MarkupSafe-2.1.5 Werkzeug-3.0.4 blinker-1.8.2 cachecontrol-0.14.0 cachetools-5.5.0 certifi-2024.7.4 cffi-1.17.0 charset-normalizer-3.3.2 click-8.1.7 cloudevents-1.9.0 cryptography-43.0.0 deprecation-2.1.0 firebase-admin-6.5.0 firebase_functions-0.1.2 flask-3.0.3 flask-cors-4.0.1 functions-framework-3.8.1 google-api-core-2.19.2 google-api-python-client-2.143.0 google-auth-2.34.0 google-auth-httplib2-0.2.0 google-cloud-core-2.4.1 google-cloud-firestore-2.18.0 google-cloud-storage-2.18.2 google-crc32c-1.5.0 google-events-0.12.0 google-resumable-media-2.7.2 googleapis-common-protos-1.65.0 grpcio-1.66.0 grpcio-status-1.66.0 gunicorn-23.0.0 httplib2-0.22.0 idna-3.8 itsdangerous-2.2.0 msgpack-1.0.8 packaging-24.1 proto-plus-1.24.0 protobuf-5.27.4 pyasn1-0.6.0 pyasn1-modules-0.4.0 pycparser-2.22 pyjwt-2.9.0 pyparsing-3.1.4 pyyaml-6.0.2 requests-2.32.3 rsa-4.9 typing-extensions-4.12.2 uritemplate-4.1.1 urllib3-2.2.2 watchdog-5.0.0

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...
i  Writing gitignore file to .gitignore...

✔  Firebase initialization complete!

となって必要なパッケージがインストールされる

ls

で中身を確認すると

firebase.json	functions

が作成されているのがわかる

とりあえずここまでできたので
次は faster-whisper をマイクからできるようにする

LLMを使うようにコード変更

実行環境
M1 MacbookAir 16GB

LLMを使うようにコード変更

import re
import csv
from datetime import datetime

# ファイルからテキストを読み込む
with open('ocr.txt', 'r', encoding='utf-8') as file:
  text = file.read()

# 情報を抽出
date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', text)
date = datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')

shop_name_match = re.search(r'とれたて食楽部', text)
shop_name = shop_name_match.group()

# 商品情報を正規表現で抽出
items = re.findall(r'内\d+ (.+?) ¥(\d+)', text)

# 現在のタイムスタンプを生成
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')

# 出力ファイル名にタイムスタンプを付ける
csv_filename = f'receipt_data_{timestamp}.csv'

# CSVファイルに出力
with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
  csv_writer = csv.writer(csvfile)
  # ヘッダー行を書き込み
  csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
  for item in items:
    product_name, price = item
    # 商品名の「/」以降を削除
    product_name_clean = product_name.split('/')[0]
    # 出力: 日付, 店名, 商品名, 数量, 金額
    row = f"{date},{shop_name},{product_name_clean},1,{price}"
    csv_writer.writerow(row.split(','))

print(f"CSVファイル '{csv_filename}' に出力しました。")

の処理を汎用性を持たせるため
プロンプトに変えたい

import re
import csv
from datetime import datetime
import ollama

class OCRToCSV:
    def __init__(self, text):
        self.text = text
        self.date, self.shop_name, self.items = self._extract_info_with_llm()

    def _extract_info_with_llm(self):
        # プロンプトを作成
        prompt = f"""
        テキストから次の情報を抽出してください:
        1. 日付(例: 2024-08-20)
        2. 店名(例: とれたて食楽部)
        3. 商品情報(例: 商品名、数量、金額)
        
        テキスト:
        {self.text}
        
        出力形式:
        日付: 2024-08-20
        店名: とれたて食楽部
        商品情報:
        - 商品名1, 1, 500
        - 商品名2, 1, 1000
        """

        # Ollamaでプロンプトを送信
        res = ollama.chat(
            model="elyza:jp8b",
            messages=[{'role': 'user', 'content': prompt}]
        )

        # 応答から内容を取得
        content = res['message']['content']

        # 応答を解析して必要な情報を取得
        date_match = re.search(r'日付:\s*(\d{4}-\d{2}-\d{2})', content)
        shop_name_match = re.search(r'店名:\s*(.+)', content)
        items_match = re.findall(r'-\s*(.+),\s*(\d+),\s*(\d+)', content)

        date = date_match.group(1) if date_match else None
        shop_name = shop_name_match.group(1) if shop_name_match else None
        items = [(item[0], item[1], item[2]) for item in items_match]

        return date, shop_name, items

    def generate_csv(self, output_dir='.', timestamp=None):
        if timestamp is None:
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
        
        csv_filename = f'{output_dir}/receipt_data_{timestamp}.csv'
        
        with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
            csv_writer = csv.writer(csvfile)
            csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
            for item in self.items:
                product_name, quantity, price = item
                row = f"{self.date},{self.shop_name},{product_name},1,{price}"
                csv_writer.writerow(row.split(','))

        print(f"CSVファイル '{csv_filename}' に出力しました。")
        return csv_filename

# 使用例
# テキストを読み込んでOCRToCSVインスタンスを作成し、CSVを生成
with open('ocr.txt', 'r', encoding='utf-8') as file:
    text = file.read()

ocr_to_csv = OCRToCSV(text)
ocr_to_csv.generate_csv()

としたが

WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1724125129.779029 15985491 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache CSVファイル './receipt_data_20240820123851.csv' に出力しました。 snowpool@kubotasorunoAir ollama % python main_ocr.py WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1724125231.314241 15987342 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache CSVファイル './receipt_data_20240820124054.csv' に出力しました。 となる また cat receipt_data_20240820124054.csv 日付,店名,商品名,数量,金額 となっていて店名などが記載されていない

なので

import re
import csv
from datetime import datetime
import ollama

class OCRToCSV:
    def __init__(self, text):
        self.text = text
        self.date, self.shop_name, self.items = self._extract_info_with_llm()

    def _extract_info_with_llm(self):
        # プロンプトを作成
        prompt = f"""
        テキストから次の情報を抽出してください:
        1. 日付(例: 2024-08-20)
        2. 店名(例: とれたて食楽部)
        3. 商品情報(例: 商品名、数量、金額)
        
        テキスト:
        {self.text}
        
        出力形式:
        日付: 2024-08-20
        店名: とれたて食楽部
        商品情報:
        - 商品名1, 1, 500
        - 商品名2, 1, 1000
        """

        # Ollamaでプロンプトを送信
        res = ollama.chat(
            model="elyza:jp8b",
            messages=[{'role': 'user', 'content': prompt}]
        )

        # 応答内容を表示(デバッグ用)
        content = res['message']['content']
        print("LLMの応答:", content)

        # 応答を解析して必要な情報を取得
        date_match = re.search(r'日付:\s*(\d{4}年\d{1,2}月\d{1,2}日)', content)
        shop_name_match = re.search(r'店名:\s*(.+)', content)
        items_match = re.findall(r'-\s*(.+)、\s*(\d+)', content)

        # 日付を %Y-%m-%d 形式に変換
        date = datetime.strptime(date_match.group(1), '%Y年%m月%d日').strftime('%Y-%m-%d') if date_match else None
        shop_name = shop_name_match.group(1) if shop_name_match else None
        # 商品情報の数量をデフォルトで1に設定
        items = [(item[0], '1', item[1]) for item in items_match]

        return date, shop_name, items

    def generate_csv(self, output_dir='.', timestamp=None):
        if timestamp is None:
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
        
        csv_filename = f'{output_dir}/receipt_data_{timestamp}.csv'
        
        with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
            csv_writer = csv.writer(csvfile)
            csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
            for item in self.items:
                product_name, quantity, price = item
                row = f"{self.date},{self.shop_name},{product_name},{quantity},{price}"
                csv_writer.writerow(row.split(','))

        print(f"CSVファイル '{csv_filename}' に出力しました。")
        return csv_filename

# 使用例
with open('ocr.txt', 'r', encoding='utf-8') as file:
    text = file.read()

ocr_to_csv = OCRToCSV(text)
ocr_to_csv.generate_csv()

へコード変更

これでもダメ

import re
import csv
from datetime import datetime
import ollama

class OCRToCSV:
    def __init__(self, text):
        self.text = text
        self.date, self.shop_name, self.items = self._extract_info_with_llm()

    def _extract_info_with_llm(self):
        # プロンプトを作成
        prompt = f"""
        テキストから次の情報を抽出してください:
        1. 日付(例: 2024-08-20)
        2. 店名(例: とれたて食楽部)
        3. 商品情報(例: 商品名、数量、金額)
        
        テキスト:
        {self.text}
        
        出力形式:
        日付: 2024-08-20
        店名: とれたて食楽部
        商品情報:
        - 商品名1, 1, 500
        - 商品名2, 1, 1000
        """

        # Ollamaでプロンプトを送信
        res = ollama.chat(
            model="elyza:jp8b",
            messages=[{'role': 'user', 'content': prompt}]
        )

        # 応答内容を表示(デバッグ用)
        content = res['message']['content']
        print("LLMの応答:", content)

        # 応答を解析して必要な情報を取得
        date_match = re.search(r'日付:\s*(\d{4}-\d{2}-\d{2})', content)
        shop_name_match = re.search(r'店名:\s*(.+)', content)
        items_match = re.findall(r'-\s*(.+)、\s*(\d+)', content)

        # 日付をそのまま使用
        date = date_match.group(1) if date_match else None
        shop_name = shop_name_match.group(1) if shop_name_match else None
        items = [(item[0], '1', item[1]) for item in items_match]

        return date, shop_name, items

    def generate_csv(self, output_dir='.', timestamp=None):
        if timestamp is None:
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
        
        csv_filename = f'{output_dir}/receipt_data_{timestamp}.csv'
        
        with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
            csv_writer = csv.writer(csvfile)
            csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
            for item in self.items:
                product_name, quantity, price = item
                row = f"{self.date},{self.shop_name},{product_name},{quantity},{price}"
                csv_writer.writerow(row.split(','))

        print(f"CSVファイル '{csv_filename}' に出力しました。")
        return csv_filename

# 使用例
with open('ocr.txt', 'r', encoding='utf-8') as file:
    text = file.read()

ocr_to_csv = OCRToCSV(text)
ocr_to_csv.generate_csv()

に変更することで解決

あとは指定のファイルのみ
main_ocr.pyで固定しているので
これを各ファイルごとにCSVに出力する
もしくはディレクトリ内にあるものを全て対象にするようにする

結局はこれはOCRして商品名を取り出すのがメインの目的で
結果をDBやキーワードリストに使いたい
ということ
ならimagesフォルダの中身を対象に実行するようにすればOK

実行後OCR済みのフォルダに移動するようにすればいい
これをやったらバグった
とりあえずLLMを使わないのならうまく動く

m1macbookAir へ ollamaを入れる

m1macbookAir へ ollamaを入れる

実行環境
M1 MacbookAir 16GB

M1MacでOllamaを試したら爆速で驚いた
を参考に実行する

インストール関連は

OllamaでLLM(Llama 3等)をローカルMacで動かす with WebUI
がわかりやすい

https://ollama.com
へアクセスすると
Download
があるのでこれをクリック

OSを判定しているので
そのまま
Download for macOS
をクリック

ファイルをダウンロードできるので
ダブルクリックで解凍

あとは

 ollama run llama3

を実行

初回のみモデルダンロードで時間がかかる
容量が4.7GBとかなり大きいので時間がある時に行わないと無理

終了する時には

 /bye

とすればOK

これでも使えるけど
https://github.com/open-webui/open-webui
にある
Open WebUI (Formerly Ollama WebUI)
を使えばブラウザから簡単に使えるようになる

Installation with Default Configuration

* If Ollama is on your computer, use this command:
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main


* If Ollama is on a Different Server, use this command:
To connect to Ollama on another server, change the OLLAMA_BASE_URL to the server's URL:
docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://example.com -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main


    * To run Open WebUI with Nvidia GPU support, use this command:
* docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda


Installation for OpenAI API Usage Only

* If you're only using OpenAI API, use this command:
docker run -d -p 3000:8080 -e OPENAI_API_KEY=your_secret_key -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main


Installing Open WebUI with Bundled Ollama Support

This installation method uses a single container image that bundles Open WebUI with Ollama, allowing for a streamlined setup via a single command. Choose the appropriate command based on your hardware setup:
* With GPU Support: Utilize GPU resources by running the following command:
docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama


* For CPU Only: If you're not using a GPU, use this command instead:
docker run -d -p 3000:8080 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama


Both commands facilitate a built-in, hassle-free installation of both Open WebUI and Ollama, ensuring that you can get everything up and running swiftly.
After installation, you can access Open WebUI at http://localhost:3000. Enjoy! 😄
Other Installation Methods

We offer various installation alternatives, including non-Docker native installation methods, Docker Compose, Kustomize, and Helm. Visit our Open WebUI Documentation or join our Discord community for comprehensive guidance.

をみると
Docker で動かす前提になっている

別の方法を調べたら
Enchantedを使えば Mac の場合代用できるらしい

Mac用 Enchanted アプリで文章を自由自在に活用してみる
を参考に

「Enchanted」 を使って iPhone から Ollama にアクセスしてみる
によれば
iPhone からでも使えるらしい

私の環境は Android なので使えないけど…

https://github.com/AugustDev/enchanted
でコードが公開されている

とりあえず先に日本語モデルを入れるのが先

OCRのモジュール化とCSVファイルの作成

OCRのモジュール化

画像ファイルを引数にして使うのでモジュール化する

from google.cloud import vision

client = vision.ImageAnnotatorClient()

with open("test.jpg", "rb") as fb:
    content = fb.read()

image = vision.Image(content=content)

response = client.document_text_detection(image=image)
texts = response.text_annotations
print(texts[0].description)

をモジュールにする

touch ocr_module.py

コードは

# ocr_module.py

from google.cloud import vision

class OCRProcessor:
    def __init__(self):
        # Vision APIクライアントの初期化
        self.client = vision.ImageAnnotatorClient()

    def extract_text_from_image(self, image_path):
        """
        画像からテキストを抽出するメソッド

        Args:
            image_path (str): 画像ファイルのパス

        Returns:
            str: 画像から抽出されたテキスト
        """
        with open(image_path, "rb") as fb:
            content = fb.read()

        image = vision.Image(content=content)
        response = self.client.document_text_detection(image=image)
        texts = response.text_annotations

        if texts:
            return texts[0].description
        else:
            return ""

使う時には

# main.py

from ocr_module import OCRProcessor

def main():
    # OCRProcessorのインスタンスを作成
    ocr_processor = OCRProcessor()

    # 画像ファイルパスを指定
    image_path = "test.jpg"

    # 画像からテキストを抽出
    extracted_text = ocr_processor.extract_text_from_image(image_path)

    # 抽出されたテキストを出力
    print("抽出されたテキスト:")
    print(extracted_text)

if __name__ == "__main__":
    main()

というようにする

さらに

import re
import csv
from datetime import datetime

# ファイルからテキストを読み込む
with open('ocr.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 情報を抽出
date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', text)
date = datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')

shop_name_match = re.search(r'とれたて食楽部', text)
shop_name = shop_name_match.group()

# 商品情報を正規表現で抽出
items = re.findall(r'内\d+ (.+?) ¥(\d+)', text)

# 現在のタイムスタンプを生成
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')

# 出力ファイル名にタイムスタンプを付ける
csv_filename = f'receipt_data_{timestamp}.csv'

# CSVファイルに出力
with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
    csv_writer = csv.writer(csvfile)
    # ヘッダー行を書き込み
    csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
    for item in items:
        product_name, price = item
        # 商品名の「/」以降を削除
        product_name_clean = product_name.split('/')[0]
        # 出力: 日付, 店名, 商品名, 数量, 金額
        row = f"{date},{shop_name},{product_name_clean},1,{price}"
        csv_writer.writerow(row.split(','))

print(f"CSVファイル '{csv_filename}' に出力しました。")

のCSV変換もモジュール化する

 touch ocr_to_csv.py
# ocr_to_csv.py

import re
import csv
from datetime import datetime

class OCRToCSV:
    def __init__(self, input_file):
        self.input_file = input_file
        self.text = self._read_text_from_file()
        self.date = self._extract_date()
        self.shop_name = self._extract_shop_name()
        self.items = self._extract_items()

    def _read_text_from_file(self):
        with open(self.input_file, 'r', encoding='utf-8') as file:
            return file.read()

    def _extract_date(self):
        date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', self.text)
        if date_match:
            return datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')
        return None

    def _extract_shop_name(self):
        shop_name_match = re.search(r'とれたて食楽部', self.text)
        return shop_name_match.group() if shop_name_match else None

    def _extract_items(self):
        return re.findall(r'内\d+ (.+?) ¥(\d+)', self.text)

    def generate_csv(self, output_dir='.', timestamp=None):
        if timestamp is None:
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
        
        csv_filename = f'{output_dir}/receipt_data_{timestamp}.csv'
        
        with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
            csv_writer = csv.writer(csvfile)
            csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
            for item in self.items:
                product_name, price = item
                product_name_clean = product_name.split('/')[0]
                row = f"{self.date},{self.shop_name},{product_name_clean},1,{price}"
                csv_writer.writerow(row.split(','))

        print(f"CSVファイル '{csv_filename}' に出力しました。")
        return csv_filename

この2つを使い
OCRした結果を受け取りCSVファイルにするようにする

touch main_ocr.py
# main.py

from ocr_module import OCRProcessor
from ocr_to_csv import OCRToCSV

def main():
    # OCRProcessorのインスタンスを作成
    ocr_processor = OCRProcessor()

    # 画像ファイルパスを指定
    image_path = 'test.jpg'

    # 画像からテキストを抽出
    extracted_text = ocr_processor.extract_text_from_image(image_path)

    # OCRToCSVのインスタンスを作成し、抽出されたテキストを処理
    ocr_to_csv = OCRToCSV(extracted_text)
    ocr_to_csv.generate_csv()

if __name__ == "__main__":
    main()

しかし、これで実行すると

I0000 00:00:1723753428.164426 15335390 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
Traceback (most recent call last):
  File "/Users/snowpool/aw10s/receit_ocr/main_ocr.py", line 21, in <module>
    main()
  File "/Users/snowpool/aw10s/receit_ocr/main_ocr.py", line 17, in main
    ocr_to_csv = OCRToCSV(extracted_text)
  File "/Users/snowpool/aw10s/receit_ocr/ocr_to_csv.py", line 10, in __init__
    self.text = self._read_text_from_file()
  File "/Users/snowpool/aw10s/receit_ocr/ocr_to_csv.py", line 16, in _read_text_from_file
    with open(self.input_file, 'r', encoding='utf-8') as file:
FileNotFoundError: [Errno 2] No such file or directory: 'それで食楽部\n登録番号 15080401017738\nとれたて食楽部\n2024年8月10日 (土) 08:59 #000011\n000801精算機 1 000801精算機1\n3901\nお会計券 #000003 R9309 09:08\n000008 西澤\n内8 きゅうり/鈴木仁 ¥150\nP2023300101503\n内8 きゅうり/小林宗作 ¥130\nP2055600101303\n内8 リーフレタス/(有)成神工 ¥216\nP2086402402169\n小計\n¥496\n(内税8%対象額\n¥496)\n買上点数\n3点\n合計\n¥496\n(税率8%対象額\n¥496)\n(内消費税等 8%\n¥36)\n課税事業者\n(税率 8%対象額\n¥216)\n(内消費税等 8%\n¥16)\n免税事業者\n(税率 8%対象額\n¥280)\nクレジット\n¥496\n(内消費税等\n¥36)\n8、内容は軽減税率対象商品です。\n約專業者商品'

となる

原因はモジュールがファイルを渡す前提になっているため
渡されたテキストを処理するようにする

OCRToCSVクラスの__init__メソッドで、self.textとして直接テキストを受け取るように変更しました。
_read_text_from_fileメソッドは削除しました。代わりに、コンストラクタで直接テキストを受け取ります。

import re
import csv
from datetime import datetime

class OCRToCSV:
    def __init__(self, text):
        self.text = text
        self.date = self._extract_date()
        self.shop_name = self._extract_shop_name()
        self.items = self._extract_items()

    def _extract_date(self):
        date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', self.text)
        if date_match:
            return datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')
        return None

    def _extract_shop_name(self):
        shop_name_match = re.search(r'とれたて食楽部', self.text)
        return shop_name_match.group() if shop_name_match else None

    def _extract_items(self):
        return re.findall(r'内\d+ (.+?) ¥(\d+)', self.text)

    def generate_csv(self, output_dir='.', timestamp=None):
        if timestamp is None:
            timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
        
        csv_filename = f'{output_dir}/receipt_data_{timestamp}.csv'
        
        with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
            csv_writer = csv.writer(csvfile)
            csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
            for item in self.items:
                product_name, price = item
                product_name_clean = product_name.split('/')[0]
                row = f"{self.date},{self.shop_name},{product_name_clean},1,{price}"
                csv_writer.writerow(row.split(','))

        print(f"CSVファイル '{csv_filename}' に出力しました。")
        return csv_filename

これで再度実行すると問題なくCSVファイルが作成される

レシートをCSVファイルに出力

レシートをCSVファイルに出力する

レシート画像を
test.jpg
にリネーム

from google.cloud import vision

client = vision.ImageAnnotatorClient()

with open("test.jpg", "rb") as fb:
    content = fb.read()

image = vision.Image(content=content)

response = client.document_text_detection(image=image)
texts = response.text_annotations
print(texts[0].description)

python vision_api_test.py

として実行

結果

それで食楽部
登録番号 15080401017738
とれたて食楽部

2024年8月10日 (土) 08:59 #000011
000801精算機 1 000801精算機1
3901
お会計券 #000003 R9309 09:08
000008 西澤
内8 きゅうり/鈴木仁 ¥150
P2023300101503
内8 きゅうり/小林宗作 ¥130
P2055600101303
内8 リーフレタス/(有)成神工 ¥216
P2086402402169
小計
¥496
(内税8%対象額
¥496)
買上点数
3点
合計
¥496
(税率8%対象額
¥496)
(内消費税等 8%
¥36)
課税事業者
(税率 8%対象額
¥216)
(内消費税等 8%
¥16)
免税事業者
(税率 8%対象額
¥280)
クレジット
¥496
(内消費税等
¥36)
8、内容は軽減税率対象商品です。
約專業者商品

となる

これをCSVに出力できるようにする
この時に
日付、購入した店名、商品名、数量、商品ごとの金額を抽出し
他の情報を削除する

import re
import csv
from datetime import datetime

# 入力されたテキスト
text = """
それで食楽部
登録番号 15080401017738
とれたて食楽部

2024年8月10日 (土) 08:59 #000011
000801精算機 1 000801精算機1
3901
お会計券 #000003 R9309 09:08
000008 西澤
内8 きゅうり/鈴木仁 ¥150
P2023300101503
内8 きゅうり/小林宗作 ¥130
P2055600101303
内8 リーフレタス/(有)成神工 ¥216
P2086402402169
小計
¥496
(内税8%対象額
¥496)
買上点数
3点
合計
¥496
(税率8%対象額
¥496)
(内消費税等 8%
¥36)
課税事業者
(税率 8%対象額
¥216)
(内消費税等 8%
¥16)
免税事業者
(税率 8%対象額
¥280)
クレジット
¥496
(内消費税等
¥36)
8、内容は軽減税率対象商品です。
約專業者商品
"""

# 情報を抽出
date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', text)
date = datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')

shop_name_match = re.search(r'とれたて食楽部', text)
shop_name = shop_name_match.group()

# 商品情報を正規表現で抽出
items = re.findall(r'内\d+ (.+?) ¥(\d+)', text)

# CSV形式で出力
output = []
for item in items:
    product_name, price = item
    row = f"{date},{shop_name},{product_name},1,{price}"
    output.append(row)

# CSVファイルに出力
csv_filename = 'receipt_data.csv'
with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
    csv_writer = csv.writer(csvfile)
    csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
    for row in output:
        csv_writer.writerow(row.split(','))

print(f"CSVファイル '{csv_filename}' に出力しました。")

以下解説

1. 日付の抽出: 正規表現を使用して、日付情報を抽出しています。その後、datetimeを使ってフォーマットをYYYY-MM-DDに変換しています。
2. 店名の抽出: テキスト内の特定の店名を正規表現で探して抽出しています。
3. 商品の抽出: 商品名と価格を正規表現で抽出しています。数量はレシートに明示されていないため、ここでは全て1と仮定しています。
4. CSV形式の出力: csvモジュールを使用して、指定された形式でCSVファイルに出力しています。CSVファイルには、ヘッダー行が含まれています。
このスクリプトを実行すると、指定された形式のCSVファイルが生成されます。生成されたCSVファイルは、receipt_data.csvとして保存されます。このファイルには、各商品の情報がカンマ区切りで含まれています。

しかしこれだと
商品名の後に /生産者もしくは出品者が残ってしまう

実行結果のファイルは

日付,店名,商品名,数量,金額
2024-08-10,とれたて食楽部,きゅうり/鈴木仁,1,150
2024-08-10,とれたて食楽部,きゅうり/小林宗作,1,130
2024-08-10,とれたて食楽部,リーフレタス/(有)成神工,1,216

となっている

このため
商品名の / 以降を削除
またファイルの上書きを防ぐためタイムスタンプをファイル名に追加

import re
import csv
from datetime import datetime

# ファイルからテキストを読み込む
with open('ocr.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 情報を抽出
date_match = re.search(r'\d{4}年\d{1,2}月\d{1,2}日', text)
date = datetime.strptime(date_match.group(), '%Y年%m月%d日').strftime('%Y-%m-%d')

shop_name_match = re.search(r'とれたて食楽部', text)
shop_name = shop_name_match.group()

# 商品情報を正規表現で抽出
items = re.findall(r'内\d+ (.+?) ¥(\d+)', text)

# 現在のタイムスタンプを生成
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')

# 出力ファイル名にタイムスタンプを付ける
csv_filename = f'receipt_data_{timestamp}.csv'

# CSVファイルに出力
with open(csv_filename, mode='w', newline='', encoding='utf-8') as csvfile:
    csv_writer = csv.writer(csvfile)
    # ヘッダー行を書き込み
    csv_writer.writerow(["日付", "店名", "商品名", "数量", "金額"])
    for item in items:
        product_name, price = item
        # 商品名の「/」以降を削除
        product_name_clean = product_name.split('/')[0]
        # 出力: 日付, 店名, 商品名, 数量, 金額
        row = f"{date},{shop_name},{product_name_clean},1,{price}"
        csv_writer.writerow(row.split(','))

print(f"CSVファイル '{csv_filename}' に出力しました。")

とコード変更

これで

python ocr_to_csv.py

とすれば

receipt_data_20240814054441.csv

が作成され

日付,店名,商品名,数量,金額
2024-08-10,とれたて食楽部,きゅうり,1,150
2024-08-10,とれたて食楽部,きゅうり,1,130
2024-08-10,とれたて食楽部,リーフレタス,1,216

というように商品名のみになる

Google cloud vision API サンプル

Google cloud vision API サンプル

https://nikkie-ftnext.hatenablog.com/entry/ocr-with-google-vision-api-python-first-step
によれば

Vision APIのOCRには2つあり
* TEXT_DETECTION
* DOCUMENT_TEXT_DETECTION
の2つがある

リファレンスは
https://cloud.google.com/vision/docs/ocr?hl=ja#optical_character_recognition_ocr
TEXT_DETECTION
任意の画像からテキストを検出、抽出します。
たとえば、写真に道路名や交通標識が写っていれば、
抽出された文字列全体、個々の単語、それらの境界ボックスが JSON レスポンスに含まれます。

DOCUMENT_TEXT_DETECTION
画像からテキストを抽出しますが、
高密度のテキストやドキュメントに応じてレスポンスが最適化され、
ページ、ブロック、段落、単語、改行の情報が JSON に含まれます

手書き入力の抽出とファイル(PDF / TIFF)からのテキスト抽出については、DOCUMENT_TEXT_DETECTION をご覧ください

とのこと

コードのサンプルについては
https://cloud.google.com/vision/product-search/docs/samples?hl=ja
にある

とりあえずまず動くか試したいので
2023-03-16【GCP/Python】Vision APIのOCR(光学文字認識)でテキスト抽出!
を参考に動かす

ファイル名を

vision_api_test.py

とする

cd aw10s
cd store_adversting_list 
vim vision_api_test.py


まずは
JSONを任意の場所に置いて読み込むらしいが
情報が古い

この時に認証関連のコマンドを使ってない
2024-01-03GoogleのVision APIをPythonから呼び出して、画像内のテキストを検出する

を参考に
とりあえず

from google.cloud import vision

client = vision.ImageAnnotatorClient()

with open("kanji.png", "rb") as fb:
    content = fb.read()

image = vision.Image(content=content)

response = client.document_text_detection(image=image)
texts = response.text_annotations
print(texts[0].description)

のファイルパスを変えて実行してみる

from google.cloud import vision

client = vision.ImageAnnotatorClient()

with open("test.jpg", "rb") as fb:
    content = fb.read()

image = vision.Image(content=content)

response = client.document_text_detection(image=image)
texts = response.text_annotations
print(texts[0].description)

スマホで撮影したチラシの画像でテスト

実行結果が大量になりそうなので

python vision_api_test.py >> result.txt

でテキストファイルに格納する

結果は

Aグループ版 オモテ
コミュニティー
15
魚担当
おすすめ
16
日
握りのセット!
うなぎの太巻、押寿司
では、うなぎ
―んびょうきゅうりそうなぎの
た
いて
今ぎをのせました。
→サイズ
1208195
うなぎ 28
うなぎ
うなぎり
醬
27.
水公園
coop
ユーコープ
いつもの商品を
膀胱! わくわく 日替りセール!!
お求めやすく!!」
7/100
7/110
7/100
14日
お一家族様
合わせて2点限り
14日
乾
麺10
店頭では10%引の価格を表示しています。
加工食品コーナーの商品に限ります。
※一部対象外の商品がございます。
魚
大
冷凍食品 20
●アイスクリームなど一部対象外商品があります。
詳しくは店頭でご確認ください。
例えばこちらの商品も20%引でこの
7/12 (金
7/13 土
毎週水曜日は
牛乳の日
毎週木曜日は
たまごの日
写真は全てイメージです。
毎週金曜日は
パンの日
コーブ牛乳
お一家族様5点限り
お一家族様 たまご
CO-OP コープ牛乳
1点限り
10個入
パスコ 超熟食パン
静岡県産など
金目鯛切身
切 1パック
680
味つき
734分
えだまめ
超
・6枚
8枚
熟
138円)
刺身用かつお
11バッグ ¥429円
宮格率から 398円 なども
真あじ
128
茶豆
税込
xg 138円
89
参考税込 149 円
天候などにより、水揚げのない場合はご容赦ください。
※写真はイメージです
写真は全てイメージです
新潟県などの国内産
ぶなしめじ 128円
(Wバック)
1袋
税込138円
13
土
7/
8%
群馬県などの国内産
わけあり
牛乳 KOO
成分散調整
「コープ牛乳」
¥198
参考税込
税込 213円
商品は店頭でご確認ください。
7/13 0
1000ml
178
参考税込
8% 192
子音 "14
子育て14日
ポイント
5 倍デー
co-op
岩手ひと
岩手ひとめぼれ
国館
洗米
ブルガリア ¥1,680円 1,780円
18% 各
Co-op
・塩味つきえ
・塩味つき茶
【各250g
15
参考税达 17
8%
19100-1
写真は
です
トマト (小箱)
桃(2個)
1パック/
山梨県などの国内産 ¥498円
$398
茶美豚
鹿児島県-
岩手県:
群馬県產
北海道產
100g当り とかち
100g当り
参考同认
8537
8%
番号税込 429 円
co-op
5ke
あらびきポーク
スペ
商品に限りがあるため、品切れの場合はご容赦ください。
●写真は全てイメージです
茶美酥
豚バラ
うすぎり
ポイントカードはお会計時にご提示ください
明治
特別栽培米
20 特別栽培無洗米
岩手ひとめぼれ 岩手ひとめぼれ
5kg
5kg
ポイントカードはお会計時にご提示ください プリマハム
総菜コーナー
11時販売開始
(本
彩り手巻き寿司
入り)
4本入
658円
710円
本 198円 本 本 378 円
参考税込
※税込) 213円 (交雑種) 税込
408円
販売開始
7種の天ぷら
盛り合わせ
1バック
398円
Dead 429
·伊右衛門
烏龍茶
各2L
配合 138 円
税込
8%
サントリー
税込 149 円
"15"16
ほほえみ
ポイント
15 モチー
限り
スモークの
香薰
こうくん
金賞受賞
香あらびき
キッコーマン ポーク体 238円
濃いだし ウインナー 参考税込 257円
めんつゆ
本つゆ
1L
大体228円
参考税込
税込 246円
※写真はイメージです
本つゆ
通常の5倍
90g×2
合わせ味噌
麺づくり
7/10 水 16 火 お野菜
いつも
※写真は全てイメージです。
おトク宣言!
群馬県などの
国内産
レタス
店内のこの
群馬県などの
国内産
きゃべつ
meiji
くちど
ヨーグルト
明治
R
ブルガリア
LB81
税込 1,814 円
税込 1,922 円
¥400g
LBSD プレーン
ヨーグルトの正本
全体 138円
見た目のキレイ
見た目のキレイ
LROT
参考税込
WWB 400M
税込 149 円
通常の
Aroma
ネスレ
Rich
25
Aroma
Rich
25
www
エクセラ
倍
・無糖
サイズ
コースの
甘さひかえめ お一家族様よりどり2点限り
【茶美豚
マルちゃん
NESCAFE
Excell
Freally
NESCAFE 各900ml
100g当り
ライオン
鹿児島県・
体各
¥78円
アロマリッチ
円 ジュリエット 合 378円 茶美豚
岩手県・群馬県産
198
参考税込
各 84 円
・キャサリン
豚ロース生姜焼・
参考税込
8% 各4円 各詰替950ml
税込 各 415円 豚丼用
参考税込。
8%
1 213 円
麺づくり
・鶏ガラ醤油
0円 ・合わせ味噌合 118
・鶏だし塩 [参考税込
0円 各1食
日香 127円
1個
108
参考税込 116円
1個
138
円 国内産
1個
お酒酒などの肴 158円
税込 149円 ブロッコリー 170円
8%
商品に限りがあるため、品切れの場合はご容赦ください。
●商品に併記している「参考税込」は、お支払い金額の目安として表示しています。 消費税は、レジで精算する際にお買い物小計に対してかかります。 ●酒類・日用品・雑貨などは消費税率10%対象です。 ●お酒は20歳未満の方への販売は致しておりません。
ざいません。
減にもつながります。
①Aグループ版 ウラ
COOP ユーコース
毎週
土曜日は子育て5倍デー 毎月5日 15日 15日 読み
シニア・
ほほえみ
ポイント
本 5 倍デー 7/100-160
組合員限定プレゼント!
対象商品を1点お買上げにつき
レジにて表示のポイントを
プレゼント致します。
広告の売り出し期間
ポイント
「プレゼント
※写真はイメージです
写真はイメージです。
広告実施店 よくお確かめの上、ご来店ください。
冷L中華
しょうゆだま
0000
冷中華
・ごまだれ
5
ポイント
プレゼント
CCO-OP 冷し中華
本番 218 円
・しょうゆだれ・ごまだれ 参考税込 235円
各110g×3食
「ラーメン
19
10%
「プレゼント」
COOD ざるラーメン 各¥ 298円
和風しょうゆつゆ
110g×3食
●税込 321 円
群馬県などの
国内産
たま
各
7/100 140
表示価格は
7/100 140
co-op
を味わう!
「とっておき
北海道産小麦使用
釜揚げうどん
400g
2番 160円)
● 172 円
10%
表示しています。
※写真はイメージです。
乾麺 10%
10%を表示しています。
コーナーのります。
品がございます。
本 158 円
きゅうり 1袋 170m
高知県などの
国内産
おくら 1ネット
149
●写真はイメージです
・コス
MENU
7/10 160
暴口
co-op & コスモ
直火燒
カレールーカレールー
**
カレールー
[カレール
中華
・中辛・辛口
•直火燒
よりどり
108278 (20
税込
300円
りんごカレー
各8皿分
かつお
メージです
うなぎ
神奈川食
ALCI
8594-2580
中原
230-463-36-30
並木あおば店
23342-758-2141
あさ9時よる9
ACC
末吉店 ハーモス深谷 片
045-581-0850 045-853-1141
洋光台店 神大寺店 竹
045-833-1537 045-431-3630
AC
セレク
04
ジョン 指定
鹿児島:大隅産
うなぎ蒲焼(長焼)
本 2,380円
白根店長後駅前店
045-954-1254
0466-43-4121
AC
南台店 茅ヶ崎高
1尾1バック
●者税込 2,570円
20-466-44-7750
0467-51-8777 46
ガッツリお肉で
スタミナチャージ!
[●写真は
イメージ
[100g当り
378円
税込 408円
税込298円
mmmm321
うまさのためにしない
強いこだわり
●平から収屋
当日出荷
さん兄
5
100g当り
全 498 円
ニュージーランド
ニュージーランドビーフ
牛リブロースステーキ 537円
●写真は
ニュージー
ニュージーランドビーフ
牛モモかたまり
ポイント
プレゼント
[焼そば
co-a
ACC
南林間店 ハーモス 厚木戸店
046-274-7202 046-257-3335 045-295-6600
AC
秦野曽屋店
0463-75-0357 0463-83-2830
ALG
城北店 千代田店 富士中央店
54-247-1326 054-264-1991 25-45-55-2555
新沢田店 袋井田町店 小豆店
-25-5000 239-43-7020 053-473-553
さんじの店 桜づつみ店
1053-441-8787 BUSS-989-99228
あさ9時30分よる9時
安台店
1045-983-1321
あさ10mよる8時
100g当り
268円
289 円
太麺焼そば
450g×2食
西港倉店
0467-32-5422
as 10 239-30
神記
大谷店
046-235-6432
A218 夏の
235円
8310 239
井田三舞店
044-798-8806
ハーモス
045-912-9955
東严塚駅前店
45-426-921
上今泉店
0046-231-7263
トマカ
●チャージ祭
7月・8月は
10. 20. 30.
税込 537 円
体 498円
アメリカ産
ブラントさんの牛肉
牛バラカルビ焼肉用
KA
御殿場高原
あらびきポーク
190g
138円)
CO-OP
いろいろ使える
味菜卵の
たま 178円 長ねぎ 1袋
国内産品
茨城県などの
198円
価 213 円
● 192 円
慮ください。
コース 高知県産
産直 黄金しょうが
+ 100円
総菜コーナー 11時販売開始
●写真はイメージです
バック
みょうが(2本): 138円 良) 138円
*税込108円
愛知県の国内産
大業
100g当り
●前
149円
なまぶし
ご飯(いくら)
1袋
があるため、品切れの場合はご容赦ください。
149円
1本釣り刺身用
日光丸で握った 258円
●
使わず
かつおたたき(解凍) 278円
イメージです
冷し中華
COOP
コーコース
7月24号
土用丑の日
3個入
7/130-140
●写真はイコージです
※写真はイメージです。
本
イパック 478 円
24 16
【ご予約承~ 6月15日(土)~7月15日
7月2日月・2日・2日
焼(長焼)
<130g
2380円
2,570 円
本日より1
2.580
しじみ汁に!
EAGEDO
7318
やきとりセット
(もも&ねぎま・たれ)
●516円
バック
4 498 円
537円
入り
ごちそう握り寿司
バック
1,080 円
1,166円
コープ
純正
ごま油
3008
548円
税込591円
イオシッコ
カ
カスピ海
ヨーグルト
グレ 400g
生乳
税込258円
・まさ 278円
82
沖縄県伊平屋島産
味付けもずく
(EHB-REBAV)
70g×3 1バック
コース
178円 税
192
オレ達のえだ豆
4 298円
組合員さんの声
「ほどよいごたえと、
かみしめるほどあふれてくる
ピリカちゃんさん
321がないです!
めください。
ユーコープはいつでもどなたでも加入して、ご利用いただける組合員のお店です。 ホームページはこちらから ユーコープwww.ucoop.or.jp/service/omise ●店舗により一部が異なる場合がございます。万一売り切れの場合はご容敬ください。一部パッケージの
собр
西部エリア

というようにかなり正確に取得できる
以前OCR関連のライブラリで行ったりchatgptで
チラシの内容を表示しようとした時にはできなかったことができた

ただし、スマホの撮影の場合
チラシ以外のものが入ると
その部分まで文字を認識してしまう

次回はチラシの画像のみで行うことにする

チラシの取得は以前Gmailで特定のメールのみ取得することができたので
Shuhooや特売のメールのみ取得し
リンク先から画像を取得すればできそう

あとは画像と数字の結び付け、もしくは
直接商品と価格を結び付けて取得できればOK

gcloud の初期化

gcloud を初期化

gcloud CLI をインストールする
を参考に続ける

gcloud -v 

を実行すると

Google Cloud SDK 477.0.0
bq 2.1.4
core 2024.05.17
gcloud-crc32c 1.0.0
gsutil 5.29
Updates are available for some Google Cloud CLI components.  To install them,
please run:
  $ gcloud components update

となる

gcloud CLI のコンポーネントの管理
によれば

gcloud components update コマンドを使用して、インストールされているすべてのコンポーネントを、使用可能な最新バージョンの gcloud CLI に更新できる

以前正常に動作していたバージョンに戻す必要があり、gcloud CLI を直接インストール(パッケージ マネージャーではなく、インタラクティブ インストーラ、静的バージョン、Windows インストーラ、Homebrew などを使用して)している場合は、gcloud components update を使用して、指定したバージョンに戻します。

gcloud components update –version VERSION

とあるので
多分失敗しても戻せるはず
ログでバージョンが判明しているので
一度更新してみる

実行すると

To help improve the quality of this product, we collect anonymized usage data 
and anonymized stacktraces when crashes are encountered; additional information 
is available at <https://cloud.google.com/sdk/usage-statistics>. This data is 
handled in accordance with our privacy policy 
<https://cloud.google.com/terms/cloud-privacy-notice>. You may choose to opt in 
this collection now (by choosing 'Y' at the below prompt), or at any time in the
 future by running the following command:

    gcloud config set disable_usage_reporting false

となるが
N
にしておく

次に

Beginning update. This process may take several minutes.


Your current Google Cloud CLI version is: 477.0.0
You will be upgraded to version: 484.0.0

┌───────────────────────────────────────────────────────────────────────────┐
│                     These components will be updated.                     │
├───────────────────────────────────────────────────┬────────────┬──────────┤
│                        Name                       │  Version   │   Size   │
├───────────────────────────────────────────────────┼────────────┼──────────┤
│ BigQuery Command Line Tool                        │      2.1.7 │  1.7 MiB │
│ Cloud Storage Command Line Tool                   │       5.30 │ 11.3 MiB │
│ Google Cloud CLI Core Libraries                   │ 2024.07.12 │ 19.1 MiB │
│ Google Cloud CRC32C Hash Tool (Platform Specific) │      1.0.0 │  1.2 MiB │
│ gcloud cli dependencies                           │ 2024.07.12 │ 16.6 MiB │
└───────────────────────────────────────────────────┴────────────┴──────────┘
┌────────────────────────────────────────────────────────────────────┐
│                These components will be installed.                 │
├─────────────────────────────────────────────┬────────────┬─────────┤
│                     Name                    │  Version   │   Size  │
├─────────────────────────────────────────────┼────────────┼─────────┤
│ gcloud cli dependencies (Platform Specific) │ 2021.04.16 │ < 1 MiB │
└─────────────────────────────────────────────┴────────────┴─────────┘

The following release notes are new in this upgrade.
Please read carefully for information about new features, breaking changes,
and bugs fixed.  The latest full release notes can be viewed at:
  https://cloud.google.com/sdk/release_notes

484.0.0 (2024-07-16)
  Breaking Changes
      ▪ **(GKE Hub)** gcloud container fleet memberships get-credentials now
        requires the permission gkehub.gateway.generateCredentials
        (automatically included in roles gkehub.gatewayReader,
        gkehub.gatewayEditor, and gkehub.gatewayAdmin), as well as network
        access to *connectgateway.googleapis.com.

  AlloyDB
      ▪ Added --node-ids flag to gcloud alloydb instances restart command in
        the alpha and beta tracks. This flag allows users to allow users to
        specify a comma-separated list of read pool node IDs to perform the
        restart on. Without specifying this flag, every node in the read pool
        will be restarted.

  App Engine
      ▪ Removed Google App Engine PHP 5/5 support.

      ▪ Updated the Java SDK to version 2.0.29 build from the open source
        project
        <https://github.com/GoogleCloudPlatform/appengine-java-standard/releases/tag/v2.0.29>.

  Artifact Registry
      ▪ Fixed error codes for gcloud artifacts docker upgrade migrate.

  Batch
      ▪ Fixed the --filter flag of gcloud batch list command to match gcloud
        topic filters syntax.

  BigQuery
      ▪ Added support for non-ASCII characters in the field mask when
        updating Connections.
      ▪ Added support for configuration.authentication.profile_id in the
        field mask when updating Connections.
      ▪ Fixed a bug where bq init would be called even when --use_google_auth
        is specified.

  Cloud Build
      ▪ Add support in gcloud builds worker-pools commands for default region
        set in config.

  Cloud Data Fusion
      ▪ Added three new optional arguments to gcloud beta data-fusion
        instances create command:
        ◆ --maintenance-window-start
        ◆ --maintenance-window-end
        ◆ --maintenance-window-recurrence
        ◆ These arguments allow users to specify the start time, end time,
          and recurrence of the maintenance window for their Data Fusion
          instance.
      ▪ Add four new optional arguments to gcloud beta data-fusion instances
        update command:
        ◆ --maintenance-window-start
        ◆ --maintenance-window-end
        ◆ --maintenance-window-recurrence
        ◆ --clear-maintenance-window
        ◆ These arguments allow users to update maintenance window for their
          Data Fusion instance by specifying the start time, end time, and
          recurrence, or clear the maintenance window using
          --clear-maintenance-window.

  Cloud Run
      ▪ Allows --revision-suffix to be specified with empty string to clear
        client-set revision naming.

  Cloud SQL
      ▪ Added --[no-]enable-dataplex-integration flag to gcloud sql instances
        create and gcloud sql instances patch to support Dataplex Integration
        for Cloud SQL.
      ▪ Added support for MySQL 8.4.

  Cloud Spanner
      ▪ Promoted --type=DATABASE_CHANGE_QUORUM option in gcloud spanner
        operations list to GA.
      ▪ Fixed the DATABASE_CHANGE_QUORUM type filter string in gcloud spanner
        operations list.

  Cloud Workstations
      ▪ Adding disable_ssl_validation support for workstations
        start-tcp-tunnel and workstations ssh.

  Compute Engine
      ▪ Added gcloud compute routers add-route-policy-term which adds policy
        term to a Route Policy in Cloud Router.
      ▪ Promoted gcloud compute routers add-route-policy-term to beta.
      ▪ Added gcloud compute routers update-route-policy-term which updates
        policy term in a Route Policy in Cloud Router.
      ▪ Promoted gcloud compute routers update-route-policy-term to beta.
      ▪ Added gcloud compute routers remove-route-policy-term which removes
        policy term from Route Policy in Cloud Router.
      ▪ Promoted gcloud compute routers remove-route-policy-term to beta.
      ▪ Fixed a bug in gcloud beta compute ssh where a third-party identity
        subject bearing an '@' sign wouldn't be URL-escaped in the way the OS
        Login API expects, causing spurious rejection.
      ▪ Promoted support of flags to --detection-load-threshold,
        detection-absolute-qps, detection-relative-to-baseline-qps, and
        traffic-granularity-configs in gcloud compute security-policies
        add-layer7-ddos-defense-threshold-config to GA.

  Dataproc Metastore
      ▪ Promoted --min-scaling-factor, --max-scaling-factor, and
        --autoscaling-enabled flag of gcloud metastore services create and
        gcloud metastore services update to GA.

  Distributed Cloud Edge
      ▪ Added --offline-reboot-ttl flag to gcloud edge-cloud container
        clusters create and gcloud edge-cloud container clusters update
        commands. This flag specifies the maximum duration a node can reboot
        offline (without connection to Google) and then rejoin its cluster to
        resume its designated workloads.

  Kubernetes Engine
      ▪ Added flag option --addons=RayOperator to enable/disable the Ray
        Operator addon for GKE Standard clusters.
      ▪ Added flag --[no]-enable-ray-operator to enable/disable the Ray
        Operator addon for GKE Autopilot clusters.
      ▪ Added flag --[no]-enable-ray-cluster-logging to enable/disable
        automatic log collection for Ray clusters when the Ray Operator addon
        is enabled.
      ▪ Added flag --[no]-enable-ray-cluster-monitoring to enable/disable
        automatic metrics collection for Ray clusters when the Ray Operator
        addon is enabled.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

483.0.0 (2024-07-02)
  Google Cloud CLI
      ▪ Enabled faster component update mode by default on Linux. This avoids
        making a backup copy of the installation directory when running certain
        gcloud components commands, which should significantly improve the time
        taken by these operations (including installation and updates).
      ▪ Fixed issue where gcloud components update would leave installation
        in an unusable state when downloading certain components failed.

  AlloyDB
      ▪ Added the following flags to gcloud alloydb instances create and
        gcloud alloydb instances update in alpha and beta:
        ◆ --observability-config-enabled
        ◆ --observability-config-preserve-comments
        ◆ --observability-config-track-wait-events
        ◆ --observability-config-max-query-string-length
        ◆ --observability-config-record-application-tags
        ◆ --observability-config-query-plans-per-minute
        ◆ --observability-config-track-active-queries
      ▪ Promoted AlloyDB Cross Region Replication commands to beta and GA
        track. Modified commands include: alloydb clusters switchover.
      ▪ Added creating cross region and project backups support to gcloud
        alloydb backups create command.
      ▪ Added ability to create clusters with database_version POSTGRES_16 in
        beta track.

  Batch
      ▪ Release resource-allowances commands to the alpha track.

  Cloud Access Context Manager
      ▪ Promoted gcloud access-context-manager supported-services to GA.

  Cloud Filestore
      ▪ Enable Filestore promote-replica command in GA track.

  Cloud Functions
      ▪ Added --binary-authorization and --clear-binary-authorization flags
        for 2nd gen function in alpha and beta track.

  Cloud NetApp
      ▪ Updated psa-range comments on gcloud netapp storage-pools and gcloud
        netapp volumes to indicate that the psa-range key is not used and will
        be ignored.

  Cloud SQL
      ▪ Adding support for clean and if-exists flags to parallel import and
        single-threaded-export.

  Cloud Workstations
      ▪ Added --vm-tags flag to gcloud workstations config create to add tags
        to the workstation's underlying VM.

  Compute Engine
      ▪ Promoted --preference flag of gcloud compute backend-services
        add-backend and gcloud compute backend-services update-backend to GA.
      ▪ Promoted --service-lb-policy flag of gcloud compute backend-services
        create and gcloud compute backend-services update to GA.
      ▪ Promote gcloud compute instances ops-agents to GA.
      ▪ Added IDPF to the list of guestOsFeatures.
      ▪ Promoted --max-run-duration flag of gcloud compute instances create
        to v1.
        ◆ Allows specifying the duration of time after which the instance
          will terminate.
      ▪ Promoted --termination-time flag of gcloud compute instances create
        to v1.
        ◆ Allows specifying the timestamp that the instance will terminate.
      ▪ Promoted --discard-local-ssds-at-termination-timestamp flag of gcloud
        compute instances create to v1.
        ◆ Allows specifying the option to whether discard attached local SSDs
          when automatically stopping this VM

  Network Security
      ▪ Renamed FIREWALL_POLICY column to SOURCE_RESOURCE column in gcloud
        networksecurity address-groups list-references command.
      ▪ Added --purpose flag to gcloud alpha/beta network-security
        address-groups create/update commands.

  Secret Manager
      ▪ Added flag --location and --regional-kms-key-name for secrets to use
        the regional secrets.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

482.0.0 (2024-06-25)
  App Engine
      ▪ Removed unused python2 dependencies that have CVEs.

  Cloud Bigtable
      ▪ Adds force option to cbt setgcpolicy.

  Cloud Dataflow
      ▪ Elevate jinja variables to top-level flag in dataflow yaml run.

  Cloud Functions
      ▪ Added --clear-build-service-account flag for gcloud functions deploy.

  Cloud Key Management Service
      ▪ Added --allowed-access-reasons flag to gcloud kms keys create to
        create a key with a Key Access Justifications policy configured.
      ▪ Added --allowed-access-reasons flag to gcloud kms keys update to
        update the Key Access Justifications policy on a key.
      ▪ Added --remove-key-access-justifications-policy flag to gcloud kms
        keys update to remove the Key Access Justifications policy on a key.

  Cloud Services
      ▪ Promoted gcloud services policies add-enable-rules to beta.
      ▪ Promoted gcloud services policies remove-enable-rules to beta.
      ▪ Promoted gcloud services policies get to beta.
      ▪ Promoted gcloud services policies get-effective to beta.
      ▪ Promoted gcloud services policies test-enabled to beta.
      ▪ Promoted gcloud services groups list-ancestor-groups to beta.
      ▪ Promoted gcloud services groups list-descendant-services to beta.
      ▪ Promoted gcloud services groups list-members to beta.

  Compute Engine
      ▪ Added --size flag to gcloud compute instance-groups managed update
        for v1.
      ▪ Promoted --confidential-compute-type flag for the command gcloud
        compute instance create to GA.
      ▪ Promoted --performance-monitoring-unit flag for the command gcloud
        compute instance-templates create to GA.
      ▪ Promoted --performance-monitoring-unit flag for the command gcloud
        compute instances bulk create to GA.
      ▪ Promoted --performance-monitoring-unit flag for the command gcloud
        compute instances create  to GA.

  Kubernetes Engine
      ▪ Updated default kubectl from 1.27.14 to 1.27.15.
      ▪ Additional kubectl versions:
        ◆ kubectl.1.27 (1.27.15)
        ◆ kubectl.1.28 (1.28.11)
        ◆ kubectl.1.25 (1.29.6)
        ◆ kubectl.1.30 (1.30.2)

  Network Connectivity
      ▪ Added include-import-ranges flag to hybrid spoke creation to support
        importing hub subnets.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

481.0.0 (2024-06-18)
  Breaking Changes
      ▪ **(Cloud Dataflow)** Deprecated gcloud dataflow sql command group.
        The command group will be removed by 2025-01-31. See Beam YAML
        (https://beam.apache.org/documentation/sdks/yaml/) and Beam notebooks
        (https://cloud.google.com/dataflow/docs/guides/notebook-advanced#beam-sql)
        for alternatives.

  AlloyDB
      ▪ Added another option ASSIGN_IPV4 to flag --assign-inbound-public-ip
        to enable public IP for an instance to gcloud alloydb instances create
        and gcloud alloydb instances create-secondary.
      ▪ Added flag --authorized-external-networks to set a list of authorized
        external networks on an instance to gcloud alloydb instances create and
        gcloud alloydb instances create-secondary.
      ▪ Added switchover command.

  Artifact Registry
      ▪ Fixed a bug where gcloud artifacts files download and gcloud
        artifacts generic download would crash.

  BigQuery
      ▪ Added undelete command for datasets.
      ▪ Updated google-auth to version 2.29.0.
      ▪ Improved authentication error messaging.

  Cloud Domains
      ▪ Implemented the following commands for gcloud domains registrations
        google-domains-dns
        ◆ get-forwarding-config
        ◆ export-dns-record-sets

  Cloud Filestore
      ▪ Added --source-instance flag to gcloud filestore instances create and
        gcloud beta filestore instances create command to specify the instance
        will be created as a Standby replica of the source-instance.
      ▪ Added promote-replica verb for filestore instances. promote-replica
        promotes a standby replication instance to a regular instance.

  Cloud Functions
      ▪ Promoted --build-service-account flag for gcloud functions deploy to
        GA.

  Cloud Identity-Aware Proxy
      ▪ Promoted gcloud iap regional command to beta and GA.

  Cloud Pub/Sub
      ▪ Promoted --cloud-storage-use-topic-schema flag of gcloud pubsub
        subscriptions create to GA. Added the ability to set whether to use
        topic schemas in Cloud Pub/Sub to Cloud Storage subscriptions. For more
        information, see
        <https://cloud.google.com/pubsub/docs/create-cloudstorage-subscription#use-topic-schema>.
      ▪ Promoted --cloud-storage-use-topic-schema flag of gcloud pubsub
        subscriptions update. to GA. Added the ability to update whether to use
        topic schemas in Cloud Pub/Sub to Cloud Storage subscriptions. For more
        information, see
        <https://cloud.google.com/pubsub/docs/create-cloudstorage-subscription#use-topic-schema>.

  Cloud Spanner
      ▪ Added gcloud beta spanner instance-partitions command group.
      ▪ Added --instance-partition flag to gcloud beta spanner operations
        list, gcloud beta spanner operations describe, and gcloud beta spanner
        operations cancel.

  Cloud Storage
      ▪ Added commands for creating, listing, describing, and deleting
        folders in buckets with hierarchical namespace enabled:
        ◆ Added gcloud alpha storage folders create which creates folders.
        ◆ Added gcloud alpha storage folders list which lists folders in
          buckets.
        ◆ Added gcloud alpha storage folders describe which gets the folder's
          metadata.
        ◆ Added gcloud alpha storage folders delete which deletes folders.
      ▪ Updated gsutil component to 5.30.

  Compute Engine
      ▪ Promoted --confidential-compute-type flag for the command gcloud
        compute instance create to GA.
      ▪ Added --size flag to gcloud compute instance-groups managed update
        for v1.

  Network Connectivity
      ▪ Updated gcloud network-connectivity internal-ranges update to support
        setting and clearing labels.
      ▪ Added support for include-export-ranges to support include filters
        for VPC spokes.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

480.0.0 (2024-06-11)
  App Engine
      ▪ Updated the Java SDK to version 2.0.28 build from the open source
        project
        <https://github.com/GoogleCloudPlatform/appengine-java-standard/releases/tag/v2.0.28>.

  Artifact Registry
      ▪ gcloud artifacts docker upgrade migrate now automatically creates
        repos for pkg.dev-based migration.
        ◆ Added gcloud artifacts files delete command.

  Cloud Datastream
      ▪ Added --type and --sqlserver-* flags to gcloud datastream
        connection-profiles create|update and gcloud datastream objects lookup
        commands to support SQL server source.
      ▪ Added --type and --sqlserver-* flags to gcloud datastream streams
        create|update commands to support SQL server source.
      ▪ Added --sqlserver-rdbms-file flag and support for SQL Server profile
        to --connection-profile-object-file to gcloud datastream
        connection-profiles discover commands to support SQL server source.

  Cloud Domains
      ▪ Implemented the following commands for gcloud domains registrations
        ◆ renew-domain
        ◆ initiate-push-transfer

  Cloud Functions
      ▪ Added support for --execution-id flag when used together with --gen2
        flag for gcloud functions logs read.

  Cloud Healthcare
      ▪ Added beta flag --enable-history-modifications to the fhir-stores
        create and fhir-stores update commands.

  Cloud IAM
      ▪ Updated iam service-accounts keys list to return additional
        properties, namely:
        ◆ disable_reason: The reason the Service Account Key as been disabled
          (if applicable)
        ◆ extended_status: Additional metadata about the Service Account Key

  Cloud Memorystore
      ▪ Added --zone-distribution-mode and --zone flags to gcloud redis
        clusters create for creating single zone clusters.

  Cloud Pub/Sub
      ▪ Added --bigquery-service-account-email and
        --cloud-storage-service-account-email flags to gcloud pubsub
        subscriptions create to set the service account for writing messages to
        BigQuery and Cloud Storage, respectively.
      ▪ Added --bigquery-service-account-email and
        --cloud-storage-service-account-email flags to gcloud pubsub
        subscriptions create to update the service account for writing messages
        to BigQuery and Cloud Storage, respectively.

  Cloud Spanner
      ▪ Added --proto-descriptors-file to gcloud spanner databases create
        command to allow creating database with proto and enum type columns.
      ▪ Added --proto-descriptors-file to gcloud spanner databases ddl update
        command to allow updating database with proto and enum type columns.
      ▪ Added --include-proto-descriptors to gcloud spanner databases ddl
        describe command to allow proto descriptors for a database with proto
        and enum type columns.
      ▪ Promoted gcloud spanner databases change-quorum command to GA.

  Cloud Storage
      ▪ Adds support of Cross Bucket Replication Feature in alpha track of
        gcloud transfer command group.

  Cloud Workstations
      ▪ Added --allowed-ports flag to gcloud beta workstations configs create
        and gcloud beta workstations configs update commands.
      ▪ Added enable-nested-virtualization pool-size and boot-disk-size to
        --boost-configs flag in beta workstations configs create and beta
        workstations configs update.

  Compute Engine
      ▪ Added support for version=24.04 and short-name=ubuntu in --os-types
        for gcloud beta compute instances ops-agents policies [create|update].
      ▪ Promoted Tls Early Data in TargetHttpsProxy compute API to v1.
      ▪ Added gce_vm_ip_portmap Network Endpoint Group for gcloud compute
        network-endpoint-groups beta support.
      ▪ Added --access-mode flag to gcloud compute disks create and gcloud
        compute disks update.
      ▪ Added --tls-early-data flag to gcloud compute v1 target-https-proxies
        create/update to Tls Early Data field in Target Https Proxy.

  Secret Manager
      ▪ Added --version-destroy-ttl flag to gcloud secrets create to let
        users enable secret version delayed destruction on a secret.
      ▪ Added --version-destroy-ttl flag to gcloud secrets update to let
        users enable/update secret version delayed destruction on a secret.
      ▪ Added --remove-version-destroy-ttl flag to gcloud secrets update to
        let users disable secret version delayed destruction on a secret.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

479.0.0 (2024-06-04)
  Breaking Changes
      ▪ **(Cloud Dataflow)** gcloud dataflow flex-template build for Dataflow
        Flex Templates in Python with --env
        FLEX_TEMPLATE_PYTHON_REQUIREMENTS_FILE=/path/to/requirements.txt
        defined will run pip check after pip install while building the
        container image. This will break the build process if newly installed
        packages override pre-installed packages with a version that is known
        to be incompatible with other pre-installed packages. See
        <https://cloud.google.com/dataflow/docs/guides/templates/configuring-flex-templates>
        for alternative methods to build a container image without pip check.

  Artifact Registry
      ▪ Updated gcloud artifacts docker images command to include tags as
        list instead of string to enable use of --filter=tags=<SearchTerm>.

  Cloud Composer
      ▪ Added gcloud composer environments check-upgrade command. It checks
        that an environment upgrade does not fail because of PyPI module
        conflicts.
      ▪ Added gcloud composer environments list-upgrades command. It lists
        all possible target versions that an existing environment can be
        upgraded to.

  Cloud Dataproc
      ▪ Updated gcloud dataproc session-templates export to filter out
        additional output only fields.

  Cloud NetApp
      ▪ Added --administrators flag to gcloud netapp active-directories
        create and gcloud netapp active-directories update.

  Cloud SQL
      ▪ Added --preferred-secondary-zone flag to gcloud sql instances clone
        command.

  Compute Engine
      ▪ Updated import and export schemas for gcloud compute
        forwarding-rules.
      ▪ Promoted --ip-collection flag of gcloud compute forwarding-rules
        create to GA.
      ▪ Promoted --ip-collection-region flag of gcloud compute
        forwarding-rules create to GA.

  Compute OS Config
      ▪ Added --allow-missing flag to gcloud compute os-config
        os-policy-assignments update to allow for creation of a new OS policy
        assignment resource if it does not exist.

  Database Migration
      ▪ Updated gcloud database-migration connection-profiles create cloudsql
        to support POSTGRES_16 version option for Cloud SQL connection
        profiles.

  Distributed Cloud Edge
      ▪ Added add/remove exclusion window flags for gcloud edge-cloud
        container clusters update to allow users to add/remove exclusion
        windows where automatic upgrades will be blocked within.

  Service Extensions
      ▪ Added the metadata field to the DEP extensions.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

478.0.0 (2024-05-29)
  Google Cloud CLI
      ▪ Improved error message for authentication errors.
      ▪ Improved error message for service account impersonation refresh
        errors.
      ▪ Fixed issue where some commands with a --uri flag would produce no
        output.

  App Engine
      ▪ Enable fetch_instance_after_connect_error for compute
        start-iap-tunnel in GA.
      ▪ Allow IAP tunneling for instances with external IP when explicitly
        enabled via flag.

  App Engine Flexible Environment
      ▪ Enable fetch_instance_after_connect_error for compute
        start-iap-tunnel in GA.
      ▪ Allow IAP tunneling for instances with external IP when explicitly
        enabled via flag.

  Artifact Registry
      ▪ Added gcloud artifacts files describe command.

  Backup For GKE
      ▪ Added --volume-data-restore-policy-bindings flag to gcloud container
        backup-restore restore-plans create and gcloud container backup-restore
        restore-plans update to enhance volume restore flexibility.
      ▪ Added --volume-data-restore-policy-overrides-file flag to gcloud
        container backup-restore restores create to enhance volume restore
        flexibility.
      ▪ Added --permissive-mode flag to gcloud container backup-restore
        backup-plans create and gcloud container backup-restore backup-plans
        update to enable bypassing the new backup-time restorability
        enforcement.
      ▪ Added --filter-file flag to gcloud container backup-restore restores
        create to support Backup for GKE fine-grained restore.
      ▪ Added --restore-order-file flag to gcloud <alpha|beta> container
        backup-restore restore-plans create and gcloud <alpha|beta> container
        backup-restore restore-plans update to support custom ordering while
        performing restore as part of Backup for GKE.
      ▪ Added the following enum values for the flag
        --namespaced-resource-restore-mode to gcloud <alpha|beta> container
        backup-restore restore-plans create and gcloud <alpha|beta> container
        backup-restore restore-plans update to expand namespaced resource
        restore mode options:
        ◆ merge-skip-on-conflict
        ◆ merge-replace-volume-on-conflict
        ◆ merge-replace-on-conflict
      ▪ Deprecated --substitution-rules-file flag. Use
        --transformation-rules-file instead.

  BigQuery
      ▪ Added support for map_target_type with external parquet tables.
      ▪ Added support for column_name_character_map to map special characters
        in column names during load jobs.
      ▪ Added a printout of unreachable locations when datasets and jobs are
        listed and a region is down.

  Cloud Dataplex
      ▪ Promoted gcloud dataplex aspect-types command group to GA.
      ▪ Promoted gcloud dataplex entry-groups command group to GA.
      ▪ Promoted gcloud dataplex entry-types command group to GA.

  Cloud Deploy
      ▪ Fixed issue where skaffold files generated from deploy releases
        create flags did not include all profiles in the release's Delivery
        Pipeline.

  Cloud Firestore
      ▪ Promoted Cloud Firestore Backups and Restore gcloud CLI changes to
        beta.
        ◆ Promoted gcloud firestore backups list command to beta.
        ◆ Promoted gcloud firestore backups describe command to beta.
        ◆ Promoted gcloud firestore backups delete command to beta.
        ◆ Promoted gcloud firestore backups schedules create command to beta.
        ◆ Promoted gcloud firestore backups schedules update command to beta.
        ◆ Promoted gcloud firestore backups schedules describe command to
          beta.
        ◆ Promoted gcloud firestore backups schedules delete command to beta.
        ◆ Promoted gcloud firestore backups schedules list command to beta.
        ◆ Promoted gcloud firestore databases restore command to beta.
      ▪ Promoted Cloud Firestore Backups and Restore gcloud CLI changes to
        GA.
        ◆ Promoted gcloud firestore backups list command to GA.
        ◆ Promoted gcloud firestore backups describe command to GA.
        ◆ Promoted gcloud firestore backups delete command to GA.
        ◆ Promoted gcloud firestore backups schedules create command to GA.
        ◆ Promoted gcloud firestore backups schedules update command to GA.
        ◆ Promoted gcloud firestore backups schedules describe command to GA.
        ◆ Promoted gcloud firestore backups schedules delete command to GA.
        ◆ Promoted gcloud firestore backups schedules list command to GA.
        ◆ Promoted gcloud firestore databases restore command to GA.

  Cloud Firestore Emulator
      ▪ Release Cloud Firestore emulator v1.19.7
        ◆ Fixes unexpected responses from nested queries in Datastore Mode.
        ◆ Add Auth Context support for Firestore triggers (2nd gen) in
          Firestore Emulator

  Cloud Functions
      ▪ Added validation to --runtime-update-policy argument.

  Cloud SQL
      ▪ Added PostgreSQL 16 to database versions.
      ▪ Fixed issue where gcloud sql instances export and gcloud sql
        instances import would display only the operation selfLink field
        instead of the whole operation when run asynchronously with --async,
        regardless of the --format flag specified.
        ◆ This behavior is now consistent with other gcloud sql instances
          commands.
        ◆ To display only the selfLink field, use --format="value(selfLink)".

  Cloud Workstations
      ▪ Adding --env flag to gcloud workstations create.

  Compute Engine
      ▪ Added IPV6_ONLY option to --stack-type flag of gcloud compute
        vpn-gateways create command to create an IPv6-only VPN gateway.

  Config Connector
      ▪ Updated Google Cloud Config Connector to version 1.118.1. See Config
        Connector Overview for more details
        https://cloud.google.com/config-connector/docs/overview
        (https://cloud.google.com/config-connector/docs/overview).

  Database Migration
      ▪ Updated gcloud database-migrate connection-profiles update to update
        Database Migration Service connection profile for SQL Server to Cloud
        SQL-SQL Server migrations.
      ▪ Updated gcloud database-migrate migration-jobs update to update
        Database Migration Service migration job for SQL Server to Cloud
        SQL-SQL Server migrations.

  Dataproc Metastore
      ▪ Added --deletion-protection flags to gcloud metastore services create
        GA release track to allow creating a Dataproc Metastore instance with
        delete protection.
      ▪ Added --deletion-protection and --no-deletion-protection flags to
        gcloud metastore services update GA release track to allow updating a
        Dataproc Metastore instance with delete protection.

  Security Command Center
      ▪ Added --filter-modules flag in gcloud scc manage services describe
        ... api to filter response by modules.

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce
    (https://groups.google.com/forum/#!forum/google-cloud-sdk-announce).

Once started, canceling this operation may leave your SDK installation in an 
inconsistent state.

となる
これで
Y
とすると更新される

Performing in place update...

╔════════════════════════════════════════════════════════════╗
╠═ Uninstalling: BigQuery Command Line Tool                 ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Cloud Storage Command Line Tool            ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Google Cloud CLI Core Libraries            ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Google Cloud CRC32C Hash Tool              ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: gcloud cli dependencies                    ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: BigQuery Command Line Tool                   ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud Storage Command Line Tool              ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Google Cloud CLI Core Libraries              ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Google Cloud CRC32C Hash Tool (Platform S... ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: gcloud cli dependencies                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: gcloud cli dependencies (Platform Specific)  ═╣
╚════════════════════════════════════════════════════════════╝

Performing post processing steps...done.                                       

Update done!

To revert your CLI to the previously installed version, you may run:
  $ gcloud components update --version 477.0.0

となるのでログを翻訳

後処理ステップを実行しています…完了しました。

アップデート完了!

CLI を以前にインストールしたバージョンに戻すには、次のコマンドを実行します。
$ gcloud コンポーネントの更新 –バージョン 477.0.0
となる

つまりこのコマンドを実行すれば不具合があっても戻せるはず

とりあえず更新処理はできたので初期化をする

./google-cloud-sdk/bin/gcloud init

を実行

Welcome! This command will take you through the configuration of gcloud.

Your current configuration has been set to: [default]

You can skip diagnostics next time by using the following flag:
  gcloud init --skip-diagnostics

Network diagnostic detects and fixes local network connection issues.
Checking network connection...done.                                            
Reachability Check passed.
Network diagnostic passed (1/1 checks passed).

You must log in to continue. Would you like to log in (Y/n)?  

となるので
Y
にする

これでブラウザで認証画面になるので
ログインして処理を進めていき
最後に許可を押せばOK

Your browser has been opened to visit:


Please enter numeric choice or text value (must exactly match list item):     

となるので
今回使うのプロジェクトの番号を入力

これで

* Commands that require authentication will use snowpoollovely@gmail.com by default
* Commands will reference project `raspberrypi-ea1b6` by default
Run `gcloud help config` to learn how to change individual settings

This gcloud configuration is called [default]. You can create additional configurations if you work with multiple accounts and/or projects.
Run `gcloud topic configurations` to learn more.

Some things to try next:

* Run `gcloud --help` to see the Cloud Platform services you can interact with. And run `gcloud help COMMAND` to get help on any gcloud command.
* Run `gcloud topic --help` to learn about advanced features of the SDK like arg files and output formatting
* Run `gcloud cheat-sheet` to see a roster of go-to `gcloud` commands.

となる

gcloud config list

を実行すると
設定の確認ができる

とりあえず設定はできたので
次に
gcloudコマンドでApplication Default Credentials (ADC)の作成