Module 01: Chatbot Service (API)1.5 GraphQL API & Code Examples
Module 01 • API Gateway
1.5.3 Gửi Câu Hỏi Cho AI (SendAiMessage)
MUTATION
Yêu cầu Bearer Token
SendAiMessage.gql
Variables
Response 200 OK
sendAiMessage.ts
Dữ Liệu Trả Về (
Gửi câu hỏi của người dùng tới mô hình AI. Hệ thống sẽ tiếp nhận yêu cầu và phản hồi ngay lập tức các mã định danh (chatSessionId, assistantMessageId, idempotencyKey) để Client kết nối Firebase Firestore nhận stream câu trả lời.
Non-Blocking Architecture
API này không đợi AI sinh toàn bộ câu trả lời mới trả về HTTP response. Do đó, request hoàn tất rất nhanh (thường dưới 300ms), loại bỏ hoàn toàn nguy cơ HTTP Timeout khi người dùng đặt câu hỏi phức tạp.
💻 Chi Tiết Truy Vấn & Mã Nguồn Mẫu
GraphQL Mutation & Payload:
GraphQL Mutation
mutation SendAiMessage($request: AiChatRequestDtoInput!, $images: [Upload!]) {
sendAiMessage(request: $request, images: $images) {
chatSessionId
chatRequestId
idempotencyKey
userMessageId
assistantMessageId
channel
requestStatus
}
}Variables (JSON)
{
"request": {
"question": "VUS có những khóa học nào dành cho trẻ em?",
"channel": "WEB_APP",
"chatSessionId": null,
"agentCode": "buddy",
"topic": "qa",
"idempotencyKey": "idem-1740200010000-abc1234"
},
"images": []
}Phản Hồi Thành Công (JSON Response)
{
"data": {
"sendAiMessage": {
"chatSessionId": "6a7d45b5aa2c04f1151bee2b",
"chatRequestId": "req-1740200010000-abc1234",
"idempotencyKey": "idem-1740200010000-abc1234",
"userMessageId": "6a8913448201e708713c6e47",
"assistantMessageId": "6a8913448201e708713c6e48",
"channel": "WEB_APP",
"requestStatus": "PROCESSING"
}
}
}TypeScript / Axios:
import axios from 'axios';
export interface SendAiMessageResult {
chatSessionId: string;
chatRequestId: string;
idempotencyKey: string;
userMessageId: string;
assistantMessageId: string;
channel: string;
requestStatus: 'PROCESSING' | 'COMPLETED' | 'FAILED';
}
/**
* Gửi câu hỏi của người dùng tới Pango AI Chatbot
* @param apiUrl Endpoint GraphQL Gateway
* @param token JWT Access Token sau khi ExternalLogin
* @param question Nội dung câu hỏi người dùng nhập
* @param activeSessionId Session ID hiện tại (null nếu là câu hỏi mở đầu phiên mới)
* @param agentCode Mã định danh agent (mặc định 'buddy')
* @param channel Kênh gửi tin ('WEB_APP' | 'MOBILE_APP')
*/
export async function sendAiMessage(
apiUrl: string = process.env.VITE_API_URL!,
token: string,
question: string,
activeSessionId: string | null = null,
agentCode: string = 'buddy',
channel: string = 'WEB_APP'
): Promise<SendAiMessageResult> {
const query = `
mutation SendAiMessage($request: AiChatRequestDtoInput!, $images: [Upload!]) {
sendAiMessage(request: $request, images: $images) {
chatSessionId
chatRequestId
idempotencyKey
userMessageId
assistantMessageId
channel
requestStatus
}
}
`;
// Tạo khóa Idempotency duy nhất chống gửi trùng
const idempotencyKey = `idem-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
const variables = {
request: {
question,
channel,
chatSessionId: activeSessionId || null,
agentCode,
uploads: null,
imageUrls: null,
webPageUrls: null,
staffInfo: null,
topic: 'qa',
times: null,
idempotencyKey,
},
images: [],
};
const response = await axios.post(
apiUrl,
{
query,
variables,
operationName: 'SendAiMessage',
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
'orgId': process.env.VITE_ORG_ID,
'x-org-id': process.env.VITE_ORG_ID,
'x-client-type': 'app',
'x-external-private-key': process.env.VITE_EXTERNAL_PRIVATE_KEY,
},
}
);
return response.data?.data?.sendAiMessage;
}📑 Bảng Tham Số (Schema Definition)
AiChatRequestDtoInput
| Thuộc Tính | Kiểu Dữ Liệu | Bắt Buộc | Mô Tả |
|---|---|---|---|
question | String! | Có | Nội dung câu hỏi người dùng nhập |
channel | String! | Có | Định danh kênh gửi ("WEB_APP", "MOBILE_APP") |
chatSessionId | String | Không | ID phiên chat đang tiếp diễn. Nếu gửi null, hệ thống tự sinh phiên mới |
agentCode | String! | Có | Mã bot (mặc định "buddy") |
topic | String | Không | Chủ đề hội thoại (mặc định "qa") |
idempotencyKey | String! | Có | Khóa chống lặp (UUID hoặc chuỗi ngẫu nhiên có timestamp) |
Dữ Liệu Trả Về (SendAiMessageResponse)
| Thuộc Tính | Kiểu Dữ Liệu | Mô Tả |
|---|---|---|
chatSessionId | String! | ID phiên chat (Lưu lại để gửi kèm các tin nhắn sau) |
assistantMessageId | String! | Rất quan trọng: ID tin nhắn của bot dùng để lắng nghe Stream trên Firestore |
userMessageId | String! | ID tin nhắn của người dùng trong hệ cơ sở dữ liệu |
requestStatus | String! | Trạng thái ban đầu ("PROCESSING") |