bettercx-widget
Version:
Professional AI-powered chat widget for BetterCX platform. Seamlessly integrate intelligent customer support into any website.
122 lines (121 loc) • 4.11 kB
JavaScript
/**
* API Service
* Handles all API communication with backend services
*/
import { AuthService } from "./auth.service";
export class ApiService {
authService;
dbServiceUrl;
aiServiceUrl;
constructor(dbServiceUrl = 'http://localhost:8000', aiServiceUrl = 'http://localhost:8081', authService) {
this.dbServiceUrl = dbServiceUrl;
this.aiServiceUrl = aiServiceUrl;
this.authService = authService || new AuthService(dbServiceUrl);
}
/**
* Fetch widget configuration from backend
*/
async getWidgetConfig(organizationId) {
const token = this.authService.getToken();
if (!token) {
throw new Error('No valid session token available');
}
try {
const response = await fetch(`${this.dbServiceUrl}/api/widgets/org/${organizationId}/widget-config/`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
...this.authService.getAuthHeader(),
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
catch (error) {
throw error;
}
}
/**
* Send a chat message to the AI service
*/
async sendMessage(message) {
const token = this.authService.getToken();
if (!token) {
throw new Error('No valid session token available');
}
const request = {
content: message,
};
try {
const response = await fetch(`${this.aiServiceUrl}/widget/ai/respond/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...this.authService.getAuthHeader(),
},
body: JSON.stringify(request),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || `HTTP ${response.status}: ${response.statusText}`);
}
// Return the response stream for streaming
return response.body;
}
catch (error) {
throw error;
}
}
/**
* Parse streaming response from AI service
*/
async *parseStreamResponse(stream) {
const reader = stream.getReader();
const decoder = new TextDecoder();
let currentEventType = 'streaming_output'; // Default event type
try {
while (true) {
const { done, value } = await reader.read();
if (done)
break;
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('event: ')) {
currentEventType = line.slice(7).trim();
continue;
}
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') {
return;
}
try {
const parsed = JSON.parse(data);
if (parsed.content) {
yield { type: currentEventType, content: parsed.content };
}
}
catch (e) {
// Skip invalid JSON
continue;
}
}
}
}
}
finally {
reader.releaseLock();
}
}
/**
* Get the auth service instance
*/
getAuthService() {
return this.authService;
}
}
//# sourceMappingURL=api.service.js.map