Claris FileMaker ile OpenAI (ChatGPT) Semantic Find

Aşağıdaki rehber, Claris FileMaker ile OpenAI (ChatGPT) API’sini kullanarak basit bir “semantic find” (anlamsal arama) uygulaması oluşturmanın genel mantığını anlatır. Buradaki temel yaklaşım, OpenAI Embeddings özelliğini kullanarak verileri ve arama sorgusunu “vektör” formuna dönüştürmek ve benzerlik skoruna göre en alakalı kayıtları getirmektir. “Semantic find” dendiğinde kastedilen, metinlerin sadece kelime eşleşmesiyle değil, anlam düzeyinde bir benzerlik karşılaştırması yapmaktır.


Kavramsal Ön Bilgi

Embeddings (Vektör Temsili)

Embedding, bir metni (cümle, paragraf, belge vb.) matematiksel olarak bir vektör (örneğin 1536 boyutlu bir dizi) şeklinde temsil eder.

OpenAI’nin “text-embedding-ada-002” gibi modelleriyle kelimelerin ve cümlelerin anlamsal benzerliklerini ölçmek mümkün hale gelir.

İki metnin embedding’leri arasındaki kozinüs benzerliği (cosine similarity) veya Öklid mesafesi (euclidean distance) hesaplanarak hangi metinlerin birbirine anlam olarak daha yakın olduğu tespit edilebilir.

Neden Embeddings Tabanlı Yaklaşım?

Geleneksel FileMaker “Find” işlemi, büyük oranda kelime eşleşmesine dayanır (özel arama operatörleriyle bir ölçüde geliştirilebilir). Ancak “semantic find” ile “araba” ve “otomobil” kelimeleri arasındaki benzerliği ya da sinonimleri sezgisel olarak yakalayabilir, hatta metnin tüm bağlamını anlayabilirsiniz.


Genel Adımlar

Veritabanı Tasarımı

    Bir tablo (örneğin Documents) olsun. Aşağıdaki alanlara sahip olabilir:

    docID (Numara veya metin, benzersiz kimlik)

    docText (Metin, arama yapılacak içerik)

    docEmbedding (metin veya JSON alanı; embeddings verisini saklayacağımız yer)

    Metin İçin Embedding Alma

      docText alanındaki içeriği, OpenAI’nin Embeddings endpoint’ine (ör: https://api.openai.com/v1/embeddings) göndererek bir vektör (dizi) elde edeceğiz.

      Alınan bu dizi ([0.123, -0.045, 0.879, … ] gibi) docEmbedding alanına kaydedilir. Bu işlemi, tabloya yeni kayıt eklendikçe veya kayıt güncellendikçe otomatik olarak yapan bir script yazabilirsiniz.

      Kullanıcının Sorgusunu Embedding’e Dönüştürme

        Kullanıcı bir arama sorgusu (ör. “Hızlı ve ucuz bir otomobil arıyorum”) girdiğinde, aynı şekilde bu metni de OpenAI Embeddings API’sine gönderip sorgunun vektörel temsilini elde edersiniz (ör: $queryEmbedding).

        Benzerlik Hesaplaması

          Tüm kayıtlardaki docEmbedding alanıyla $queryEmbedding arasında bir benzerlik skoru (örneğin kozinüs benzerliği) hesaplanır.

          Daha yüksek skor, sorguyla daha yakından ilişkili bir metin anlamına gelir.

          Sonuçları Sıralama veya Filtreleme

            Kozinüs benzerliği belli bir eşik değerinin (ör. 0.80) üzerindeyse o kayıtları “benzer” kabul edip sonuç listesine dahil edebilirsiniz.

            Veya skorlamaya göre sıralama yaparak en yüksekten en düşüğe listelersiniz.

            Sonuçları Listeleme

              FileMaker tarafında bir “Sonuç” portalı veya liste görünümü oluşturarak kullanıcıya en alakalı kayıtları gösterin.


              Örnek Teknik Uygulama Adımları

              Aşağıdaki adımlar, “Embeddings” kullanan tipik bir “semantic find” için örnek betik akışı sağlar. Burada varsayım olarak text-embedding-ada-002 modelini kullanıyoruz. (Bu model, 1536 boyutlu bir vektör döndürür. Güncel OpenAI dokümantasyonunu mutlaka inceleyin.)

              Not: Aşağıdaki cURL örnekleri “Insert from URL” script adımında kullanılabilir.

              Kayıt Oluşturma / Güncelleme Script’i

              Amaç: Yeni bir belge eklendiğinde veya mevcut belge güncellendiğinde OpenAI’den embedding alıp docEmbedding alanına kaydetmek.

              // 1) Gerekli değişkenleri set et
              Set Variable [ $apiKey ; Value: "YOUR_OPENAI_API_KEY" ]
              Set Variable [ $text ; Value: Documents::docText ]
              
              // 2) JSON body oluştur
              Set Variable [ $jsonBody ; Value: 
              "{
                \"input\": \"" & Substitute($text; "\""; "\\\"") & "\",
                \"model\": \"text-embedding-ada-002\"
              }"
              ]
              
              // 3) Embedding endpoint URL
              Set Variable [ $url ; Value: "https://api.openai.com/v1/embeddings" ]
              
              // 4) API çağrısı yap
              Insert from URL [
                 Select;
                 With dialog: Off;
                 Target: $response;
                 URL: $url;
                 cURL options:
                 "--request POST " &
                 "--header \"Content-Type: application/json\" " &
                 "--header \"Authorization: Bearer " & $apiKey & "\" " &
                 "--data " & Quote($jsonBody)
              ]
              
              // 5) Dönen JSON içinde "data[0].embedding" yolunu al
              Set Variable [ $embedding ; Value: JSONGetElement($response; "data[0].embedding") ]
              
              // 6) docEmbedding alanına kaydet
              Set Field [ Documents::docEmbedding ; $embedding ]

              Bu script’i, OnRecordCommit veya özel bir buton üzerinden çalıştırabilirsiniz.

              $embedding tipik olarak [0.01, 0.234, -0.12, ...] şeklinde bir dizi (JSON Array) olacaktır.

              Kullanıcının Arama Sorgusu İçin Embedding Alma

              Amaç: Kullanıcı, “Ne arıyorsunuz?” benzeri bir alana sorgu girer. Bu sorgunun embedding’ini alıp diğer kayıtlarla karşılaştıracağız.

              // 1) Sorguyu al
              Set Variable [ $query ; Value: GlobalFields::UserSearchQuery ]
              
              // 2) JSON body
              Set Variable [ $jsonBody ; Value:
              "{
                \"input\": \"" & Substitute($query; "\""; "\\\"") & "\",
                \"model\": \"text-embedding-ada-002\"
              }"
              ]
              
              // 3) API çağrısı
              Insert from URL [
                 Select;
                 With dialog: Off;
                 Target: $response;
                 URL: "https://api.openai.com/v1/embeddings";
                 cURL options:
                 "--request POST " &
                 "--header \"Content-Type: application/json\" " &
                 "--header \"Authorization: Bearer YOUR_OPENAI_API_KEY\" " &
                 "--data " & Quote($jsonBody)
              ]
              
              // 4) $queryEmbedding i al
              Set Variable [ $queryEmbedding ; Value: JSONGetElement($response; "data[0].embedding") ]

              Benzerlik Hesaplama

              FileMaker’ın yerleşik olarak kozinüs benzerliği veya vektör matematiği fonksiyonları yoktur. Aşağıdaki yaklaşımlardan birini seçebilirsiniz:

              FileMaker’da “Custom Function” (Özel Fonksiyon)

                cosineSimilarity(vectorA; vectorB) şeklinde bir custom function yazıp, JSON içindeki vektörleri döngüyle parse ederek toplamları hesaplayabilirsiniz.

                Ardından her kayıt için cosineSimilarity(Documents::docEmbedding; $queryEmbedding) şeklinde bir değer elde edersiniz.

                Script Döngüsü ve JSONGetElement

                  Tüm kayıtları bir script ile dolaşarak embedding alanındaki dizi elemanlarını JSONGetElement ile çekip $queryEmbedding’in elemanlarıyla çarpar, toplamı alır, normları hesaplar vs.

                  Elde ettiğiniz skoru geçici bir alana (örneğin similarityScore) yazarsınız.

                  Dış Kaynak / Mikro Hizmet

                    Bazı geliştiriciler bu matematiksel işlemleri bir mikroserviste veya Python/R gibi bir ortamda yapıp sonucu FileMaker’a geri gönderirler.

                    Bu, büyük veri setlerinde performansı artırabilir.

                    Kozinüs Benzerliği Formülü:

                    [
                    \text{cosineSimilarity}(A, B)
                    = \frac{A \cdot B}{|A| \times |B|}
                    = \frac{\sum_{i=1}^{n} A_i \times B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \times \sqrt{\sum_{i=1}^{n} B_i^2}}
                    ]

                    Örnek bir pseudo-FMP Script (tam code değil, fikir vermek amaçlı):

                    // Tüm Documents kayıtlarında dön
                    Go to Layout [ "Documents" (Documents) ]
                    Show All Records
                    Go to Record/Request/Page [ First ]
                    
                    Loop
                      // docEmbedding i JSON array olarak çek
                      Set Variable [ $docVector ; Value: Documents::docEmbedding ]
                      // similarity score u hesapla
                      Set Variable [ $score ; Value: CosineSimilarity($docVector; $queryEmbedding) ]
                    
                      // Bir alana yazabilirsiniz veya geçici bir global alan tutabilirsiniz
                      Set Field [ Documents::similarityScore ; $score ]
                    
                      Go to Record/Request/Page [ Next ; Exit after last ]
                    End Loop
                    
                    // Ardından "similarityScore" a göre Sort yapıp en yüksek skorlu kayıtları gösterebilirsiniz.

                    Buradaki CosineSimilarity fonksiyonunu bir Custom Function olarak tanımlamanız gerekir (FM’de döngü, toplam vs. ile). Örneğin:

                    CosineSimilarity ( jsonVectorA ; jsonVectorB ) = 
                    Let([
                      ~countA = JSONListCount ( jsonVectorA );
                      ~countB = JSONListCount ( jsonVectorB )
                    ];
                      If(
                        ~countA ≠ ~countB;
                        0;
                        // ...döngüsel çarpım, norm hesaplama işlemleri...
                      )
                    )

                    Böyle bir fonksiyon yazmak biraz uğraştırabilir ama bir kez yazıldıktan sonra sürekli kullanabilirsiniz.

                    Sonuçları Listelemek

                    Benzerlik Skoruna Göre Sıralama

                    similarityScore alanına göre inen sırada sort ederek en alakalı kayıtları en üste alabilirsiniz.

                    Belirli Bir Eşik Değerine Göre Filtre

                      Örneğin similarityScore >= 0.80 olan kayıtları listeleyin.

                      Bu kayıtları bir “BUL” (Find) işlemiyle değil, muhtemelen bir If kontrolü veya İlişkili Kayıt (ör. global field = “1” ve similarityScore ilişkisi) kullanarak getirebilirsiniz.


                      ChatGPT Modeli İle “Semantic Find”

                      Yukarıda anlattığımız Embeddings yaklaşımı, “semantic search” için en doğru yol. Ancak daha küçük veri setlerinde, “Chat Completions” API’sini “arama verisini prompt’a gömerek” da kullanabilirsiniz. Örneğin, şöyle bir sistem mesajı verip:

                      “Aşağıda bir dizi belgenin özetleri var. Kullanıcının sorduğu soruyla en alakalı belgeyi belirle ve cevabı döndür.”

                      Ardından user mesajında hem doküman özetlerini hem de sorguyu verebilirsiniz. Bu, basit sistemlerde çalışabilir ama veri seti büyüdükçe performans ve token maliyeti artar.


                      Özet / Sonuç

                      Embeddings Altyapısını Kullanın:

                      Her kayıt için embedding’i bir defa alıp veritabanına kaydedin.

                      Kullanıcı sorgusunu embedding’e dönüştürüp kayıtlarla benzerlik skorunu hesaplayın.

                      FileMaker’da Vektör Karşılaştırması:

                      Kendi “custom function” veya bir script döngüsüyle kozinüs benzerliğini hesaplayın.

                      En benzer kayıtları listeleyin.

                      Optimizasyon ve Pratiklik:

                      Kayıt sayınız çok fazlaysa, bu işlemi bir “mikroservis/Python” katmanıyla hızlandırmayı düşünün.

                      Eşik değeri (ör. 0.75, 0.80) ile benzerlik sonuçlarını filtreleyerek kullanıcının görmek istemediği düşük alakalı sonuçları eleyin.

                      Böylece, Claris FileMaker içinde geleneksel “string find” yerine, anlam odaklı (semantic) bir arama sistemi kurgulayabilir; kullanıcıların yakın anlamlı kelime veya benzer içerik arayışlarını daha iyi karşılayan bir deneyim sunabilirsiniz.

                      Bir yanıt yazın

                      E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir