interface ChatEvent {
type: "chat_metadata" | "processing" | "visualization" | "message" | "error";
data: any;
}
async function sendChatMessage(
message: string,
integrationId: string,
token: string,
onEvent: (event: ChatEvent) => void
): Promise<void> {
const response = await fetch("https://api.trellis.sh/v1/chats", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
Accept: "text/event-stream",
},
body: JSON.stringify({
message,
integration_id: integrationId,
}),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (reader) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
let currentEvent = "";
for (const line of lines) {
if (line.startsWith("event: ")) {
currentEvent = line.slice(7);
} else if (line.startsWith("data: ") && currentEvent) {
const data = JSON.parse(line.slice(6));
onEvent({ type: currentEvent as ChatEvent["type"], data });
currentEvent = "";
}
}
}
}
// Handle each event type
sendChatMessage("Show me orders by region", "integration_id", "token", (event) => {
switch (event.type) {
case "chat_metadata":
console.log("Chat ID:", event.data.id, "| User message:", event.data.user_message_id);
break;
case "processing":
showLoadingIndicator(event.data.status);
break;
case "visualization":
if (event.data.type === "table") {
renderTable(event.data.headers, event.data.rows);
} else if (event.data.type === "chart") {
renderChart(event.data.chart_type, event.data.title, event.data.data);
}
break;
case "message":
displayMessage(event.data.content);
hideLoadingIndicator();
break;
case "error":
showError(event.data.error);
break;
}
});