PR

【LMstudio】自分のサイトに無料のローカルで動くAIチャットを搭載しよう!

Rintaが書いた

皆さん。こんな悩みを持ったことはありますか?

サイトにチャットボットを搭載したいけど料金が高い、、

せっかくいいサーバーを買ったけれど性能を出し切れていない、、

一回、無料で搭載してみて実際にどんな感じか試したい

今回は、そんな人のためのページとなっております。高校1年生でもできる(これを書いてる)ので、試してみましょう!
今回は、ローカルHTMLで動作させるのでDNS設定などは飛ばします。なので、実際にサーバ上で動作させる際はドメイン設定をしてください。
LMstudioとは、テキスト生成AIをローカル(自分のパソコン)で実行できるソフトです。LLMというAIのデータみたいなものを実行できます。GUIで動いているので直感的に使用できるのが特徴です。外からプロンプトを投げる際も、OpenAIと同じ文法で使用でき、シンプルなのでとても使いやすいです。おすすめです。

また、HTMLを使用するので基礎的な知識は用意しておいてください。

スポンサーリンク
スポンサーリンク

下準備

LMstudioの設定

毎度おなじみLMstudioです。前回までの記事を見ていない方は、短いのでぜひそちらから見てください。

LMstudioのインストール
LMstudioにプロンプトをコンソールから投げる

適当なサイトを作る(表示したいサイトでも可能)

今回はテスト用として適当に作りました。

一応、コードは貼り付けておきます。

コード
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>テスト用サイト</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <h1>テスト用サイト</h1>
  </header>
  <nav>
    <ul>
      <li><a href="#">ホーム</a></li>
      <li><a href="#">サービス</a></li>
      <li><a href="#">問い合わせ</a></li>
    </ul>
  </nav>
  <main>
    <section>
      <h2>見出し</h2>
      <p>本文</p>
    </section>
    <section>
      <h2>見出し</h2>
      <p>本文</p>
    </section>
  </main>
  <footer>
    <p>© lorinta.xsrv.jp</p>
  </footer>
</body>
</html>
body {
    font-family: sans-serif;
    margin: 0;
    padding: 0;
  }
  
  header {
    background-color: #f0f0f0;
    padding: 20px;
  }
  
  h1 {
    text-align: center;
  }
  
  nav {
    background-color: #ccc;
    padding: 10px;
  }
  
  nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  
  nav li {
    display: inline-block;
    margin-right: 20px;
  }
  
  nav a {
    text-decoration: none;
    color: #333;
  }
  
  section {
    padding: 20px;
    border-bottom: 1px solid #ddd;
  }
  
  h2 {
    margin-top: 0;
  }
  
  footer {
    background-color: #f0f0f0;
    text-align: center;
    padding: 20px;
  }
  

見た目(型)を作る

LMstudioサーバーの起動

まず、前回と同じようにサーバーを起動します。
起動確認として次のコードを投げてみましょう。

import requests

def send_inference_request(prompt):
  url = 'http://localhost:1234/v1/completions'
  headers = {'Content-Type': 'application/json'}
  data = {
    'prompt': prompt,
    'temperature': 0.7,
    'max_tokens': 100
  }

  response = requests.post(url, headers=headers, json=data)

  if response.status_code == 200:
    generated_text = response.json()['choices'][0]['text']
    print('生成されたテキスト:', generated_text)
  else:
    print('エラーが発生しました:', response.status_code, response.text)

if __name__ == '__main__':
  prompt = input('プロンプトを入力してください: ')
  send_inference_request(prompt)

しっかりと帰ってくることを確認しましょう。

HTMLでチャットのデザインを書く

アイコンが押される→テキストボックスが表示される→入力して投げる→表示する

という流れて動作させていくので、まずは「アイコンが押される→テキストボックスが表示される」までを作っていきましょう。
 また、私は変数の名前を考えるのが苦手でa b cを順番に使っていくのですが、今回は読解性も強くしたいのでcodic というサイトで変数や関数名やタグは作っていきます。結構めんどくさいですが苦手な方はこれを使って練習していきましょう。(おすすめ)
 変数名は適当に変えてもらって構いませんが、変数以外は変えると動かなくなるものもあるので見分けがつかない方はそのままコピーしてください。

codicを使ってみる(画像)
<head>
  <meta name=di"viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="./style/ai-style.css">
</head>
<body>
  <div id="image-box">
    <div id="balloon"></div>
    <img id="image" src="画像のパス">
  </div>

  <div id="input-box">
    <input type="text" id="input-text" placeholder="AIで生成されたため間違いが生じる可能性があります">
    <button id="submit-button">送信</button>
  </div>

  <script src="./script/ai.js"></script>
</body>

上記のhtmlコードでは、画像とチャット画面を作るものです。”image”で画像、”baloon”で受信したメッセージを表示る場所、”input-box”で、入力するところを指定しています。下に、css(デザイン指定するやつ)をを置きます。ファイルは、./style/ai-style.cssに作ってください。

#image-box {
    position: relative;
    width: 100px;
    height: 100px;
    position:absolute;	
		bottom:-150px;
		right:30px;
  }
  
  #image {
    width: 80px;
    height: 80px;
    position:absolute;
    bottom:-100px;
		right:30px;
  }

  #balloon {
    position: fixed; 
    top: 70%;
    left: 70%; 
    transform: translate(-50%, -50%); 
    background-color: #fff; 
    padding: 20px; 
    border: 1px solid #ccc; 
    border-radius: 5px; 
    display: none; 
  }
  
  
  #input-box {
    display: none;
    position: absolute;
    bottom:-150px;
	right:0px;
    width: 300px;
    height: 100px;
    background-color: rgba(0, 0, 0, 0.5);
    text-align: center;
    padding: 20px;
  }
  
  #input-text {
    width: 80%;
    padding: 10px;
    border: 1px solid #ccc;
  }
  
  #submit-button {
    padding: 10px;
    border: 1px solid #ccc;
    cursor: pointer;
  }
  

このままだと、結構下の方に表示されてしまいます。サイドバーに埋め込めるかたは埋め込んでもらったらいいのですが、できない方はドラック&ドロップで動かせるようにしましょう。

const image = document.getElementById('image');
const inputBox = document.getElementById('input-box');
const inputText = document.getElementById('input-text');
const submitButton = document.getElementById('submit-button');

let isDragging = false;
let startX, startY;

image.addEventListener('mousedown', (event) => {
  isDragging = true;
  startX = event.clientX - image.offsetLeft;
  startY = event.clientY - image.offsetTop;
});

document.addEventListener('mousemove', (event) => {
  if (isDragging) {
    image.style.left = event.clientX - startX + 'px';
    image.style.top = event.clientY - startY + 'px';
  }
});

document.addEventListener('mouseup', () => {
  isDragging = false;
});

script.jsに以上のコードを入力してみましょう。画像が動かせるようになったはずです。

PR

動作させる

やること

いよいよ本格的にAIに触れていきます。複雑になってくるので今まででつらい方はやめておきましょう。やることリストをまとめておきます。

  • javascriptで入力欄を動作させる
  • LMstudioに投げる用のpythonを作る
  • 「javascriptとpython間通信」を設定する
  • javascriptに入力→pythonに投げる→LMstudioに投げる→逆再生→htmlに表示 を実装す

最後だけ長い気がしますがセットなので許してください。

入力して投げる→表示する

上で分けましたが、実際はセットで実行しなければいけないので一気に走り抜けます。


image.addEventListener('click', () => {
  inputBox.style.display = 'block';
});

submitButton.addEventListener('click', () => {
  const text = inputText.value;
  // post() 関数の実装
  const socket = new WebSocket("ws://localhost:8000");

socket.onopen = function(event) {
    console.log("Connected to Python server!");

    socket.send(text);
};

socket.onmessage = function(event) {
    console.log("Received from Python:", event.data);
    const balloon = document.getElementById('balloon');
const text = event.data; // textに表示したいテキストを代入

// 5秒後に非表示にする関数
function hideBalloon() {
  balloon.style.display = 'none';
}

// 吹き出しを表示
balloon.textContent = text;
balloon.style.display = 'block';

// 5秒後に非表示
setTimeout(hideBalloon, 15000); 
};

socket.onerror = function(event) {
    console.error("Error:", event.message);
};

socket.onclose = function(event) {
    console.log("Disconnected from Python server.");
}; 

  // 入力内容をクリア
  inputText.value = '';

  // inputBox を非表示
  inputBox.style.display = 'none';
});

上のコードを付け足します。プログラムとコメントを頼りに読み解いてください。

続いて、pythonファイルを作り次のプログラムを書きます。次のライブラリをインストールしてください。そして、コードを入力してください。

asyncio
websockets
requests
# coding: UTF-8
import asyncio
import websockets
import requests


async def handler(websocket, path):
    while True:
        data = await websocket.recv()
        

        def send_inference_request(data):
            url = 'http://localhost:1234/v1/completions'
            headers = {'Content-Type': 'application/json'}
            data = {
                'prompt': "次の、koreに関する質問に答えて。簡潔に答えて。うその情報は書かないで。自然な文章で話す。###koreとは###koreの説明を入力###質問:"+data+"###回答:",
                'temperature': 0.7,
                'max_tokens': 100
            }

            response = requests.post(url, headers=headers, json=data)
            if response.status_code == 200:
                generated_text = response.json()["choices"][0]["text"]
                websocket.send(generated_text)
                return generated_text
            else:
                print("エラーが発生しました:", response.status_code, response.text)
                return None
    
        await websocket.send(send_inference_request(data))
    
            

async def main():
    async with websockets.serve(handler, "", 8000):
        await asyncio.Future()

if __name__ == "__main__":
    asyncio.run(main())

適当に解説すると、websocketはpythonとjavascriptをつなぐものです。
pythonコードは前回を見てください。

使い方

pythonコードを実行→ブラウザで開く→入力する→表示されるのを確認

まとめ

結構長くなりましたが、大丈夫でしたか?
今回は、疲れていた時に書いたので画像が少なかったのはごめんなさい。元気が出たら付け足します。
ありがとうございました





コメント

タイトルとURLをコピーしました