【Spring Boot】ChatGPTライクなアプリを作ってみた【ChatGPT】

ChatGPT

OpenAIのサイトより事前にOpenAIのキーを取得すること。
・OpenAIのライブラリ(非公式)を利用。

ソースコードは下記の通り、
内容としてはテキストボックスに入力した質問内容を
入力した先生がChatGPTライクに回答するというシンプルなもの

ChatGPTライクに回答が表示されるようにSseEmitterを使う。

package com.example.demo.controller;

import java.io.IOException;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@Controller
@RequestMapping("")
public class ChatGptController {
		@GetMapping("/")
		public String getIndex(Model model){
	       return "index";
	    }

	    @GetMapping(value="/chat", produces = "text/event-stream")
	    public SseEmitter streamData(@RequestParam String teacher, @RequestParam String question) {
	    	SseEmitter emitter = new SseEmitter();
			OpenAIHelper helper = new OpenAIHelper();
			helper.openAi(teacher, question).subscribe(
				    data -> {
				        try {
				            emitter.send(SseEmitter.event().data(data.getChoices().get(0)));
		    				Thread.sleep(50);
				        } catch (IOException e) {
				            // エラーハンドリング
				            e.printStackTrace();
				        }
				    },
				    error -> {
				        // エラーハンドリング
				        error.printStackTrace();
				    },
				    () -> {
				        // ストリームの終了時の処理
				        emitter.complete();
				    }
				);
			return emitter;
	    }
}
package com.example.demo.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

import com.theokanning.openai.completion.chat.ChatCompletionChunk;
import com.theokanning.openai.completion.chat.ChatCompletionRequest;
import com.theokanning.openai.completion.chat.ChatMessage;
import com.theokanning.openai.completion.chat.ChatMessageRole;
import com.theokanning.openai.service.OpenAiService;

import io.reactivex.Flowable;
@Component
public class OpenAIHelper {

	public Flowable<ChatCompletionChunk> openAi(String teacher, String question) {
		OpenAiService service = new OpenAiService("取得したOPEN AI KEY");
		List<ChatMessage> messages = new ArrayList<ChatMessage>();
		ChatMessage systemMessage = new ChatMessage(ChatMessageRole.SYSTEM.value(), "あなたは" + teacher + "です。これから質問をするので、" + teacher + "の口調で回答してください。文字数は100文字程度でお願いします。必ず、5文字ごとに改行をしてください。");
		ChatMessage userMessage = new ChatMessage(ChatMessageRole.USER.value(), question);
		messages.add(systemMessage);
		messages.add(userMessage);
		ChatCompletionRequest completionRequest = ChatCompletionRequest.builder()
				.messages(messages)
				.stream(true)
		        .model("gpt-3.5-turbo")
		        .build();
		return service.streamChatCompletion(completionRequest);
	}
}
<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
	<script src="/js/chat.js"></script>
    <title>ChatGPTライクなアプリ</title>
</head>
<body>
   <h1>ChatGPTライクなアプリ</h1>
   <h2>誰に質問しますか?</h2><br>
   <input type="text" id="teacher" value="孫悟空"></input><br>
   <h2>何を質問しますか?</h2><br>   
   <input type="text" id="question" size="70"></input>
   <input type="button" id="btn" value="送信">
   <input type="button" id="stop" value="STOP">
   </form>
   <div id="dataContainer"></div>
</body>
</html>
var eventSource;
$(function() {
	$("#btn").on("click", function(){
		callChatGTP();
	});
	$("#stop").on("click", function(){
		eventSource.close();
	});
});

function callChatGTP() {
	dataContainer.innerHTML = "";
	var teacher = document.getElementById("teacher").value;
	var question = document.getElementById("question").value;
	eventSource = new EventSource("/chat?question=" + question + "&teacher=" + teacher);
    eventSource.onmessage = function(event) {
        var data = event.data;
        console.log(data);
		var jsonData = JSON.parse(data);
		if (jsonData.finish_reason != null) {
			console.log(jsonData.finish_reason);
			eventSource.close();
		}else if(jsonData.message.content != null){
			displayData(jsonData.message.content);					
		}
    };
}

function displayData(data) {
    var formattedAnswer = data.replace(/\n/g, "<br>"); // 改行を <br> タグに置換する
    dataContainer.innerHTML += formattedAnswer;
}

精度は調整の余地有り。

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