4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【忙しい人必見⚡】Difyを利用した次世代型ToDoリスト Part2(Dify×Llama3.1編)

Last updated at Posted at 2024-07-30

今回は2週間前の記事の発展ということで、まだご覧になっていない方は先にご覧いただくことをおすすめします。

今回は何をするか(おさらい)

前回は、AppSheet(ToDoリスト)に新規項目を追加した際に、その項目名をそのままLLMに入力して、何を買うべきか回答を生成させていました。

ですので、 ハルシネーション と呼ばれる誤った情報を出力する場合がありました。
それを解決するためには RAG(Retrieval-Augmented Generation:検索拡張生成) の仕組みを活用することが有効であるとお伝えしました。

具体的には入力文をいったんGoogleなどに検索をかけ、入力文とWeb検索結果を併用してLLMから回答を得る仕組みに修正していきたいと考えています。

作成したワークフロー図

早速ですが、今回作成したDifyのワークフロー図です。

フローとしては、以下のようになります。

  1. 新規項目を追加
  2. 1.をGoogle翻訳で英語に変換
  3. 2.のイメージ画像をStable Diffusionで生成
  4. 「2.の内容+recommend」でGoogle検索で検索
  5. 2.の内容に4.の内容を加えてLLMにおすすめを提案させる
  6. 5.の内容をGoogle翻訳で日本語に変換
  7. 3.の画像と6.の内容を出力させる

今回利用したLLM

前回はLLMにGoogle社のGemini 1.5 Proを利用しました。
今回は違ったLLMに挑戦しようということで、Meta社から一週間前(7月23日)に発表されたばかりのLlama3.1を利用することにしました。

GPT-4o超えとの噂もありますが、今回は軽量で高速処理が特徴の8Bモデルを利用しました。

Llama3.1は日本語でプロンプトを入力してもnullしか返してきませんでした。

ですので、先述の作成したワークフロー図のように、Llama3.1への入力を日本語⇒英語にし、出力を英語⇒日本語にするためにLLMの前後にGoogle翻訳のブロックを挟んでいます。

Llama3.1に入力するプロンプトは以下の通りです。
前回のプロンプトをベースに英語で作成しました。

プロンプト
## Commands
* You are a "moving pro".

A user is considering buying "{{#1722207567888.text#}}".

* Provide quick recommendations on what to buy based on the following criteria and "Google search results".
"Google search results": {{#1721200265906.text#}}

* Suggest specific manufacturers and product names.

## Criteria
- Couple in their 20s
- 1LDK
- Love Scandinavian style
- Minimalist
- Save money

Llama3.1をどうやって利用するか

私のような初学者にとってはここが一番のハードルではないかと思います。

できるだけ丁寧に説明したいと思いますが、結論として2024年7月30日現在Llama3.1Hugging FaceのInference APIで利用するにはPro Account($9/month)に登録する必要があります。
Freeプランであれば前モデルのLlama3が使えると思うので、読み替えてください。

Llama3.1の利用申請

手順としては、まず以下のHugging FaceのMeta-Llama-3.1-8B-Instructモデルのページに移動します。

そこで、Llama3.1モデルの利用申請をSubmitします。
私の場合、数十分で承認のメールがきました。

Hugging Faceのアクセストークン発行

続いて、Hugging Faceのアクセストークンを発行します。

  • Hugging Faceの右上メニューからSettings
  • Access Tokens
  • Create new token
  • Token typeとしてReadを選択
  • 任意のToken nameを入力
  • Create token
  • hfから始まるアクセストークンをCopy
  • Done

DifyにLlama3.1追加

続いて、DifyにLlama3.1を追加します。

  • Difyの右上メニューから設定
  • モデルプロバイダー
  • Hugging Faceのモデルの追加
  • Model TypeはLLM
  • Model Nameはmeta-llama/Meta-Llama-3.1-8B-Instruct
  • Endpoint TypeはHosted Inference API
  • API Tokenは先ほどHugging Faceでコピーしたものを貼り付け
  • 保存

Llama3.1のトークン数の設定

最後にLlama3.1のトークン数を設定します。デフォルトは20ですが、出力文が非常に短くなってしまいます。
トークン数が多くし過ぎると回答の生成が遅くなってしまうので適度な値に設定します。
私は今回101に設定しました。

これでセットアップ完了です。
あとは、先述の作成したワークフロー図の通りにブロックを追加して接続していきます。

なぜStable Diffusionを挟んでいるのか

前回から相違点としてLLMの違いの他に、今回新たにStable Diffusionのブロックを挟んでいます。
これは、AppSheet(ToDoリスト)の各項目のサムネイル用として、アイキャッチ画像を生成したいと考えて追加しました。

ちなみにStable DiffusionのAPIは従量課金制のため、クレジットをもっていなければStability AI Developer Platformから課金をする必要があります。

今回は生成スピード重視でStable Diffuison 3 Turboを使用しました。
Stable Diffuison 3 Turboも割と最近(2024年4月18日)にAPIが公開された高性能なモデルになります。

APIキーはログインして以下から+ Create API Keyで発行します。

Google Apps Scriptコードの修正

Stable Diffusionで生成した画像のURLをAppSheetに紐づいたGoogleスプレッドシートに書き込む必要があります。

ですので前回のコードに、コメントを含めて以下の6行だけ追加すればOKです。

追加するコード
    // 画像URLの抽出と書き込み(新規追加)
    if (outputs.files && outputs.files.length > 0) {
      const imageUrl = outputs.files[0].url;
      // H列に画像URLを書き込み
      sheet.getRange('H' + lastRow).setValue(imageUrl);
    }
←全体のコードは三角マークを押すと確認することができます。
Google Apps Scriptコード
function sendChildrenQuestion() {
  // スプレッドシートのIDは、スプレッドシートのURLに含まれています。
  // 例えば、URLが https://docs.google.com/spreadsheets/d/abcd1234efgh5678ijkl90mnopqrstuv の場合、
  // abcd1234efgh5678ijkl90mnopqrstuv がスプレッドシートのIDです
  const spreadsheetId = 'YOUR_SPREADSHEET_ID';  // TODO スプレッドシートのIDを書き換え
  const sheetName = 'シート1';

  const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
  const sheet = spreadsheet.getSheetByName(sheetName);

  // B列のデータをすべて取得
  const data = sheet.getRange('B:B').getValues();

  // 最後の非空の行を特定
  let lastRow = data.length;
  while (lastRow > 0 && data[lastRow - 1][0] === '') {
    lastRow--;
  }

  // 最後の非空の行の質問を取得
  const question = sheet.getRange('B' + lastRow).getValue();

  const url = 'https://api.dify.ai/v1/workflows/run';  // リクエストを送るURL

  // リクエストのヘッダー情報
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer {YOUR_DIFY_API_KEY}'  // TODO DifyワークフローのAPIキーで書き換え
  };

  // リクエストのボディデータ
  const payload = {
    'inputs': {Input:question},  // TODO Difyのワークフローの開始で設定した変数名
    'response_mode': 'blocking',
    'user': 'user123'
  };

  // オプションの設定
  const options = {
    'method': 'post',
    'headers': headers,
    'payload': JSON.stringify(payload),
    'muteHttpExceptions': true  // これをtrueにすると、エラーが発生しても例外がスローされません
  };

  // HTTP POSTリクエストの送信
  try {
    const response = UrlFetchApp.fetch(url, options);
    // Logger.log(response.getContentText());  // レスポンスの内容をログに出力
    const jsonResponse = response.getContentText()

    // JSONをオブジェクトに変換
    const responseObject = JSON.parse(jsonResponse);

    // 必要なデータを取得
    const taskId = responseObject.task_id;
    const workflowRunId = responseObject.workflow_run_id;
    const responseData = responseObject.data;
    const status = responseData.status;
    const outputs = responseData.outputs;
    const answer = outputs.text;

    // ログに出力
    Logger.log('Task ID: ' + taskId);
    Logger.log('Workflow Run ID: ' + workflowRunId);
    Logger.log('Status: ' + status);
    Logger.log('Outputs Text: ' + answer);

    // G列に返却された値を書き込み
    sheet.getRange('G' + lastRow).setValue(answer);

    // 画像URLの抽出と書き込み(新規追加)
    if (outputs.files && outputs.files.length > 0) {
      const imageUrl = outputs.files[0].url;
      // H列に画像URLを書き込み
      sheet.getRange('H' + lastRow).setValue(imageUrl);
    }
    
  } catch (e) {
    Logger.log('Error: ' + e.message);  // エラーメッセージをログに出力
  }

  // LINE Notify用の処理を追加
  const lineNotifyToken = 'YOUR_LINE_NOTIFY_TOKEN'; // TODO: LINE Notifyのトークンを設定してください
  const lineNotifyUrl = 'https://notify-api.line.me/api/notify';
  
  // B列(質問)とG列(回答)の最新の内容を取得
  const latestQuestion = sheet.getRange('B' + lastRow).getValue();
  const latestAnswer = sheet.getRange('G' + lastRow).getValue();
  
  // LINE Notifyに送信するメッセージを作成
  const message = '\n' + latestQuestion + '】 が追加されました!' + '\n\n【AI提案】\n' + latestAnswer + '\n"ご自身のAppSheetの共有リンク"';
  
  const lineNotifyOptions = {
    'method': 'post',
    'headers': {
      'Authorization': 'Bearer ' + lineNotifyToken,
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    'payload': 'message=' + encodeURIComponent(message)
  };
  
  // LINE Notifyに通知を送信
  try {
    const lineResponse = UrlFetchApp.fetch(lineNotifyUrl, lineNotifyOptions);
    Logger.log('LINE Notify Response: ' + lineResponse.getContentText());
  } catch (error) {
    Logger.log('LINE Notify Error: ' + error.message);
  }
}

デモ

あとがき

Hugging FaceのInference APIを利用してみたくてLLMをLlama3.1にしてみましたが、デモ動画からわかる通り、出力結果は翻訳感の強い残念な結果となってしまいました。。。

翻訳を使わずとも日本語入力に対応できれば、また可能性は広がりそうですね!

これまで作製したプロダクトのご紹介

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?