・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;
}
精度は調整の余地有り。