Bu rehber, Google Gemini 2.5 Flash ve Supabase kullanarak kendi verilerini bilen bir asistanı sıfırdan inşa etmek isteyenler için hazırlanmıştır.
1. Proje Kurulumu ve Dosya Yapısı
İlk olarak bilgisayarımızda projemiz için bir çalışma alanı oluşturuyoruz.
Terminal (Bash) Komutları:
# Proje klasörünü oluştur
mkdir webasistant-master && cd webasistant-master
# Node.js projesini initialize et
npm init -y
# Gerekli bağımlılıkları yükle
npm install @google/generative-ai @supabase/supabase-js dotenv tsx typescript @types/node
# TypeScript ayarlarını yap
npx tsc --init
# Klasör ve dosya yapısını kurgula
mkdir scripts
touch .env
touch scripts/ingest-data.ts
Oluşması gereken nihai dosya yapısı:
node_modules/scripts/ingest-data.ts(Veri yükleme).env(Anahtarlar)package.jsonwebasistant-ai-chat.php(WordPress Eklentisi)
2. Veritabanı Katmanı: Supabase & pgvector
Yapay zekanın hafızası (RAG) için Supabase üzerinde vektör desteğini kuruyoruz. Supabase panelindeki SQL Editor kısmına bu bloğu yapıştırın ve Run deyin:
-- 1. Vektör eklentisini etkinleştir
create extension if not exists vector;
-- 2. Dökümanları saklayacağımız tablo
create table documents (
id bigserial primary key,
content text,
embedding vector(768) -- Gemini'nin vektör boyutu 768'dir
);
-- 3. Semantik Arama Fonksiyonu (RPC)
-- Bu fonksiyon, sorulan sorunun vektörü ile tablodaki en yakın 3 dökümanı getirir.
create or replace function match_documents (
query_embedding vector(768),
match_threshold float,
match_count int
) returns table (id bigint, content text, similarity float)
language plpgsql as $$
begin
return query
select documents.id, documents.content, 1 - (documents.embedding <=> query_embedding) as similarity
from documents
where 1 - (documents.embedding <=> query_embedding) > match_threshold
order by similarity desc
limit match_count;
end;
$$;
3. Verileri Vektörleştirip Yükleme: scripts/ingest-data.ts
VS Code içerisinde scripts/ingest-data.ts dosyasını açın ve şu kodları yapıştırın. Bu kod, metni alır, Gemini API ile vektöre çevirir ve Supabase’e yazar.
typescript kodu:
import { GoogleGenerativeAI } from "@google/generative-ai";
import { createClient } from '@supabase/supabase-js';
// Yapılandırma Bilgileri
const GOOGLE_KEY = "BURAYA_GOOGLE_API_KEY_GELECEK";
const SUPABASE_URL = "BURAYA_SUPABASE_URL_GELECEK";
const SUPABASE_KEY = "BURAYA_SUPABASE_ANON_KEY_GELECEK";
const genAI = new GoogleGenerativeAI(GOOGLE_KEY);
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
async function addDataToMemory(text: string) {
try {
console.log("🔄 Metin analiz ediliyor...");
// Gemini Embedding Modelini Çağırıyoruz
const model = genAI.getGenerativeModel({ model: "models/gemini-embedding-001" }, { apiVersion: 'v1beta' });
// Metni vektöre dönüştür
const result = await model.embedContent(text);
const embedding = result.embedding.values;
console.log("💾 Veritabanına yazılıyor...");
const { error } = await supabase.from('documents').insert({
content: text,
embedding: embedding
});
if (error) throw error;
console.log("✅ Başarıyla eklendi: " + text.substring(0, 50) + "...");
} catch (err) {
console.error("❌ Hata:", err);
}
}
// Örnek kullanım:
addDataToMemory("WebAsistantAI yıllık abonelik ücreti 1500 TL'dir ve sınırsız destek içerir.");
Çalıştırmak için terminale şunu yazın: npx tsx scripts/ingest-data.ts
4. WordPress Eklentisi: webasistant-ai-chat.php
İşte tüm yapıyı bir araya getiren, yönetim panelli ve AJAX destekli WordPress eklentisi. Bu dosyayı wp-content/plugins/webasistant-ai-chat/ içine koyun.
<?php
/*
Plugin Name: WebAsistant AI Master Pro
Description: Gemini 2.5 Flash ve Supabase RAG tabanlı, yönetim panelli tam teşekküllü AI asistanı.
Version: 2.0
Author: Senin Adın
*/
if (!defined('ABSPATH')) exit;
// 1. ADIM: WordPress Admin Menüsü
add_action('admin_menu', function() {
add_menu_page('WebAsistant AI', 'WebAsistant AI', 'manage_options', 'wai-settings', 'wai_render_settings', 'dashicons-id-alt');
});
function wai_render_settings() {
if (isset($_POST['wai_save'])) {
update_option('wai_settings', $_POST['wai_settings']);
echo '<div class="updated"><p>Ayarlar başarıyla kaydedildi.</p></div>';
}
$opt = get_option('wai_settings');
?>
<div class="wrap">
<h1>WebAsistant AI Yapılandırması</h1>
<form method="post">
<table class="form-table">
<tr><th>Google API Key</th><td><input type="text" name="wai_settings[g_key]" value="<?php echo esc_attr($opt['g_key']); ?>" class="regular-text"></td></tr>
<tr><th>Supabase URL</th><td><input type="text" name="wai_settings[s_url]" value="<?php echo esc_attr($opt['s_url']); ?>" class="regular-text"></td></tr>
<tr><th>Supabase Key</th><td><input type="text" name="wai_settings[s_key]" value="<?php echo esc_attr($opt['s_key']); ?>" class="regular-text"></td></tr>
<tr><th>Bot Adı</th><td><input type="text" name="wai_settings[name]" value="<?php echo esc_attr($opt['name']); ?>" placeholder="Örn: WebAsistant Destek"></td></tr>
<tr><th>Tema Rengi</th><td><input type="color" name="wai_settings[color]" value="<?php echo esc_attr($opt['color']); ?>"></td></tr>
</table>
<?php submit_button('Kaydet', 'primary', 'wai_save'); ?>
</form>
</div>
<?php
}
// 2. ADIM: Frontend Widget (Sohbet Penceresi)
add_action('wp_footer', function() {
$opt = get_option('wai_settings');
if (empty($opt['g_key'])) return;
$color = $opt['color'] ?: '#2271b1';
?>
<style>
#wai-chat-box { display: none; width: 350px; height: 500px; background: #fff; border-radius: 15px; position: fixed; bottom: 90px; right: 20px; flex-direction: column; box-shadow: 0 10px 25px rgba(0,0,0,0.2); overflow: hidden; border: 1px solid #eee; z-index: 999999; }
.wai-msg { padding: 10px 14px; border-radius: 15px; max-width: 80%; font-size: 14px; margin-bottom: 8px; line-height: 1.5; }
.wai-user { align-self: flex-end; background: <?php echo $color; ?>; color: #fff; border-radius: 15px 15px 0 15px; }
.wai-bot { align-self: flex-start; background: #f1f1f1; color: #333; border-radius: 15px 15px 15px 0; }
</style>
<div id="wai-chat-container" style="position: fixed; bottom: 20px; right: 20px; z-index: 999999; font-family: sans-serif;">
<div id="wai-chat-btn" style="background:<?php echo $color; ?>; width:60px; height:60px; border-radius:50%; cursor:pointer; display:flex; align-items:center; justify-content:center; color:#fff; font-size:30px; box-shadow:0 4px 15px rgba(0,0,0,0.3);">💬</div>
<div id="wai-chat-box">
<div style="background:<?php echo $color; ?>; color:#fff; padding:15px; font-weight:bold; display:flex; justify-content:space-between;">
<span><?php echo esc_html($opt['name']); ?></span>
<span id="wai-close" style="cursor:pointer">✕</span>
</div>
<div id="wai-messages" style="flex:1; overflow-y:auto; padding:15px; background:#fff; display:flex; flex-direction:column;">
<div class="wai-msg wai-bot">Merhaba, size nasıl yardımcı olabilirim?</div>
</div>
<div style="padding:10px; border-top:1px solid #eee; display:flex; gap:5px; background:#fff;">
<input type="text" id="wai-input" placeholder="Yazın..." style="flex:1; border:1px solid #ddd; padding:10px; border-radius:5px; outline:none;">
<button id="wai-send" style="background:<?php echo $color; ?>; color:#fff; border:none; padding:0 15px; border-radius:5px; cursor:pointer;">></button>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
$('#wai-chat-btn').click(() => $('#wai-chat-box').fadeToggle(200).css('display', 'flex'));
$('#wai-close').click(() => $('#wai-chat-box').hide());
function send() {
let s = $('#wai-input').val().trim(); if(!s) return;
$('#wai-messages').append('<div class="wai-msg wai-user">'+s+'</div>');
$('#wai-input').val('');
$('#wai-messages').scrollTop($('#wai-messages')[0].scrollHeight);
let lid = 'l-'+Date.now();
$('#wai-messages').append('<div id="'+lid+'" style="font-size:11px; color:#999; margin: 5px 0;">Düşünüyor...</div>');
$.post('<?php echo admin_url('admin-ajax.php'); ?>', { action: 'wai_ask_ai', question: s }, function(r) {
$('#'+lid).remove();
if(r.success) { $('#wai-messages').append('<div class="wai-msg wai-bot">'+r.data+'</div>'); }
$('#wai-messages').scrollTop($('#wai-messages')[0].scrollHeight);
});
}
$('#wai-send').click(send);
$('#wai-input').keypress(e => { if(e.which == 13) send(); });
});
</script>
<?php
});
// 3. ADIM: Arka Plan AJAX İşleyici (Gemini & Supabase Köprüsü)
add_action('wp_ajax_wai_ask_ai', 'wai_ajax_process');
add_action('wp_ajax_nopriv_wai_ask_ai', 'wai_ajax_process');
function wai_ajax_process() {
$opt = get_option('wai_settings');
$q = sanitize_text_field($_POST['question']);
// A. Embedding (Soru Vektörü)
$e_res = wp_remote_post("https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:embedContent?key=".$opt['g_key'], [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode(["content" => ["parts" => [["text" => $q]]], "outputDimensionality" => 768])
]);
$vec = json_decode(wp_remote_retrieve_body($e_res), true)['embedding']['values'];
// B. Supabase RAG (En Yakın Bilgiyi Bul)
$s_res = wp_remote_post($opt['s_url']."/rest/v1/rpc/match_documents", [
'headers' => ['Content-Type' => 'application/json', 'apikey' => $opt['s_key'], 'Authorization' => 'Bearer ' . $opt['s_key']],
'body' => json_encode(["query_embedding" => $vec, "match_threshold" => 0.1, "match_count" => 3])
]);
$docs = json_decode(wp_remote_retrieve_body($s_res), true);
$ctx = ""; if(!empty($docs)) { foreach($docs as $d) { $ctx .= $d['content'] . "\n"; } }
// C. Gemini 2.5 Flash ile Cevap Üret
$c_res = wp_remote_post("https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=".$opt['g_key'], [
'headers' => ['Content-Type' => 'application/json'],
'body' => json_encode(["contents" => [["parts" => [["text" => "Sen {$opt['name']} danışmanısın. Bilgiler:\n$ctx\nSoru: $q"]]]]])
]);
$ans = json_decode(wp_remote_retrieve_body($c_res), true)['candidates'][0]['content']['parts'][0]['text'];
wp_send_json_success($ans);
}
Sonuç
Bu rehberle, modern bir AI asistanının tüm katmanlarını geçtik:
- Vektör Hafızası: Supabase ile semantik arama kurduk.
- Veri İşleme: Node.js ile verileri “beyne” enjekte ettik.
- WordPress: Tüm yapıyı güvenli ve yönetilebilir bir eklentiye dönüştürdük.
Artık elinizde saniyeler içinde cevap veren, sitenizin her köşesinde çalışan ve tamamen sizin verilerinizle beslenen devasa bir yapay zeka asistanı var.