AIチャットボットのAPIをつなぐコード
エンジニア用
AIでチャットボットを作る時のコードです。
<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>●●タイトル●●</title>
<style>
body {
background-color: #004896;
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
height: 100vh;
box-sizing: border-box;
}
.container {
background-color: #004896; /* 全体の背景色 */
flex: 1;
display: flex;
flex-direction: column;
padding: 10px;
box-sizing: border-box;
overflow: hidden;
}
.form-group {
display: flex;
align-items: center;
background-color: #004896; /* 入力エリアの背景色 */
padding: 10px 0; /* 縦のパディングを10pxに設定、横は0 */
border-radius: 4px;
margin-bottom: 0;
justify-content: space-between; /* 入力欄を最大限広げてボタンを右端に配置 */
}
#question {
flex-grow: 1; /* 入力欄をできるだけ広げる */
height: 50px;
font-size: 16px;
padding: 10px 0.5em; /* 縦のパディングを10px、横を0.5文字分に設定 */
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
margin-right: 10px; /* ボタンとの間隔を調整 */
color: gray; /* プレースホルダー用の色 */
}
#question:focus {
color: black; /* 入力時に黒に変更 */
}
#response {
flex: 1;
font-size: 16px;
padding: 10px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #ffffff; /* 出力エリアの背景色 */
white-space: pre-wrap;
overflow-y: auto;
margin-bottom: 10px;
}
.citation {
margin-top: 10px;
padding: 10px;
border-top: 1px solid #ccc;
}
.input-container {
background-color: #004896; /* 入力エリア全体の背景色 */
padding: 10px 0;
box-sizing: border-box;
}
.user-query, .ai-response {
margin-bottom: 10px;
}
.user-query {
color: blue;
}
.ai-response {
color: black;
}
button {
height: 50px;
font-size: 16px;
padding: 10px 20px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #ffeb3b; /* ボタンの背景色を黄色に変更 */
color: black; /* テキストの色を黒に変更 */
font-weight: bold; /* テキストを太字に変更 */
margin-left: auto; /* ボタンを右端に寄せる */
}
</style>
<script>
function clearPlaceholder() {
const questionField = document.getElementById('question');
if (questionField.value === "ここにいれて") {
questionField.value = "";
questionField.style.color = "black";
}
}
function restorePlaceholder() {
const questionField = document.getElementById('question');
if (questionField.value === "") {
questionField.value = "ここにいれて";
questionField.style.color = "gray";
}
}
async function getAIResponse() {
const query = document.getElementById('question').value;
const responseField = document.getElementById('response');
// ユーザーの質問を表示
const userQueryDiv = document.createElement('div');
userQueryDiv.className = 'user-query';
userQueryDiv.innerHTML = `あなた:${query}`;
responseField.appendChild(userQueryDiv);
const data = {
"inputs": {},
"query": query,
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
};
try {
const response = await fetch('https://●●●●●●●●●●/chat-messages', {
method: 'POST',
headers: {
'Authorization': '●●API●●Bearer app-●●',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`エラー: ${response.status} ${response.statusText}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let result = '';
const aiResponseDiv = document.createElement('div');
aiResponseDiv.className = 'ai-response';
let isFirstChunk = true; // 最初のチャンクかどうかを判定する
while (true) {
const { done, value } = await reader.read();
if (done) break;
result += decoder.decode(value, { stream: true });
const jsonChunks = result.split('data: ').filter(chunk => chunk.trim() !== '');
result = '';
jsonChunks.forEach(chunk => {
try {
const jsonData = JSON.parse(chunk);
if (jsonData.answer) {
let formattedAnswer = jsonData.answer.replace(/\n/g, '<br>');
if (isFirstChunk) {
aiResponseDiv.innerHTML = `●名前●:${formattedAnswer}`;
responseField.appendChild(aiResponseDiv);
isFirstChunk = false;
} else {
aiResponseDiv.innerHTML += formattedAnswer;
}
// スクロールを下に
responseField.scrollTop = responseField.scrollHeight;
}
if (jsonData.retriever_resources && jsonData.retriever_resources.length > 0) {
jsonData.retriever_resources.forEach(resource => {
const citationElement = document.createElement('div');
citationElement.className = 'citation';
citationElement.innerHTML = `引用元: <a href="${resource.url}" target="_blank">${resource.url}</a>`;
aiResponseDiv.appendChild(citationElement);
});
}
} catch (e) {
console.error('JSONの解析エラー:', e);
}
});
}
// 全てのデータが読み込まれた後に置換処理を実行
aiResponseDiv.innerHTML = aiResponseDiv.innerHTML.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
} catch (error) {
const errorDiv = document.createElement('div');
errorDiv.className = 'ai-response';
errorDiv.innerHTML = `エラー: ${error.message}`;
responseField.appendChild(errorDiv);
// スクロールを下に
responseField.scrollTop = responseField.scrollHeight;
}
}
function clearInput() {
document.getElementById('question').value = 'ここにいれて';
document.getElementById('question').style.color = "gray";
}
// ページロード時に初期メッセージとプレースホルダーを設定
window.onload = function() {
const responseField = document.getElementById('response');
const initialMessageDiv = document.createElement('div');
initialMessageDiv.className = 'ai-response';
initialMessageDiv.innerHTML = '●●スタートメッセージ●●例、ボウサイ:私は防災のデータを大量学習した専門家のAIの「ボウサイ」です。南海トラフなど、防災や地震の事を私に相談してください。';
responseField.appendChild(initialMessageDiv);
// スクロールを下に
responseField.scrollTop = responseField.scrollHeight;
// プレースホルダーを設定
const questionField = document.getElementById('question');
questionField.value = "ここにいれて";
questionField.style.color = "gray";
questionField.addEventListener('focus', clearPlaceholder);
questionField.addEventListener('blur', restorePlaceholder);
};
</script>
</head>
<body>
<div class="container">
<div id="response"></div>
<div class="input-container">
<div class="form-group">
<textarea id="question" name="question" rows="2" required></textarea>
<button onclick="getAIResponse(); clearInput();">●●例、相談する●●</button>
</div>
</div>
</div>
</body>
</html>
いいなと思ったら応援しよう!
ありがとうございます。
よろしくお願いします。