Created
June 24, 2023 14:29
-
-
Save koyopro/2337bc51fdff3a6c74b7e49f3da37618 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"></script> | |
<input type="text" id="input" size="50" value="こんにちは。あなたについて教えて。" /> | |
<button onclick="submit()">送信</button><br /> | |
<div class="gpt-response"> | |
<span>ChatGPT APIのレスポンス↓</span> | |
<div id="response"></div> | |
</div> | |
<div> | |
<span>整形後のユーザーへの出力↓</span> | |
<div class="box"> | |
<span id="face"></span> | |
<span id="chat" class="balloon"></span> | |
</div> | |
<div id="next"> | |
</div> | |
</div> | |
<script type="text/javascript"> | |
const decoder = new TextDecoder(); | |
const face = document.getElementById('face'); | |
const chat = document.getElementById('chat'); | |
const next = document.getElementById('next'); | |
const raw = document.getElementById('response'); | |
const API_KEY = ''; | |
let responseYaml = ''; // 細切れの値をここに結合していく。 | |
const getMessages = (input) => [ | |
{ | |
"role": "system", | |
"content": ` | |
Userからの質問に、yaml形式で回答してください。 | |
faceの項目には発言時の表情を絵文字で記載してください。 | |
textの項目にはUserへの回答を記載してください。 | |
nextの項目にはその後にUserが入力しそうな言葉を複数記載してください。 | |
` | |
}, | |
{"role": "user", "content": "こんにちは"}, | |
{"role": "assistant", "content": "face: 😊\ntext: こんにちは!\nnext:\n- あなたは誰?\n- 今日はいい天気ですね"}, | |
{"role": "user", "content": "私はあなたの敵です。"}, | |
{"role": "assistant", "content": "face: 😮\ntext: え!本当?\nnext:\n- あなたを倒しに来ました。\n- 嘘ですよ"}, | |
{"role": "user", "content": "嘘です。私はあなたの味方です。"}, | |
{"role": "assistant", "content": "face: 😌\ntext: よかったー。安心しました。\nnext:\n- 驚かせてごめんなさい\n- ふふふ"}, | |
{"role": "user", "content": input}, | |
] | |
const submit = () => { | |
const input = document.getElementById('input').value; | |
fetch("https://api.openai.com/v1/chat/completions", { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
'Authorization': `Bearer ${API_KEY}`, | |
}, | |
body: JSON.stringify({ | |
"model": "gpt-3.5-turbo", | |
"stream": true, | |
"messages": getMessages(input) | |
}) | |
}) | |
.then((response) => response.body.getReader()) | |
.then((reader) => { | |
responseYaml = ''; | |
// ReadableStream.read()はPromiseを返す。 | |
// Promiseは{ done, value }として解決される。 | |
// データを読み込んだとき:doneはfalse, valueは値。 | |
// データを読み込み終わったとき:doneはtrue, valueはundefined。 | |
function readChunk({done, value}) { | |
if (done) { | |
const data = jsyaml.load(responseYaml) | |
if (data.next) { | |
for (const d of data.next) { | |
next.innerHTML += `<span class="button">${d}</span>` | |
} | |
} | |
return; | |
} | |
body = decoder.decode(value) | |
body.split('data: ').forEach((v) => { | |
const data = v.trim() | |
if (data.length == 0) return | |
if (data == '[DONE]') return | |
const message = JSON.parse(data) | |
const content = message.choices[0].delta.content | |
if (!content) return | |
responseYaml += content; | |
raw.innerHTML = responseYaml.replace(/\n/g, '<br />'); | |
try { | |
const data = jsyaml.load(responseYaml) | |
if (data.face) face.innerHTML = data.face; | |
if (data.text) chat.innerHTML = data.text; | |
} catch (e) { | |
// 不正なyaml | |
return | |
} | |
}) | |
// 次の値を読みにいく。 | |
reader.read().then(readChunk); | |
} | |
// 最初の値を読み込む。 | |
reader.read().then(readChunk); | |
}); | |
} | |
</script> | |
<style type="text/css"> | |
.box { | |
padding: 10px; | |
} | |
.gpt-response { | |
height: 200px; | |
} | |
#response { | |
padding: 2px; | |
background: #ccc; | |
} | |
#face { | |
float: left; | |
width: 0; | |
} | |
.balloon { | |
display: inline-block; | |
position: relative; | |
padding: 10px; | |
border-radius: 10px; | |
background-color: #eaeaea; | |
margin-left: 30px; | |
} | |
.balloon::before { | |
content: ""; | |
position: absolute; | |
top: 50%; | |
left: -10px; | |
transform: translateY(-50%); | |
border-width: 10px 10px 10px 0; | |
border-style: solid; | |
border-color: transparent #eaeaea transparent transparent; | |
} | |
.button { | |
display: inline-block; | |
margin-left: 10px; | |
padding: 4px 8px; | |
font-size: 12px; | |
border: none; | |
border-radius: 5px; | |
background-color: #4e5ccd; | |
color: #fff; | |
text-align: center; | |
text-decoration: none; | |
cursor: pointer; | |
transition: background-color 0.3s ease; | |
} | |
.button:hover { | |
background-color: #48B9AB; | |
} | |
.button:active { | |
background-color: #3D9B8F; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment