flare / flare-tasarim.md
ciyidogan's picture
Upload 2 files
e9e7e37 verified
|
raw
history blame
26.8 kB

🏗 Genel Mimari

Flare, Spark LLM motorunun üstünde çalışan, çok adımlı ve akıllı bir orchestration katmanıdır. Görevleri:

✅ Kullanıcıdan gelen mesajları Spark kullanarak sohbet halinde sürdürmek, ✅ Spark ile, kullanıcı mesajından intent ve parametre extraction akışını yönetmek, ✅ Eksik parametre değerleri için system prompt oluşturup, Spark ile insani mesaja dönüştürerek bu parametrelerin değerlerini kullanıcıya tamamlatmak, ✅ Doğru parameter değerleri ile API çağrıları yapmak, ✅ API cevabını Spark üzerinden insanileştirilmiş metne dönüştürmek ve kullanıcıya iletmek, ✅ Her şeyi session bazında, state machine mantığında takip etmek. ✅ TTS (Text-to-Speech) desteği ile bot yanıtlarını sesli olarak sunmak. ✅ STT (Speech-to-Text) desteği ile kullanıcıdan sesli girdi almak (gelecek özellik).

Bu yapı Parloa gibi sistemlerde kullanılan "flow engine + LLM + tool orchestration" yaklaşımına dayanır.

LLM Provider Abstraction

Flare, farklı LLM provider'larını desteklemek için abstraction layer kullanır. Desteklenen provider'lar:

  • Spark (HuggingFace): On-premise ve HuggingFace cloud deployment'lar için
  • GPT-4o (OpenAI): OpenAI API üzerinden GPT-4o modeli kullanımı için
  • GPT-4o-mini (OpenAI): Düşük maliyetli alternatif için GPT-4o-mini modeli

Work mode'a göre (hfcloud, cloud, on-premise, gpt4o, gpt4o-mini) uygun LLM provider seçilir ve tüm LLM çağrıları bu abstraction üzerinden yapılır. Bu sayede farklı LLM'ler aynı intent detection, parameter extraction ve response generation mantığıyla çalışabilir.

Spark Entegrasyonu

Spark servisinin base url'i service_config.jsonc dosyasında config.spark_endpoint olarak tanımlanmıştır.

Spark'a gönderilecek tüm request'lerde header'a Authorization: Bearer eklenmelidir. SPARK_TOKEN, .env dosyasında tanımlıdır.

GPT-4o Entegrasyonu

Work mode gpt4o veya gpt4o-mini seçildiğinde, Spark yerine OpenAI API kullanılır. OpenAI API key, config.cloud_token alanında şifrelenmiş olarak saklanır (mevcut encryption_utils kullanılarak).

GPT-4o için özel konfigürasyonlar:

  • Model seçimi: gpt-4o veya gpt-4o-mini
  • Temperature: 0-2 arası (varsayılan 0.3)
  • Max tokens: Response uzunluğu limiti
  • System prompt ve conversation history OpenAI format'ına dönüştürülür

Maliyet Optimizasyonu:

  • gpt-4o: ~$0.01-0.03 per konuşma
  • gpt-4o-mini: ~$0.001-0.003 per konuşma (10x daha ucuz)

TTS/STT Entegrasyonu

Flare, sesli etkileşim için TTS (Text-to-Speech) ve STT (Speech-to-Text) motorlarını destekler:

TTS (Text-to-Speech)

Desteklenen motorlar:

  • ElevenLabs: Yüksek kaliteli, çok dilli TTS desteği
  • Blaze: Alternatif TTS motoru (yakında)
  • No TTS: TTS devre dışı

TTS Konfigürasyonu service_config.jsonc içinde:

  • tts_engine: Kullanılacak motor ("no_tts", "elevenlabs", "blaze")
  • tts_engine_api_key: Motor API anahtarı (şifrelenmiş)

STT (Speech-to-Text)

Desteklenen motorlar:

  • ElevenLabs: Sesli girdi desteği
  • Flicker: Alternatif STT motoru (yakında)
  • No STT: STT devre dışı

STT Konfigürasyonu:

  • stt_engine: Kullanılacak motor
  • stt_engine_api_key: Motor API anahtarı (şifrelenmiş)

Chat'te TTS Kullanımı

  1. Chat başlatılırken "Use TTS" seçeneği işaretlenebilir
  2. Bot yanıtları otomatik olarak TTS ile seslendirilebilir
  3. Her mesaj için ayrı ses dosyası üretilir ve oynatılabilir
  4. Ses oynatma sırasında waveform visualizasyon gösterilir

Internal Prompt Mekanizması

Flare servisi, tüm LLM isteklerinde kullanılmak üzere merkezi bir internal_prompt tanımına sahiptir. Bu prompt, service_config.jsonc dosyasında config.internal_prompt olarak saklanır ve her intent detection işleminde project version'daki general_prompt'un başına otomatik olarak eklenir.

Internal prompt, LLM'in tutarlı davranış sergilemesi için gerekli temel kuralları içerir:

  • Intent detection formatı ve kuralları
  • Dil ayarları ( placeholder'ı ile)
  • Intent isimleri ve caption'ları ( ve placeholder'ları ile)
  • Selamlama ve small talk davranışları
  • Güvenlik kuralları

Bu mekanizma sayesinde tüm projeler arasında ve farklı LLM provider'ları arasında tutarlı bir davranış sağlanır. Internal prompt içindeki placeholder'lar runtime'da gerçek değerlerle değiştirilir:

  • : Proje versiyonu içinde tanımlı intentlerin name'leri, tırnak içinde ve virgülle ayrılmış şekilde
  • : Proje versiyonu içinde tanımlı intentlerin caption'ları, tırnak içinde ve virgülle ayrılmış şekilde
  • : Projenin default_language alanından alınan dil (Turkish, English, German, vb.)

Startup

Flare servisi ayağa kalktıktan sonra ilk iş olarak service_config.jsonc dosyasında tanımlı enabled=true olan her bir project için, projenin published=true olan en büyük id'ye sahip versiyonundaki bilgilerle startup işlemi yapar:

Spark Mode (hfcloud, cloud, on-premise): Spark servisine /startup request'i gönderir:

{
  "work_mode": "<config.work_mode>",
  "cloud_token": "<config.cloud_token>",
  "project_name": "<project.name>",
  "project_version": <project.version.id>,
  "repo_id": "<project.version.llm.repo_id>",
  "generation_config": <project.version.llm.generation_config>,
  "use_fine_tune": <project.version.llm.use_fine_tune>,
  "fine_tune_zip": "<project.version.llm.fine_tune_zip>"
}

GPT-4o Mode: OpenAI API key'in geçerliliği kontrol edilir. Ek startup işlemi gerekmez.

Chat

Chat request'leri work_mode'a göre ilgili LLM provider'a yönlendirilir:

Spark için /generate endpoint'ine:

{
  "project_name": "project1",
  "system_prompt": "you are an helpful virtual assistant...",
  "user_input": "en ekşi meyve nedir?",
  "context": [
    { "role": "user", "content": "Merhaba!" },
    { "role": "assistant", "content": "Merhaba, nasıl yardımcı olabilirim?" }
  ]
}

GPT-4o için OpenAI Chat Completion API'ye uygun formatta:

{
  "model": "gpt-4o",
  "messages": [
    { "role": "system", "content": "you are an helpful virtual assistant..." },
    { "role": "user", "content": "Merhaba!" },
    { "role": "assistant", "content": "Merhaba, nasıl yardımcı olabilirim?" },
    { "role": "user", "content": "en ekşi meyve nedir?" }
  ],
  "temperature": 0.3,
  "max_tokens": 512
}

🧠 İş Akışı

İş akışı tüm LLM provider'lar için aynıdır:

  1. Sohbet için bir session ve state takibi yapılacağından, Flare'e öncelikle, request body'de project_name bilgisi içeren bir /start_session request'i gönderilir.
  2. Flare unique bir session_id üretir ve bir session objesi yaratıp, session_id üzerinden indekslenmiş olan session dictionary'sine ekler ve response'ta session_id değerini döndürür. Session objesi içinde, gönderilen project_name'e karşılık gelen proje bilgileri (id, name, caption) ve proje tanımı altındaki versions array'indeki published=true olan version'lardan en büyük id'ye sahip olanın altındaki bilgileri (llm nesnesi hariç) alıp session nesnesine set eder. Oluşturduğu session'ın işleyişinde bundan sonra bu bilgileri kullanır.
  3. Session nesnesi içinde ayrıca sohbetin context'ini takip edeceği chat_history array'i ve intent tespit etmesi durumunda, tespit ettiği intent, extract edilen parametreler ve eksik parametreleri takip edeceği property'ler, session state gibi sohbet akışında ihtiyaç duyacağı bilgileri tutar.
  4. Ardından Flare'e bu session ile gönderilen tüm request'lerin header'ında X-Session-ID key içinde session_id değeri gönderilir.
  5. Flare, kendisine gelen /chat request'lerini işletirken header'daki X-Session-ID değerini alır (yoksa hata döndürür) ve gönderilen session_id ile session dictionary'sinden ilgili session nesnesini bulur, sohbeti işletmek için session nesnesindeki değerleri kullanır.
  6. Sohbet sırasında user_input bilgisi, session_id header'ıyla Flare'in /chat endpoint'ine gönderilir.

1️⃣ Intent Detection

  1. Kullanıcı mesajı alınır.
  2. LLM'e, kullanıcı mesajı, session'da tutulan sohbet tarihçesi ve session'da tutulan project version nesnesindeki intent tanımları birleştirilerek (detection_prompt ve intent detection'ı kolaylaştırma amaçlı örnek cümleler içeren examples kısmı) bir system prompt halinde gönderilir.
  3. Eğer kullanıcının söyledikleri bir intent içermiyorsa, LLM kullanıcıyla normal sohbet eder.
  4. LLM eğer intent belirlerse, parametreleri bu aşamada extract etmez. Bulduğu intent'in adını özel bir formatta döndürür. Örnek: #DETECTED_INTENT:search_flight_intent

2️⃣ Parametre Extraction

  1. Belirlenen intent'e göre beklenen parametre listesi çıkarılır.
  2. LLM'e, user_input ile birlikte parametre extraction_prompt'ları birleştirilip tek bir system prompt olarak gönderilir. LLM buradan parametre değerlerini extract eder ve özel bir formatta döndürür. Örnek: #PARAMETERS:{ "extracted": [ { "to_city": "İstanbul" } ], "missing": [ "to_city", "date"] }
  3. Döndürülen parametreler tanımdaki variable_name key'i ile session'a eklenir. Eğer birden fazla intent'te aynı variable_name'e sahip parametreler varsa, aynı değişken değerini paylaşırlar.

3️⃣ Eksik Parametre Tamamlama

  1. Zorunlu parametrelerden eksik olanlar varsa, Flare bunları kullanıcıdan istemek için uygun prompt'u hazırlar ve LLM'e gönderir. Bunun için, eksik parametrelerin tanımlarındaki name ve intent.parameters.extraction_prompt'lar birleştirilerek tek bir system prompt haline getirilir.
  2. LLM, kullanıcı cevabını işleyip tekrar extraction yapar ve yukarıdaki #PARAMETERS formatında Flare'e dönüş yapar. Eksik parametre değeri kalmayan kadar Flare-LLM iletişimi bu şekilde döner.
  3. Sohbette bir intent tespit edildiğinde, bu intent'in zorunlu bir parametresinin variable_name'i session'da zaten mevcutsa ve değer içeriyorsa, bu parametre tekrar extract edilmeye çalışılmaz, session'daki ilgili variable'dan alınıp kullanılır.

4️⃣ Parametre Validation

  1. Alınan her parameter değeri, parameter tanımındaki tip ve regex (min/max uzunluk gibi) kurallarla doğrulanır.
  2. Hatalı değerler varsa, bu parametrelerin invalid_prompt'ları birleştirilip LLM'e tek bir system prompt olarak gönderilir ve LLM kullanıcıya doğrudan döndürülecek insani hata mesajını oluşturup döndürür. Örnek: "Söylediğiniz uçuş numarası hatalı. Uçuş numaranız 6 haneli bir numara olmalıdır."

5️⃣ API Çağrısı

Tüm parametreler tamamlanınca Flare, intent'e bağlı API çağrısını yapar. Intent'e bağlı API adı, service_config.json'da ilgili intent nesnesinin action alanında tanımlıdır. Bu adı kullanarak apis altındaki ilgili api tanımına ulaşılabilir.

Bu aşamada kritik bir detay:

🔑 Eğer API tanımında auth bölümü varsa:

  • Api çağırılmadan önce, session içinde auth_tokens[api_name] var mı control edilir. Varsa bu token kullanılır.
  • Eğer yoksa, token alma işlemi yapılır.
  • Token almak için, token_endpoint ve body_template kullanılarak token api servisine request gönderilir, dönen json response içinden response_token_path json path'i kullanılarak token değeri alınır.
  • Alınan token session içinde auth_tokens[api_name] olarak saklanır.
  • Token expire ederse, token_refresh_endpoint ve token_refresh_body kullanılarak mevcut token refresh edilir.
  • Header ve body'lerdeki {auth_tokens.api_name.token} placeholder'ları bu token ile doldurulur.

Eğer auth tanımı yoksa, API çağrısı doğrudan yapılır. Bu mekanizma API erişiminde güvenlik ve süreklilik sağlar.

6️⃣ Response Mapping

API'den dönen JSON response'tan belirli değerleri session değişkenlerine aktarma mekanizmasıdır. Her API tanımında response_mappings array'i ile tanımlanır:

"response_mappings": [
  {
    "variable_name": "booking_id",
    "type": "str",
    "json_path": "booking.confirmation_number"
  },
  {
    "variable_name": "departure_time", 
    "type": "date",
    "json_path": "flight_details.departure.time"
  }
]

Bu mapping'ler API başarılı response döndüğünde (status 200) otomatik olarak işlenir. Belirtilen json_path'teki değerler, tanımlanan type'a göre dönüştürülüp session.variables içine variable_name ile kaydedilir.

Desteklenen type'lar: str, int, float, bool, date

Bu mekanizma sayesinde API response'larından alınan değerler, sonraki intent'lerde veya API çağrılarında kullanılabilir hale gelir.

7️⃣ API Cevabını İnsanileştirme

Api'den dönen ham json, api tanımı altındaki response_prompt ile birlikte LLM'e gönderilir ve akıcı, insani bir cevap üretilir.

Not: Api tanımındaki response_prompt içindeki {{api_response}} değeri, api'den dönen json string ile replace edilir.

Örnek: "response_prompt": "Aşağıdaki JSON döviz kuru bilgilerini içeriyor. Kullanıcıya anlaşılır bir Türkçe özet hazırla:\n\n{{api_response}}"

8️⃣ Session ve State Takibi

Her kullanıcı sohbeti bir session ID ile takip edilir. Session üzerinde:

  • Son 10 adet konuşma tarihçesi,
  • Son intent,
  • Toplanan parametreler,
  • Eksik parametreler,
  • Akışın neresinde olduğumuz (intent detection, parameter extraction, api call, response humanization)
  • Api token'ları

tutulur. Bu, çok adımlı akışlarda state kaybını engeller.

Date Type Desteği

Parametre tanımlarında "date" type'ı desteklenmektedir. Date parametreleri:

  • ISO format (YYYY-MM-DD) olarak saklanır
  • Türkçe tarih ifadeleri otomatik olarak parse edilir (bugün, yarın, 15 Temmuz, vb.)
  • Extraction prompt'larında güncel tarih context'i sağlanır
  • Validation sırasında geçerli tarih formatı kontrolü yapılır

🏗 Mimari Bileşenler

Bileşen Görev
LLM Interface Farklı LLM provider'larını abstract eden katman
Spark LLM HuggingFace Spark servisi ile iletişim
GPT-4o LLM OpenAI API ile iletişim
TTS Interface Farklı TTS provider'larını abstract eden katman
ElevenLabs TTS ElevenLabs TTS servisi ile iletişim
Flare Session Manager Her kullanıcı için session ve state takibi
Flare Prompt Engine Her aşamada LLM'e gönderilecek uygun system prompt'u dinamik hazırlayan yapı
API Connector Tanımlı API'lere parametrelerle çağrı yapan, auth/refresh yöneten katman
Validation Engine Parametre değerlerini tip ve format bazlı doğrulayan yapı
UI ve Config Katmanı Flare işleyiş konfigürasyonu ve api tanımları; version bazlı project tanımlamaları; project tanımı altında intent tanımları; intent tanımı altında parametre tanımlarını yöneten arayüz

📋 Yapılacaklar

✅ LLM abstraction layer geliştirilmesi ✅ Spark ile intent tespiti için system prompt tasarımı → Örnek cümlelerle zenginleştirme ✅ GPT-4o için prompt optimization ✅ Parametre extraction için intent bazlı prompt şablonları hazırlanması ✅ Eksik parametre tamamlama için eksik parametre bazlı prompt oluşturma ✅ Parametre tip tanımları ve validation engine geliştirilmesi ✅ API connector modülü → auth, refresh, token yönetimi, timeout, retry mantığı ile geliştirme ✅ Humanization prompt'larının API cevabına göre dinamik hazırlanması ✅ Session ve state machine geliştirme ✅ Response mapping mekanizması ✅ Internal prompt sistemi ✅ Date type desteği ✅ Multi-provider support ✅ TTS (Text-to-Speech) entegrasyonu ✅ ElevenLabs TTS provider ⏳ STT (Speech-to-Text) entegrasyonu ⏳ Blaze TTS provider ⏳ Flicker STT provider

🔑 Önemli Notlar (Unutulmaması Gerekenler)

  1. LLM prompt'ları tek seferde şişirilmemeli; sohbetin her aşamasında sadece gereken system prompt dinamik oluşturulup gönderilmeli.
  2. Parametre extraction'da ek bir model (BERT vb.) yerine sadece seçilen LLM kullanılacak.
  3. Intent başına (proje başına max ~8-10 intent), her bir intent için max ~5-6 örnek cümle şeklinde bir kapasite planlaması düşünülebilir.
  4. Parametre tip ve regex validation başarısızsa, LLM üzerinden insani bir hata mesajı oluşturulup kullanıcıya döndürülmeli.
  5. API response'larının insanileştirilmesi, kullanıcıya daha iyi bir deneyim sunmak için LLM'den geçmeli.
  6. API token yönetimi ve refresh mekanizması, Flare içinde güvenli ve izlenebilir şekilde tutulmalı.
  7. GPT-4o kullanımında token maliyetleri göz önünde bulundurulmalı, conversation history sınırlandırılmalı.
  8. Farklı LLM'lerin response formatları normalize edilmeli (#DETECTED_INTENT ve #PARAMETERS formatları korunmalı).
  9. TTS kullanımında API key güvenliği ve maliyet kontrolü sağlanmalı.
  10. Tüm API key'ler (OpenAI, ElevenLabs, vb.) şifrelenmiş olarak saklanmalı.

Servis Konfigürasyonu

Flare'in tanımlarını tutan bir document database gibi kullanacağımız service_config.jsonc dosyasının yapısı, örnek data ve alan açıklamaları ile birlikte aşağıdadır.

{
  // =====================================================
  // FLARE GLOBAL CONFIGURATION
  // =====================================================
  "config": {
    "work_mode": "hfcloud", // "hfcloud" | "cloud" | "on-premise" | "gpt4o" | "gpt4o-mini"
    "cloud_token": "<your cloud token or OpenAI API key>", // work_mode'a göre Spark token veya OpenAI API key (şifrelenmiş)
    "spark_endpoint": "https://ucsturkey-spark.hf.space", // Spark servisi URL (GPT mode'da kullanılmaz)
    "internal_prompt": "⚠️ **NEVER output \"#DETECTED_INTENT:\"...", // Merkezi LLM kuralları
    "project_id_counter": 1, // Yeni proje ID'leri için counter
    "last_update_date": "2025-06-08T12:00:00.000Z", // Race condition kontrolü için
    "last_update_user": "admin",
    
    // === TTS/STT Configuration ==============
    "tts_engine": "no_tts", // "no_tts" | "elevenlabs" | "blaze"
    "tts_engine_api_key": "enc:...", // Şifrelenmiş TTS API key
    "stt_engine": "no_stt", // "no_stt" | "elevenlabs" | "flicker"
    "stt_engine_api_key": "enc:...", // Şifrelenmiş STT API key
    
    // === Login Users (bcrypt hash + salt): Flare UI kullanılabilecek user'lar ==============
    "users": [
      {
        "username": "admin",
        "password_hash": "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
        "salt": "random_salt_string"
      }
    ]
  },

  // =====================================================
  // PROJECTS: Her bir proje bir virtual agent'ı tanımlar
  // =====================================================
  "projects": [
    {
      "id": 1,
      "name": "coronos_assistant", // Virtual agent adı
      "caption": "Coronos Sanal Asistan",
      "icon": "folder", // Material icon adı
      "description": "Coronos müşteri hizmetleri asistanı", // Proje açıklaması
      "enabled": true, // Kullanımda olma durumu
      "default_language": "tr", // Varsayılan dil kodu
      "supported_languages": ["tr", "en"], // Desteklenen diller
      "timezone": "Europe/Istanbul", // Saat dilimi
      "region": "tr-TR", // Bölge kodu
      "last_version_number": 1, // Projelerin version_number için versiyon counter. Artarak ilerler.
      "last_update_date": "2025-06-08T12:00:00.000Z",
      "last_update_user": "admin",
      "deleted": false,
      "created_date": "2025-06-08T12:00:00.000Z",
      "created_by": "admin",

      // --------------------------------------------------------
      // VERSIONS: Proje revizyonları ayrı bir version_number ile takip edilir.
      // Yayınlanmış versiyonlar üzerinde düzenleme yapılamaz.
      // Yeni versiyon oluşturumak için published versiyonlardan biri seçilir ve kopyası oluştulur, bu kopya üzerinde düzenleme yapılabilir.
      // --------------------------------------------------------
      "versions": [
        {
          "id": 1, // Proje versiyonu
          "caption": "v1",
          "published": true, // Versiyonun yayınlanma durumu.
          
          // === Virtual agent'ın yapabileceği işleri tarifler =========
          "general_prompt": "You are an airline assistant. You can book tickets, give information about booked tickets ...",
          
          // === LLM configuration =======================
          "llm": {
            // Spark mode için:
            "repo_id": "ytu-ce-cosmos/Turkish-Llama-8b-DPO-v0.1", // HuggingFace model repo ID
            "generation_config": { // LLM generation parametreleri
              "max_new_tokens": 128,
              "temperature": 0.3,
              "top_p": 0.7,
              "repetition_penalty": 1.1
            },
            "use_fine_tune": false, // LoRA fine-tune model kullanılma durumu
            "fine_tune_zip": "", // use_fine_tune: true ise, kullanılacak LoRA adapter zip'in URL'i
            
            // GPT-4o mode için (work_mode = "gpt4o" veya "gpt4o-mini" olduğunda kullanılır):
            "gpt_model": "gpt-4o", // "gpt-4o" | "gpt-4o-mini"
            "gpt_temperature": 0.3, // 0-2 arası
            "gpt_max_tokens": 512 // Maximum response token sayısı
          },
          
          // === INTENTS =================================
          "intents": [
            {
              "name": "currency_rate_intent", // alt çizgi, tire yok
              "caption": "Kur sorgulama",
              "locale": "tr-TR",
              "dependencies": [], // intent bağımlılıkları.
              
              // Intent detection
              "examples": [
                "What is the dollar rate?",
                "How much is the euro?"
              ],
              "detection_prompt": "Identify if user is asking for currency rate information.", // Intent detection için kullanılacak system prompt.
              
              // Parameters: Intent tespit edildiğinde, kullanıcının ifadesinden extract edilecek parametreler
              "parameters": [
                {
                  "name": "currency",
                  "caption": "Döviz cinsi", // Eksik parametreyi tamamlarken kullanıcıya söylenebilecek parametre adı
                  "type": "str", // "str" | "int" | "float" | "bool" | "date"
                  "required": true,
                  "variable_name": "currency", // Parametre değerini set edeceğimiz session değişkeni adı
                  "extraction_prompt": "Extract the currency code (USD, EUR, TRY) from the user message.", // Parametre extraction için kullanılacak system prompt
                  "validation_regex": "^(USD|EUR|TRY)$", // kullanıcıdan alınan parametre değerini validate etmek için kullanılacak regex. Opsiyonel.
                  "invalid_prompt": "Geçersiz para birimi girdiniz. USD, EUR veya TRY şeklinde giriniz.", // Parametre değeri invalid ise kullanıcıya söylenecek mesajı oluşturacak system prompt
                  "type_error_prompt": "Para birimi metin olmalıdır (ör: USD)." // Eğer parametre tipi hatalıysa kullanıcıya söylenecek mesajı oluşturacak system prompt
                }
              ],
              
              // API to call
              "action": "currency_api", // Bu intent tespit edilip, parametreleri tamamlandığında çağırılacak api'nin adı.
              
              // Fallbacks
              "fallback_timeout_prompt": "Kur servisinde gecikme yaşanıyor. Lütfen biraz sonra tekrar deneyin.", // Api timeout durumunda kullanıcıya söylenecek mesajı oluşturacak system prompt
              "fallback_error_prompt": "Kur bilgileri alınırken bir hata oluştu, daha sonra tekrar deneyebilir misiniz?" // Api hatası durumunda kullanıcıya söylenecek mesajı oluşturacak system prompt
            }
            // ... başka intent'ler
          ],
          
          "last_update_date": "2025-06-08T12:00:00.000Z",
          "last_update_user": "admin",
          "deleted": false,
          "created_date": "2025-06-08T12:00:00.000Z",
          "created_by": "admin",
          "publish_date": "2025-06-08T12:00:00.000Z",
          "published_by": "admin"
        }
        // ... yeni versiyonlar
      ]
    }
    // ... başka projeler
  ],

  // =====================================================
  // API DEFINITIONS (dict by name): Intent'lerde action olarak kullanılacak api tanımları
  // =====================================================
  "apis": [
    {
      "name": "currency_api",
      "url": "https://mock.api/currency",
      "method": "POST",
      
      // Headers as dict; placeholders destekler
      "headers": {
        "Content-Type": "application/json",
        "Authorization": "Bearer {{auth_tokens.currency_api.token}}"
      },
      
      // Body template
      "body_template": {
        "currency": "{{variables.currency}}"
      },
      
      // Timeout & retry
      "timeout_seconds": 5,
      "retry": {
        "retry_count": 3,
        "backoff_seconds": 2,
        "strategy": "static" // "static" | "exponential"
      },
      
      // Auth (optional)
      "auth": {
        "enabled": false,
        "token_endpoint": "https://mock.api/auth",
        "token_request_body": {},
        "response_token_path": "token", // json-path style. Ex: xx.yy.z
        "token_refresh_endpoint": null, // opsiyonel
        "token_refresh_body": {} // token_refresh_endpoint varsa zorunlu, yoksa opsiyonel.
      },
      
      "proxy": "", // Proxy (optional)
      
      // API response → human-friendly answer
      "response_prompt": "Aşağıdaki JSON döviz kuru bilgilerini içeriyor. Kullanıcıya anlaşılır bir Türkçe özet hazırla:\n\n{{api_response}}",
      
      // Response mapping
      "response_mappings": [
        {
          "variable_name": "exchange_rate",
          "type": "float",
          "json_path": "data.rate"
        }
      ],
      
      "last_update_date": "2025-06-08T12:00:00.000Z",
      "last_update_user": "admin",
      "deleted": false,
      "created_date": "2025-06-08T12:00:00.000Z",
      "created_by": "admin"
    }
  ],

  // =====================================================
  // ACTIVITY LOG
  // =====================================================
  "activity_log": [
    {
      "id": 1,
      "timestamp": "2025-06-08T12:00:00.000Z",
      "user": "admin",
      "action": "CREATE_PROJECT",
      "entity_type": "project",
      "entity_id": 1,
      "entity_name": "airline_agent",
      "details": "Created new project"
    }
  ]
}