Dify APIを使ってみる〜その2

先日投稿した「Dify APIを使ってみる」で紹介したNodeJSを使ったアプリケーションの続きです。

まずは実行中の様子。VS Codium上でThunderClientという拡張機能からHTTPリクエストを送信しています。

こんな結果が帰ってきます。生成された文章がMarkdown形式だったので、VS CodiumのMarkdownプレビュー画面で表示しています。

以下、ソースコードです。

const axios = require('axios')
const http = require('http')
require('dotenv').config()

const API_KEY = process.env.API_KEY
const API_URL = process.env.API_URL
const PORT = process.env.PORT

const messages = [
  { "role": "user", "content": "こんにちは!" },
  { "role": "assistant", "content": "こんにちは! 何についてお話しましょうか?" },
  { "role": "user", "content": "日本語で会話しましょう。" }
];

const default_messages = [
  { "role": "user", "content": "こんにちは!" },
  { "role": "assistant", "content": "こんにちは! 何についてお話しましょうか?" },
  { "role": "user", "content": "日本語で会話しましょう。" }
]


const conversation = { messages }

const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json',
};

const data = {
  "response_mode": "blocking",
  "conversation_id": "",
  "user": "kazuo.tsubaki@zikuu.space",
  "files": [
    {
      "type": "image",
      "transfer_method": "remote_url",
      "url": "https://cloud.dify.ai/logo/logo-site.png"
    }
  ]
};

const inference_call = async(prompt, id, res) => {
  data.query = prompt;
  if(id) {
    data.conversation_id = id;
  } else {
    data.conversation_id = "";
    conversation.messages = default_messages;
  }
  data.inputs = conversation.messages;

  console.log('API:', data);

  await axios.post(API_URL, data, { headers })
    .then(response => {
      const resp = response.data;
      const assistantMessage = resp.answer;
      console.log('アシスタント:', assistantMessage);

      conversation.id = resp.conversation_id
      // 過去のメッセージ履歴にアシスタントの応答を追加
      conversation.messages.push({ "role": "user", "content": prompt });
      conversation.messages.push({ "role": "assistant", "content": assistantMessage });
      console.log(conversation)
      // 結果を返す
      res.statusCode = 200;
      res.setHeader('Content-type', 'application/json');
      res.end(JSON.stringify({id: conversation.id, answer: assistantMessage}, null, 2));

    })
    .catch(error => {
      console.error('エラーが発生しました:', error);
    });
}


const server = http.createServer((req, res) =>  {
  const { method, url } = req;


  if (method === 'POST' && url === '/chat') {
    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });
    req.on('end', () => {
      try {
        console.log('Received data: ', body);
        const json = JSON.parse(body);
        console.log(json)
        const prompt = json.prompt;
        const id = json.id;
        inference_call(prompt, id, res).then(() => { }, (error) => {
          res.statusCode = 400;
          res.setHeader('Content-Type', 'text/plain');
          res.end(`エラーが発生しました: ${error}`);          
        });
      } catch (error) {
        res.statusCode = 400;
        res.setHeader('Content-Type', 'text/plain');
        res.end(`エラーが発生しました: ${error}`);

      }
    });

  } else {
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Not Found');
  }

})

server.listen(PORT, '127.0.0.1', () => {
  console.log(`Server running at http://127.0.0.1:${PORT}/`);
})

使用した大規模言語モデルはGemma 2の9B。それをOllamaで動かし、Difyでチャットボットとして利用しているものです。

モノづくり塾のアプリケーションサーバーにはディスクリートGPUが搭載されていないので、まだこのような生成AIアプリケーションを運用できていませんが、いずれサーバーにGPUを載せて、Dockerでこのアプリケーションをデプロイし、ZIKUUコミュニティーのDiscordから呼び出せるようにしようと思っています。

コメントする