328 lines
19 KiB
JavaScript
328 lines
19 KiB
JavaScript
/**
|
|
* TalkingQ Platform - API Interface Layer
|
|
* All API calls are defined here as stubs.
|
|
* Replace BASE_URL and implement fetch calls to connect backend.
|
|
*/
|
|
|
|
const API = {
|
|
BASE_URL: '/api/v1', // TODO: Replace with actual backend URL
|
|
|
|
// ─── Auth ───────────────────────────────────────────────────────
|
|
auth: {
|
|
login: (credentials) => API._post('/auth/login', credentials),
|
|
logout: () => API._post('/auth/logout'),
|
|
me: () => API._get('/auth/me'),
|
|
getPermissions: () => API._get('/auth/permissions'),
|
|
refreshToken: () => API._post('/auth/refresh'),
|
|
},
|
|
|
|
// ─── Dashboard ──────────────────────────────────────────────────
|
|
dashboard: {
|
|
getOverview: (params) => API._get('/dashboard/overview', params),
|
|
getDAUTrend: (params) => API._get('/dashboard/dau-trend', params),
|
|
getSessionStats: (params) => API._get('/dashboard/sessions', params),
|
|
getTurnsPerSession: (params) => API._get('/dashboard/turns', params),
|
|
getActivationRate: (params) => API._get('/dashboard/activation', params),
|
|
getRetentionCohort: (params) => API._get('/dashboard/retention', params),
|
|
getIntentDistribution: (params) => API._get('/dashboard/intents', params),
|
|
getLanguageStats: (params) => API._get('/dashboard/languages', params),
|
|
},
|
|
|
|
// ─── Agent Development ──────────────────────────────────────────
|
|
agentDev: {
|
|
// ASR (Automatic Speech Recognition)
|
|
getASRProviders: () => API._get('/agent-dev/asr/providers'),
|
|
listASRModels: (params) => API._get('/agent-dev/asr/models', params),
|
|
createASRModel: (data) => API._post('/agent-dev/asr/models', data),
|
|
updateASRModel: (id, data) => API._put(`/agent-dev/asr/models/${id}`, data),
|
|
deleteASRModel: (id) => API._delete(`/agent-dev/asr/models/${id}`),
|
|
validateASRModel: (id, data = {}) => API._post(`/agent-dev/asr/models/${id}/validate`, data),
|
|
testASRModel: (id, data = {}) => API._post(`/agent-dev/asr/models/${id}/test`, data),
|
|
setASRModelEnabled: (id, enabled) => API._put(`/agent-dev/asr/models/${id}/enabled`, { enabled }),
|
|
getASRConfig: (agentId) => API._get(`/agent-dev/${agentId}/asr`),
|
|
updateASRConfig: (agentId, config) => API._put(`/agent-dev/${agentId}/asr`, config),
|
|
testASR: (agentId, audioBlob) => API._post(`/agent-dev/${agentId}/asr/test`, { audio: audioBlob }),
|
|
getHotwordGroups: (params) => API._get('/agent-dev/asr/hotword-groups', params),
|
|
createHotwordGroup: (data) => API._post('/agent-dev/asr/hotword-groups', data),
|
|
updateHotwordGroup: (id, data) => API._put(`/agent-dev/asr/hotword-groups/${id}`, data),
|
|
deleteHotwordGroup: (id) => API._delete(`/agent-dev/asr/hotword-groups/${id}`),
|
|
getAgentHotwordGroups: (agentId) => API._get(`/agent-dev/${agentId}/asr/hotword-groups`),
|
|
bindHotwordGroups: (agentId, groupIds) => API._put(`/agent-dev/${agentId}/asr/hotword-groups`, { groupIds }),
|
|
|
|
// TTS (Text-to-Speech)
|
|
getTTSProviders: () => API._get('/agent-dev/tts/providers'),
|
|
listTTSModels: (params) => API._get('/agent-dev/tts/models', params),
|
|
createTTSModel: (data) => API._post('/agent-dev/tts/models', data),
|
|
updateTTSModel: (id, data) => API._put(`/agent-dev/tts/models/${id}`, data),
|
|
deleteTTSModel: (id) => API._delete(`/agent-dev/tts/models/${id}`),
|
|
validateTTSModel: (id, data = {}) => API._post(`/agent-dev/tts/models/${id}/validate`, data),
|
|
setTTSModelEnabled: (id, enabled) => API._put(`/agent-dev/tts/models/${id}/enabled`, { enabled }),
|
|
getTTSConfig: (agentId) => API._get(`/agent-dev/${agentId}/tts`),
|
|
updateTTSConfig: (agentId, config) => API._put(`/agent-dev/${agentId}/tts`, config),
|
|
testTTS: (agentId, text) => API._post(`/agent-dev/${agentId}/tts/test`, { text }),
|
|
previewVoice: (provider, voiceId, text) => API._post('/agent-dev/tts/preview', { provider, voiceId, text }),
|
|
|
|
// Text / LLM models
|
|
listTextModels: (params) => API._get('/agent-dev/text/models', params),
|
|
createTextModel: (data) => API._post('/agent-dev/text/models', data),
|
|
updateTextModel: (id, data) => API._put(`/agent-dev/text/models/${id}`, data),
|
|
deleteTextModel: (id) => API._delete(`/agent-dev/text/models/${id}`),
|
|
validateTextModel: (id, data = {}) => API._post(`/agent-dev/text/models/${id}/validate`, data),
|
|
setTextModelEnabled: (id, enabled) => API._put(`/agent-dev/text/models/${id}/enabled`, { enabled }),
|
|
getTextConfig: (agentId) => API._get(`/agent-dev/${agentId}/text`),
|
|
updateTextConfig: (agentId, config) => API._put(`/agent-dev/${agentId}/text`, config),
|
|
testTextModel: (agentId, prompt) => API._post(`/agent-dev/${agentId}/text/test`, { prompt }),
|
|
|
|
// Runtime variables / state storage
|
|
listVariables: (agentId, params) => API._get(`/agent-dev/${agentId}/variables`, params),
|
|
createVariable: (agentId, data) => API._post(`/agent-dev/${agentId}/variables`, data),
|
|
updateVariable: (agentId, variableId, data) => API._put(`/agent-dev/${agentId}/variables/${variableId}`, data),
|
|
deleteVariable: (agentId, variableId) => API._delete(`/agent-dev/${agentId}/variables/${variableId}`),
|
|
injectVariableToPrompt: (agentId, variableId, data = {}) => API._post(`/agent-dev/${agentId}/variables/${variableId}/inject`, data),
|
|
getVariableState: (agentId, sessionId, params) => API._get(`/agent-dev/${agentId}/sessions/${sessionId}/variables`, params),
|
|
updateVariableState: (agentId, sessionId, data) => API._put(`/agent-dev/${agentId}/sessions/${sessionId}/variables`, data),
|
|
|
|
// RAG (Retrieval Augmented Generation)
|
|
getKnowledgeBases: () => API._get('/agent-dev/rag/knowledge-bases'),
|
|
getAgentRAG: (agentId) => API._get(`/agent-dev/${agentId}/rag`),
|
|
attachKnowledgeBase: (agentId, kbId) => API._post(`/agent-dev/${agentId}/rag/attach`, { kbId }),
|
|
detachKnowledgeBase: (agentId, kbId) => API._delete(`/agent-dev/${agentId}/rag/detach/${kbId}`),
|
|
createKnowledgeBase: (data) => API._post('/agent-dev/rag/knowledge-bases', data),
|
|
uploadDocument: (kbId, file) => API._upload(`/agent-dev/rag/knowledge-bases/${kbId}/docs`, file),
|
|
deleteDocument: (kbId, docId) => API._delete(`/agent-dev/rag/knowledge-bases/${kbId}/docs/${docId}`),
|
|
testRAGQuery: (agentId, query) => API._post(`/agent-dev/${agentId}/rag/test`, { query }),
|
|
|
|
// Language
|
|
getSupportedLanguages: () => API._get('/agent-dev/languages'),
|
|
getAgentLanguages: (agentId) => API._get(`/agent-dev/${agentId}/languages`),
|
|
updateAgentLanguages: (agentId, langs) => API._put(`/agent-dev/${agentId}/languages`, { languages: langs }),
|
|
setPrimaryLanguage: (agentId, lang) => API._put(`/agent-dev/${agentId}/languages/primary`, { language: lang }),
|
|
|
|
// General agent config
|
|
saveConfig: (agentId, config) => API._put(`/agent-dev/${agentId}/config`, config),
|
|
deployAgent: (agentId, data = {}) => API._post(`/agent-dev/${agentId}/deploy`, data),
|
|
getDeployStatus: (agentId) => API._get(`/agent-dev/${agentId}/deploy/status`),
|
|
},
|
|
|
|
// ─── Agent Management ───────────────────────────────────────────
|
|
agents: {
|
|
list: (params) => API._get('/agents', params),
|
|
get: (id) => API._get(`/agents/${id}`),
|
|
create: (data) => API._post('/agents', data),
|
|
update: (id, data) => API._put(`/agents/${id}`, data),
|
|
delete: (id) => API._post(`/agents/${id}/recycle`, { retentionDays: 7 }),
|
|
listRecycleBin: (params) => API._get('/agents/recycle-bin', params),
|
|
restore: (id) => API._post(`/agents/${id}/restore`),
|
|
purge: (id) => API._delete(`/agents/${id}`),
|
|
cleanupRecycleBin: () => API._post('/agents/recycle-bin/cleanup'),
|
|
getVersions: (id) => API._get(`/agents/${id}/versions`),
|
|
rollback: (id, version) => API._post(`/agents/${id}/rollback`, { version }),
|
|
},
|
|
|
|
// ─── Prompt Management ──────────────────────────────────────────
|
|
prompts: {
|
|
list: (params) => API._get('/prompts', params),
|
|
get: (id) => API._get(`/prompts/${id}`),
|
|
create: (data) => API._post('/prompts', data),
|
|
update: (id, data) => API._put(`/prompts/${id}`, data),
|
|
delete: (id) => API._delete(`/prompts/${id}`),
|
|
publish: (id) => API._post(`/prompts/${id}/publish`),
|
|
getVersions: (id) => API._get(`/prompts/${id}/versions`),
|
|
startABTest: (data) => API._post('/prompts/ab-test', data),
|
|
getABTestResults: (testId) => API._get(`/prompts/ab-test/${testId}/results`),
|
|
},
|
|
|
|
// ─── Products ───────────────────────────────────────────────────
|
|
products: {
|
|
list: (params) => API._get('/products', params),
|
|
get: (id) => API._get(`/products/${id}`),
|
|
create: (data) => API._post('/products', data),
|
|
update: (id, data) => API._put(`/products/${id}`, data),
|
|
delete: (id) => API._delete(`/products/${id}`),
|
|
},
|
|
|
|
// ─── Tenant / Company Scope ─────────────────────────────────────
|
|
tenants: {
|
|
listCompanies: (params) => API._get('/tenants/companies', params),
|
|
createCompany: (data) => API._post('/tenants/companies', data),
|
|
updateCompany: (companyId, data) => API._put(`/tenants/companies/${companyId}`, data),
|
|
deleteCompany: (companyId) => API._delete(`/tenants/companies/${companyId}`),
|
|
deleteCompanyWithTransfer: (companyId, data = {}) => API._post(`/tenants/companies/${companyId}/delete`, data),
|
|
getMyCompany: () => API._get('/tenants/me/company'),
|
|
getMyScope: () => API._get('/tenants/me/scope'),
|
|
switchCompany: (companyId) => API._post('/tenants/switch-company', { companyId }),
|
|
},
|
|
|
|
// ─── Devices ────────────────────────────────────────────────────
|
|
devices: {
|
|
list: (params) => API._get('/devices', params),
|
|
get: (id) => API._get(`/devices/${id}`),
|
|
create: (data) => API._post('/devices', data),
|
|
batchCreate: (data) => API._post('/devices/batch', data),
|
|
validateBatch: (data) => API._post('/devices/batch/validate', data),
|
|
importFile: (file, meta) => API._upload('/devices/import', file, meta),
|
|
update: (id, data) => API._put(`/devices/${id}`, data),
|
|
delete: (id) => API._delete(`/devices/${id}`),
|
|
getHeartbeat: (id) => API._get(`/devices/${id}/heartbeat`),
|
|
reboot: (id) => API._post(`/devices/${id}/reboot`),
|
|
getLogs: (id, params) => API._get(`/devices/${id}/logs`, params),
|
|
bindProduct: (id, productId) => API._post(`/devices/${id}/bind`, { productId }),
|
|
unbind: (id) => API._post(`/devices/${id}/unbind`),
|
|
export: (params) => API._get('/devices/export', params),
|
|
},
|
|
|
|
// ─── OTA ────────────────────────────────────────────────────────
|
|
ota: {
|
|
list: (params) => API._get('/ota/tasks', params),
|
|
get: (id) => API._get(`/ota/tasks/${id}`),
|
|
create: (data) => API._post('/ota/tasks', data),
|
|
cancel: (id) => API._post(`/ota/tasks/${id}/cancel`),
|
|
resume: (id) => API._post(`/ota/tasks/${id}/resume`),
|
|
getProgress: (id) => API._get(`/ota/tasks/${id}/progress`),
|
|
getFirmwares: (params) => API._get('/ota/firmwares', params),
|
|
getFirmwaresByProduct: (productId) => API._get('/ota/firmwares', { productId }),
|
|
uploadFirmware: (file, meta) => API._upload('/ota/firmwares', file, meta),
|
|
setLatestFirmware: (id, data) => API._post(`/ota/firmwares/${id}/set-latest`, data),
|
|
setLatestAndCreateTask: (id, data) => API._post(`/ota/firmwares/${id}/set-latest-and-upgrade`, data),
|
|
deleteFirmware: (id) => API._delete(`/ota/firmwares/${id}`),
|
|
upgradeSingle: (deviceId, data) => API._post('/ota/single', { device_id: deviceId, ...data }),
|
|
},
|
|
|
|
// ─── Sessions ───────────────────────────────────────────────────
|
|
sessions: {
|
|
list: (params) => API._get('/sessions', params),
|
|
get: (id) => API._get(`/sessions/${id}`),
|
|
getMessages: (id) => API._get(`/sessions/${id}/messages`),
|
|
replay: (id) => API._get(`/sessions/${id}/replay`),
|
|
export: (params) => API._get('/sessions/export', params),
|
|
getStats: (params) => API._get('/sessions/stats', params),
|
|
},
|
|
|
|
// ─── Bad Cases ──────────────────────────────────────────────────
|
|
badCases: {
|
|
list: (params) => API._get('/bad-cases', params),
|
|
get: (id) => API._get(`/bad-cases/${id}`),
|
|
tag: (id, tags) => API._put(`/bad-cases/${id}/tags`, { tags }),
|
|
review: (id, data) => API._post(`/bad-cases/${id}/review`, data),
|
|
close: (id, resolution) => API._post(`/bad-cases/${id}/close`, { resolution }),
|
|
export: (params) => API._get('/bad-cases/export', params),
|
|
getStats: (params) => API._get('/bad-cases/stats', params),
|
|
},
|
|
|
|
// ─── Notifications ──────────────────────────────────────────────
|
|
notifications: {
|
|
// Backend should return tenant/company-scoped notifications only.
|
|
// Notification item shape:
|
|
// {
|
|
// id, eventType, category, severity, title, detail, objectType,
|
|
// objectId, companyId, companyName, metric, read, createdAt, actionPage
|
|
// }
|
|
list: (params) => API._get('/notifications', params),
|
|
get: (id) => API._get(`/notifications/${id}`),
|
|
getCatalog: () => API._get('/notifications/catalog'),
|
|
create: (data) => API._post('/notifications', data),
|
|
markRead: (id) => API._post(`/notifications/${id}/read`),
|
|
markAllRead: (params) => API._post('/notifications/read-all', params),
|
|
archive: (id) => API._post(`/notifications/${id}/archive`),
|
|
getStats: (params) => API._get('/notifications/stats', params),
|
|
},
|
|
|
|
// ─── RBAC ───────────────────────────────────────────────────────
|
|
rbac: {
|
|
getUsers: (params) => API._get('/rbac/users', params),
|
|
createUser: (data) => API._post('/rbac/users', data),
|
|
updateUser: (id, data) => API._put(`/rbac/users/${id}`, data),
|
|
deleteUser: (id) => API._delete(`/rbac/users/${id}`),
|
|
getRoles: () => API._get('/rbac/roles'),
|
|
getCurrentPermissions: () => API._get('/rbac/me/permissions'),
|
|
createRole: (data) => API._post('/rbac/roles', data),
|
|
updateRole: (id, data) => API._put(`/rbac/roles/${id}`, data),
|
|
deleteRole: (id) => API._delete(`/rbac/roles/${id}`),
|
|
getPermissions: () => API._get('/rbac/permissions'),
|
|
assignRole: (userId, roleId) => API._post('/rbac/users/assign-role', { userId, roleId }),
|
|
getAuditLogs: (params) => API._get('/rbac/audit-logs', params),
|
|
},
|
|
|
|
// ─── Privacy / PII ──────────────────────────────────────────────
|
|
privacy: {
|
|
getConfig: () => API._get('/privacy/config'),
|
|
updateConfig: (data) => API._put('/privacy/config', data),
|
|
getRules: () => API._get('/privacy/pii-rules'),
|
|
createRule: (data) => API._post('/privacy/pii-rules', data),
|
|
updateRule: (id, data) => API._put(`/privacy/pii-rules/${id}`, data),
|
|
deleteRule: (id) => API._delete(`/privacy/pii-rules/${id}`),
|
|
getDataRequests: (params) => API._get('/privacy/data-requests', params),
|
|
processDataRequest: (id, action) => API._post(`/privacy/data-requests/${id}/${action}`),
|
|
getRetentionPolicies: () => API._get('/privacy/retention-policies'),
|
|
updateRetentionPolicy: (id, data) => API._put(`/privacy/retention-policies/${id}`, data),
|
|
},
|
|
|
|
// ─── Settings ───────────────────────────────────────────────────
|
|
settings: {
|
|
getTenantInfo: () => API._get('/settings/tenant'),
|
|
updateTenantInfo: (data) => API._put('/settings/tenant', data),
|
|
getNotifications: () => API._get('/settings/notifications'),
|
|
// Notification settings shape:
|
|
// {
|
|
// rules: {
|
|
// [eventType]: { enabled, threshold?, thresholdUnit?, channels: ['in_app','email','webhook'] }
|
|
// }
|
|
// }
|
|
updateNotifications: (data) => API._put('/settings/notifications', data),
|
|
getIntegrations: () => API._get('/settings/integrations'),
|
|
testWebhook: (url) => API._post('/settings/webhooks/test', { url }),
|
|
getApiKeys: () => API._get('/settings/api-keys'),
|
|
createApiKey: (data) => API._post('/settings/api-keys', data),
|
|
revokeApiKey: (id) => API._delete(`/settings/api-keys/${id}`),
|
|
},
|
|
|
|
// ─── Internal helpers ───────────────────────────────────────────
|
|
_headers() {
|
|
const token = localStorage.getItem('tq_token');
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
...(token ? { 'Authorization': `Bearer ${token}` } : {}),
|
|
};
|
|
},
|
|
|
|
async _request(method, path, body, params) {
|
|
// TODO: Replace with actual fetch when backend is ready
|
|
// Simulated delay for demo
|
|
await new Promise(r => setTimeout(r, 150 + Math.random() * 100));
|
|
// Return mock success
|
|
return { success: true, data: null, message: 'OK (mock)' };
|
|
|
|
/* Real implementation (uncomment when backend ready):
|
|
const url = new URL(API.BASE_URL + path, window.location.origin);
|
|
if (params) Object.entries(params).forEach(([k,v]) => v != null && url.searchParams.set(k, v));
|
|
const res = await fetch(url, {
|
|
method,
|
|
headers: API._headers(),
|
|
...(body ? { body: JSON.stringify(body) } : {}),
|
|
});
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res.json();
|
|
*/
|
|
},
|
|
|
|
_get: (path, params) => API._request('GET', path, null, params),
|
|
_post: (path, body) => API._request('POST', path, body),
|
|
_put: (path, body) => API._request('PUT', path, body),
|
|
_delete: (path) => API._request('DELETE', path),
|
|
|
|
async _upload(path, file, meta = {}) {
|
|
// TODO: Implement multipart upload when backend ready
|
|
await new Promise(r => setTimeout(r, 300));
|
|
return { success: true, data: { fileId: 'mock-file-id', filename: file?.name }, message: 'OK (mock)' };
|
|
},
|
|
};
|
|
|
|
// Global error handler
|
|
window.addEventListener('unhandledrejection', e => {
|
|
if (e.reason?.message?.includes('401')) {
|
|
// Redirect to login
|
|
console.warn('Session expired');
|
|
}
|
|
});
|