Google Apps Script と Dify API を用いたチャットメッセージ送信におけるエラー解決

この記事では、Google Apps Script で Dify API を使用してチャットメッセージを送信する際に発生する可能性のあるエラーとその解決策について解説します。 

## 問題の発生状況

Dify API を使用してチャットメッセージを送信するための Google Apps Script 関数 `sendChatMessage` を作成しました。 この関数は、ユーザーメッセージ、会話 ID、ユーザー ID を入力として受け取り、Dify API を使用してチャットメッセージを送信します。 

```javascript
function sendChatMessage(userMessage, conversation_id, user_id) {
  // ... (コードは省略)
}
```

https://github.com/langgenius/dify/issues/4534


しかし、この関数を呼び出すと、次のエラーが発生しました。

```
Exception: Request failed for https://dify-2r9mn-u16998.vm.elestio.app returned code 405. Truncated server response: {"code": "method_not_allowed", "message": "The method is not allowed for the requested URL.", "status": 405}
 (use muteHttpExceptions option to examine full response)
```

このエラーに加えて、"blockingが良くなくて、エージェントだから、streaming限定だったらしい" という情報も得られました。
API アクセスのベース URL 文字列が正しくないため、API エンドポイントにアクセスできません。提供されたベース URL を使用してアクセスを試みると、エンドポイントに到達できません。
![スクリーンショット 2024-05-20 190746.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486826/1fb6a84a-552c-05b3-3cef-c73352474ca6.png)


## エラー分析

### HTTP ステータスコード 405

エラーメッセージに含まれる "returned code 405" は、HTTP ステータスコード 405 (Method Not Allowed) を示しています。 これは、リクエストされた URL に対して使用された HTTP メソッド (この場合は `POST`) が許可されていないことを意味します。 Dify API のエンドポイントは、特定の HTTP メソッドのみを受け入れるように設計されている可能性があります。 

### Blocking vs. Streaming

Dify API は、"blocking" と "streaming" の 2 つのレスポンスモードを提供している可能性があります。 

- **Blocking:**  API リクエストを送信すると、レスポンスが完全に返されるまでスクリプトの実行がブロックされます。
- **Streaming:** API リクエストを送信すると、レスポンスが断片的にストリーミングされ、スクリプトはレスポンスの完了を待たずに処理を続行できます。

"エージェントだから、streaming限定だったらしい" という情報から、Dify API はエージェントとの対話にストリーミングレスポンスモードを必要としていることがわかります。

## 解決策

エラーを解決するには、次の手順を実行する必要があります。

1. **Dify API ドキュメントを確認する:**  Dify API のエンドポイントで許可されている HTTP メソッドと、エージェントとの対話に必要なレスポンスモードを確認します。
2. **`muteHttpExceptions` オプションを使用する:** エラーメッセージ全体を取得して分析します。 
3. **コードを修正する:**  Dify API の要件に合わせて、`sendChatMessage` 関数の HTTP メソッドとレスポンスモードを調整します。

### 修正されたコード例

```javascript
function sendChatMessage(userMessage,conversation_id,user_id) {
  var options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ' + DIFY_API_KEY
    },
    'payload': JSON.stringify({
      'inputs': {},
      'query': userMessage,
      'response_mode': 'streaming',
      'user': user_id,
      'conversation_id': conversation_id
    }),
    'muteHttpExceptions': true
  };

  // Logger.log(options);

  try {
    var response = UrlFetchApp.fetch("https://hogehoge.vm.elestio.app/v1"+ "chat-messages", options);
    // Logger.log(response);
    var result = "";
    var lines = response.getContentText().split("\n");
    // Logger.log(lines);
    for (var i = 0; i < lines.length; i++) {
      var line = lines[i];
      if (line.startsWith("data: ")) {
        var data = JSON.parse(line.substring(6));
          // Logger.log("id" + data.conversation_id);
        // Logger.log('data:' + data);
        // Logger.log(data.event);
        if (data.event === "agent_message") {
          // Logger.log(data.answer)
          result += data.answer;
        } else if (data.event === "message_end") {
          // Logger.log(result);
          return result;
        }else if(data.event === "error"){
          return result;
        }
      }
    }
  } catch (e) {
    Logger.log(e.toString());
    logMessage(arguments.callee.name, e.toString());
    return { error: 'An error occurred while processing the request.' };
  }
}
```

## まとめ

Dify API を使用してチャットメッセージを送信する場合、HTTP メソッドとレスポンスモードを API の要件に合わせる必要があります。 エラーが発生した場合は、`muteHttpExceptions` オプションを使用して完全なエラーメッセージを取得し、Dify API ドキュメントを参照して問題を診断します。