گفتگو
POST /v1/assistants/:assistantCode/chat:assistantCode همان مقدار id از
GET /v1/assistants است.
بدنهی درخواست
| فیلد | نوع | الزامی | محدودیتها |
|---|---|---|---|
principal | string | بله | ۱ تا ۲۵۵ کاراکتر |
message | string | بله، مگر اینکه attachment باشد | ۰ تا ۲۰٬۰۰۰ نویسه. برای پیامِ فقط-صدا خالی بگذارید |
conversationId | string | خیر | ۳۲ کاراکتر Hex با حروف کوچک — همان conversationId از یک پاسخ قبلی، برای ادامهی همان مکالمه |
newConversation | boolean | خیر | true یک مکالمهی کاملاً تازه برای همین principal شروع میکند (روی conversationId غلبه میکند) |
attachment | object | خیر | { filename, contentBase64 }. صدا (webm، m4a، mp3، wav، ogg و مانند آن) فقط وقتی روی دستیار acceptVoice روشن است |
principal: این مکالمه برای چه کسی است؟
یک کلید API متعلق به کل حساب شماست، اما تقریباً همیشه از طریق آن به بسیاری
از کاربران نهاییِ مستقل خودتان خدمت میدهید (کاربران اپلیکیشن خودتان، هر
کدام یک مکالمهی پلکسیت جداگانه). principal روشی است که با آن به پلکسیت
میگویید این تماس مشخص برای کدامیک از کاربران شماست — رشتهای است که
خودتان انتخاب میکنید (شناسهی کاربر، ایمیل، هر چیز پایدار و یکتا برای آن
کاربر در سمت شما).
پیش از رسیدن به موتور گفتگو، بهصورت داخلی با پیشوند api:<principal>
فضانامگذاری میشود، تا هرگز با شناسههای سایر کانالها تداخل نکند (ویجت
جاسازیشونده از فضانام خودش، u:<endUserId>، استفاده میکند) — نیازی
نیست خودتان هیچ پیشوندی اضافه کنید، فقط مقداری پایدار و یکتا برای هر
کاربر نهایی ارسال کنید.
{ "principal": "user_9f21", "message": "How do I reset my password?" }استفادهی مجدد از یک رشتهی principal یکسان برای دو کاربر نهاییِ واقعیِ
متفاوت، از دید پلکسیت تاریخچهی گفتگوی آنها را با هم ادغام میکند. چیزی
به همان اندازهی شناسههای کاربریِ خودتان یکتا انتخاب کنید.
attachment
برخلاف Endpointهای بارگذاری انبوه اسناد (که multipart/form-data هستند)،
بدنهی این مسیر JSON است، پس یک پیوست تکی بهصورت base64 و درون همان بدنه
ارسال میشود:
{
"principal": "user_9f21",
"message": "What does this error mean?",
"attachment": {
"filename": "screenshot.png",
"contentBase64": "iVBORw0KGgoAAAANSUhEUgAA..."
}
}این برای پیوستهای کوچک و اتفاقیِ درون یک مکالمه (یک اسکرینشات، یک قطعهی
کوتاه) در نظر گرفته شده — base64 حدود ۳۳٪ سربار اضافه میکند، که برای
پیوستهای اندازهی گفتگو قابل قبول است. contentBase64 حداکثر
۷,۰۰۰,۰۰۰ کاراکتر (حدود ۵ مگابایت پس از دیکد) و filename حداکثر ۲۵۵ کاراکتر مجاز است. برای اسناد انبوهِ
پایگاه دانش، از Endpointهای بارگذاری اسناد
استفاده کنید که همچنان multipart هستند (حداکثر ۱۰ فایل در هر درخواست،
هر فایل تا ۲۵ مگابایت).
conversationId: ادامهی یک مکالمه
conversationId یک پاسخ قبلی را بفرستید تا دقیقاً همان مکالمه، همراه با کل
زمینهی قبلی، ادامه یابد. اگر نفرستید، آخرین مکالمهی بازِ همان principal
ادامه پیدا میکند (یا اگر نداشته باشد یکی ساخته میشود) و پاسخ همیشه در
conversationId میگوید کدام بوده است. برای شروع اجباریِ یک مکالمهی تازه و
بیربط، "newConversation": true بفرستید. برای الگوی کامل به
راهنمای اختصاصی مراجعه کنید.
پاسخ
OutboundReplyResponse:
{
"data": {
"conversationId": "9c1e3f5a7b9d2c4e6f8a0b2d4f6a8c0e",
"text": "You can reset your password from Settings → Security.",
"sources": [
{ "fileId": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "path": "/help/password-reset.md", "chunk": 1 }
],
"model": "sol",
"reasoning": "low",
"degraded": false,
"quota": { "...": "مبهم، توضیح در ادامه" },
"ui": [],
"voice": null
},
"response": { "status": "success", "message": "..." }
}| فیلد | نوع | توضیح |
|---|---|---|
conversationId | string | برای ادامهی این مکالمه، همین مقدار را بهعنوان conversationId ارسال کنید. |
text | string | پاسخ دستیار. |
sources | { fileId, path, chunk }[] | قطعات سندی که پاسخ بر اساس آنها ساخته شده، در صورت وجود (استنادهای RAG). اگر پاسخ از هیچ سند بارگذاریشدهای استفاده نکرده باشد، آرایهای خالی است. |
model | string | یک key از GET /v1/models — مدلی که واقعاً این پاسخ را سرو کرده. |
reasoning | string | یکی از none، low، medium، high. |
degraded | boolean | اگر true باشد، این پاسخ از یک مسیر تنزلیافته/جایگزین سرو شده است. ارزش لاگکردن دارد؛ هنوز enum مستند و پایداری برای چرایی آن وجود ندارد. |
quota | object | عیناً از دفتر هزینهی retrieval عبور داده میشود. آن را یک شیء مبهم در نظر بگیرید — شکل داخلی آن بخشی از قرارداد این API نیست. |
ui | object[] | کارتهایی که ابزارهای دستیار خواستهاند کنار text نشان داده شوند (یک محصول با عکس و قیمت، یک فهرست، یک وضعیت). معمولاً []. بخش اجزای ui را ببینید. |
voice | { audioFileId, transcript } | null | فقط وقتی نوبتِ بازدیدکننده صدا بوده. transcript متنی است که از صدا خوانده و در پایگاه ذخیره شده (اگر سکوت بوده null). audioFileId شناسهٔ فایل ضبطشده است؛ بایتهایش را از GET /assistants/:assistantCode/customer-files/:audioFileId بگیرید (همان کلید API). در غیر این صورت null. |
اجزای ui
وقتی دستیار از یک ابزار استفاده میکند — مثلاً جستجوی محصول — ابزار
میتواند علاوه بر چیزی که گفته میشود، چیزی هم برای نمایش برگرداند. هر
عضو v: 1، یک type و یک fallback متنی ساده دارد:
type | فیلدها |
|---|---|
card | title، و اختیاری subtitle، body، imageUrl (نشانی http(s)) و fields: { label, value }[] |
list | اختیاری title، و items: { title, subtitle? }[] |
choices | اختیاری prompt، و options: { label, value }[] |
status | tone (success، error، info) و text |
form، confirm | اجزای تعاملی ویجت. |
{
"v": 1,
"type": "card",
"title": "گوشی سامسونگ Galaxy A15",
"subtitle": "12,000,000 تومان",
"body": "موبایل",
"imageUrl": "https://cdn.example.com/a15.png",
"fields": [{ "label": "رنگ", "value": "آبی" }],
"fallback": "گوشی سامسونگ Galaxy A15 — 12,000,000 تومان"
}نوعهای جدید ممکن است در طول زمان اضافه شوند. نوعهایی را که میشناسید
نمایش دهید و برای هر نوع دیگر fallback را نشان دهید — همیشه هست، پس
یک جزء ناشناخته هرگز رابط شما را خراب نمیکند.
اجزای form و confirm به جریان تعاملی ویجت نیاز دارند (کسی که یک
اقدام را تأیید میکند). این API مسیری برای پاسخ دادن به آنها ندارد؛ پس
متن fallback را نشان دهید و بگذارید کاربر نهایی با یک پیام معمولی ادامه
دهد. ضمناً این Endpoint استریم نمیشود: کل پاسخ یکجا میرسد.
مثال کامل
curl
curl -X POST "https://api.plexit.ir/v1/assistants/<assistantCode>/chat" \
-H "Authorization: Bearer $PLEXIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"principal": "user_9f21",
"message": "How do I reset my password?"
}'