JavaScript/Node.js Implementation
This example demonstrates how to implement the ZeroinAI Chat Service API using JavaScript in a Node.js environment.
Backend Implementation (Node.js)
Setting Up the Project
First, create a new Node.js project and install the required dependencies:
mkdir zeroinai-chat-demo
cd zeroinai-chat-demo
npm init -y
npm install express axios dotenv cors
Create a .env file to store your API key:
ZEROINAI_API_KEY=your_api_key_here
ZEROINAI_API_URL=https://api.zeroinai.com/micro-apps/for-api-providers/chat-service
Creating the Server
Create a file named server.js with the following code:
const express = require('express');
const axios = require('axios');
const cors = require('cors');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static('public'));
// API configuration
const API_URL = process.env.ZEROINAI_API_URL;
const API_KEY = process.env.ZEROINAI_API_KEY;
// Create a new chat session
app.post('/api/chats', async (req, res) => {
try {
const response = await axios.post(`${API_URL}/chats/`, {
token_limit: req.body.token_limit || 1000.0
}, {
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
});
res.json(response.data);
} catch (error) {
console.error('Error creating chat:', error.response?.data || error.message);
res.status(error.response?.status || 500).json({
error: error.response?.data || 'Failed to create chat session'
});
}
});
// Send a message and get AI response
app.post('/api/messages', async (req, res) => {
try {
const { chat_id, content } = req.body;
if (!chat_id || !content) {
return res.status(400).json({ error: 'chat_id and content are required' });
}
const response = await axios.post(`${API_URL}/chats/messages/`, {
chat_id,
content
}, {
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
});
res.json(response.data);
} catch (error) {
console.error('Error sending message:', error.response?.data || error.message);
// Handle token limit exceeded
if (error.response?.status === 402) {
return res.status(402).json({
error: 'Token limit exceeded',
message: 'The chat has reached its token limit'
});
}
res.status(error.response?.status || 500).json({
error: error.response?.data || 'Failed to send message'
});
}
});
// Get chat history
app.get('/api/chats/:chatId/messages', async (req, res) => {
try {
const { chatId } = req.params;
const { limit = 10, offset = 0 } = req.query;
const response = await axios.get(`${API_URL}/chats/${chatId}/messages/?limit=${limit}&offset=${offset}`, {
headers: {
'X-API-Key': API_KEY
}
});
res.json(response.data);
} catch (error) {
console.error('Error getting messages:', error.response?.data || error.message);
res.status(error.response?.status || 500).json({
error: error.response?.data || 'Failed to get chat messages'
});
}
});
// Add more tokens to a chat
app.put('/api/chats/:chatId/tokens', async (req, res) => {
try {
const { chatId } = req.params;
const { additional_tokens } = req.body;
if (!additional_tokens) {
return res.status(400).json({ error: 'additional_tokens is required' });
}
const response = await axios.put(`${API_URL}/chats/${chatId}/tokens/`, {
additional_tokens
}, {
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
});
res.json(response.data);
} catch (error) {
console.error('Error adding tokens:', error.response?.data || error.message);
res.status(error.response?.status || 500).json({
error: error.response?.data || 'Failed to add tokens'
});
}
});
// Delete a chat
app.delete('/api/chats/:chatId', async (req, res) => {
try {
const { chatId } = req.params;
const response = await axios.delete(`${API_URL}/chats/${chatId}`, {
headers: {
'X-API-Key': API_KEY
}
});
res.json(response.data);
} catch (error) {
console.error('Error deleting chat:', error.response?.data || error.message);
res.status(error.response?.status || 500).json({
error: error.response?.data || 'Failed to delete chat'
});
}
});
// Start the server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
Frontend Implementation (JavaScript)
Create a public folder in your project and add the following files:
HTML (public/index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZeroinAI Chat Demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h1>ZeroinAI Chat Demo</h1>
</div>
<div class="chat-messages" id="chat-messages"></div>
<div class="chat-input-container">
<input type="text" id="message-input" placeholder="Type your message...">
<button id="send-button">Send</button>
</div>
<div class="token-info">
<div id="token-usage">Tokens: 0 / 1000</div>
<button id="add-tokens-button">Add 500 Tokens</button>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
CSS (public/styles.css)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.chat-container {
width: 100%;
max-width: 600px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
height: 80vh;
}
.chat-header {
padding: 15px;
background-color: #007BFF;
color: white;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.chat-header h1 {
font-size: 20px;
font-weight: normal;
}
.chat-messages {
flex: 1;
padding: 15px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 10px;
}
.message {
padding: 10px 15px;
border-radius: 18px;
max-width: 80%;
word-wrap: break-word;
}
.user-message {
align-self: flex-end;
background-color: #007BFF;
color: white;
}
.ai-message {
align-self: flex-start;
background-color: #f0f0f0;
color: #333;
}
.system-message {
align-self: center;
background-color: #f8d7da;
color: #721c24;
font-size: 14px;
padding: 8px 12px;
border-radius: 10px;
}
.chat-input-container {
display: flex;
padding: 15px;
border-top: 1px solid #eee;
}
#message-input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 20px;
outline: none;
}
#send-button {
margin-left: 10px;
padding: 10px 15px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
}
.token-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 15px;
background-color: #f8f9fa;
border-top: 1px solid #eee;
font-size: 14px;
}
#add-tokens-button {
padding: 5px 10px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 12px;
}
JavaScript (public/app.js)
// State management
let chatId = null;
let tokenLimit = 1000;
let tokenUsed = 0;
// DOM elements
const chatMessages = document.getElementById('chat-messages');
const messageInput = document.getElementById('message-input');
const sendButton = document.getElementById('send-button');
const tokenUsageElement = document.getElementById('token-usage');
const addTokensButton = document.getElementById('add-tokens-button');
// Initialize chat session
async function initChat() {
try {
displaySystemMessage('Creating chat session...');
const response = await fetch('/api/chats', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token_limit: tokenLimit })
});
if (!response.ok) {
throw new Error('Failed to create chat session');
}
const data = await response.json();
chatId = data.chat_id;
tokenLimit = data.token_limit;
tokenUsed = data.token_used;
updateTokenDisplay();
displaySystemMessage('Chat session created. You can start chatting!');
// Enable input after chat is initialized
messageInput.disabled = false;
sendButton.disabled = false;
} catch (error) {
console.error('Error initializing chat:', error);
displaySystemMessage('Error: Failed to create chat session. Please refresh the page.');
}
}
// Send message and get AI response
async function sendMessage() {
const content = messageInput.value.trim();
if (!content || !chatId) return;
try {
// Display user message immediately
displayMessage(content, true);
messageInput.value = '';
// Show typing indicator
const typingIndicator = displayTypingIndicator();
// Send message to API
const response = await fetch('/api/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
chat_id: chatId,
content: content
})
});
// Remove typing indicator
chatMessages.removeChild(typingIndicator);
if (response.status === 402) {
displaySystemMessage('Token limit reached. Adding more tokens...');
await addTokens();
// Retry sending the message
return sendMessage();
}
if (!response.ok) {
throw new Error('Failed to send message');
}
const data = await response.json();
// Display AI response
displayMessage(data.content, false);
// Update token usage (fetch latest chat info)
await updateChatInfo();
} catch (error) {
console.error('Error sending message:', error);
displaySystemMessage('Error: Failed to send message. Please try again.');
}
}
// Add more tokens to the chat
async function addTokens() {
try {
const response = await fetch(`/api/chats/${chatId}/tokens`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
additional_tokens: 500
})
});
if (!response.ok) {
throw new Error('Failed to add tokens');
}
const data = await response.json();
tokenLimit = data.token_limit;
tokenUsed = data.token_used;
updateTokenDisplay();
displaySystemMessage('Added 500 more tokens to the conversation.');
return true;
} catch (error) {
console.error('Error adding tokens:', error);
displaySystemMessage('Error: Failed to add more tokens.');
return false;
}
}
// Update chat info to get latest token usage
async function updateChatInfo() {
try {
// This is a simplified approach - in a real app, you might want to
// create an endpoint to get the chat details including token usage
const response = await fetch(`/api/chats/${chatId}/messages?limit=1`);
if (!response.ok) {
throw new Error('Failed to get chat info');
}
// For this example, we're just incrementing the token usage
// In a real app, you would get the actual token usage from the API
tokenUsed += 10; // Simplified token counting
updateTokenDisplay();
} catch (error) {
console.error('Error updating chat info:', error);
}
}
// Display functions
function displayMessage(content, isUser) {
const messageElement = document.createElement('div');
messageElement.className = `message ${isUser ? 'user-message' : 'ai-message'}`;
messageElement.textContent = content;
chatMessages.appendChild(messageElement);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function displaySystemMessage(content) {
const messageElement = document.createElement('div');
messageElement.className = 'system-message';
messageElement.textContent = content;
chatMessages.appendChild(messageElement);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function displayTypingIndicator() {
const typingElement = document.createElement('div');
typingElement.className = 'message ai-message';
typingElement.textContent = 'AI is typing...';
chatMessages.appendChild(typingElement);
chatMessages.scrollTop = chatMessages.scrollHeight;
return typingElement;
}
function updateTokenDisplay() {
tokenUsageElement.textContent = `Tokens: ${tokenUsed} / ${tokenLimit}`;
}
// Event listeners
sendButton.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
addTokensButton.addEventListener('click', addTokens);
// Initialize the app
document.addEventListener('DOMContentLoaded', () => {
// Disable input until chat is initialized
messageInput.disabled = true;
sendButton.disabled = true;
initChat();
});
Running the Application
Start the server:
node server.js
Open your browser and navigate to http://localhost:3000 to use the chat application.
Key Features of This Implementation
-
Proxy Server: The Node.js server acts as a proxy between the frontend and the ZeroinAI API, keeping your API key secure.
-
Token Management: The application tracks token usage and automatically adds more tokens when needed.
-
Error Handling: Comprehensive error handling for various API error scenarios.
-
Real-time UI Updates: The UI updates in real-time to show messages, typing indicators, and system notifications.
-
Responsive Design: The chat interface is designed to work well on both desktop and mobile devices.
Extending the Application
You can extend this basic implementation in several ways:
-
User Authentication: Add user authentication to associate chats with specific users.
-
Persistent Storage: Store chat IDs in localStorage or a database to allow users to continue conversations.
-
Chat History: Implement a feature to view and search through past conversations.
-
Custom Styling: Customize the UI to match your brand's look and feel.
-
Message Formatting: Add support for markdown or rich text formatting in messages.
-
Attachments: Implement file uploads and attachments in the chat interface.