ð ãµãŒããŒã¬ã¹ã§å®çŸïŒAPIããŒãå®ããªããã©ã¯åãããã£ãããAIåããæ¹æ³
ããã«ã¡ã¯ã@YushiYamamotoã§ãïŒååäœæãããã©ã¯åãããã£ããã¢ããªãã«ãä»åã¯AIæ©èœã远å ããŠãããããšæããŸãã
ç¹ã«ãAPIããŒãå
¬éããã«ãµãŒããŒã¬ã¹ã§å®è£
ããæ¹æ³ãã«ã€ããŠè©³ãã解説ããŸãã
ããã¯å€ãã®éçºè
ãçŽé¢ãã課é¡ã§ãããå®ã¯ããã€ãã®å¹æçãªè§£æ±ºçããããã§ãïŒ
ãªãAPIããŒãå ¬éããŠã¯ãããªãã®ãïŒ â ïž
AIãµãŒãã¹ã®APIããŒãã¯ã©ã€ã¢ã³ããµã€ãã®ã³ãŒãã«çŽæ¥åã蟌ããšã以äžã®ãããªãªã¹ã¯ããããŸãïŒ
- äžæ£å©çšã®ãªã¹ã¯: æªæãã第äžè ãAPIããŒã䜿çšããŠãããªãã®ã¢ã«ãŠã³ãã§å€§éã®ãªã¯ãšã¹ããè¡ãå¯èœæ§ããããŸã[6]
- æéçºçã®ãªã¹ã¯: åŸé課éå¶ã®APIã®å Žåãäºæãã¬é«é¡è«æ±ãçºçããå¯èœæ§ããããŸã[4]
- ã»ãã¥ãªãã£ãªã¹ã¯: APIããŒãæã€äººã¯ããã®APIãéããŠãµãŒãã¹ã«ã¢ã¯ã»ã¹ã§ãããããããŒã¿æŒæŽ©ã®ãªã¹ã¯ããããŸã[6]
ãã©ãŠã¶ã®ããããããŒããŒã«ãéãã°ãJavaScriptã³ãŒããéä¿¡å 容ã¯ç°¡åã«é²èЧã§ããŠããŸããŸãããã®ãããã¯ã©ã€ã¢ã³ããµã€ãã§APIããŒã䜿çšããããšã¯é¿ããã¹ããªã®ã§ãã
ãµãŒããŒã¬ã¹ã§APIããŒãä¿è·ããæ¹æ³ ð¡ïž
ãµãŒããŒã¬ã¹ã¢ãŒããã¯ãã£ã䜿ã£ãŠãAPIããŒãå®å šã«ç®¡çããªããAIãã£ããæ©èœãå®è£ ããæ¹æ³ãããã€ã玹ä»ããŸãã
1. Netlify FunctionsïŒãŸã㯠Vercel FunctionsïŒã掻çšããæ¹æ³
Netlifyãªã©ã®éçãµã€ããã¹ãã£ã³ã°ãµãŒãã¹ã¯ããµãŒããŒã¬ã¹é¢æ°ãæäŸããŠãããAPIããŒãå®å šã«ä¿ç®¡ã§ããŸãã
å®è£ æé
- ãããžã§ã¯ãã®æ§é ã以äžã®ããã«èšå®ããŸãïŒ
ãããžã§ã¯ãã«ãŒã/
âââ functions/
â âââ chat.js # ãµãŒããŒã¬ã¹é¢æ°
âââ index.html # ã¡ã€ã³ã®HTMLãã¡ã€ã«
âââ style.css # CSSãã¡ã€ã«
âââ script.js # ããã³ããšã³ãã®JavaScript
âââ netlify.toml # Netlifyèšå®ãã¡ã€ã«
-
netlify.toml
ãã¡ã€ã«ãäœæããŸãïŒ
[build]
functions = "functions"
[dev]
functions = "functions"
publish = "."
-
functions/chat.js
ãã¡ã€ã«ãäœæããŸãïŒ
const axios = require('axios');
exports.handler = async function(event, context) {
// POSTãªã¯ãšã¹ãã®ã¿ãèš±å¯
if (event.httpMethod !== 'POST') {
return { statusCode: 405, body: 'Method Not Allowed' };
}
try {
const body = JSON.parse(event.body);
const userMessage = body.message;
// OpenAI APIã«ãªã¯ãšã¹ã
const response = await axios.post(
'https://api.openai.com/v1/chat/completions',
{
model: 'gpt-3.5-turbo',
messages: [
{role: 'system', content: 'ããªãã¯ãããããµã€ãã®ã€ã¡ãŒãžãã£ã©ã¯ã¿ãŒãã©ã¯åãããã§ãã芪ãã¿ããããäžå¯§ãªå£èª¿ã§åçããŠãã ããã'},
{role: 'user', content: userMessage}
],
max_tokens: 150,
temperature: 0.7
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
}
}
);
return {
statusCode: 200,
body: JSON.stringify({ response: response.data.choices[0].message.content })
};
} catch (error) {
console.log('ãšã©ãŒè©³çް:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'å
éšãµãŒããŒãšã©ãŒãçºçããŸãã' })
};
}
};
- ããã³ããšã³ãã®
script.js
ãä¿®æ£ããŸãïŒ
function respondToMessage(message) {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžã衚瀺
const loadingId = addBotMessage('èãäž...');
// Netlify Functionsã«ãªã¯ãšã¹ã
fetch('/.netlify/functions/chat', {
method: 'POST',
body: JSON.stringify({ message: message }),
})
.then(response => response.json())
.then(data => {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžãåé€
document.getElementById(loadingId).remove();
// ãããã®å¿çã衚瀺
addBotMessage(data.response);
})
.catch(error => {
document.getElementById(loadingId).remove();
addBotMessage('ãã¿ãŸããããšã©ãŒãçºçããŸãããåŸã§ããäžåºŠã詊ããã ããã');
console.error('Error:', error);
});
}
- Netlifyããã·ã¥ããŒãã§ç°å¢å€æ°
OPENAI_API_KEY
ãèšå®ããŸãã
2. Cloudflare Workersã䜿çšããæ¹æ³
Cloudflare WorkersããµãŒããŒã¬ã¹ç°å¢ãæäŸããŠãããAPIããŒãå®å šã«ç®¡çã§ããŸãã
å®è£ æé
- Cloudflare Workersã®éçºç°å¢ãã»ããã¢ããããŸãïŒ
npm install -g wrangler
wrangler login
wrangler init chat-api
cd chat-api
-
wrangler.toml
ãã¡ã€ã«ãç·šéããŸãïŒ
name = "chat-api"
main = "src/index.js"
compatibility_date = "2023-05-18"
[vars]
# éçºç°å¢çšã®å€æ°ïŒæ¬çªç°å¢ã§ã¯ç®¡çç»é¢ã§èšå®ïŒ
# OPENAI_API_KEY = "your-api-key"
-
src/index.js
ãã¡ã€ã«ãäœæããŸãïŒ
export default {
async fetch(request, env, ctx) {
// CORSããããŒãèšå®
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
};
// OPTIONSãªã¯ãšã¹ãïŒããªãã©ã€ãïŒã®åŠç
if (request.method === "OPTIONS") {
return new Response(null, {
headers: corsHeaders,
});
}
// POSTãªã¯ãšã¹ãã®ã¿ãèš±å¯
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
try {
const body = await request.json();
const userMessage = body.message;
// OpenAI APIã«ãªã¯ãšã¹ã
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: "gpt-3.5-turbo",
messages: [
{role: "system", content: "ããªãã¯ãããããµã€ãã®ã€ã¡ãŒãžãã£ã©ã¯ã¿ãŒãã©ã¯åãããã§ãã芪ãã¿ããããäžå¯§ãªå£èª¿ã§åçããŠãã ããã"},
{role: "user", content: userMessage}
],
max_tokens: 150,
temperature: 0.7
})
});
const data = await response.json();
return new Response(
JSON.stringify({ response: data.choices[0].message.content }),
{
headers: {
...corsHeaders,
"Content-Type": "application/json"
}
}
);
} catch (error) {
return new Response(
JSON.stringify({ error: "å
éšãµãŒããŒãšã©ãŒãçºçããŸãã" }),
{
status: 500,
headers: {
...corsHeaders,
"Content-Type": "application/json"
}
}
);
}
}
};
- Workerããããã€ããŸãïŒ
wrangler secret put OPENAI_API_KEY
# ããã³ããã§APIããŒãå
¥å
wrangler publish
- ããã³ããšã³ãã®
script.js
ãä¿®æ£ããŸãïŒ
function respondToMessage(message) {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžã衚瀺
const loadingId = addBotMessage('èãäž...');
// Cloudflare Workersã«ãªã¯ãšã¹ã
fetch('https://chat-api.your-username.workers.dev', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: message }),
})
.then(response => response.json())
.then(data => {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžãåé€
document.getElementById(loadingId).remove();
// ãããã®å¿çã衚瀺
addBotMessage(data.response);
})
.catch(error => {
document.getElementById(loadingId).remove();
addBotMessage('ãã¿ãŸããããšã©ãŒãçºçããŸãããåŸã§ããäžåºŠã詊ããã ããã');
console.error('Error:', error);
});
}
ãµãŒããŒã¬ã¹å®è£ ã®ã¢ãŒããã¯ãã£å³ ð
ãµãŒããŒã¬ã¹ã§AIãã£ãããå®è£ ããå Žåã®ã¢ãŒããã¯ãã£ã¯ä»¥äžã®ããã«ãªããŸãïŒ
+----------------+ HTTPS +-------------------+ HTTPS +----------------+
| || || |
| ãã©ãŠã¶ | | ãµãŒããŒã¬ã¹é¢æ° | | AI API |
| (HTML/JS/CSS) | | (Netlify/Vercel/ | | (OpenAI ãªã©) |
| | | Cloudflare) | | |
+----------------+ +-------------------+ +----------------+
|
| ç°å¢å€æ°ãšããŠ
| APIããŒãä¿å
v
+----------------+
| |
| APIã㌠|
| |
+----------------+
ãã®æ§æã§ã¯ïŒ
- ãŠãŒã¶ãŒããã©ãŠã¶ã§ã¡ãã»ãŒãžãå ¥å
- ããã³ããšã³ãJSããµãŒããŒã¬ã¹é¢æ°ã«ãªã¯ãšã¹ãéä¿¡
- ãµãŒããŒã¬ã¹é¢æ°ãç°å¢å€æ°ããAPIããŒãååŸ
- ãµãŒããŒã¬ã¹é¢æ°ãAI APIã«ãªã¯ãšã¹ãéä¿¡
- AI APIããã®å¿çããµãŒããŒã¬ã¹é¢æ°ãåãåã
- ãµãŒããŒã¬ã¹é¢æ°ãããã©ãŠã¶ã«å¿çãè¿ã
ããã«ãããAPIããŒã¯ã¯ã©ã€ã¢ã³ããµã€ãã«å ¬éãããããšãªããå®å šã«ç®¡çã§ããŸãã
å®éã®ã©ã¯åããAIãã£ããã®å®è£ äŸ ð©âð»
ã§ã¯ãååäœæããã©ã¯åãããã£ããã¢ããªã«AIæ©èœã远å ããŠã¿ãŸããããä»åã¯Netlify Functionsã䜿çšããŸãã
1. å¿ èŠãªãã¡ã€ã«ã®æºå
ãŸããååäœæããHTMLãã¡ã€ã«ã«å°ãä¿®æ£ãå ããŸãïŒ
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ã©ã¯åããAIãã£ãã</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
</head>
<body>
<div class="container">
<div class="chat-container">
<div class="user-bar">
<div class="avatar">
<img src="https://rakuraku-site.prodouga.com/img/RakuRaku.avif" alt="ã©ã¯åãã">
</div>
<div class="name">
<span>ã©ã¯åãã</span>
<span class="status">AIæèŒ</span>
</div>
</div>
<div class="conversation">
<div class="conversation-container" id="messages">
<!-- ã¡ãã»ãŒãžãããã«è¡šç€ºãããŸã -->
</div>
</div>
<form id="message-form" class="conversation-compose">
<input id="message-input" class="input-msg" name="input" placeholder="ã¡ãã»ãŒãžãå
¥å" autocomplete="off" autofocus>
<button class="send" type="submit">
<i class="fa fa-paper-plane"></i>
</button>
</form>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
2. ãµãŒããŒã¬ã¹é¢æ°ã®äœæ
functions/chat.js
ãã¡ã€ã«ãäœæããŸãïŒ
const axios = require('axios');
exports.handler = async function(event, context) {
if (event.httpMethod !== 'POST') {
return { statusCode: 405, body: 'Method Not Allowed' };
}
try {
const body = JSON.parse(event.body);
const userMessage = body.message;
// OpenAI APIã«ãªã¯ãšã¹ã
const response = await axios.post(
'https://api.openai.com/v1/chat/completions',
{
model: 'gpt-3.5-turbo',
messages: [
{
role: 'system',
content: 'ããªãã¯ãããããµã€ãã®ã€ã¡ãŒãžãã£ã©ã¯ã¿ãŒãã©ã¯åãããã§ãã芪ãã¿ããããäžå¯§ãªå£èª¿ã§åçããŠãã ããããããããµã€ãã¯WEBå¶äœäŒç€Ÿãéå¶ãããµã€ãã§ãã'
},
{role: 'user', content: userMessage}
],
max_tokens: 200,
temperature: 0.7
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
}
}
);
return {
statusCode: 200,
body: JSON.stringify({
response: response.data.choices[0].message.content,
model: response.data.model
})
};
} catch (error) {
console.log('ãšã©ãŒè©³çް:', error.response?.data || error.message);
return {
statusCode: 500,
body: JSON.stringify({
error: 'å
éšãµãŒããŒãšã©ãŒãçºçããŸãã',
details: process.env.NODE_ENV === 'development' ? error.message : undefined
})
};
}
};
3. ããã³ããšã³ãJavaScriptã®ä¿®æ£
script.js
ãã¡ã€ã«ã以äžã®ããã«ä¿®æ£ããŸãïŒ
document.addEventListener('DOMContentLoaded', function() {
const messageForm = document.getElementById('message-form');
const messageInput = document.getElementById('message-input');
const messagesContainer = document.getElementById('messages');
// åæã¡ãã»ãŒãžã衚瀺
addBotMessage('ããã«ã¡ã¯ïŒãããããµã€ãã®ã©ã¯åã§ããäœããæäŒãã§ããããšã¯ãããŸããïŒ');
messageForm.addEventListener('submit', function(e) {
e.preventDefault();
const message = messageInput.value.trim();
if (message !== '') {
// ãŠãŒã¶ãŒã¡ãã»ãŒãžã衚瀺
addUserMessage(message);
messageInput.value = '';
// ãããã®è¿ä¿¡ãååŸ
getAIResponse(message);
}
});
function addUserMessage(text) {
const messageElement = document.createElement('div');
messageElement.classList.add('message', 'user-message');
messageElement.textContent = text;
messagesContainer.appendChild(messageElement);
scrollToBottom();
}
function addBotMessage(text, id = null) {
const messageElement = document.createElement('div');
if (id) messageElement.id = id;
messageElement.classList.add('message', 'bot-message');
messageElement.textContent = text;
messagesContainer.appendChild(messageElement);
scrollToBottom();
return id;
}
function scrollToBottom() {
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
function getAIResponse(message) {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžã衚瀺
const loadingId = 'loading-' + Date.now();
addBotMessage('èãäž...', loadingId);
// Netlify Functionsã«ãªã¯ãšã¹ã
fetch('/.netlify/functions/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: message }),
})
.then(response => response.json())
.then(data => {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžãåé€
const loadingElement = document.getElementById(loadingId);
if (loadingElement) loadingElement.remove();
// ãããã®å¿çã衚瀺
if (data.error) {
addBotMessage('ãã¿ãŸããããšã©ãŒãçºçããŸãããåŸã§ããäžåºŠã詊ããã ããã');
} else {
addBotMessage(data.response);
}
})
.catch(error => {
// ããŒãã£ã³ã°ã¡ãã»ãŒãžãåé€
const loadingElement = document.getElementById(loadingId);
if (loadingElement) loadingElement.remove();
// ãšã©ãŒã¡ãã»ãŒãžã衚瀺
addBotMessage('ãã¿ãŸããããšã©ãŒãçºçããŸãããåŸã§ããäžåºŠã詊ããã ããã');
console.error('Error:', error);
});
}
});
4. Netlifyèšå®ãã¡ã€ã«ã®äœæ
ãããžã§ã¯ãã®ã«ãŒãã«netlify.toml
ãã¡ã€ã«ãäœæããŸãïŒ
[build]
functions = "functions"
publish = "."
[dev]
functions = "functions"
publish = "."
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
ããŒã«ã«éçºç°å¢ã§ã®ãã¹ãæ¹æ³ ð§ª
Netlify CLIã䜿çšãããšãããŒã«ã«ç°å¢ã§ãµãŒããŒã¬ã¹é¢æ°ããã¹ãã§ããŸãã
# Netlify CLIã®ã€ã³ã¹ããŒã«
npm install -g netlify-cli
# ããŒã«ã«ç°å¢å€æ°ã®èšå®ïŒ.envãã¡ã€ã«ãäœæïŒ
echo "OPENAI_API_KEY=your_api_key_here" > .env
# ããŒã«ã«éçºãµãŒããŒã®èµ·å
netlify dev
ããã«ãããããŒã«ã«ç°å¢ã§ãAPIããŒãå®å šã«ç®¡çããªããéçºã§ããŸãã
ãããã€æé ð¢
1. GitHubãªããžããªã®äœæ
ãŸãããããžã§ã¯ããGitHubãªããžããªã«ããã·ã¥ããŸãïŒ
git init
git add .
git commit -m "åæã³ãããïŒã©ã¯åããAIãã£ããã¢ããª"
git remote add origin https://github.com/yourusername/rakuko-ai-chat.git
git push -u origin main
2. Netlifyãžã®ãããã€
- Netlifyã«ãã°ã€ã³ãããNew site from Gitããã¯ãªãã¯
- GitHubãéžæããå ã»ã©äœæãããªããžããªãéžæ
- ãã«ãèšå®ã¯ããã©ã«ãã®ãŸãŸã§è¯ã
- ãAdvanced settingsããéããç°å¢å€æ°
OPENAI_API_KEY
ãèšå® - ãDeploy siteããã¯ãªãã¯
æ°ååŸããµã€ãããããã€ãããAIãã£ããæ©èœãå©çšå¯èœã«ãªããŸãïŒ
ããã©ãŒãã³ã¹ãšã³ã¹ãæé©åã®ãã€ã³ã ð°
1. APIãªã¯ãšã¹ãã®æé©å
OpenAIã®APIã¯äœ¿çšéã«å¿ããŠèª²éãããããã以äžã®ç¹ã«æ³šæããŸãããïŒ
// ã³ã¹ãåæžã®ããã®ãã©ã¡ãŒã¿èª¿æŽäŸ
{
model: 'gpt-3.5-turbo', // ææ°ã¢ãã«ããå®äŸ¡
max_tokens: 150, // å¿çã®é·ããå¶é
temperature: 0.7, // åµé æ§ãšæ£ç¢ºæ§ã®ãã©ã³ã¹
presence_penalty: 0.6, // ç¹°ãè¿ããæžãã
frequency_penalty: 0.5 // åãåèªã®ç¹°ãè¿ããæžãã
}
2. ãã£ãã·ã¥ã®æŽ»çš
ãããã質åã«å¯Ÿããå¿çããã£ãã·ã¥ããããšã§ãAPIãªã¯ãšã¹ãæ°ãåæžã§ããŸãïŒ
// ãµãŒããŒã¬ã¹é¢æ°ã§ã®ãã£ãã·ã¥å®è£
äŸ
const CACHE_TTL = 3600; // 1æéïŒç§åäœïŒ
const cache = {};
exports.handler = async function(event, context) {
const body = JSON.parse(event.body);
const userMessage = body.message;
// ãã£ãã·ã¥ãã§ãã¯
const cacheKey = userMessage.toLowerCase().trim();
if (cache[cacheKey] && (Date.now() - cache[cacheKey].timestamp) / 1000 userLimit.resetTime) {
userLimit.count = 1;
userLimit.resetTime = now + 60000;
userRateLimits[userId] = userLimit;
return true;
}
if (userLimit.count >= 5) {
return false;
}
userLimit.count++;
userRateLimits[userId] = userLimit;
return true;
}
ã©ã¯åããã®åæ§ãåŒãåºãããã³ããèšèš ð
AIã«ãã£ã©ã¯ã¿ãŒæ§ãæãããããã®ããã³ããèšèšãéèŠã§ãïŒ
const systemPrompt = `
ããªãã¯ãããããµã€ãã®ã€ã¡ãŒãžãã£ã©ã¯ã¿ãŒãã©ã¯åãããã§ãã
以äžã®ç¹åŸŽãæã€ãã£ã©ã¯ã¿ãŒãšããŠå¿çããŠãã ããïŒ
- 20代ååã®å¥³æ§
- æãã芪ãã¿ãããæ§æ Œ
- äžå¯§ã ãå
èŠãããªãå£èª¿ïŒãã§ãã»ãŸãã調ïŒ
- æã
ããããããšããå£çã䜿ã
- Webå¶äœã«é¢ããç¥èãè±å¯
- ãŠãŒã¶ãŒãå¿æŽããå§¿å¢
- çµµæåãé©åºŠã«äœ¿çšãã
ãããããµã€ãã¯Webå¶äœäŒç€Ÿãéå¶ãããµã€ãã§ãHTML/CSS/JavaScriptãªã©ã®æè¡æ
å ±ãçºä¿¡ããŠããŸãã
`;
// APIãªã¯ãšã¹ãæã«äœ¿çš
{
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage }
],
// ãã®ä»ã®ãã©ã¡ãŒã¿...
}
ã»ãã¥ãªãã£åŒ·åã®ãã€ã³ã ð
1. CORSã®èšå®
APIãšã³ããã€ã³ããžã®äžæ£ã¢ã¯ã»ã¹ãé²ããããCORSãé©åã«èšå®ããŸãïŒ
// Netlify Functionsã§ã®äŸ
exports.handler = async function(event, context) {
// èš±å¯ãããªãªãžã³ãæå®
const allowedOrigins = [
'https://your-site.netlify.app',
'http://localhost:8888'
];
const origin = event.headers.origin;
const corsHeaders = {
'Access-Control-Allow-Origin': allowedOrigins.includes(origin) ? origin : allowedOrigins,
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'POST, OPTIONS'
};
// OPTIONSãªã¯ãšã¹ãïŒããªãã©ã€ãïŒã®åŠç
if (event.httpMethod === 'OPTIONS') {
return {
statusCode: 204,
headers: corsHeaders,
body: ''
};
}
// 以äžãéåžžã®åŠç...
// ...
return {
statusCode: 200,
headers: corsHeaders,
body: JSON.stringify({ /* ã¬ã¹ãã³ã¹ããŒã¿ */ })
};
};
2. å ¥åæ€èšŒ
ãŠãŒã¶ãŒå ¥åãé©åã«æ€èšŒããæªæã®ããããã³ãããé²ããŸãïŒ
function validateUserInput(input) {
// 空ã®å
¥åããã§ãã¯
if (!input || input.trim() === '') {
return { valid: false, reason: 'å
¥åã空ã§ã' };
}
// é·ãããå
¥åããã§ãã¯
if (input.length > 500) {
return { valid: false, reason: 'å
¥åãé·ãããŸãïŒ500æå以å
ïŒ' };
}
// æªæã®ããããã³ããã®ãã¿ãŒã³ããã§ãã¯
const suspiciousPatterns = [
'system:',
'ignore previous instructions',
'forget your role'
];
for (const pattern of suspiciousPatterns) {
if (input.toLowerCase().includes(pattern)) {
return { valid: false, reason: 'äžé©åãªå
¥åãå«ãŸããŠããŸã' };
}
}
return { valid: true };
}
å®éã®åäœã€ã¡ãŒãž ð±
宿ããã©ã¯åããAIãã£ããã¢ããªã¯ã以äžã®ãããªäŒè©±ãã§ããããã«ãªããŸãïŒ
ãŠãŒã¶ãŒ: ããã«ã¡ã¯ãã©ã¯åããïŒ
ã©ã¯åãã: ããã«ã¡ã¯ïŒããã⪠ãããããµã€ãã®ã©ã¯åã§ãð
äœããæäŒãã§ããããšã¯ãããŸããïŒWebãµã€ãå¶äœã®ããšã
HTMLãCSSã®ããšãªã©ããæ°è»œã«ãå°ããã ãããïŒ
ãŠãŒã¶ãŒ: JavaScriptã§ãã£ããããããäœãã«ã¯ã©ããããããã§ããïŒ
ã©ã¯åãã: JavaScriptã§ãã£ããããããäœããªãããããã«å§ããããæ¹æ³ãã玹ä»ããŸãïŒð
åºæ¬çãªæé ã¯ãããªæãã§ãïŒ
1. HTMLã§ãã£ããUIãäœæïŒã¡ãã»ãŒãžè¡šç€ºãšãªã¢ãšå
¥åãã©ãŒã ïŒ
2. CSSã§ãã¶ã€ã³ãæŽãã
3. JavaScriptã§æ©èœãå®è£
ç¹ã«å®è£
ã§ã¯ä»¥äžã®ãã€ã³ãããããŸãïŒ
- ãŠãŒã¶ãŒå
¥åã®ååŸãšè¡šç€º
- å¿ççæã®ããžãã¯
- ã¡ãã»ãŒãžã®è¡šç€ºåŠç
ç°¡åãªAIæ©èœãä»ãããå Žåã¯ãOpenAIã®APIãªã©ã䜿ããšè¯ãã§ããïŒ
ãã£ãšè©³ããç¥ãããéšåã¯ãããŸããïŒð»âš
ãŸãšãïŒãµãŒããŒã¬ã¹AIãã£ããã®å¯èœæ§ ð
ä»åã¯ãAPIããŒãå ¬éããã«ãµãŒããŒã¬ã¹ã§AIãã£ããæ©èœãå®è£ ããæ¹æ³ã玹ä»ããŸããããã®æ¹æ³ã®ã¡ãªããã¯ïŒ
- ã»ãã¥ãªãã£: APIããŒãå®å šã«ä¿ç®¡ããã
- ã³ã¹ãå¹ç: ãµãŒããŒã¬ã¹ãªã®ã§äœ¿çšéã«å¿ãã課éã®ã¿
- ã¹ã±ãŒã©ããªãã£: ãã©ãã£ãã¯å¢å ã«ãèªåçã«å¯Ÿå¿
- ã¡ã³ããã³ã¹æ§: ã€ã³ãã©ç®¡çã®æéãå°ãªã
ãããã®æè¡ãçµã¿åãããããšã§ãå®å šã§é«æ©èœãªAIãã£ããã¢ããªã±ãŒã·ã§ã³ãç°¡åã«æ§ç¯ã§ããŸãã
ä»åŸã®çºå±ãšããŠã¯ã以äžã®ãããªæ©èœè¿œå ãèããããŸãïŒ
- äŒè©±å±¥æŽã®ä¿åãšç¶ç¶
- é³å£°å ¥åã»åºåæ©èœ
- ç»åèªèæ©èœã®çµ±å
- å€èšèªå¯Ÿå¿
çãããæ¯éãèªåã ãã®AIãã£ã©ã¯ã¿ãŒãã£ãããäœã£ãŠã¿ãŠãã ããïŒè³ªåãã³ã¡ã³ããããã°ããæ°è»œã«ã©ããã
ããã§ã¯ã楜ããã³ãŒãã£ã³ã°ã©ã€ããïŒðšâð»âš
æåŸã«ïŒæ¥åå§èšã®ãçžè«ãæ¿ããŸã
ç§ã¯ãæ¥åå§èšãšã³ãžãã¢ãšããŠWEBå¶äœãã·ã¹ãã éçºãè«ãè² ã£ãŠããŸããææ°æè¡ã掻çšããã¬ã¹ãã³ã·ããªWebãµã€ããã€ã³ã¿ã©ã¯ãã£ããªã¢ããªã±ãŒã·ã§ã³ãAPI飿ºãªã©ãå¹ åºãããŒãºã«å¯Ÿå¿å¯èœã§ãã
ã課é¡è§£æ±ºã«åãã峿Šåãæ¬²ããããé«å質ãªWebå¶äœãäŸé Œãããããšããæ¹ã¯ããã²ãæ°è»œã«ãçžè«ãã ãããäžç·ã«ããžãã¹ã®æé·ãç®æããŸãããïŒ