2023年3月30日木曜日

GAS で ChatGPT の API を利用した簡単な LINE bot を作ってみる

-----
・追記(2023-4-4)
複数回のやりとりができるバージョンを作りました → 「GAS で ChatGPT とやりとりできる簡単な LINE bot の作り方
-----

GAS (Google Apps Script) で ChatGPT の API を利用した簡単な LINE bot を作ってみました。

作ってみましたと言いつつ、コード自体は ChatGPT とやり取りしながらほぼ作ってもらいました。自分で作ると(どうせ自分で使うものだしと思って)疎かにしがちなエラー処理も付いています。


LINE Messaging API チャンネルの作成とアクセストークンの取得。及び、OpenAI の API キー取得は済んでる想定です。

それぞれ、GAS の「プロジェクトの設定」よりスクリプト プロパティとして追加・保存しておきます。プロパティ名は「Line_key」と「OpenAI_key」としてコード内で使っています。

ちなみに、OpenAI の API 使用は有料ですが、5ドル分(3か月有効)が無料枠として設けられているようです、たぶん。(正確に把握できているか自信がないので詳細は調べてみてください)


以下がコードになります。

function doPost(e) {
  try {
    const replyToken = getReplyToken(e);
    const englishMessage = getEnglishMessage(e);
    const requestMessage = [{'role': 'user', 'content': englishMessage}];
    const openAiParams = generateOpenAIParams(requestMessage);
    const response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', openAiParams);
    const resData = JSON.parse(response.getContentText());
    const replyMessage = resData.choices[0].message.content;
    const translatedMessage = LanguageApp.translate(replyMessage, "en", "ja");
    const replyContent = `${englishMessage}\n-----\n${translatedMessage}\n\n${replyMessage}`;
    const linePayload = generateLinePayload(replyToken, replyContent);
    sendLineMessage(linePayload);
  } catch (error) {
    console.error(`An error occurred: ${error}`);
  }
}

// pushメッセージからreplyTokenを取得する関数
function getReplyToken(e) {
  const event = JSON.parse(e.postData.contents).events[0];
  return event.replyToken;
}

// pushメッセージからリクエストメッセージを取得する関数
function getEnglishMessage(e) {
  const event = JSON.parse(e.postData.contents).events[0];
  const message = event.message;
  const messageContent = message.type === 'text' ? message.text : '';
  return LanguageApp.translate(messageContent, "", "en");
}

// OpenAIのリクエストパラメータを生成する関数
function generateOpenAIParams(requestMessage) {
  const openAiHeaders = {
    'Authorization': `Bearer ${PropertiesService.getScriptProperties().getProperty('OpenAI_key')}`,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  const openAiPayload = {
    'model': 'gpt-3.5-turbo', // 使用するモデル
    'max_tokens': 1024, // 生成する文章の最大トークン数
    'temperature': 1, // 生成された文章のランダムさを制御するパラメータ。値が高いほど、よりランダムな文章が生成される
    'messages': requestMessage // 生成する文章の元になるプロンプト
  };
  return {
    'method': 'POST',
    'headers': openAiHeaders,
    'payload': JSON.stringify(openAiPayload),
  };
}

// LINEに返信するメッセージを生成する関数
function generateLinePayload(replyToken, replyMessage) {
  return {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${PropertiesService.getScriptProperties().getProperty('Line_key')}`,
    },
    'payload': JSON.stringify({
      'replyToken': replyToken,
      'messages': [{
        'type': 'text',
        'text': replyMessage,
      }],
    }),
  };
}

// LINEにメッセージを送信する関数
function sendLineMessage(linePayload) {
  const response = UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', linePayload);
  const responseCode = response.getResponseCode();
  if (responseCode !== 200) {
    console.error(`LINE API returned an error: ${responseCode}`);
  }
}

動きとしては、メッセージを英語に翻訳して ChatGPT の API に投げ、英語で受け取った回答を日本語に翻訳して返信しています。質問は英語の方が精度が良いらしいのと、課金の計算元になるトークンのカウントが少なくてすむようです。

コード作成後にウェブアプリとして公開、URL を LINE Messaging API チャンネルで Webhook として設定します。

動かしてみるとこんな感じになります。


英語の勉強も兼ねて、この形式での返信にしています(笑)。


Google スプレッドシートにやりとりを格納して引き出すようにすれば、複数回のやりとりも可能そうです。(→ 作りました「GAS で ChatGPT とやりとりできる簡単な LINE bot の作り方」)

今後もいろいろ試しながら、あわよくば農業への利用の可能性を探っていきたいと思います。


***

ChatGPT、コードを書いてもらったり、説明してもらったりは本当にめちゃくちゃ便利ですね。あと、私のような素人はコードの改善点を指摘してもらえる機会も少ないのでとてもありがたいです。

2023年3月27日月曜日

徒然じゃない日々(23)

農業と春について

春は農業にとって重要な季節です。冬の寒さが去り、暖かくなることで、作物の種まきや植え付けが可能になります。農家の人々は、春が来ると一年のうちでもっとも忙しい時期がやってくると言っても過言ではありません。

農業は、人々が生きるために必要不可欠な産業です。私たちが食べる食べ物のほとんどは、農業によって作られています。しかし、現代の農業は、環境汚染や過剰な農薬使用などの問題に直面しています。これらの問題を解決するために、持続可能な農業が求められています。

春は、持続可能な農業にとって重要な季節でもあります。持続可能な農業は、環境に配慮し、地球にやさしい方法で作物を育てることを目的としています。春には、有機物を土壌に追加し、土壌を栄養豊富にすることができます。また、農薬や化学肥料を最小限に抑えることもできます。

春は、農業にとってだけでなく、私たちにとっても特別な季節です。冬が去り、自然は新しい命を生み出し始めます。花が咲き、鳥たちがさえずり、木々が葉を茂らせます。私たちは、春がやってくると、新しい始まりの季節を感じます。

農業と春には、深い関係があります。春がやってくると、農家たちは新しい作物の収穫を期待し、持続可能な農業を実践するための新しい方法を探求します。私たちは、春がやってくることで、食べ物と環境について考えるきっかけを得ることができます。


遅ればせながら、人工知能チャットボット ChatGPT が話題ですね。

何かうまいこと農業に使えないかなあと考えていたもののあまり思いつかず……。でもまあ、とりあえず使ってみるかということで使ってみた結果が冒頭の文章です。

「農業と春に関するエッセイをくだけた文章で書いてください。」で出力しました。ちゃんとそれっぽいことを書きますね(くだけてはいないですが)。

プロンプトと呼ばれる指示文をもっとしっかり書けるようになると精度も上げられるみたいです。プログラムの作成にもぜひ利用してみたいところ。

いかに適切な問いをたてられるかが、より人に求められる能力になっていきそうですね。


ちなみに、「ChatGPTの農業利用の可能性は?」で得られた回答が以下です。

-----
ChatGPTは人工知能の大規模言語モデルであり、農業に関する情報を処理し、農業関連の質問に回答することができます。また、ChatGPTは自然言語生成の能力を持っており、農業に関する文章を生成することもできます。

農業においては、ChatGPTは以下のような活用が考えられます。

1. 農業情報の分析と予測
ChatGPTは、大量の農業データを処理することができます。農業に関するデータを収集し、ChatGPTに学習させることで、農業のトレンドや市場動向を分析し、将来の予測を行うことができます。

2. 農業技術の開発支援
ChatGPTは、農業技術の開発支援にも活用できます。農業に関する論文や研究データを分析し、新しい農業技術の開発を支援することができます。

3. 農業関連の問題解決支援
ChatGPTは、農業に関連する問題の解決支援にも活用できます。例えば、病気や害虫に対する対策、天候による作物の被害に対する対策など、様々な問題に対する解決策を提供することができます。

4. 農業関連の情報提供
ChatGPTは、農業に関連する情報の提供にも活用できます。例えば、特定の地域での農業に適した作物、肥料の使い方、作物の収穫時期など、様々な情報を提供することができます。

以上のように、ChatGPTは農業において、様々な活用が期待できます。ただし、ChatGPT自身が農業を行うわけではないため、農業技術の開発や問題解決策の提供には、ChatGPTとともに専門家や実際の農業現場の知見を活用する必要があります。
-----

なるほど……。すごいですね。


ChatGPT、自作スマート機器に組み込んで、何か日々の農業の中で役立つようなものが作れたら面白そうですね。




Twitter (@nkkmd) 日々更新中です。

2023年3月19日日曜日

新しい農業経営像 in 昭和56年

先日、図書館のブックリサイクルにて昭和56年発行の「日本農業の動き 新しい農業経営像」という書籍を入手しました。



昭和56年というと約40年前になります。ちょうど両親が農業を始めた頃です。

両親がどんな風に農業に取り組んできたかというのは何となく聞いてはいますが、また違った視点から当時の状況を知ることができて非常に興味深いですね。

そして、もし自分だったらどんな農業経営をしただろうかと想像してみるのも楽しいです。

そんなわけで、読んでみました。



まず感想として抱いたのは、日本の農業が抱えた課題感は根本的な部分で40年前から現在までほとんど変わっていないんだなということです。

ざっくり言えば、時代に合わせていかに経営規模を拡大して生産性を高めていくか、また担い手・後継者を確保していくかということですね。

一方で、これらの課題に対する取り組みは異なっています。

当時の焦点は、個別の経営体の活動への上乗せで地域がいかに連携していくか、そのためにどういった組織を作っていくかという部分にあったのかなと感じました。(あくまでこの一冊の内容から読み取ったところとして)

これらはやはり、現在と比較するとまだ余力(経営体数なり人手なり)があったからこそできたことですね。

おそらく今だと、個別の経営体がどう生き残っていくのかの議論が中心になるのではないかと思います。

ただ、その個別の経営も先人が作り上げた機能(産地なり組織なり)の上に成り立っていることが多々あるわけで、そう考えると先人への感謝は忘れてはいけないなと。

同時に、今ある機能をただ引き継ぐだけでは将来に対して不十分で、時代に合わせて変化させていくことこそ重要だと思いました。


細かい部分で知らないことも多く、とても勉強になりました。たまにこういった昔の本を読むのもいいですね。温故知新。

ちなみに自分だったらということで考えてみると……空回ってバタりといっていたんじゃなかろうかという気がします。

ただ、もう少し遡って江戸時代ならいける気がします(根拠なく笑)。


百姓たちの江戸時代 (ちくまプリマー新書)
百姓たちの江戸時代 (ちくまプリマー新書)

by SimpleImageLink


Twitter (@nkkmd) 日々更新中です。

2023年3月5日日曜日

GAS を使って「青果物市況情報」及び「青果物卸売市場調査(日別調査)」の CSV ファイルを毎日自動取得する

農林水産省が公開している「青果物市況情報」及び「青果物卸売市場調査(日別調査)」の CSV ファイルを取得する GAS (Google Apps Script) を作りました。

元データのサイトは国外からのアクセスが制限されているようで、GAS から直接データの取得をすることができません。

そこで、cultivationdata.net で公開している市況等 Web API からデータを取得します。もちろん無料。トリガー設定により毎日自動で取得することも可能です。

ちなみに、cultivationdata.net の市況等 Web API は先日作り直しまして、レスポンス速度がだいぶ改善しました。


以下、GAS のコードです。まるっとコピペして数カ所書き換えればお使いいただけます。


▼ 青果物市況情報の CSV ファイルを自動取得する GAS


function getMcCsv() {
  //// cultivationdata.net より CSV ファイルを取得
  const mc = "市場コード"; // 市場コード
  const cat = "種別"; // 種別
  const url = "https://api.cultivationdata.net/mcdata?mc=" + mc + "&cat=" + cat + "&type=csv";

  // CSVデータの取得
  let response = "";
  try {
    response = UrlFetchApp.fetch(url);
  } catch(e) {
    return response;
  }
  let data = response.getContentText(); // CSV データ
  let arr = Utilities.parseCsv(data); // 配列化

  // 取得ファイルのチェック
  if(arr[0][0] == "市場のデータが見つかりませんでした。") { // 市場のデータが見つかりませんでした。
    return
  }

  // 取得した CSV ファイルの日付を取得 
  let dt = Utilities.formatDate(new Date(arr[1][0]), 'JST', 'yyyyMMdd');

  //// ファイルの保存
  const folderId = "フォルダ ID"; // 保存先フォルダ ID

  // 最新の取得済みファイルの日付を取得
  const files = DriveApp.getFolderById(folderId).getFiles(); // 既存ファイル一覧
  let latest_dt = "";
  if(files.hasNext() != false) {
    let files_dt= [];
    while(files.hasNext()) {
      files_dt.push([files.next().getName().replace(mc + "_" + cat + "_", "").replace(".csv", "")]);
    }
    files_dt.sort(function(a, b) {return b[0] - a[0]});
    latest_dt = files_dt[0][0]; // 最新の日付
  }

  // 未取得ファイルであれば保存
  if(dt == latest_dt) { // 取得済みファイル
    return
  } else {
    // 出力先のフォルダとファイル名
    const fileName = mc + "_" + cat + "_" + dt + '.csv'; // 出力するファイル名

    // ファイルの保存
    const charset = "utf-8"; // 文字コード
    const contentType = 'text/csv'; //コンテンツタイプ
    const blob = Utilities.newBlob('', contentType, fileName).setDataFromString(data, charset); // Bolb作成
    DriveApp.getFolderById(folderId).createFile(blob); // 保存
  }
}

3行目「市場コード」、4行目「種別」、26行目「フォルダ ID」を書き換えてください。

市場コード及び種別は「青果物市況情報API説明書」を参照してください。

フォルダ ID は Google ドライブ内の CSV ファイルの保存先フォルダの ID になります。当該フォルダを開いた際の URL の末尾部分の英数字になります(https://drive.google.com/drive/folders/ここの部分)。


▼ 青果物卸売市場調査(日別調査)の CSV ファイルを自動取得する GAS


function getWmrCsv() {
  //// cultivationdata.net より CSV ファイルを取得
  const cc = "都市コード"; // 都市コード
  const cat = "種別"; // 種別
  const url = "https://api.cultivationdata.net/wmr?cc=" + cc + "&cat=" + cat + "&type=csv";

  // CSVデータの取得
  let response = "";
  try {
    response = UrlFetchApp.fetch(url);
  } catch(e) {
    return response;
  }
  let data = response.getContentText(); // CSV データ
  let arr = Utilities.parseCsv(data); // 配列化

  // 取得ファイルのチェック
  if(arr[0][0] == "都市のデータが見つかりませんでした。") { // 都市のデータが見つかりませんでした。
    return
  }

  // 取得した CSV ファイルの日付を取得 
  let dt = Utilities.formatDate(new Date(arr[1][0]), 'JST', 'yyyyMMdd');

  //// ファイルの保存
  const folderId = "フォルダ ID"; // 保存先フォルダ ID

  // 最新の取得済みファイルの日付を取得
  const files = DriveApp.getFolderById(folderId).getFiles(); // 既存ファイル一覧
  let latest_dt = "";
  if(files.hasNext() != false) {
    let files_dt= [];
    while(files.hasNext()) {
      files_dt.push([files.next().getName().replace(cc + "_" + cat + "_", "").replace(".csv", "")]);
    }
    files_dt.sort(function(a, b) {return b[0] - a[0]});
    latest_dt = files_dt[0][0]; // 最新の日付
  }

  // 未取得ファイルであれば保存
  if(dt == latest_dt) { // 取得済みファイル
    return
  } else {
    // 出力先のフォルダとファイル名
    const fileName = cc + "_" + cat + "_" + dt + '.csv'; // 出力するファイル名

    // ファイルの保存
    const charset = "utf-8"; // 文字コード
    const contentType = 'text/csv'; //コンテンツタイプ
    const blob = Utilities.newBlob('', contentType, fileName).setDataFromString(data, charset); // Bolb作成
    DriveApp.getFolderById(folderId).createFile(blob); // 保存
  }
}

3行目「都市コード」、4行目「種別」、26行目「フォルダ ID」を書き換えてください。

市場コード及び種別は「青果物卸売市場調査(日別調査)API説明書」を参照してください。

フォルダ ID は Google ドライブ内の CSV ファイルの保存先フォルダの ID になります。当該フォルダを開いた際の URL の末尾部分の英数字になります(https://drive.google.com/drive/folders/ここの部分)。


▼ トリガー設定について


今回作成した GAS は、新しいデータが追加された場合のみ CSV ファイルの取得を行います。休場日で更新がない日には取得しません。そのため、トリガーは毎日に設定してしまって問題ありません(毎重複して取得はしません)。

データの取得先となる市況等 Web API は16時頃に更新されるので、設定時間はそれ以降とします。


詳解! Google Apps Script完全入門 [第3版]
詳解! Google Apps Script完全入門 [第3版]

by SimpleImageLink


***

これで、都度ポチポチやってファイルを取得する手間を省けます。無駄な手間はコツコツ省いていきましょう。

一つひとつはわずか数分、数秒だとしても、塵も積もれば山となります。

生み出した真水のような時間は、何にでも自由に使うことができます。


きな粉


・関連投稿
青果物市況情報を JSON 形式で取得する Web API を作りました。(更新:CSV 形式での取得も可能になりました)

青果物卸売市場調査(日別調査)を JSON 形式で取得する Web API を作りました。(更新:CSV 形式での取得も可能になりました)


Twitter (@nkkmd) 日々更新中です。

2023年3月3日金曜日

【定期】家計の見直し(2023年3月)

経営と家計が一体化した家族経営では、家計の最適化が心強い生存基盤になります。翻って、家族や自身にとって本当に価値あるものが何なのか、確認する良い機会になります。

さて2023年も弛まぬ家計の見直しを実行していきましょう。


・いわき市でキャッシュレス決済30%還元


3月はいわき市でキャッシュレス決済30%還元のキャンペーンをやっています。ありがたや。

支払い方法は au PAY、d払い、PayPay が利用でき、ポイント還元の上限は各3,000円分となっているようです。1万円ずつ、計3万円分のお買いものをすると9,000円分のポイントが戻ってくるということですね、たぶん。

30%のインパクトは大きいですが、普段買わないものを買ってしまっても本末転倒ですのでそこは自制しつつ。

いろいろと値上げラッシュの春、うまく使っていきたいと思います。


・三井住友FG「Olive(オリーブ)」はひとまず様子見


近頃、経済圏競争が激化しており安住の地を見つけるのが難しいですね。

修行を経て年会費無料の三井住友カード ゴールド(NL)を取得済みで、かつ三井住友銀行の口座も持っていないので Olive はひとまず様子見しようかと思っています。

ポイント還元率や銀行系の特典は魅力的なものの仕組みが若干ややこしく、現状はメリットが口座が増えることへのハードルを超えていません。

他のところが似たようなサービスで追随して来る可能性もありますしね。


・電気代はもう仕方ない


電気代はもうあっちがお得、こっちがお得という段階ではなさそうなので、ひとまず使わない期間がある契約は基本料金0円の楽天でんき。それ以外は東北電力でいこうと思います。

また細かい部分ですが、楽天でんきの支払いクレジットカードを楽天カードからエポスゴールドカードに変更。これでボーナスポイントをもらえれば0.5%+1%程度のポイント還元率にできます(たぶん)。東北電力も同じくエポスゴールドカードでの支払いで、こちらはさらに選べる「ポイントアップショップ」に設定しているので1.5%+1%程度です。

その上で、やはり一番の対策は節電ですね。たまにアプリで送られてくる節電チャレンジにもせっせと参加しています。

-----
・追記(2023/3/17)

こたつが壊れたので新調&掘りごたつの内側がコンクリート張りで非常に冷えるので、プチプチを貼って保温に努めました。結果、1月の電気代はなんと27%減…!断熱って大事ですね。あとはやはり新しいとエネルギー効率もいいようです。
-----

エネルギーはタダみたいなもの、という意識は捨て去らねばなりませんね。農業においても、電気代や燃料代が重くのしかかるようなやり方は根本的に変えていかないと生き残っていけないような気がします。

あとは、電気への変換を経ずにダイレクトにエネルギーを有効活用する仕組みを身の回りでいろいろ増やしていけたらなと思っています。まあ、これを考えると結局いつもビニールハウスってすごい、ということで落ち着きます(笑)。


***

最近巷を賑わしているインド映画『RRR』にわが家もドハマりしまして、映画も複数回観に行ってしまいました。あと1回は観る予定です(笑)。

そして、インド文化にも興味が出まして妻と一緒にいろいろ本を読んだりインドカレーを食べに行ったりしています。

今まで海外の文化に触れるというと旅行が主でしたが、こういうのも大いにありですね。


新版 インドを知る事典
新版 インドを知る事典

by SimpleImageLink

インド神話 (岩波少年文庫)
インド神話 (岩波少年文庫)

by SimpleImageLink


コケモモ


Twitter (@nkkmd) 日々更新中です。