Hwandji's picture
feat: initial HuggingFace Space deployment
4343907
raw
history blame
6.82 kB
/**
* SAAP API Client - HuggingFace Deployment Compatible
* Automatically detects environment and uses correct base URL
*/
import axios from 'axios';
// 🌐 Environment-aware base URL detection
const getApiBaseUrl = () => {
// Production HuggingFace Spaces deployment
if (window.location.hostname.includes('hf.space')) {
return '/api/v1'; // Relative path - nginx routes to backend
}
// Local development
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
return 'http://localhost:8000/api/v1';
}
// Network development (IP-based)
if (window.location.hostname.match(/^\d+\.\d+\.\d+\.\d+$/)) {
return `http://${window.location.hostname}:8000/api/v1`;
}
// Fallback: relative path
return '/api/v1';
};
const API_BASE_URL = getApiBaseUrl();
console.log('πŸ”§ SAAP API Configuration:');
console.log(` Environment: ${window.location.hostname}`);
console.log(` API Base URL: ${API_BASE_URL}`);
// Create axios instance with base configuration
const apiClient = axios.create({
baseURL: API_BASE_URL,
timeout: 120000, // πŸš€ ErhΓΆht auf 2 Minuten fΓΌr Multi-Agent Chat (Jane β†’ Spezialist Delegation)
headers: {
'Content-Type': 'application/json',
},
withCredentials: false, // Changed from true for HuggingFace
});
// Request interceptor for logging
apiClient.interceptors.request.use(
(config) => {
console.log(`πŸ”„ API Request: ${config.method?.toUpperCase()} ${config.url}`);
console.log(`πŸ”„ Full URL: ${config.baseURL}${config.url}`);
return config;
},
(error) => {
console.error('❌ Request Error:', error);
return Promise.reject(error);
}
);
// Response interceptor for error handling
apiClient.interceptors.response.use(
(response) => {
console.log(`βœ… API Response: ${response.status} ${response.config.url}`);
return response;
},
(error) => {
if (error.response) {
console.error('❌ API Error:', {
status: error.response.status,
data: error.response.data,
message: error.message
});
} else if (error.request) {
console.error('❌ Network Error: No response received', error.message);
} else {
console.error('❌ Request Setup Error:', error.message);
}
return Promise.reject(error);
}
);
// API Methods
const saapApi = {
// Agent Management
async getAgents() {
const response = await apiClient.get('/agents');
return response.data;
},
async getAgent(agentId) {
const response = await apiClient.get(`/agents/${agentId}`);
return response.data;
},
async createAgent(agentData) {
const response = await apiClient.post('/agents', agentData);
return response.data;
},
async updateAgent(agentId, agentData) {
const response = await apiClient.put(`/agents/${agentId}`, agentData);
return response.data;
},
async deleteAgent(agentId) {
const response = await apiClient.delete(`/agents/${agentId}`);
return response.data;
},
// Agent Lifecycle
async startAgent(agentId) {
const response = await apiClient.post(`/agents/${agentId}/start`);
return response.data;
},
async stopAgent(agentId) {
const response = await apiClient.post(`/agents/${agentId}/stop`);
return response.data;
},
// Agent Communication
async sendMessage(agentId, message) {
const response = await apiClient.post(`/agents/${agentId}/chat`, {
message: message,
timestamp: Date.now()
});
return response.data;
},
// Multi-Agent System
async multiAgentChat(message, options = {}) {
const response = await apiClient.post('/multi-agent/chat', {
user_message: message,
...options
});
return response.data;
},
async getMultiAgentStatus() {
const response = await apiClient.get('/multi-agent/status');
return response.data;
},
// Templates
async getAgentTemplates() {
const response = await apiClient.get('/templates/agents');
return response.data;
},
async createAgentFromTemplate(templateName) {
const response = await apiClient.post(`/templates/agents/${templateName}`);
return response.data;
},
// Health Check
async healthCheck() {
const response = await apiClient.get('/health');
return response.data;
},
};
// WebSocket connection for real-time updates
class SaapWebSocket {
constructor() {
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 1000;
this.listeners = new Map();
}
connect() {
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsHost = window.location.hostname.includes('hf.space')
? window.location.host
: 'localhost:8000';
const wsUrl = `${wsProtocol}//${wsHost}/ws`;
console.log(`πŸ”Œ Connecting to WebSocket: ${wsUrl}`);
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log('βœ… WebSocket connected');
this.reconnectAttempts = 0;
this.emit('connected', {});
};
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log('πŸ“¨ WebSocket message:', data);
this.emit('message', data);
} catch (error) {
console.error('❌ WebSocket message parse error:', error);
}
};
this.ws.onerror = (error) => {
console.error('❌ WebSocket error:', error);
this.emit('error', error);
};
this.ws.onclose = () => {
console.log('❌ WebSocket disconnected');
this.emit('disconnected', {});
this.attemptReconnect();
};
}
attemptReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = this.reconnectDelay * this.reconnectAttempts;
console.log(`πŸ”„ Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => this.connect(), delay);
} else {
console.error('❌ Max reconnection attempts reached');
}
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
}
emit(event, data) {
if (this.listeners.has(event)) {
this.listeners.get(event).forEach(callback => callback(data));
}
}
send(data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
console.error('❌ WebSocket not connected');
}
}
disconnect() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
}
const saapWebSocket = new SaapWebSocket();
// Export both default and named for compatibility
export default saapApi;
export { saapApi, saapWebSocket };