# Sonecentral metin asistanı API'si: dokümanın tamamı > Sonecentral metin asistanını kendi uygulamanızdan ve sitenizden çağırmak için genel API. OpenAI Chat Completions, OpenAI Responses ve Vercel AI SDK biçimleriyle çalışır; yanıtı WhatsApp'taki aynı asistan verir. Kaynak: https://docs.sonecentral.com/. Bu dosya https://docs.sonecentral.com/llms-full.txt adresinde yayınlanır ve her derlemede yeniden üretilir. Sayfalar kenar menüsündeki sırayla gelir; her sayfa kendi başlığı ve adresiyle başlar. --- # Giriş Sayfa: https://docs.sonecentral.com/ Markdown: https://docs.sonecentral.com/index.md > Sonecentral metin asistanınızı kendi uygulamanızdan ve sitenizden, sektörün bildiği OpenAI ve Vercel AI SDK biçimleriyle çağırın. > **Dokümanı ajanınıza verin.** Dokümanın tamamı tek bir Markdown dosyasında: https://docs.sonecentral.com/llms-full.txt . Kodlama ajanınıza bu adresi yapıştırın. Tek bir sayfa için o sayfanın .md adresini verin, örneğin https://docs.sonecentral.com/hizli-baslangic.md . Sayfaların listesi: https://docs.sonecentral.com/llms.txt ## Bu API ne yapar Sonecentral'da kurduğunuz metin asistanı WhatsApp'ta, Instagram'da ve Messenger'da müşterilerinize yanıt veriyor. Bu API aynı asistanı sizin uygulamanıza, sitenize ya da arka uç kodunuza açar. Yanıtı bir dil modeli değil, **sizin asistanınız** verir. Panelde yazdığınız talimat ve çalışma alanınızda tanımlı her şey burada WhatsApp, Instagram ve Messenger'daki gibi aynen geçerlidir: hizmetleriniz, ürünleriniz ve stokunuz, katalog öğeleriniz, ekibiniz, bölümleriniz, çalışma saatleriniz, işletme bilgileriniz, kampanyalarınız, kargo kurallarınız, fiyat listeniz ve iskonto yetkiniz, Bilgi Bankası'ndaki belgeler ve onlardan çıkarılan işletme verileri, sipariş ve randevu talepleri, ekibe devir. Çünkü ortada ikinci bir asistan yok: istek, WhatsApp mesajını yanıtlayan aynı çalışma zamanından geçer. Tek fark ziyaretçinin anonim olmasıdır. Asistan kişinin kendi kayıtlarına bakmaz, randevuyu kendisi kesinleştirmez; her sipariş ve randevu ekibinizin onayını bekleyen bir taleptir. ## Adres ve biçimler Bütün istekler tek adrese gider: ```txt https://pb.sonecentral.com/api/v1 ``` Üç biçimden birini seçin. Üçü de aynı asistanla, aynı sohbet kaydıyla çalışır. | Uç nokta | Biçim ve ne zaman | | --- | --- | | `POST /chat/completions` | OpenAI Chat Completions. OpenAI SDK'sı ya da onunla uyumlu bir istemci zaten elinizdeyse. | | `POST /responses` | OpenAI Responses. Sohbeti `previous_response_id` ile sürdürmek istiyorsanız. | | `POST /chat` | Vercel AI SDK. React ya da Next.js'te `useChat` ile sohbet penceresi yapıyorsanız. | `model` alanına asistanınızın kimliğini yazarsınız. Kimlikleri [Asistanlar ve modeller](https://docs.sonecentral.com/asistanlar-ve-modeller.md) sayfasındaki `GET /models` listeler. Anahtarınız tek bir asistana açıksa `"default"` yazmanız yeterli. ## Bilinmesi gerekenler - **Ziyaretçiler anonimdir.** API'den gelen kişinin kimliği doğrulanmaz. Asistan ona ürün, fiyat, stok ve randevu uygunluğu gibi herkese açık konularda yardım eder; geçmiş siparişler ya da mevcut randevular gibi kişisel kayıtları paylaşmaz. Ayrıntılar: [Siparişler, randevular ve gizlilik](https://docs.sonecentral.com/siparis-randevu-gizlilik.md). - **Yanıt balon balon gelir.** İşletmenin güvenlik kontrolleri yanıtın tamamına bakar, metin bu kontrollerden sonra yola çıkar. Akışta harf harf değil, mesaj mesaj ilerlersiniz. Ayrıntılar: [Akış](https://docs.sonecentral.com/akis.md). - **Zengin mesajlar düz metinle birlikte gelir.** Ürün kartları, düğmeler ve dosyalar yapılandırılmış veri olarak gelir; her birinin düz metin karşılığı da vardır. Ayrıntılar: [Zengin mesajlar](https://docs.sonecentral.com/zengin-mesajlar.md). - **Sohbetler Mesajlar ekranında görünür.** API'den açılan her sohbet Sonecentral'daki Mesajlar ekranında **API** kaynağıyla, ziyaretçi **API ziyaretçisi** adıyla görünür. Asistan gerektiğinde sohbeti ekibinize devreder; ekip oradan yazar, ziyaretçi bu yanıtları API'den okur. Ayrıntılar: [İnsan devri ve ekip yanıtları](https://docs.sonecentral.com/insan-devri.md). ## Uç noktalar | Uç nokta | Açıklama | | --- | --- | | `GET /models` | Anahtarın kullanabildiği asistanlar. [Asistanlar ve modeller](https://docs.sonecentral.com/asistanlar-ve-modeller.md) | | `GET /models/{id}` | Tek bir asistan. | | `POST /chat/completions` | OpenAI Chat Completions, akışlı ya da akışsız. [Chat Completions](https://docs.sonecentral.com/chat-completions.md) | | `POST /responses` | OpenAI Responses, akışlı ya da akışsız. [Responses API](https://docs.sonecentral.com/responses.md) | | `GET /responses/{id}` | Saklanan bir yanıt. | | `DELETE /responses/{id}` | Saklanan bir yanıtı siler. | | `GET /responses/{id}/input_items` | Bir yanıtın girdi öğeleri. | | `POST /responses/{id}/cancel` | Yanıt varsa her zaman `400 not_cancellable` döner, yoksa `404 response_not_found`; yanıtlar istek içinde tamamlanır. | | `POST /chat` | Vercel AI SDK UI mesaj akışı, yani `useChat`. [Vercel AI SDK](https://docs.sonecentral.com/vercel-ai-sdk.md) | | `GET /chat/{id}/stream` | `useChat({ resume: true })` için. Her zaman `204` döner. [Bağlantı koparsa](https://docs.sonecentral.com/vercel-ai-sdk.md#baglanti-koparsa) | | `GET /conversations/{id}` | Sohbetin kimde olduğu: asistanda ya da ekipte. [Sohbetin durumu](https://docs.sonecentral.com/insan-devri.md#sohbetin-durumu) | | `GET /conversations/{id}/messages` | Bir sohbetin mesajları; ekip yanıtlarını okumak için. [İnsan devri](https://docs.sonecentral.com/insan-devri.md) | | `GET /files/{id}` | Asistanın paylaştığı bir dosyanın imzalı indirme adresi. Anahtar istemez. [Dosyayı indirmek](https://docs.sonecentral.com/zengin-mesajlar.md#dosya-indirme) | | `GET /key` | Kullandığınız anahtarın özeti. [Kimlik doğrulama](https://docs.sonecentral.com/kimlik-dogrulama.md#anahtari-denetlemek) | Hepsi `OPTIONS` ön isteğine yanıt verir, bu yüzden tarayıcıdan tarayıcı anahtarıyla çağrılabilir. `GET /files/{id}` dışındaki her uç nokta anahtar ister ve anahtarın [sınırlarına](https://docs.sonecentral.com/limitler.md) sayılır. ## Sonraki adım [Hızlı başlangıç](https://docs.sonecentral.com/hizli-baslangic.md) ile anahtarınızı oluşturup ilk isteği gönderin. --- # Hızlı başlangıç Sayfa: https://docs.sonecentral.com/hizli-baslangic Markdown: https://docs.sonecentral.com/hizli-baslangic.md > Anahtarınızı oluşturun, asistanınızın kimliğini bulun ve ilk mesajı gönderin. > **Dokümanı ajanınıza verin.** Dokümanın tamamı tek bir Markdown dosyasında: https://docs.sonecentral.com/llms-full.txt . Kodlama ajanınıza bu adresi yapıştırın. Tek bir sayfa için o sayfanın .md adresini verin, örneğin https://docs.sonecentral.com/hizli-baslangic.md . Sayfaların listesi: https://docs.sonecentral.com/llms.txt Bir kodlama ajanıyla çalışıyorsanız işin en kısa yolu bu: yukarıdaki adresi ajanınıza verin, ne yapmak istediğinizi söyleyin. Kendiniz yazacaksanız aşağıdaki dört adım yeterli. ### Anahtar oluşturun Sonecentral'da **Metin asistanı** sayfasını açın ve **API anahtarları** bölümünden yeni anahtar oluşturun. Bu bölümü yalnız çalışma alanının yöneticileri görür. **Tür** alanında iki seçenek var: - **Sunucu anahtarı** `sk-sone-v1-` ile başlar ve arka uç kodunuz içindir. Tarayıcıya, mobil uygulama paketine ya da herkese açık bir depoya asla koymayın. - **Tarayıcı anahtarı** `pk-sone-v1-` ile başlar ve sitenizdeki sohbet penceresi içindir. Yalnız izin verdiğiniz sitelerden çalışır. Anahtar yalnız oluşturulduğu anda bir kez gösterilir. Hemen ortam değişkeni olarak saklayın: ```bash export SONE_API_KEY="sk-sone-v1-..." ``` Ayrıntılar: [Kimlik doğrulama ve anahtarlar](https://docs.sonecentral.com/kimlik-dogrulama.md). ### Asistanınızın kimliğini bulun ```bash curl https://pb.sonecentral.com/api/v1/models \ -H "Authorization: Bearer $SONE_API_KEY" ``` Listedeki `id`, `model` alanına yazacağınız değerdir. Anahtar tek bir asistana açıksa `"default"` yazmanız da yeter. ### İlk mesajı gönderin **curl** ```bash curl https://pb.sonecentral.com/api/v1/chat/completions \ -H "Authorization: Bearer $SONE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "default", "messages": [ { "role": "user", "content": "Yarın öğleden sonra randevu alabilir miyim?" } ] }' ``` **OpenAI JS** ```ts import OpenAI from 'openai'; const client = new OpenAI({ baseURL: 'https://pb.sonecentral.com/api/v1', apiKey: process.env.SONE_API_KEY, }); const completion = await client.chat.completions.create({ model: 'default', messages: [{ role: 'user', content: 'Yarın öğleden sonra randevu alabilir miyim?' }], }); console.log(completion.choices[0].message.content); ``` **OpenAI Python** ```python import os from openai import OpenAI client = OpenAI( base_url="https://pb.sonecentral.com/api/v1", api_key=os.environ["SONE_API_KEY"], ) completion = client.chat.completions.create( model="default", messages=[{"role": "user", "content": "Yarın öğleden sonra randevu alabilir miyim?"}], ) print(completion.choices[0].message.content) ``` **Vercel AI SDK** ```ts import { createOpenAI } from '@ai-sdk/openai'; import { generateText } from 'ai'; const sone = createOpenAI({ baseURL: 'https://pb.sonecentral.com/api/v1', apiKey: process.env.SONE_API_KEY, }); const { text } = await generateText({ model: sone.chat('default'), prompt: 'Yarın öğleden sonra randevu alabilir miyim?', }); console.log(text); ``` Kurulum: `npm i openai`, `pip install openai` ya da `npm i ai @ai-sdk/openai`. Örnekler `openai` 7 (Node), `openai` 2 (Python), `ai` 7 ve `@ai-sdk/openai` 4 ile denendi. ### Sohbeti sürdürün Yanıtta `choices[0].message.sone.conversation_id` gelir. Sonraki mesajda bunu `metadata` içinde geri gönderin; asistan önceki mesajları hatırlar. Yalnız yeni mesajı gönderdiğiniz için her mesaja bir `Idempotency-Key` de ekleyin: ağ hatasından sonra aynı anahtarla yeniden denerseniz mesaj iki kez kaydedilmez. ```ts // `sone` OpenAI tiplerinde yok; tipini Chat Completions sayfasında bulursunuz. const { sone } = completion.choices[0].message as unknown as { sone: { conversation_id: string }; }; await client.chat.completions.create( { model: 'default', metadata: { conversation_id: sone.conversation_id }, messages: [{ role: 'user', content: 'Saat dört uygun mu?' }], }, { headers: { 'Idempotency-Key': crypto.randomUUID() } }, ); ``` Başka yollar, yeniden deneme ve tarayıcıda saklama: [Sohbet sürekliliği](https://docs.sonecentral.com/sohbet-surekliligi.md). ## Buradan nereye - Sitenize sohbet penceresi koymak: [Site içine sohbet penceresi](https://docs.sonecentral.com/sohbet-penceresi.md) - React ve Next.js: [Vercel AI SDK](https://docs.sonecentral.com/vercel-ai-sdk.md) - Ürün kartları ve düğmeler: [Zengin mesajlar](https://docs.sonecentral.com/zengin-mesajlar.md) --- # Kimlik doğrulama ve anahtarlar Sayfa: https://docs.sonecentral.com/kimlik-dogrulama Markdown: https://docs.sonecentral.com/kimlik-dogrulama.md > Sunucu anahtarı ile tarayıcı anahtarı arasındaki fark, anahtarın nasıl gönderildiği, izin verilen siteler ve anahtarın nasıl iptal edildiği. ## İki anahtar türü | | Sunucu anahtarı | Tarayıcı anahtarı | | --- | --- | --- | | Biçim | `sk-sone-v1-` ve 48 harf ya da rakam | `pk-sone-v1-` ve 48 harf ya da rakam | | Nerede | Arka uç kodu, sunucusuz işlev, betik | Sitenizdeki sohbet penceresi | | Tarayıcıdan | Reddedilir (`403 secret_key_in_browser`) | Yalnız izin verilen sitelerden | | `user` ile sohbet bulma | Var | Yok, gönderilen değer yok sayılır | | Geliştirici bağlamı | Var | Yok, gönderilen bağlam yok sayılır | | Yeni sohbete aktarılan geçmiş | Ziyaretçi ve asistan satırları | Yalnız ziyaretçinin satırları | | İstek sınırı | Anahtar başına dakikada 120 | Ziyaretçi adresi başına dakikada 30; anahtar başına saatte 1.200 istek ve 20.000 okuma | | Otomatik yanıt sınırı | Çalışma alanının sınırı: saatte 60, günde 300 tur | Bu sınırın içinde bütün tarayıcı anahtarlarının ortak payı: saatte 40, günde 200 tur | Anahtarları Sonecentral'da **Metin asistanı** sayfasının **API anahtarları** bölümünde oluşturur, düzenler ve iptal edersiniz. Bu bölümü yalnız çalışma alanının yöneticileri görür. Bir çalışma alanında aynı anda en fazla 50 etkin anahtar olabilir; iptal edilen anahtarlar bu sayıya girmez. ## Anahtarı göndermek Anahtarı `Authorization` başlığında taşıyın: ```http Authorization: Bearer sk-sone-v1-... ``` `x-api-key` başlığı da kabul edilir. İkisi birden gelirse `Authorization` kullanılır. ```http x-api-key: sk-sone-v1-... ``` OpenAI SDK'ları ve Vercel AI SDK, `apiKey` seçeneğine verdiğiniz değeri zaten `Authorization: Bearer` olarak gönderir. ## Anahtar ne zaman gösterilir Anahtarın tamamı yalnız oluşturulduğu anda, bir kez gösterilir. Sonecentral onu saklamaz, yalnız özetini tutar; listede ilk karakterleri ve son dört karakteri görürsünüz. İstek kayıtlarımız da anahtarı tutmaz; `Authorization` ile de, `x-api-key` ile de gönderilse. Anahtarı kaybettiyseniz yenisini oluşturup eskisini iptal edin. ## Anahtarın ayarları Anahtar oluşturulurken şunlar seçilir: - **Ad.** Anahtarı listede tanımanız için, en fazla 80 karakter. `GET /key` yanıtında da görünür; gizli bilgi yazmayın. - **Tür.** Sunucu anahtarı ya da tarayıcı anahtarı. Tür sonradan değiştirilemez; gerekirse yeni anahtar oluşturun. - **Asistanlar.** Anahtarın çağırabileceği asistanlar. Hepsi seçilirse çalışma alanında yayında olan bütün asistanlar, sonradan yayınlananlar da. Henüz yayında olmayan bir asistan da seçilebilir; anahtar onunla asistan yayınlandığında çalışır. - **İzin verilen siteler.** Yalnız tarayıcı anahtarında. En az bir, en fazla 20 site. - **Sipariş ve randevu talebi alabilir.** Açıksa asistan bu sohbetlerde yeni sipariş ya da randevu talebi açabilir; talepler ekibinizin onayını bekler. Kapalıysa asistan isteği ayrıntılarıyla ekibe iletir. Varsayılan olarak açıktır. Ayrıntılar: [Siparişler, randevular ve gizlilik](https://docs.sonecentral.com/siparis-randevu-gizlilik.md). Tür dışındaki ayarlar sonradan düzenlenebilir; değişiklik bir sonraki istekte geçerli olur. ## İzin verilen siteler Tarayıcı, siteler arası her istekte `Origin` başlığını kendisi gönderir. Tarayıcı anahtarı yalnız `Origin` değeri listedeki sitelerden biriyle aynıysa kabul edilir. `Origin` başlığı olmayan bir istekte tarayıcı anahtarı kullanılamaz. Site adresleri şöyle yazılır: - `https://www.ornek.com` gibi, yalnız şema ve alan adı. Alan adında en az bir nokta olmalıdır. 443 dışında bir port gerekiyorsa `https://www.ornek.com:8443` gibi yazılır. - Yol, sorgu, `*` joker karakteri, IP adresi ve `https://localhost` kabul edilmez. - `https://ornek.com` ile `https://www.ornek.com` iki ayrı sitedir; ikisini de kullanıyorsanız ikisini de ekleyin. - Geliştirme için yalnız `http://localhost` ve `http://127.0.0.1` eklenebilir, portlu ya da portsuz: `http://localhost:3000`, `http://127.0.0.1:5173`. Bunun dışında `http` kabul edilmez. Alan adı küçük harfe çevrilerek karşılaştırılır. Listede olmayan bir siteden gelen istek `403 origin_not_allowed` ile reddedilir. ## Sunucu anahtarı tarayıcıda çalışmaz Sunucu anahtarı sitenizin koduna girerse onu herkes okuyabilir ve sizin adınıza istek gönderebilir. Bunun önüne geçmek için Sonecentral, `Origin` başlığında anahtarın listelemediği bir site taşıyan istekte sunucu anahtarını `403 secret_key_in_browser` ile reddeder. Panel sunucu anahtarına site eklemez; bu yüzden tarayıcıdan gelen her istek reddedilir. Tarayıcıda her zaman tarayıcı anahtarını kullanın. Bu bir güvenlik ağıdır, garanti değildir. Bilgisayardaki bir dosyadan ya da korumalı bir çerçeveden açılan sayfalar `Origin: null` gönderir. Sonecentral böyle bir isteği sunucudan gelen bir istekten ayıramaz ve reddetmez. Sunucu anahtarını tarayıcıya, mobil uygulama paketine ya da herkese açık bir depoya hiçbir zaman koymayın. > **Dikkat** > > OpenAI SDK'sının `dangerouslyAllowBrowser` seçeneği bu kuralı aşmaz. Tarayıcıda sunucu anahtarı yerine tarayıcı anahtarı kullanın. Tarayıcıdaki kodunuz yanıtın şu başlıklarını okuyabilir: `x-request-id`, `retry-after`, `x-should-retry` ve `x-sone-conversation-id`. ## Geliştirici bağlamı Sunucu anahtarıyla gönderdiğiniz `system` ve `developer` rolündeki mesajlar, Responses'taki `instructions` alanı ve Vercel AI SDK'daki `context` alanı asistana **yalnız bilgi olarak** iletilir. Örneğin ziyaretçinin hangi ürün sayfasında olduğunu ya da uygulamanızdaki dil tercihini bildirebilirsiniz. Bu metin işletmenin talimatını ve kurallarını değiştiremez; içindeki talimatlara uyulmaz. Birden çok bağlam alt alta birleştirilir ve en fazla 2.000 karakteri dikkate alınır. Responses'taki `instructions` 2.000 karakterden ya da JSON olarak 4 KB'tan uzunsa istek `400 instructions_too_long` alır. Bağlam, gönderildiği tur için geçerlidir: sonraki istekte göndermezseniz kalkar. Tarayıcı anahtarıyla gönderilen geliştirici bağlamı yok sayılır ve saklanmaz, çünkü onu ziyaretçi de değiştirebilir. ## İptal Anahtarı **API anahtarları** bölümünden iptal ettiğiniz anda kullanılamaz olur; sonraki istekler `401 revoked_api_key` alır. İptal geri alınmaz, iptal edilen anahtar düzenlenemez; gerekirse yeni anahtar oluşturun. Anahtarın açtığı sohbetler Mesajlar ekranında kalır. İptal edilen anahtarın sakladığı yanıtlar 30 gün sonra kendiliğinden silinir. Aynı asistanı çağırabilen yeni bir anahtar onları okuyabilir ve `previous_response_id` ile sürdürebilir, ama silemez; `instructions`, `safety_identifier` ve `user` alanlarını da göremez: [Saklanan yanıtlar](https://docs.sonecentral.com/responses.md#saklanan-yanitlar). ## Anahtarı denetlemek `GET /key` kullandığınız anahtarın özetini döner. Anahtarın doğru çalışma alanına ve asistanlara bağlı olduğunu kurulumda bununla doğrulayabilirsiniz. ```bash curl https://pb.sonecentral.com/api/v1/key \ -H "Authorization: Bearer $SONE_API_KEY" ``` ```json { "data": { "label": "pk-sone-v1-Ab3…", "name": "Web sitesi sohbeti", "kind": "publishable", "assistants": ["k3m9x2p7q1w8e4r"], "requests": true, "allowed_origins": ["https://www.ornek.com"], "limits": { "requests_per_minute_per_visitor": 30, "requests_per_hour": 1200, "read_requests_per_hour": 20000, "assistant_turns_per_hour": 60, "assistant_turns_per_day": 300, "browser_assistant_turns_per_hour": 40, "browser_assistant_turns_per_day": 200 } } } ``` | Alan | Tür | Açıklama | | --- | --- | --- | | `label` | string | Anahtarın ilk 14 karakteri ve üç nokta. Anahtarın tamamı hiçbir yanıtta yer almaz. | | `name` | string | Anahtara Sonecentral'da verdiğiniz ad. | | `kind` | "secret" \| "publishable" | secret sunucu anahtarı, publishable tarayıcı anahtarıdır. | | `assistants` | string[] | Anahtarın şu an çağırabildiği, yayında olan asistanların kimlikleri, adlarına göre sıralı. | | `requests` | boolean | Sipariş ve randevu talebi alabilir ayarı açık mı. | | `allowed_origins` | string[] | İzin verilen siteler. Sunucu anahtarında boştur. | | `limits` | object | Sunucu anahtarında requests_per_minute. Tarayıcı anahtarında requests_per_minute_per_visitor, requests_per_hour (okuma dışındaki istekler), read_requests_per_hour (okumalar) ve tarayıcı anahtarlarının otomatik yanıt payı: browser_assistant_turns_per_hour ve browser_assistant_turns_per_day. İkisinde de çalışma alanının API için saatlik ve günlük otomatik yanıt sınırı: assistant_turns_per_hour ve assistant_turns_per_day. | Sunucu anahtarında `limits` şöyledir: ```json { "requests_per_minute": 120, "assistant_turns_per_hour": 60, "assistant_turns_per_day": 300 } ``` `GET /key` isteği de bir okumadır ve anahtarın sınırına sayılır: [Limitler](https://docs.sonecentral.com/limitler.md). ## Hatalar | Durum | `code` | Ne zaman | | --- | --- | --- | | `401` | `missing_api_key` | Anahtar gönderilmedi. | | `401` | `invalid_api_key` | Anahtar tanınmadı, biçimi bozuk ya da öneki türüyle uyuşmuyor. | | `401` | `revoked_api_key` | Anahtar iptal edilmiş. | | `403` | `origin_not_allowed` | Tarayıcı anahtarı listede olmayan bir siteden ya da `Origin` başlığı olmadan kullanıldı. | | `403` | `secret_key_in_browser` | Sunucu anahtarı, anahtarın listelemediği bir sitedeki tarayıcıdan kullanıldı. | | `429` | `rate_limit_exceeded` | Anahtarın istek ya da okuma sınırı aşıldı. `Retry-After` kadar bekleyin. | Bütün hata kodları: [Hatalar](https://docs.sonecentral.com/hatalar.md). --- # Asistanlar ve modeller Sayfa: https://docs.sonecentral.com/asistanlar-ve-modeller Markdown: https://docs.sonecentral.com/asistanlar-ve-modeller.md > model alanına ne yazılır, asistanlar nasıl listelenir ve "default" ne anlama gelir. OpenAI biçiminde `model` bir dil modelinin adıdır. Burada ise **asistanınızın kimliğidir**: hangi asistanın yanıt vereceğini seçer. Dil modelini, talimatı ve araçları asistanın Sonecentral'daki ayarları belirler; istekten değiştirilemez. ## Asistan neleri kullanır API'deki asistan, WhatsApp'ta, Instagram'da ve Messenger'da yanıt veren asistanın kendisidir. Çalışma alanınızda tanımlı her şeyi orada nasıl kullanıyorsa burada da aynen öyle kullanır: - hizmetleriniz; fiyat, süre, görsel ve bağlantılarıyla, - ürünleriniz ve stokunuz; fiyat, görsel ve bağlantılarıyla, - katalog öğeleriniz ve paketleriniz, - ekibiniz, bölümleriniz ve çalışma saatleriniz, - işletme bilgileriniz: ad, adres ve telefon, - bağlı mağazanızın kargo kuralları ve kampanyaları, - fiyat listeniz ve tanımladıysanız iskonto yetkiniz, - Bilgi Bankası'ndaki belgeler, gönderilebilir olarak tanımladığınız belgeler ve belgelerinizden çıkarılan işletme verileri, - anahtarda talep ayarı açıksa sipariş ve randevu talepleri ile uygun randevu saatleri, - ekibe not bırakmak ve sohbeti ekibe devretmek. Ürün ve hizmet kartları, düğmeler ve dosyalar yapılandırılmış veri olarak gelir: [Zengin mesajlar](https://docs.sonecentral.com/zengin-mesajlar.md). API ziyaretçisinin kimliği doğrulanmadığı için asistan bilerek şunları yapmaz: kişinin kendi kayıtlarını (geçmiş siparişler, mevcut randevular, müşteri kartı, hatırlanan bilgiler, bağlı paneldeki hesap) okumaz ya da değiştirmez ve randevuyu kendisi kesinleştirmez. Ayrıntılar: [Siparişler, randevular ve gizlilik](https://docs.sonecentral.com/siparis-randevu-gizlilik.md). ## Asistanları listelemek ```bash curl https://pb.sonecentral.com/api/v1/models \ -H "Authorization: Bearer $SONE_API_KEY" ``` ```json { "object": "list", "data": [ { "id": "k3m9x2p7q1w8e4r", "object": "model", "created": 1760889600, "owned_by": "sonecentral", "name": "Mağaza asistanı" } ] } ``` Liste yalnız **anahtarın çağırabildiği** ve **yayında olan** asistanları içerir. Taslak ya da kurulumu bitmemiş bir asistan listede görünmez. Sıra, asistanların adına göredir. | Alan | Tür | Açıklama | | --- | --- | --- | | `id` | string | Asistanın kimliği. model alanına bu yazılır. | | `object` | "model" | Her zaman model. | | `created` | integer | Asistanın oluşturulduğu an, Unix saniyesi. | | `owned_by` | "sonecentral" | Her zaman sonecentral. | | `name` | string | Asistanın paneldeki adı. | Tek bir asistan için `GET /models/{id}` aynı nesneyi döner. ```bash curl https://pb.sonecentral.com/api/v1/models/k3m9x2p7q1w8e4r \ -H "Authorization: Bearer $SONE_API_KEY" ``` OpenAI SDK'larında aynı şey `client.models.list()` ve `client.models.retrieve(id)` ile yapılır. `model` değerinde son `/` işaretinden öncesi yok sayılır. Bu yüzden model adlarının önüne sağlayıcı adı koyan araçlarda `sonecentral/k3m9x2p7q1w8e4r` gibi bir değer de aynı asistanı seçer. ## `"default"` `model` boş bırakılırsa ya da `"default"` yazılırsa asistan şu sırayla seçilir: 1. Anahtar yalnız bir asistanı çağırabiliyorsa o asistan. 2. Değilse, anahtar onu çağırabiliyorsa çalışma alanının varsayılan metin asistanı. 3. O da yoksa anahtarın çağırabildiği asistanlardan adı alfabede ilk gelen. Anahtarınız birden çok asistana açıksa ve hangisinin yanıt vereceği önemliyse kimliği açıkça yazın. ## Sohbet ve asistan Bir sohbet açıldığı asistana bağlıdır. Aynı sohbeti başka bir `model` ile sürdürmeye çalışırsanız istek `400 conversation_model_mismatch` alır. Aynı asistanla sürdürün ya da yeni bir sohbet başlatın. ## Hatalar | Durum | `code` | Ne zaman | | --- | --- | --- | | `404` | `model_not_found` | Bu kimlikte yayında bir asistan yok ya da anahtar onu çağıramaz. Asistan taslaktaysa ya da kurulumu bitmemişse de bu kod gelir. | | `400` | `conversation_model_mismatch` | Sohbet başka bir asistanla açılmış. | --- # Chat Completions Sayfa: https://docs.sonecentral.com/chat-completions Markdown: https://docs.sonecentral.com/chat-completions.md > POST /chat/completions ile OpenAI Chat Completions biçiminde mesaj gönderin; yanıtın sone alanı sohbetin kimliğini, durumunu ve zengin mesajları taşır. ```http POST https://pb.sonecentral.com/api/v1/chat/completions ``` OpenAI Chat Completions'ın istek ve yanıt biçimini kullanır. OpenAI SDK'ları, LangChain ve OpenAI uyumlu her istemci `baseURL` değiştirilerek çalışır. ## İstek ```json { "model": "default", "messages": [ { "role": "user", "content": "Bu hafta sonu açık mısınız?" } ], "metadata": { "conversation_id": "conv_x8k2m9p4q7w1r3t" }, "stream": false } ``` | Alan | Tür | Açıklama | | --- | --- | --- | | `model` | string | Asistanın kimliği ya da "default". Asistanlar ve modeller sayfası kimliklerin nasıl bulunduğunu anlatır. Zorunlu. | | `messages` | array | Sohbetin mesajları. Son assistant mesajından sonraki user mesajları yeni mesaj sayılır, en fazla 12 tane. Öncekiler yalnız sohbeti bulmak ve yeni bir sohbeti başlatmak için okunur. Zorunlu. | | `stream` | boolean | true ise yanıt sunucu tarafından gönderilen olaylarla, yani SSE ile akar. Varsayılan: false. | | `stream_options` | object | include_usage: true ise akışın sonunda kullanım bilgisi gelir. | | `conversation_id` | string | Sonecentral uzantısı. Sürdürülecek sohbetin kimliği. | | `metadata` | object | Yalnız metadata.conversation_id okunur ve conversation_id ile aynı işi görür. Geri kalanı kullanılmaz, saklanmaz. | | `user` | string | Yalnız sunucu anahtarıyla dikkate alınır. Kendi sisteminizdeki ziyaretçi kimliği; aynı değer aynı sohbeti bulur. | | `safety_identifier` | string | user ile aynı işi görür. İkisi birden gelirse bu kullanılır. | Sohbetin kimliği birden çok yoldan gelebilir. Sonecentral ilk dolu olanı şu sırayla kullanır: 1. Gövdedeki `conversation_id`. 2. Gövdedeki `sone.conversation_id`. 3. `X-Sone-Conversation-Id` başlığı. 4. `metadata.conversation_id`. 5. Geçmişe olduğu gibi eklediğiniz bir asistan mesajının `sone.conversation_id` alanı. Birden çok varsa en sonuncusu. Kimlik hiç gelmezse sohbet başka yollarla aranır: [Sohbet sürekliliği](https://docs.sonecentral.com/sohbet-surekliligi.md#sohbet-nasil-bulunur). ### Mesaj rolleri | Rol | Ne olur | | --- | --- | | `user` | Ziyaretçinin mesajı. `content` metin ya da `text` parçalarından oluşan bir dizi olabilir. | | `assistant` | Önceki asistan yanıtı. Sohbeti bulmak için okunur. Sunucu anahtarıyla yeni bir sohbet açılırken geçmiş olarak da aktarılır. | | `system`, `developer` | Sunucu anahtarıyla asistana yalnız bilgi olarak iletilir, en fazla 2.000 karakter. Tarayıcı anahtarıyla yok sayılır. Ayrıntılar: [Geliştirici bağlamı](https://docs.sonecentral.com/kimlik-dogrulama.md#gelistirici-baglami). | | `tool`, `function` | Yok sayılır. | Başka bir rol `400 invalid_role` alır. Son mesaj metin taşıyan bir `user` mesajı değilse istek `400 missing_user_message` alır. Yeni bir mesaj 4.000 karakterden uzunsa `400 message_too_long` gelir. Yeni mesajda görsel, ses ya da dosya parçası varsa istek `400 unsupported_content` alır. Önceki mesajlardaki bu tür parçalar sessizce atlanır, yalnız metinleri okunur. ### Yok sayılan ve desteklenmeyen alanlar Asistanın dil modelini, üslubunu ve araçlarını Sonecentral'daki ayarlar belirler. Bu yüzden şu alanlar **yok sayılır**, hata vermez: `temperature`, `top_p`, `max_tokens`, `max_completion_tokens`, `presence_penalty`, `frequency_penalty`, `seed`, `stop`, `logit_bias`, `logprobs`, `top_logprobs`, `reasoning_effort`, `verbosity`, `service_tier`, `store`, `parallel_tool_calls`, `tool_choice`, `function_call`, `audio`, `modalities`. Burada sayılmayan bilinmeyen alanlar da yok sayılır. Şunlar **reddedilir**: | Alan | Hata | | --- | --- | | `tools`, `functions` | `400 tools_not_supported`. Asistan işletmenin kendi araçlarını kullanır. | | `n`, 1 dışında | `400 unsupported_parameter` | | `response_format`, `text` dışında | `400 unsupported_parameter` | ## Yanıt ```json { "id": "chatcmpl-9f2c4a7e1b8d3f6a0c5e2b9d", "object": "chat.completion", "created": 1760866000, "model": "k3m9x2p7q1w8e4r", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Evet, cumartesi 10.00 ile 18.00 arası açığız. Pazar kapalıyız.", "refusal": null, "annotations": [], "sone": { "conversation_id": "conv_x8k2m9p4q7w1r3t", "status": "answered", "messages": [ { "id": "msg_p4q7w1x8k2m9a5z", "role": "assistant", "type": "text", "text": "Evet, cumartesi 10.00 ile 18.00 arası açığız. Pazar kapalıyız.", "created_at": 1760866000 } ] } }, "logprobs": null, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 7, "completion_tokens": 16, "total_tokens": 23 }, "system_fingerprint": null, "sone": { "conversation_id": "conv_x8k2m9p4q7w1r3t", "status": "answered" } } ``` `model` yanıt veren asistanın kimliğidir; `"default"` gönderseniz de seçilen asistanın kimliği gelir. Sohbetin kimliği ayrıca `X-Sone-Conversation-Id` yanıt başlığında gelir. `content`, bu turda gönderilen bütün mesajların düz metnidir; birden çok mesaj araya boş satır, yani `\n\n` konularak birleştirilir. Yalnız `content` gösteren bir istemci de eksiksiz çalışır. `usage` bilgi içindir; gönderilen yeni mesajların ve gelen metnin uzunluğundan, yaklaşık dört karakter bir belirteç sayılarak tahmin edilir. Faturalama bu sayılara göre yapılmaz. ### `sone` alanı OpenAI biçimine eklenen alan budur. Tam hali `choices[0].message.sone` içinde gelir. Aynı özet, `messages` olmadan, yanıtın üst düzeyinde de vardır. | Alan | Tür | Açıklama | | --- | --- | --- | | `conversation_id` | string | Sohbetin kimliği, conv_ ile başlar. Sonraki isteklerde geri gönderin. | | `status` | "answered" \| "handoff" \| "human" \| "silent" | Bu turun sonucu. Değerler aşağıdaki tabloda. | | `messages` | SoneMessage[] | Bu turda gönderilen mesajlar, gönderildikleri sırayla. Biçimi Zengin mesajlar sayfasında. | | `status` | Anlamı | `content` | | --- | --- | --- | | `answered` | Asistan yanıt verdi. | Yanıt metni | | `handoff` | Sohbet bu turda ekibe geçti ve ziyaretçiye bir mesaj yazıldı, genellikle devri söyleyen mesaj. | Devir mesajı | | `human` | Sohbet ekipte. Asistan yanıt vermedi; mesaj ekibe ulaştı. | Boş | | `silent` | Yanıt gerekmedi, örneğin "teşekkürler" gibi bir kapanış. | Boş | `handoff` ve `human` durumunda ekibin yanıtlarını nasıl okuyacağınız [İnsan devri ve ekip yanıtları](https://docs.sonecentral.com/insan-devri.md) sayfasında. TypeScript'te bu alanları kendiniz tanımlayın: ```ts title="sone.ts" import type { SoneMessage } from './sone-message'; // Zengin mesajlar sayfasındaki tanım export type SoneStatus = 'answered' | 'handoff' | 'human' | 'silent'; // Akışsız yanıtta choices[0].message.sone export type SoneTurn = { conversation_id: string; status: SoneStatus; messages: SoneMessage[]; }; // Akışta bir parçanın üst düzeyindeki sone: her parçada yalnız biri dolu export type SoneChunk = { message?: SoneMessage; // bir mesaj tamamlandı activity?: string; // asistan bir işe bakıyor: "Ürünlere bakılıyor" conversation_id?: string; // son parçada status?: SoneStatus; // son parçada }; export const soneOfMessage = (message: unknown) => (message as { sone?: SoneTurn }).sone; export const soneOfChunk = (chunk: unknown) => (chunk as { sone?: SoneChunk }).sone; ``` Python'da OpenAI modelleri bilinmeyen alanları korur: ```python sone = completion.choices[0].message.to_dict().get("sone", {}) print(sone.get("conversation_id"), sone.get("status")) ``` ## Akış `"stream": true` ile yanıt `text/event-stream` olarak gelir. Parçalar şu sırayla gelir: 1. **İlk parça**, anahtar, sınır ve paket kontrolleri geçip asistan yanıtlamaya başladığında gelir: `delta` rolü taşır. Bu kontrollerden geçmeyen istek akış yerine sıradan bir HTTP hatası alır. 2. Asistan bir araç kullanırken **durum parçası** gelebilir: `delta` boştur, üst düzeydeki `sone.activity` "Ürünlere bakılıyor" gibi kısa bir metindir. 3. Her mesajın metni kelime grupları halinde `delta.content` olarak akar. İkinci ve sonraki mesajlar `\n\n` ile başlar. Bir mesajın **son parçası** ayrıca üst düzeyde `sone.message` taşır: o mesajın tamamı, `SoneMessage` biçiminde. Metni boş bir mesaj, `delta`'sı boş tek bir parçayla gelir. 4. **Son parça**: `finish_reason` `"stop"`, `delta` boş, üst düzeyde `sone` içinde `conversation_id` ve `status`. 5. `stream_options.include_usage` açıksa `choices` dizisi boş, `usage` dolu bir parça daha gelir. Bu durumda önceki bütün parçalarda `"usage": null` vardır. 6. Akış `data: [DONE]` ile biter. `sone` her zaman parçanın üst düzeyindedir, `choices[0].delta` içinde değildir. Sohbetin kimliği akış başlarken `X-Sone-Conversation-Id` yanıt başlığında da gelir. ```txt data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]} data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":null}],"sone":{"activity":"Çalışma saatlerine bakılıyor"}} : ping data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{"content":"Evet, cumartesi 10.00 ile "},"logprobs":null,"finish_reason":null}]} data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{"content":"18.00 arası açığız. Pazar "},"logprobs":null,"finish_reason":null}]} data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{"content":"kapalıyız."},"logprobs":null,"finish_reason":null}],"sone":{"message":{"id":"msg_p4q7w1x8k2m9a5z","role":"assistant","type":"text","text":"Evet, cumartesi 10.00 ile 18.00 arası açığız. Pazar kapalıyız.","created_at":1760866000}}} data: {"id":"chatcmpl-9f2c","object":"chat.completion.chunk","created":1760866000,"model":"k3m9x2p7q1w8e4r","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"sone":{"conversation_id":"conv_x8k2m9p4q7w1r3t","status":"answered"}} data: [DONE] ``` Örnekteki kimlikler kısaltıldı. **OpenAI JS** ```ts import type { SoneMessage } from './sone-message'; import { soneOfChunk } from './sone'; const stream = await client.chat.completions.create({ model: 'default', messages: [{ role: 'user', content: 'Bu hafta sonu açık mısınız?' }], stream: true, }); const messages: SoneMessage[] = []; for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta.content ?? ''); const sone = soneOfChunk(chunk); if (sone?.message) messages.push(sone.message); // zengin mesajı burada çizin if (sone?.activity) console.log(`\n${sone.activity}…`); if (sone?.status) console.log('\nsohbet:', sone.conversation_id, sone.status); } ``` **OpenAI Python** ```python stream = client.chat.completions.create( model="default", messages=[{"role": "user", "content": "Bu hafta sonu açık mısınız?"}], stream=True, ) messages = [] for chunk in stream: if chunk.choices: print(chunk.choices[0].delta.content or "", end="", flush=True) sone = chunk.to_dict().get("sone") or {} if "message" in sone: messages.append(sone["message"]) # zengin mesajı burada çizin elif "activity" in sone: print(f"\n{sone['activity']}…") elif "status" in sone: print("\nsohbet:", sone["conversation_id"], sone["status"]) ``` Akış başladıktan sonra bir hata olursa `data: {"error": {…}}` parçası ve ardından `data: [DONE]` gelir. OpenAI SDK'ları bu parçayı hata olarak fırlatır. Ayrıntılar: [Hatalar](https://docs.sonecentral.com/hatalar.md#akis-sirasinda-hata). Metnin neden kelime kelime değil mesaj mesaj ilerlediği ve bağlantının nasıl canlı tutulduğu: [Akış](https://docs.sonecentral.com/akis.md). ## Tekrar denemek Her yeni mesajda yeni bir `Idempotency-Key` gönderin, en fazla 200 karakter. Ağ hatasından sonra aynı mesajı yeniden gönderirken aynı değeri koyun. Sonecentral aynı mesajı ikinci kez kaydetmez: yanıt verilmişse aynı yanıt yeniden döner, asistan iki kez yanıt vermez. Aynı anahtarı başka bir metinle gönderirseniz istek `422 idempotency_key_reused` alır. Tarayıcı anahtarıyla, sohbetin kimliği olmadan başka bir ağ adresinden gelen deneme, örneğin sohbetin ilk mesajı, yeni sohbet açar: [Tekrar denemek](https://docs.sonecentral.com/sohbet-surekliligi.md#tekrar-denemek). OpenAI SDK'ları bu başlığı kendileri eklemez. İsteğin seçeneklerinde verin; SDK'nın kendi yeniden denemeleri de aynı başlığı gönderir: **OpenAI JS** ```ts const key = crypto.randomUUID(); // mesaj başına bir kez üretin, yeniden denerken aynısını kullanın const completion = await client.chat.completions.create( { model: 'default', metadata: { conversation_id: 'conv_x8k2m9p4q7w1r3t' }, messages: [{ role: 'user', content: 'Bu hafta sonu açık mısınız?' }], }, { headers: { 'Idempotency-Key': key } }, ); ``` **OpenAI Python** ```python import uuid key = str(uuid.uuid4()) # mesaj başına bir kez üretin, yeniden denerken aynısını kullanın completion = client.chat.completions.create( model="default", metadata={"conversation_id": "conv_x8k2m9p4q7w1r3t"}, messages=[{"role": "user", "content": "Bu hafta sonu açık mısınız?"}], extra_headers={"Idempotency-Key": key}, ) ``` Bütün geçmişi ve sohbetin kimliğini her istekte gönderiyorsanız Sonecentral, ilk mesaj dışında, yeniden gönderilen mesajı geçmişin sonuna bakarak da tanır. Kimliği olmadan yalnız geçmişle gelen adsız bir deneme sohbeti bulmaz: yeni bir sohbet açar ve asistan yeniden yanıt verir. Sohbetin ilk mesajı, yalnız yeni mesajı gönderen ve kimliği saklamayan istemciler için tek güvenli yol anahtardır; bu yüzden her mesajda gönderin. Ayrıntılar: [Tekrar denemek](https://docs.sonecentral.com/sohbet-surekliligi.md#tekrar-denemek). ## Hatalar | Durum | `code` | Ne zaman | | --- | --- | --- | | `400` | `missing_user_message` | Son mesaj metin taşıyan bir `user` mesajı değil. | | `400` | `invalid_role` | Tanınmayan bir mesaj rolü. | | `400` | `invalid_content` | Bir mesajın `content` alanı metin ya da parça dizisi değil. | | `400` | `unsupported_content` | Yeni mesajda görsel, ses ya da dosya var. | | `400` | `message_too_long` | Yeni bir mesaj 4.000 karakterden uzun. | | `400` | `too_many_new_messages` | Son asistan mesajından sonra 12'den fazla `user` mesajı var. | | `400` | `tools_not_supported` | `tools` ya da `functions` gönderildi. | | `400` | `unsupported_parameter` | `n` 1 dışında ya da `response_format` `text` dışında. | | `400` | `conversation_model_mismatch` | Sohbet başka bir asistanla açılmış. | | `404` | `model_not_found` | Bu kimlikte, anahtarın çağırabildiği yayında bir asistan yok. | | `404` | `conversation_not_found` | Gönderilen sohbet kimliği bu çalışma alanında bir API sohbeti değil. | | `409` | `conversation_busy` | Aynı sohbette önceki mesaj hâlâ yanıtlanıyor. | | `422` | `idempotency_key_reused` | Aynı `Idempotency-Key` başka bir metinle gönderildi. | Bütün kodlar ve ne yapılacağı: [Hatalar](https://docs.sonecentral.com/hatalar.md). --- # Responses API Sayfa: https://docs.sonecentral.com/responses Markdown: https://docs.sonecentral.com/responses.md > POST /responses ile OpenAI Responses biçiminde konuşun; sohbeti previous_response_id ya da conversation ile sürdürün, saklanan yanıtları okuyun ve silin. ```http POST https://pb.sonecentral.com/api/v1/responses ``` OpenAI Responses biçimini kullanır. Sohbeti sürdürmek için önceki yanıtın kimliğini göndermeniz yeter; geçmişi her seferinde yeniden yollamazsınız. ## İlk mesaj ve devamı **OpenAI JS** ```ts const first = await client.responses.create({ model: 'default', input: 'Saç boyası için randevu almak istiyorum.', }); console.log(first.output_text); const second = await client.responses.create({ model: 'default', previous_response_id: first.id, input: 'Perşembe öğleden sonra olur mu?', }); console.log(second.output_text); ``` **OpenAI Python** ```python first = client.responses.create( model="default", input="Saç boyası için randevu almak istiyorum.", ) print(first.output_text) second = client.responses.create( model="default", previous_response_id=first.id, input="Perşembe öğleden sonra olur mu?", ) print(second.output_text) ``` **curl** ```bash curl https://pb.sonecentral.com/api/v1/responses \ -H "Authorization: Bearer $SONE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "default", "input": "Saç boyası için randevu almak istiyorum." }' ``` `output_text` SDK'nın kolaylığıdır: bütün `output_text` parçalarını birleştirir. ## İstek | Alan | Tür | Açıklama | | --- | --- | --- | | `model` | string | Asistanın kimliği ya da "default". Zorunlu. | | `input` | string \| array | Yeni mesaj. Metin ya da OpenAI girdi öğeleri: rolü olan message öğeleri ve item_reference. Mesajlarda input_text ve output_text parçaları okunur. Bir item_reference kimliği en fazla 64 karakterdir. Son öğe ziyaretçinin metin mesajı olmalıdır. Zorunlu. | | `previous_response_id` | string | Önceki yanıtın kimliği, resp_ ve 32 karakter. Aynı sohbet sürer. conversation ile birlikte gönderilemez. Bir yanıt kimliğinden uzun bir değer reddedilir. | | `conversation` | string \| { id: string } | Sohbetin kimliği, yani sone.conversation_id. previous_response_id yerine kullanılabilir. | | `store` | boolean | false ise yanıt saklanmaz; GET /responses/{id} ve previous_response_id onu bulamaz. Varsayılan: true. | | `instructions` | string | Sunucu anahtarıyla asistana yalnız bilgi olarak iletilir. En fazla 2.000 karakter ve JSON olarak 4 KB; daha uzunu reddedilir. Tarayıcı anahtarıyla yok sayılır, saklanmaz ve yanıtta yer almaz. Saklanan yanıtta onu yalnız yanıtı saklayan anahtar görür. | | `stream` | boolean | true ise yanıt olaylarla akar. Varsayılan: false. | | `user` | string | Yalnız sunucu anahtarıyla dikkate alınır. Kendi sisteminizdeki ziyaretçi kimliği; aynı değer aynı sohbeti bulur. En fazla 64 karakter; daha uzunu reddedilir. Yanıtta yer almaz ve saklanmaz. | | `safety_identifier` | string | user ile aynı işi görür. İkisi birden gelirse bu kullanılır. En fazla 64 karakter; daha uzunu reddedilir. Sunucu anahtarıyla yanıtta yer alır ve onunla saklanır; tarayıcı anahtarıyla yok sayılır, saklanmaz ve yanıtta yer almaz. | | `metadata` | object | Yanıtta olduğu gibi geri gelir, sohbeti bulmak için kullanılmaz. Saklanan yanıtta onu yalnız yanıtı saklayan anahtar görür. En fazla 16 anahtar; anahtar en fazla 64 karakter, değer en fazla 512 karakterlik metin; tamamı JSON olarak en fazla 4 KB. | `conversation` yerine `X-Sone-Conversation-Id` başlığını da kullanabilirsiniz. `conversation` ile `previous_response_id` birlikte gelirse istek `400 conflicting_parameters` alır. `input` içindeki `system` ve `developer` mesajları `instructions` gibi [geliştirici bağlamıdır](https://docs.sonecentral.com/kimlik-dogrulama.md#gelistirici-baglami). Geri gönderdiğiniz asistan mesajları ve `item_reference` öğeleri sohbeti bulmak için okunur: [Sohbet sürekliliği](https://docs.sonecentral.com/sohbet-surekliligi.md#sohbet-nasil-bulunur). `temperature`, `top_p`, `max_output_tokens`, `reasoning`, `text.verbosity`, `tool_choice`, `truncation` ve benzeri model ayarları yok sayılır. `max_output_tokens` yanıtta olduğu gibi geri gelir ama yanıtın uzunluğunu değiştirmez. Şunlar reddedilir: | Ne | Hata | | --- | --- | | `tools` ya da `function_call` gibi işlev çağrısı öğeleri | `400 tools_not_supported` | | `background: true` | `400 unsupported_parameter` | | `text.format`, `text` dışında | `400 unsupported_parameter` | | Yeni mesajda görsel ya da dosya parçası | `400 unsupported_content` | | Tanınmayan bir girdi öğesi türü | `400 unsupported_item` | `reasoning` öğeleri sessizce atlanır. ## Yanıt ```json { "id": "resp_7c1e9a4f2b8d6e3a0f5c9b2d7e4a1c8f", "object": "response", "created_at": 1760866200, "completed_at": 1760866203, "status": "completed", "model": "k3m9x2p7q1w8e4r", "previous_response_id": null, "conversation": { "id": "conv_x8k2m9p4q7w1r3t" }, "output": [ { "type": "message", "id": "msg_w8e4rk3m9x2pq7a", "status": "completed", "role": "assistant", "content": [ { "type": "output_text", "text": "Elbette. Hangi gün size uygun?", "annotations": [], "logprobs": [] } ], "sone": { "id": "msg_w8e4rk3m9x2pq7a", "role": "assistant", "type": "text", "text": "Elbette. Hangi gün size uygun?", "created_at": 1760866203 } } ], "usage": { "input_tokens": 10, "input_tokens_details": { "cached_tokens": 0 }, "output_tokens": 8, "output_tokens_details": { "reasoning_tokens": 0 }, "total_tokens": 18 }, "sone": { "conversation_id": "conv_x8k2m9p4q7w1r3t", "status": "answered" } } ``` Örnek kısaltıldı; yanıt OpenAI'nin tanımladığı diğer alanları da taşır. `usage` [Chat Completions](https://docs.sonecentral.com/chat-completions.md)'taki gibi uzunluktan tahmin edilir. Asistanın gönderdiği her mesaj ayrı bir `message` öğesidir; öğenin `id`'si mesajın Sonecentral'daki kimliğidir. Ürün kartı, düğme ya da dosya içeren bir mesajda da `content` düz metin karşılığını taşır; yapılandırılmış hali öğenin `sone` alanındadır. Biçimi: [Zengin mesajlar](https://docs.sonecentral.com/zengin-mesajlar.md). Yanıtın üst düzeyindeki `sone` sohbetin kimliğini ve turun durumunu verir. `status` değerleri [Chat Completions](https://docs.sonecentral.com/chat-completions.md) sayfasındakiyle aynıdır. `human` ve `silent` turlarında `output` boş olur. Sohbetin kimliği ayrıca `X-Sone-Conversation-Id` yanıt başlığında gelir. ## Saklanan yanıtlar `store` açıksa yanıt saklanır. Varsayılan budur. Saklanan yanıtlar 30 gün sonra silinir; sohbetin kendisi Mesajlar ekranında kalır. | Uç nokta | Ne yapar | | --- | --- | | `GET /responses/{id}` | Yanıtı aynı biçimde döner. | | `GET /responses/{id}/input_items` | Bu istekte gönderdiğiniz kendi girdi öğelerini liste olarak döner. Varsayılan sıra yeniden eskiye; `?order=asc` eskiden yeniye verir. Liste tek sayfadır, `has_more` her zaman `false` olur. | | `DELETE /responses/{id}` | Saklanan yanıtı siler: `{ "id": "resp_…", "object": "response.deleted", "deleted": true }`. Yalnız yanıtı saklayan anahtarla çalışır. Sohbetin kendisi silinmez. | | `POST /responses/{id}/cancel` | Yanıt varsa her zaman `400 not_cancellable` döner. Yanıtlar istek içinde tamamlanır, iptal edilecek arka plan işi yoktur. | Saklanan yanıt, girdiden yalnız isteğin kendi öğelerini tutar: ziyaretçinin yeni mesajları (son asistan öğesinden sonraki kullanıcı mesajları), `item_reference` öğeleri ve sunucu anahtarıyla `system` ile `developer` mesajları. Tarayıcı anahtarının `system` ve `developer` mesajları, `instructions` gibi, kullanılmaz ve saklanmaz. Yeniden gönderdiğiniz geçmiş saklanmaz; onu sohbetin kendisi tutar. Bu öğelerden en fazla 40'ı ve JSON olarak toplam 8 KB saklanır, en yenileri önce. En yeni öğe her zaman saklanır, 8 KB'a sığmıyorsa metni sonundan kısaltılarak; her öğenin metni en fazla 4.000 karakterdir. Kimliği olmayan öğelere, girdideki yerine göre `resp_…_in_0` gibi bir kimlik verilir. Yanıtla saklanan istek alanlarının hepsi sınırlıdır: `instructions` en fazla 2.000 karakter, `metadata` en fazla 16 anahtar, `safety_identifier` ve `user` en fazla 64 karakter, bir `item_reference` kimliği en fazla 64 karakter. `instructions` ve `metadata` ayrıca JSON olarak en fazla 4 KB olabilir: karakter sınırı içinde kalsa da, örneğin dört baytlık karakterlerle, daha büyük olanı reddedilir. Sınırı aşan istek `400` alır ve hiçbir şey saklanmaz. `previous_response_id` boşlukları atılmış haliyle saklanır; bir yanıt kimliğinden uzunsa istek `400 previous_response_id_too_long` alır. Aynı mesajı yeniden gönderdiğinizde, aynı `Idempotency-Key` ile ya da aynı `previous_response_id` ve aynı `input` ile, asistan yeniden yanıt vermez ve yeni bir yanıt saklanmaz: ilk yanıt aynı kimlikle döner. Sohbet ekipteyken de aynı `Idempotency-Key` ile ya da aynı `previous_response_id` ve aynı `input` ile gelen deneme ilk yanıtı aynı kimlikle alır. Saklanan bir yanıta, yanıtın asistanını çağırabilen her anahtar kimliğiyle ulaşır: yanıtı ve girdi öğelerini okur, `previous_response_id` ile sohbeti sürdürür. Anahtarın çağıramadığı bir asistanın yanıtı ona yokmuş gibi görünür: `404 response_not_found`, `previous_response_id`'de `404 previous_response_not_found`. Geliştirici bağlamınız, `metadata` değerleriniz ve gönderdiğiniz son kullanıcı kimliği yalnız yanıtı saklayan anahtara geri döner. Başka bir anahtar yanıtı `instructions`, `safety_identifier` ve `user` alanları `null`, `metadata` alanı boş (`{}`) olarak okur; girdi öğelerinde `system` ve `developer` mesajlarını görmez. Yanıtı yalnız onu saklayan anahtar silebilir; başka bir anahtarın silme isteği `404 response_not_found` alır. Bir anahtarı yenileyip eskisini iptal ettiğinizde eskisinin sakladığı yanıtlar 30 gün sonra kendiliğinden silinir. Yanıt kimlikleri tahmin edilemeyecek kadar uzundur ama yine de onları sır gibi saklayın. ```ts const stored = await client.responses.retrieve('resp_7c1e9a4f2b8d6e3a0f5c9b2d7e4a1c8f'); const items = await client.responses.inputItems.list('resp_7c1e9a4f2b8d6e3a0f5c9b2d7e4a1c8f'); await client.responses.delete('resp_7c1e9a4f2b8d6e3a0f5c9b2d7e4a1c8f'); ``` ## Akış `"stream": true` ile olaylar OpenAI'nin tanımladığı sırayla gelir. Her olayda 0'dan başlayıp birer artan bir `sequence_number` vardır. Her asistan mesajı kendi öğesini açar ve kapatır: ```txt event: response.created data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_7c1e","status":"in_progress","conversation":{"id":"conv_x8k2m9p4q7w1r3t"},"output":[]}} event: response.in_progress data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_7c1e","status":"in_progress"}} : sone.activity {"label":"Uygun saatlere bakılıyor"} event: response.output_item.added data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"type":"message","id":"msg_w8e4","status":"in_progress","role":"assistant","content":[],"sone":{…}}} event: response.content_part.added data: {"type":"response.content_part.added","sequence_number":3,"item_id":"msg_w8e4","output_index":0,"content_index":0,"part":{"type":"output_text","text":"","annotations":[],"logprobs":[]}} event: response.output_text.delta data: {"type":"response.output_text.delta","sequence_number":4,"item_id":"msg_w8e4","output_index":0,"content_index":0,"delta":"Elbette. Hangi gün size ","logprobs":[]} event: response.output_text.delta data: {"type":"response.output_text.delta","sequence_number":5,"item_id":"msg_w8e4","output_index":0,"content_index":0,"delta":"uygun?","logprobs":[]} event: response.output_text.done data: {"type":"response.output_text.done","sequence_number":6,"item_id":"msg_w8e4","output_index":0,"content_index":0,"text":"Elbette. Hangi gün size uygun?","logprobs":[]} event: response.content_part.done data: {"type":"response.content_part.done","sequence_number":7,"item_id":"msg_w8e4","output_index":0,"content_index":0,"part":{"type":"output_text","text":"Elbette. Hangi gün size uygun?","annotations":[],"logprobs":[]}} event: response.output_item.done data: {"type":"response.output_item.done","sequence_number":8,"output_index":0,"item":{"type":"message","id":"msg_w8e4","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Elbette. Hangi gün size uygun?","annotations":[],"logprobs":[]}],"sone":{…}}} event: response.completed data: {"type":"response.completed","sequence_number":9,"response":{"id":"resp_7c1e","status":"completed","sone":{"conversation_id":"conv_x8k2m9p4q7w1r3t","status":"answered"}}} ``` Örnekteki nesneler kısaltıldı; gerçek olaylar alanların tamamını taşır. `: sone.activity` satırı bir olay değil, bir SSE yorumudur: asistan bir araç kullanırken "Uygun saatlere bakılıyor" gibi kısa bir durumu `label` alanında verir. `sequence_number` taşımaz. OpenAI SDK'ları yorum satırlarını atlar; bu durumu göstermek istiyorsanız akışı kendiniz ayrıştırın ve `: sone.activity ` ile başlayan satırın geri kalanını JSON olarak okuyun. `: ping` satırları da yorumdur. **OpenAI JS** ```ts import OpenAI from 'openai'; const stream = await client.responses.create({ model: 'default', input: 'Saç boyası için randevu almak istiyorum.', stream: true, }); try { for await (const event of stream) { if (event.type === 'response.output_text.delta') process.stdout.write(event.delta); if (event.type === 'response.output_item.done') process.stdout.write('\n'); } } catch (error) { // Akış başladıktan sonraki bir hata: SDK error olayını APIError olarak fırlatır. if (error instanceof OpenAI.APIError) console.error(error.code, error.message); else throw error; } ``` **OpenAI Python** ```python stream = client.responses.create( model="default", input="Saç boyası için randevu almak istiyorum.", stream=True, ) for event in stream: if event.type == "response.output_text.delta": print(event.delta, end="", flush=True) elif event.type == "response.output_item.done": print() elif event.type == "error": print(event.code, event.message) ``` Akış başladıktan sonra bir hata olursa önce `code` ve `message` taşıyan bir `error` olayı, ardından `response.failed` gelir ve akış kapanır. Responses akışında `data: [DONE]` yoktur; akış `response.completed` ya da `response.failed` ile biter. OpenAI'nin Node SDK'sı `error` olayında hata fırlatır; Python SDK'sı onu `type` değeri `"error"` olan bir olay olarak verir. Ayrıntılar: [Hatalar](https://docs.sonecentral.com/hatalar.md#akis-sirasinda-hata). ## Hatalar | Durum | `code` | Ne zaman | | --- | --- | --- | | `400` | `missing_input` | `input` yok. | | `400` | `invalid_input` | `input` bir metin ya da öğe dizisi değil. | | `400` | `invalid_role` | Bir mesaj öğesinin rolü yok ya da tanınmıyor. | | `400` | `missing_user_message` | Son öğe ziyaretçinin metin mesajı değil. | | `400` | `unsupported_item` | Tanınmayan bir girdi öğesi türü var. | | `400` | `conflicting_parameters` | `previous_response_id` ile `conversation` birlikte gönderildi. | | `400` | `instructions_too_long` | `instructions` 2.000 karakterden ya da JSON olarak 4 KB'tan uzun. | | `400` | `invalid_metadata` | `metadata` sınırı aşıyor (16 anahtar, 64 ve 512 karakter, JSON olarak 4 KB) ya da bir değeri metin değil. | | `400` | `safety_identifier_too_long` | `safety_identifier` 64 karakterden uzun. | | `400` | `user_too_long` | `user` 64 karakterden uzun. | | `400` | `previous_response_id_too_long` | `previous_response_id`, boşlukları atıldıktan sonra bir yanıt kimliğinden uzun. | | `400` | `item_id_too_long` | Bir `item_reference` kimliği 64 karakterden uzun. | | `400` | `not_cancellable` | `cancel` çağrıldı. | | `400` | `conversation_model_mismatch` | Sohbet başka bir asistanla açılmış. | | `404` | `response_not_found` | Yanıt yok, silinmiş, 30 günü geçmiş, `store: false` ile üretilmiş, başka bir çalışma alanına ait ya da anahtarınızın çağıramadığı bir asistanın sohbetinde. Silmede ayrıca: yanıtı başka bir anahtar saklamış. | | `404` | `previous_response_not_found` | `previous_response_id` ile gösterilen yanıt bulunamadı ya da anahtarınızın çağıramadığı bir asistanın sohbetinde. | | `404` | `conversation_not_found` | `conversation` bu çalışma alanında bir API sohbeti değil. | | `409` | `conversation_busy` | Aynı sohbette önceki mesaj hâlâ yanıtlanıyor. | Bütün kodlar: [Hatalar](https://docs.sonecentral.com/hatalar.md). --- # Vercel AI SDK Sayfa: https://docs.sonecentral.com/vercel-ai-sdk Markdown: https://docs.sonecentral.com/vercel-ai-sdk.md > useChat ile tarayıcıdan doğrudan /chat uç noktasına bağlanın, zengin mesajları tipli veri parçaları olarak çizin; ya da sunucuda OpenAI sağlayıcısıyla generateText ve streamText kullanın. Vercel AI SDK ile iki yol var: - **`useChat` ile doğrudan.** Sitenizdeki sohbet penceresi tarayıcı anahtarıyla `POST /chat` uç noktasına bağlanır. Arada sizin sunucunuz yoktur. Ürün kartları, düğmeler ve dosyalar tipli veri parçaları olarak gelir. - **Sağlayıcı olarak.** Sunucu kodunuzda `@ai-sdk/openai` ya da `@ai-sdk/openai-compatible` ile `generateText` ve `streamText` kullanırsınız. Örnekler `ai` 7, `@ai-sdk/react` 4, `@ai-sdk/openai` 4 ve `@ai-sdk/openai-compatible` 3 ile denendi. `/chat` akışı AI SDK 5 ve sonrasının UI mesaj akışı biçimindedir. ## `useChat` ile doğrudan ```npm npm i ai @ai-sdk/react ``` ```tsx title="components/chat.tsx" 'use client'; import { useChat } from '@ai-sdk/react'; import { DefaultChatTransport } from 'ai'; import { useState } from 'react'; const transport = new DefaultChatTransport({ api: 'https://pb.sonecentral.com/api/v1/chat', headers: { Authorization: `Bearer ${process.env.NEXT_PUBLIC_SONE_PUBLISHABLE_KEY}` }, body: { model: 'default' }, }); export function Chat() { const [input, setInput] = useState(''); const { messages, sendMessage, status, error } = useChat({ transport }); const busy = status === 'submitted' || status === 'streaming'; return (
{part.text}
: null, )}{error.message}
: null}{part.text}
; case 'data-sone-staff': return (Ekip: {part.data.text}
); case 'data-sone-catalog': return ({actions.text}
: null} {actions?.buttons?.map((button) => ( {button.title} ))} {actions?.choices?.map((choice) => ( ))}{part.data.text}
); default: return null; } }), )} {activity ?{activity}…
: null}