🚀 OpenAI GPT API'ya Giriş
OpenAI GPT API, dünyanın en gelişmiş doğal dil işleme modellerinden birine erişim sağlar. Node.js uygulamalarınıza ChatGPT benzeri yapay zeka yetenekleri kazandırmak için bu API'yi nasıl entegre edeceğinizi detaylıyla öğreneceksiniz.
🤖 Chat Completion
GPT-4 ve GPT-3.5-turbo modelleriyle dinamik sohbet uygulamaları geliştirin
🔧 Function Calling
AI'ın harici fonksiyonları çağırabilmesini sağlayarak güçlü entegrasyonlar oluşturun
🎯 Fine-tuning
Özel verilerinizle modeli eğiterek iş süreçlerinize özel AI asistanları yaratın
📊 Embeddings
Metinsel verileri vektörel temsillere dönüştürerek semantik arama sistemleri oluşturun
⚙️ Proje Kurulumu ve Konfigürasyon
OpenAI API'sını Node.js projenize entegre etmek için gerekli paketleri kuralım ve temel konfigürasyonu yapalım.
Gerekli Paketlerin Kurulumu
package.json
{
"name": "openai-integration-app",
"version": "1.0.0",
"description": "Node.js OpenAI API Integration",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"dependencies": {
"openai": "^4.20.1",
"express": "^4.18.2",
"dotenv": "^16.3.1",
"cors": "^2.8.5",
"helmet": "^7.1.0",
"express-rate-limit": "^7.1.5",
"winston": "^3.11.0"
},
"devDependencies": {
"nodemon": "^3.0.1",
"jest": "^29.7.0"
}
}
Terminal
npm install openai express dotenv cors helmet express-rate-limit winston
npm install -D nodemon jest
Çevre Değişkenleri Konfigürasyonu
.env
# OpenAI API Configuration
OPENAI_API_KEY=your_openai_api_key_here
OPENAI_ORGANIZATION_ID=your_org_id_here
# Application Configuration
PORT=3000
NODE_ENV=development
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# Logging
LOG_LEVEL=info
LOG_FILE_PATH=./logs/app.log
⚠️ Güvenlik Uyarısı
API anahtarınızı asla version control sistemine commit etmeyin! .env dosyasını .gitignore'a ekleyin ve production ortamında environment variables kullanın.
🎯 Temel API Kullanımı
OpenAI client'ını kurarak ilk API çağrınızı yapalım ve temel konfigürasyon seçeneklerini inceleyelim.
config/openai.js
const OpenAI = require('openai');
const winston = require('winston');
// Logger konfigürasyonu
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({
filename: process.env.LOG_FILE_PATH || './logs/app.log'
})
]
});
// OpenAI client konfigürasyonu
class OpenAIService {
constructor() {
this.client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
organization: process.env.OPENAI_ORGANIZATION_ID,
timeout: 60000, // 60 saniye timeout
maxRetries: 3, // Başarısız istekleri 3 kez tekrarla
});
// Desteklenen modeller
this.models = {
GPT4: 'gpt-4-1106-preview',
GPT4_TURBO: 'gpt-4-turbo-preview',
GPT35: 'gpt-3.5-turbo-1106',
GPT35_16K: 'gpt-3.5-turbo-16k-0613'
};
logger.info('OpenAI service initialized successfully');
}
// Model listesini getir
async getAvailableModels() {
try {
const response = await this.client.models.list();
return response.data.filter(model =>
model.id.includes('gpt')
);
} catch (error) {
logger.error('Failed to fetch models:', error);
throw error;
}
}
// Token sayısını hesapla (yaklaşık)
estimateTokenCount(text) {
// GPT tokenizer'ı tam olarak simüle etmek için tiktoken kullanılabilir
// Burada basit bir yaklaşım kullanıyoruz
return Math.ceil(text.length / 4);
}
// Maliyet hesaplama (GPT-4 için)
calculateCost(inputTokens, outputTokens, model = 'gpt-4') {
const pricing = {
'gpt-4': { input: 0.03, output: 0.06 }, // $0.03/$0.06 per 1K tokens
'gpt-3.5-turbo': { input: 0.001, output: 0.002 }
};
const modelPricing = pricing[model] || pricing['gpt-4'];
return {
inputCost: (inputTokens / 1000) * modelPricing.input,
outputCost: (outputTokens / 1000) * modelPricing.output,
totalCost: (inputTokens / 1000) * modelPricing.input +
(outputTokens / 1000) * modelPricing.output
};
}
}
module.exports = new OpenAIService();
💬 Chat Completion API
En yaygın kullanım senaryosu olan Chat Completion API'sini kullanarak konuşma tabanlı AI uygulamaları geliştirmeyi öğrenelim.
services/chatService.js
const openaiService = require('../config/openai');
const winston = require('winston');
class ChatService {
constructor() {
this.conversationHistory = new Map(); // Kullanıcı sohbet geçmişi
this.logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: './logs/chat.log' })
]
});
}
// Temel chat completion
async generateResponse(userMessage, options = {}) {
try {
const {
model = openaiService.models.GPT35,
temperature = 0.7,
maxTokens = 150,
systemPrompt = "Sen yardımcı bir AI asistanısın.",
userId = 'default'
} = options;
// Kullanıcı sohbet geçmişini getir veya oluştur
let conversation = this.conversationHistory.get(userId) || [];
// System message'ı başa ekle (sadece ilk mesajda)
if (conversation.length === 0) {
conversation.push({
role: 'system',
content: systemPrompt
});
}
// Kullanıcı mesajını ekle
conversation.push({
role: 'user',
content: userMessage
});
// OpenAI API çağrısı
const response = await openaiService.client.chat.completions.create({
model: model,
messages: conversation,
temperature: temperature,
max_tokens: maxTokens,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stream: false
});
const assistantMessage = response.choices[0].message.content;
// Assistant yanıtını sohbet geçmişine ekle
conversation.push({
role: 'assistant',
content: assistantMessage
});
// Sohbet geçmişini sakla (maksimum 20 mesaj)
if (conversation.length > 20) {
conversation = [conversation[0], ...conversation.slice(-19)];
}
this.conversationHistory.set(userId, conversation);
// İstatistikleri logla
this.logger.info('Chat completion generated', {
userId,
model,
inputTokens: response.usage.prompt_tokens,
outputTokens: response.usage.completion_tokens,
totalTokens: response.usage.total_tokens
});
return {
response: assistantMessage,
usage: response.usage,
model: model,
conversationLength: conversation.length
};
} catch (error) {
this.logger.error('Chat generation failed:', error);
throw new Error(`Chat generation failed: ${error.message}`);
}
}
// Streaming response (gerçek zamanlı yanıt)
async generateStreamingResponse(userMessage, options = {}, onChunk) {
try {
const {
model = openaiService.models.GPT35,
temperature = 0.7,
maxTokens = 150,
systemPrompt = "Sen yardımcı bir AI asistanısın.",
userId = 'default'
} = options;
let conversation = this.conversationHistory.get(userId) || [];
if (conversation.length === 0) {
conversation.push({
role: 'system',
content: systemPrompt
});
}
conversation.push({
role: 'user',
content: userMessage
});
const stream = await openaiService.client.chat.completions.create({
model: model,
messages: conversation,
temperature: temperature,
max_tokens: maxTokens,
stream: true
});
let fullResponse = '';
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
if (content) {
fullResponse += content;
onChunk(content); // Chunk'ı callback ile gönder
}
}
// Tam yanıtı sohbet geçmişine ekle
conversation.push({
role: 'assistant',
content: fullResponse
});
if (conversation.length > 20) {
conversation = [conversation[0], ...conversation.slice(-19)];
}
this.conversationHistory.set(userId, conversation);
return fullResponse;
} catch (error) {
this.logger.error('Streaming chat generation failed:', error);
throw error;
}
}
// Sohbet geçmişini temizle
clearConversation(userId) {
this.conversationHistory.delete(userId);
this.logger.info(`Conversation cleared for user: ${userId}`);
}
// Sohbet geçmişini getir
getConversationHistory(userId) {
return this.conversationHistory.get(userId) || [];
}
}
module.exports = new ChatService();
🔧 Gelişmiş Özellikler
OpenAI API'nin güçlü özelliklerinden Function Calling ve Embeddings kullanarak daha akıllı AI uygulamaları geliştirmeyi öğrenelim.
Function Calling - AI'ın Fonksiyonları Çağırması
GPT-4 ve GPT-3.5-turbo modelleri, tanımladığınız fonksiyonları çağırabilir. Bu özellik sayesinde AI, veritabanı sorguları yapabilir, API çağrıları gerçekleştirebilir ve dış kaynaklara erişebilir.
services/functionCalling.js
const openaiService = require('../config/openai');
class FunctionCallingService {
constructor() {
// Kullanılabilir fonksiyonları tanımla
this.availableFunctions = {
get_weather: this.getWeather,
search_database: this.searchDatabase,
send_email: this.sendEmail,
calculate_math: this.calculateMath
};
// Fonksiyon tanımları (OpenAI'a gönderilecek schema)
this.functionDefinitions = [
{
name: "get_weather",
description: "Belirtilen şehir için hava durumu bilgisini getirir",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "Hava durumu bilgisi alınacak şehir adı"
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "Sıcaklık birimi"
}
},
required: ["city"]
}
},
{
name: "search_database",
description: "Veritabanında ürün araması yapar",
parameters: {
type: "object",
properties: {
query: {
type: "string",
description: "Aranacak ürün adı veya kategorisi"
},
limit: {
type: "integer",
description: "Döndürülecek maksimum sonuç sayısı",
default: 10
}
},
required: ["query"]
}
}
];
}
// Hava durumu fonksiyonu
async getWeather(args) {
const { city, unit = "celsius" } = JSON.parse(args);
// Gerçek API çağrısı burada yapılabilir
return {
city: city,
temperature: unit === "celsius" ? "22°C" : "72°F",
condition: "Güneşli",
humidity: "65%"
};
}
// Veritabanı arama fonksiyonu
async searchDatabase(args) {
const { query, limit = 10 } = JSON.parse(args);
// Gerçek veritabanı sorgusu burada yapılabilir
return [
{ id: 1, name: `${query} Ürün 1`, price: 299 },
{ id: 2, name: `${query} Ürün 2`, price: 399 }
].slice(0, limit);
}
// Function calling ile chat completion
async chatWithFunctions(userMessage, userId = 'default') {
try {
const messages = [
{
role: "system",
content: "Sen yardımcı bir AI asistanısın. Kullanıcı isteklerine göre uygun fonksiyonları çağırabilirsin."
},
{
role: "user",
content: userMessage
}
];
// İlk API çağrısı - fonksiyon çağrısı gerekli mi?
const response = await openaiService.client.chat.completions.create({
model: openaiService.models.GPT4,
messages: messages,
functions: this.functionDefinitions,
function_call: "auto"
});
const message = response.choices[0].message;
// Eğer AI bir fonksiyon çağırmak istiyorsa
if (message.function_call) {
const functionName = message.function_call.name;
const functionArgs = message.function_call.arguments;
// İlgili fonksiyonu çağır
if (this.availableFunctions[functionName]) {
const functionResult = await this.availableFunctions[functionName].call(this, functionArgs);
// Fonksiyon sonucunu mesaj geçmişine ekle
messages.push(message);
messages.push({
role: "function",
name: functionName,
content: JSON.stringify(functionResult)
});
// Fonksiyon sonucu ile ikinci API çağrısı
const secondResponse = await openaiService.client.chat.completions.create({
model: openaiService.models.GPT4,
messages: messages
});
return {
response: secondResponse.choices[0].message.content,
functionCalled: functionName,
functionResult: functionResult,
usage: secondResponse.usage
};
}
}
// Fonksiyon çağrısı gerekli değilse normal yanıt
return {
response: message.content,
functionCalled: null,
usage: response.usage
};
} catch (error) {
console.error('Function calling failed:', error);
throw error;
}
}
}
module.exports = new FunctionCallingService();
Embeddings - Metinleri Vektörel Temsile Dönüştürme
Embeddings, metinleri sayısal vektörlere dönüştürerek benzerlik analizi, semantik arama ve kümeleme işlemleri yapmanızı sağlar.
services/embeddingService.js
const openaiService = require('../config/openai');
class EmbeddingService {
constructor() {
this.embeddingModel = 'text-embedding-ada-002';
this.embeddingCache = new Map(); // Embedding önbelleği
}
// Metin için embedding oluştur
async createEmbedding(text) {
try {
// Önbellekten kontrol et
const cacheKey = Buffer.from(text).toString('base64');
if (this.embeddingCache.has(cacheKey)) {
return this.embeddingCache.get(cacheKey);
}
const response = await openaiService.client.embeddings.create({
model: this.embeddingModel,
input: text,
});
const embedding = response.data[0].embedding;
// Önbelleğe kaydet
this.embeddingCache.set(cacheKey, embedding);
return embedding;
} catch (error) {
console.error('Embedding creation failed:', error);
throw error;
}
}
// Çoklu metinler için embedding oluştur
async createBatchEmbeddings(texts) {
try {
const response = await openaiService.client.embeddings.create({
model: this.embeddingModel,
input: texts,
});
return response.data.map(item => item.embedding);
} catch (error) {
console.error('Batch embedding creation failed:', error);
throw error;
}
}
// İki embedding arasındaki cosine similarity hesapla
calculateSimilarity(embedding1, embedding2) {
const dotProduct = embedding1.reduce((sum, a, i) => sum + a * embedding2[i], 0);
const magnitude1 = Math.sqrt(embedding1.reduce((sum, a) => sum + a * a, 0));
const magnitude2 = Math.sqrt(embedding2.reduce((sum, a) => sum + a * a, 0));
return dotProduct / (magnitude1 * magnitude2);
}
// Semantik arama yapı
async semanticSearch(query, documents) {
try {
// Query embedding'ini oluştur
const queryEmbedding = await this.createEmbedding(query);
// Dokuman embedding'lerini oluştur
const docEmbeddings = await this.createBatchEmbeddings(documents);
// Benzerlik skorlarını hesapla
const similarities = docEmbeddings.map((docEmbedding, index) => ({
document: documents[index],
similarity: this.calculateSimilarity(queryEmbedding, docEmbedding),
index: index
}));
// Benzerlik skoruna göre sırala
return similarities
.sort((a, b) => b.similarity - a.similarity)
.slice(0, 5); // En benzer 5 dokümanı döndür
} catch (error) {
console.error('Semantic search failed:', error);
throw error;
}
}
// Metin kümeleme
async clusterDocuments(documents, numClusters = 3) {
try {
// Tüm dokümanlar için embedding oluştur
const embeddings = await this.createBatchEmbeddings(documents);
// Basit k-means clustering implementasyonu
// Gerçek uygulamada scikit-learn benzeri kütüphaneler kullanılabilir
const clusters = Array.from({ length: numClusters }, () => []);
embeddings.forEach((embedding, index) => {
// Rastgele kümelere ata (daha sofistike clustering algoritmaları kullanılabilir)
const clusterIndex = index % numClusters;
clusters[clusterIndex].push({
document: documents[index],
embedding: embedding,
index: index
});
});
return clusters;
} catch (error) {
console.error('Document clustering failed:', error);
throw error;
}
}
}
module.exports = new EmbeddingService();
🤖 AI Chatbot Geliştirme
Express.js kullanarak tam özellikli bir AI chatbot API'si geliştirmeyi ve web arayüzü ile entegre etmeyi öğrenelim.
app.js - Ana Uygulama Dosyası
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const winston = require('winston');
require('dotenv').config();
const chatService = require('./services/chatService');
const functionCallingService = require('./services/functionCalling');
const embeddingService = require('./services/embeddingService');
const app = express();
const PORT = process.env.PORT || 3000;
// Logger konfigürasyonu
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: './logs/app.log' })
]
});
// Middleware
app.use(helmet());
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3001',
credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.static('public'));
// Rate limiting
const chatLimiter = rateLimit({
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 dakika
max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 50, // Her IP için 50 istek
message: {
error: 'Çok fazla istek gönderildi. Lütfen daha sonra tekrar deneyin.',
retryAfter: Math.ceil((parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 900000) / 1000)
},
standardHeaders: true,
legacyHeaders: false,
});
// Chat endpoint'leri
app.post('/api/chat', chatLimiter, async (req, res) => {
try {
const { message, userId, options = {} } = req.body;
if (!message || message.trim().length === 0) {
return res.status(400).json({
error: 'Mesaj boş olamaz',
code: 'EMPTY_MESSAGE'
});
}
if (message.length > 2000) {
return res.status(400).json({
error: 'Mesaj çok uzun (maksimum 2000 karakter)',
code: 'MESSAGE_TOO_LONG'
});
}
const result = await chatService.generateResponse(message, {
...options,
userId: userId || `user_${Date.now()}`
});
logger.info('Chat request processed', {
userId: userId,
messageLength: message.length,
responseLength: result.response.length,
tokensUsed: result.usage.total_tokens
});
res.json({
response: result.response,
usage: result.usage,
conversationLength: result.conversationLength,
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Chat request failed:', error);
// OpenAI API hatalarını yakala
if (error.message.includes('insufficient_quota')) {
return res.status(429).json({
error: 'API kotası doldu. Lütfen daha sonra tekrar deneyin.',
code: 'QUOTA_EXCEEDED'
});
}
if (error.message.includes('rate_limit')) {
return res.status(429).json({
error: 'Rate limit aşıldı. Lütfen daha sonra tekrar deneyin.',
code: 'RATE_LIMIT_EXCEEDED'
});
}
res.status(500).json({
error: 'Bir hata oluştu. Lütfen daha sonra tekrar deneyin.',
code: 'INTERNAL_SERVER_ERROR'
});
}
});
// Streaming chat endpoint
app.post('/api/chat/stream', chatLimiter, async (req, res) => {
try {
const { message, userId, options = {} } = req.body;
// SSE headers
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Cache-Control'
});
// Streaming response handler
const handleChunk = (chunk) => {
res.write(`data: ${JSON.stringify({ chunk, type: 'content' })}\n\n`);
};
const fullResponse = await chatService.generateStreamingResponse(
message,
{ ...options, userId: userId || `user_${Date.now()}` },
handleChunk
);
// Stream sonu
res.write(`data: ${JSON.stringify({ type: 'done', fullResponse })}\n\n`);
res.end();
} catch (error) {
logger.error('Streaming chat failed:', error);
res.write(`data: ${JSON.stringify({ type: 'error', error: error.message })}\n\n`);
res.end();
}
});
// Function calling endpoint
app.post('/api/chat/functions', chatLimiter, async (req, res) => {
try {
const { message, userId } = req.body;
const result = await functionCallingService.chatWithFunctions(
message,
userId || `user_${Date.now()}`
);
res.json({
response: result.response,
functionCalled: result.functionCalled,
functionResult: result.functionResult,
usage: result.usage,
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Function calling failed:', error);
res.status(500).json({
error: 'Function calling sırasında hata oluştu',
code: 'FUNCTION_CALL_ERROR'
});
}
});
// Semantik arama endpoint
app.post('/api/search', chatLimiter, async (req, res) => {
try {
const { query, documents } = req.body;
if (!query || !documents || !Array.isArray(documents)) {
return res.status(400).json({
error: 'Query ve documents gereklidir',
code: 'INVALID_INPUT'
});
}
const results = await embeddingService.semanticSearch(query, documents);
res.json({
results: results,
query: query,
timestamp: new Date().toISOString()
});
} catch (error) {
logger.error('Semantic search failed:', error);
res.status(500).json({
error: 'Semantik arama sırasında hata oluştu',
code: 'SEARCH_ERROR'
});
}
});
// Conversation management endpoints
app.delete('/api/chat/clear/:userId', (req, res) => {
try {
const { userId } = req.params;
chatService.clearConversation(userId);
res.json({
message: 'Sohbet geçmişi temizlendi',
userId: userId
});
} catch (error) {
logger.error('Clear conversation failed:', error);
res.status(500).json({
error: 'Sohbet geçmişi temizlenirken hata oluştu'
});
}
});
app.get('/api/chat/history/:userId', (req, res) => {
try {
const { userId } = req.params;
const history = chatService.getConversationHistory(userId);
res.json({
history: history,
userId: userId,
count: history.length
});
} catch (error) {
logger.error('Get conversation history failed:', error);
res.status(500).json({
error: 'Sohbet geçmişi alınırken hata oluştu'
});
}
});
// Health check endpoint
app.get('/api/health', (req, res) => {
res.json({
status: 'OK',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage()
});
});
// Error handling middleware
app.use((error, req, res, next) => {
logger.error('Unhandled error:', error);
res.status(500).json({
error: 'Beklenmeyen bir hata oluştu',
code: 'INTERNAL_SERVER_ERROR'
});
});
// 404 handler
app.use('*', (req, res) => {
res.status(404).json({
error: 'Endpoint bulunamadı',
code: 'NOT_FOUND'
});
});
// Server başlat
app.listen(PORT, () => {
logger.info(`Server ${PORT} portunda başlatıldı`);
console.log(`🚀 Server running on http://localhost:${PORT}`);
});
module.exports = app;
🔒 Güvenlik ve Best Practices
OpenAI API kullanırken güvenlik önlemlerini alarak güvenli ve ölçeklenebilir uygulamalar geliştirmeyi öğrenelim.
💡 Güvenlik Kontrol Listesi
- API anahtarlarını environment variables'da saklayın
- Rate limiting implementasyonu yapın
- Input validation ve sanitization uygulayın
- Logging ve monitoring sistemi kurun
- CORS politikalarını doğru yapılandırın
middleware/security.js
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const validator = require('validator');
// Input validation middleware
const validateChatInput = (req, res, next) => {
const { message, userId, options = {} } = req.body;
// Message validation
if (!message || typeof message !== 'string') {
return res.status(400).json({
error: 'Mesaj gerekli ve string tipinde olmalıdır',
code: 'INVALID_MESSAGE'
});
}
// Message length check
if (message.length > 4000) {
return res.status(400).json({
error: 'Mesaj çok uzun (maksimum 4000 karakter)',
code: 'MESSAGE_TOO_LONG'
});
}
// Message content filtering
if (containsOffensiveContent(message)) {
return res.status(400).json({
error: 'Uygunsuz içerik tespit edildi',
code: 'OFFENSIVE_CONTENT'
});
}
// UserID validation
if (userId && (!validator.isAlphanumeric(userId.replace(/[_-]/g, '')) || userId.length > 50)) {
return res.status(400).json({
error: 'Geçersiz kullanıcı ID',
code: 'INVALID_USER_ID'
});
}
// Sanitize message
req.body.message = validator.escape(message.trim());
next();
};
// Uygunsuz içerik kontrolü (basit implementasyon)
const containsOffensiveContent = (text) => {
const offensiveWords = ['spam', 'hack', 'illegal']; // Genişletilebilir
const lowerText = text.toLowerCase();
return offensiveWords.some(word => lowerText.includes(word));
};
// API anahtarı kontrolü
const validateApiKey = (req, res, next) => {
if (!process.env.OPENAI_API_KEY) {
return res.status(500).json({
error: 'API anahtarı yapılandırılmamış',
code: 'MISSING_API_KEY'
});
}
next();
};
// Rate limiting konfigürasyonu
const createRateLimiter = (windowMs, max, message) => {
return rateLimit({
windowMs,
max,
message: {
error: message,
retryAfter: Math.ceil(windowMs / 1000)
},
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => {
// IP + User Agent kombinasyonu kullan
return `${req.ip}-${Buffer.from(req.get('User-Agent') || '').toString('base64').slice(0, 20)}`;
}
});
};
// Security middleware factory
const securityMiddleware = {
// Temel güvenlik
basic: [
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
}),
validateApiKey
],
// Chat endpoint'leri için
chat: [
createRateLimiter(15 * 60 * 1000, 50, 'Çok fazla mesaj gönderildi'),
validateChatInput
],
// Admin endpoint'leri için
admin: [
createRateLimiter(15 * 60 * 1000, 10, 'Admin işlemleri için rate limit'),
(req, res, next) => {
// Admin authentication burada yapılabilir
const adminKey = req.headers['x-admin-key'];
if (adminKey !== process.env.ADMIN_KEY) {
return res.status(403).json({
error: 'Yetkisiz erişim',
code: 'UNAUTHORIZED'
});
}
next();
}
]
};
module.exports = {
securityMiddleware,
validateChatInput,
validateApiKey,
createRateLimiter
};
Uygulamanızın performansını artırmak ve maliyetleri optimize etmek için kullanabileceğiniz teknikler.
🚀 Caching Stratejileri
Sık kullanılan yanıtları ve embedding'leri önbelleğe alarak API çağrılarını azaltın
📊 Token Optimizasyonu
Prompt engineering ile token kullanımını optimize ederek maliyetleri düşürün
⚖️ Load Balancing
Çoklu API anahtarları ile yük dağılımı yaparak rate limit'leri aşın
🔄 Connection Pooling
HTTP connection pooling ile API yanıt sürelerini iyileştirin
utils/performanceOptimizer.js
const NodeCache = require('node-cache');
const crypto = require('crypto');
class PerformanceOptimizer {
constructor() {
// Cache instances
this.responseCache = new NodeCache({
stdTTL: 3600, // 1 saat
checkperiod: 600, // 10 dakikada bir temizlik
maxKeys: 1000 // Maksimum 1000 cache entry
});
this.embeddingCache = new NodeCache({
stdTTL: 86400, // 24 saat
checkperiod: 3600, // 1 saatte bir temizlik
maxKeys: 5000
});
// Statistics
this.stats = {
cacheHits: 0,
cacheMisses: 0,
totalRequests: 0,
tokensSaved: 0
};
}
// Response cache key oluştur
createCacheKey(prompt, options = {}) {
const { model, temperature, maxTokens } = options;
const keyData = {
prompt: prompt.trim().toLowerCase(),
model: model || 'default',
temperature: temperature || 0.7,
maxTokens: maxTokens || 150
};
return crypto
.createHash('md5')
.update(JSON.stringify(keyData))
.digest('hex');
}
// Cached response kontrolü
getCachedResponse(prompt, options = {}) {
this.stats.totalRequests++;
const cacheKey = this.createCacheKey(prompt, options);
const cached = this.responseCache.get(cacheKey);
if (cached) {
this.stats.cacheHits++;
this.stats.tokensSaved += cached.usage.total_tokens;
return {
...cached,
cached: true,
cacheHitRate: (this.stats.cacheHits / this.stats.totalRequests * 100).toFixed(2)
};
}
this.stats.cacheMisses++;
return null;
}
// Response'u cache'le
setCachedResponse(prompt, options, response) {
const cacheKey = this.createCacheKey(prompt, options);
this.responseCache.set(cacheKey, {
response: response.response,
usage: response.usage,
timestamp: new Date().toISOString(),
model: response.model
});
}
// Prompt optimizasyonu
optimizePrompt(userMessage, conversationHistory = []) {
// Uzun conversation history'yi kısalt
let optimizedHistory = conversationHistory;
if (conversationHistory.length > 10) {
// Son 8 mesaj + system message
optimizedHistory = [
conversationHistory[0], // system message
...conversationHistory.slice(-8)
];
}
// Gereksiz boşlukları temizle
const optimizedMessage = userMessage.trim().replace(/\s+/g, ' ');
return {
optimizedMessage,
optimizedHistory,
tokensSaved: this.estimateTokensSaved(conversationHistory, optimizedHistory)
};
}
// Token tasarrufu tahmini
estimateTokensSaved(original, optimized) {
const originalLength = JSON.stringify(original).length;
const optimizedLength = JSON.stringify(optimized).length;
return Math.ceil((originalLength - optimizedLength) / 4); // Yaklaşık token hesabı
}
// Performans istatistikleri
getStats() {
return {
...this.stats,
cacheHitRate: (this.stats.cacheHits / this.stats.totalRequests * 100).toFixed(2) + '%',
cacheSizeResponse: this.responseCache.keys().length,
cacheSizeEmbedding: this.embeddingCache.keys().length
};
}
// Cache temizleme
clearCache() {
this.responseCache.flushAll();
this.embeddingCache.flushAll();
// Stats sıfırla
this.stats = {
cacheHits: 0,
cacheMisses: 0,
totalRequests: 0,
tokensSaved: 0
};
}
}
module.exports = new PerformanceOptimizer();
🛠️ Hata Yönetimi
OpenAI API'si ile çalışırken karşılaşabileceğiniz çeşitli hata durumlarını ele almak ve kullanıcı deneyimini geliştirmek için kapsamlı hata yönetimi stratejileri.
utils/errorHandler.js
const winston = require('winston');
class OpenAIErrorHandler {
constructor() {
this.logger = winston.createLogger({
level: 'error',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: './logs/errors.log' })
]
});
// Hata türleri ve karşılık gelen kullanıcı mesajları
this.errorMessages = {
'insufficient_quota': {
message: 'API kotası doldu. Lütfen daha sonra tekrar deneyin.',
code: 'QUOTA_EXCEEDED',
statusCode: 429,
retryable: true
},
'rate_limit_exceeded': {
message: 'Çok fazla istek gönderildi. Lütfen daha sonra tekrar deneyin.',
code: 'RATE_LIMIT_EXCEEDED',
statusCode: 429,
retryable: true
},
'invalid_request_error': {
message: 'Geçersiz istek. Lütfen giriş verilerinizi kontrol edin.',
code: 'INVALID_REQUEST',
statusCode: 400,
retryable: false
},
'authentication_error': {
message: 'API anahtarı geçersiz. Lütfen konfigürasyonunuzu kontrol edin.',
code: 'AUTHENTICATION_ERROR',
statusCode: 401,
retryable: false
},
'permission_error': {
message: 'Bu işlem için izniniz yok.',
code: 'PERMISSION_ERROR',
statusCode: 403,
retryable: false
},
'not_found_error': {
message: 'İstenen kaynak bulunamadı.',
code: 'NOT_FOUND',
statusCode: 404,
retryable: false
},
'timeout': {
message: 'İstek zaman aşımına uğradı. Lütfen tekrar deneyin.',
code: 'TIMEOUT',
statusCode: 408,
retryable: true
},
'server_error': {
message: 'Sunucu hatası oluştu. Lütfen daha sonra tekrar deneyin.',
code: 'SERVER_ERROR',
statusCode: 500,
retryable: true
}
};
}
// Ana hata işleme metodu
handleError(error, context = {}) {
const errorInfo = this.categorizeError(error);
// Hata detaylarını logla
this.logger.error('OpenAI API Error', {
error: error.message,
stack: error.stack,
type: errorInfo.type,
context: context,
timestamp: new Date().toISOString()
});
return {
success: false,
error: {
message: errorInfo.userMessage,
code: errorInfo.code,
retryable: errorInfo.retryable,
retryAfter: errorInfo.retryAfter
},
statusCode: errorInfo.statusCode
};
}
// Hata türünü belirle
categorizeError(error) {
const errorMessage = error.message?.toLowerCase() || '';
const errorType = error.type?.toLowerCase() || '';
// OpenAI spesifik hatalar
if (errorMessage.includes('insufficient_quota') || errorType === 'insufficient_quota') {
return {
type: 'insufficient_quota',
...this.errorMessages['insufficient_quota'],
userMessage: this.errorMessages['insufficient_quota'].message
};
}
if (errorMessage.includes('rate_limit') || errorType === 'rate_limit_exceeded') {
return {
type: 'rate_limit_exceeded',
...this.errorMessages['rate_limit_exceeded'],
userMessage: this.errorMessages['rate_limit_exceeded'].message,
retryAfter: this.extractRetryAfter(error)
};
}
if (errorMessage.includes('invalid_request') || errorType === 'invalid_request_error') {
return {
type: 'invalid_request_error',
...this.errorMessages['invalid_request_error'],
userMessage: this.errorMessages['invalid_request_error'].message
};
}
if (errorMessage.includes('authentication') || errorType === 'authentication_error') {
return {
type: 'authentication_error',
...this.errorMessages['authentication_error'],
userMessage: this.errorMessages['authentication_error'].message
};
}
// Ağ hataları
if (errorMessage.includes('timeout') || error.code === 'ECONNABORTED') {
return {
type: 'timeout',
...this.errorMessages['timeout'],
userMessage: this.errorMessages['timeout'].message
};
}
// Varsayılan sunucu hatası
return {
type: 'server_error',
...this.errorMessages['server_error'],
userMessage: this.errorMessages['server_error'].message
};
}
// Retry-After header'ından süreyi çıkar
extractRetryAfter(error) {
const headers = error.response?.headers;
if (headers && headers['retry-after']) {
return parseInt(headers['retry-after']);
}
return 60; // Varsayılan 60 saniye
}
// Tekrar deneme stratejisi
async retryWithBackoff(asyncFunction, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await asyncFunction();
} catch (error) {
const errorInfo = this.categorizeError(error);
// Tekrar denenebilir hata değilse direkt fırlat
if (!errorInfo.retryable || attempt === maxRetries) {
throw error;
}
// Exponential backoff ile bekle
const delay = baseDelay * Math.pow(2, attempt - 1);
await this.sleep(delay);
this.logger.warn(`Retry attempt ${attempt}/${maxRetries}`, {
error: error.message,
delay: delay,
attempt: attempt
});
}
}
}
// Sleep utility
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Circuit breaker pattern implementasyonu
createCircuitBreaker(fn, threshold = 5, timeout = 60000) {
let failures = 0;
let lastFailTime = 0;
let state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
return async (...args) => {
const now = Date.now();
// Circuit açık ve timeout geçti mi?
if (state === 'OPEN' && now - lastFailTime > timeout) {
state = 'HALF_OPEN';
failures = 0;
}
// Circuit açıksa hata fırlat
if (state === 'OPEN') {
throw new Error('Circuit breaker is OPEN. Service temporarily unavailable.');
}
try {
const result = await fn(...args);
// Başarılı ise circuit'i sıfırla
if (state === 'HALF_OPEN') {
state = 'CLOSED';
}
failures = 0;
return result;
} catch (error) {
failures++;
lastFailTime = now;
// Threshold'u aştıysak circuit'i aç
if (failures >= threshold) {
state = 'OPEN';
}
throw error;
}
};
}
}
module.exports = new OpenAIErrorHandler();
⚠️ Hata Yönetimi Best Practices
- Her zaman kullanıcı dostu hata mesajları gösterin
- Teknik detayları loglarda saklayın, kullanıcıya göstermeyin
- Tekrar denenebilir hatalar için retry mekanizması kullanın
- Circuit breaker pattern ile sistem stabilitesini koruyun
- Rate limiting hatalarında kullanıcıyı bilgilendirin
🎯 Sonuç ve İleri Adımlar
OpenAI GPT API entegrasyonunu başarılı bir şekilde tamamladınız! Bu kapsamlı rehberde öğrendiklerinizi özetleyelim ve ileri adımları değerlendirelim.
📚 Öğrendikleriniz
🔧 Temel Entegrasyon
OpenAI API'sini Node.js projelerinize güvenli bir şekilde entegre etmeyi öğrendiniz
💬 Chat Sistemi
Streaming ve normal chat completion ile dinamik sohbet uygulamaları geliştirdiniz
🚀 Gelişmiş Özellikler
Function calling ve embeddings ile AI uygulamalarınıza güçlü yetenekler kazandırdınız
🛡️ Güvenlik & Performans
Production-ready uygulamalar için güvenlik ve performans optimizasyonlarını uyguladınız
🔮 İleri Adımlar
OpenAI API entegrasyonunuzu daha da geliştirmek için aşağıdaki konuları keşfedebilirsiniz:
🎯 Önerilen Sonraki Projeler
- Fine-tuning: Kendi verilerinizle özel GPT modelleri eğitin
- Multimodal AI: DALL-E ve Whisper API'lerini entegre edin
- Vector Database: Pinecone veya Weaviate ile semantic search sistemleri kurun
- Real-time Chat: WebSocket ile gerçek zamanlı AI chatbot geliştirin
- AI Agents: LangChain ile akıllı AI agent sistemleri oluşturun
📖 Ek Kaynaklar
- OpenAI Resmi Dokümantasyon: En güncel API değişikliklerini takip edin
- Node.js Best Practices: Sunucu tarafı performans optimizasyonlarını öğrenin
- AI Ethics: Yapay zeka uygulamalarında etik kullanım prensiplerini benimseyin
- Monitoring: Prometheus ve Grafana ile AI uygulamalarınızı izleyin
💡 Son Tavsiyeler
AI teknolojisi hızla gelişiyor. Yeni modeller, özellikler ve best practice'ler için düzenli olarak OpenAI'ın güncellemelerini takip edin. Community forumlarına katılın ve projelerinizi GitHub'da paylaşarak deneyim kazanın.
Bu rehberde öğrendiklerinizi kullanarak güçlü, güvenli ve ölçeklenebilir AI uygulamaları geliştirebilirsiniz. OpenAI GPT API'nin sunduğu sınırsız potansiyeli keşfetmek için bugün kodlamaya başlayın!