AI Features
Learn how to add AI features to your application through real-time chat.:
- Chat history summarization — summarize recent chat messages.
- Change message tone — rewrite the draft message into a chosen tone before send.
Important security note: all examples below call the Google generative AI. That will expose the API key in the client bundle. Only proceed if this risk is acceptable for your project (internal demo, protected app, etc.).
Getting started
Section titled “Getting started”Install
Section titled “Install”To enable AI capabilities, install the official SDKs:
npm install --save @ai-sdk/google aiyarn add @ai-sdk/google aiGet your API key
Section titled “Get your API key”Create or log in to your Google AI Studio account, then get an API key from
👉 https://aistudio.google.com/u/2/apikey
Keep this key safe — anyone with access can use your quota.
Base client init
Section titled “Base client init”By default, the SDK reads the key from your .env file using the GOOGLE_GENERATIVE_AI_API_KEY variable:
GOOGLE_GENERATIVE_AI_API_KEY=***Import the Google model:
import { google } from '@ai-sdk/google';
const googleModelAI = google('gemini-2.5-flash');This is the simplest and safest approach when building locally or in a controlled client environment.
Custom client init
Section titled “Custom client init”If you prefer to initialize manually (for example, inside a browser component), you can do it like this:
import { createGoogleGenerativeAI } from '@ai-sdk/google';
const google = createGoogleGenerativeAI({ apiKey: '***' });const googleModelAI = google('gemini-2.5-flash');⚠️ Note: In this setup, the API key will be visible to anyone who inspects your app bundle. Use this only for client-only experiments or demos.
Chat history summarization
Section titled “Chat history summarization”Goal: use an AI assistant to summarize chat messages in a conversation — helpful for users who rejoin long threads or support chats.
How it works
Section titled “How it works”- Select relevant messages (for example, only from the last week).
- Build a readable transcript string.
- Send it to the model with a summarization prompt.
- Display the generated summary in the UI.
Helpers
Section titled “Helpers”Some small utilities to format messages and pick time ranges:
import type { Users, Messages } from 'connectycube';
export const filterMessagesByDaysAgo = ( messages: Messages.Message[] = [], days: number = 0): Messages.Message[] => { const daysAgoTimestamp = days ? Math.floor(Date.now() / 1000) - days * 24 * 60 * 60 : 0; return messages.filter((message) => message.date_sent >= daysAgoTimestamp)}
export const buildMessagesString = ( messages: Messages.Message[] = [], users: Users.User[] = [], currentUserId: number = 0): string => { return messages.reduce((result, {sender_id, message, attachments}) => { const user = users[sender_id] ?? {}; const userName = user.full_name || user.login || '<unknown>'; const postfix = sender_id === currentUserId ? '(me)' : ''; const attachmentsInfo = attachments ? `[attachments: ${JSON.stringify(attachments)}]` : '';
result += `- ${userName} ${postfix}: ${message || ''} ${attachmentsInfo}\n`;
return result; }, '');}Example
Section titled “Example”Flow: filter messages → build messages string → build a prompt → call generateText → render summary in UI.
// ...import type { Users, Messages } from 'connectycube';import { generateText } from 'ai';
export const summarizeChatHistory = async ({ messages: Messages.Message[] = [], users: Users.User[] = [], currentUserId: number = 0, lng: string = 'English', days: number = 0}) => { // 1. filter (by period in days) const filteredMessages = filterMessagesByDaysAgo(messages, 7); // 2. build the transcript const messagesString = await buildMessagesString(filteredMessages, users, currentUserId); // 3. build the prompt const prompt = `You are a helpful assistant. Provide a concise summary of the following chat messages in ${lng}. Use bullet points or a short paragraph. Focus on meaningful conversation and skip system messages or irrelevant technical info. If a username ends with \" (me)", it means the message was sent by ME. Messages:\n${messagesString}`;
// 4. generate the summary try { const result = await generateText({ model: googleModelAI, prompt });
return result.text; // developer decides where to render the chat summarization } catch (error) { console.error('Summarization failed', error); throw error; }}UI integration ideas
Section titled “UI integration ideas”- Add a Summarize button in the conversation.
- Show a small loader while generating.
- Render the summary in a popup, modal, or pinned message.
- Optionally store summaries in local cache to avoid re-calling the model.
Change message tone
Section titled “Change message tone”Goal: rewrite a user’s draft message in a different tone before sending. This can make conversations sound more positive, diplomatic, or even humorous — depending on your tone options.
How it works
Section titled “How it works”- Take the current input text (before send).
- Ask AI to rewrite it in a specific tone.
- Replace the draft text with the rewritten version.
Example
Section titled “Example”Flow: obtain a draft message → build a prompt → call generateText → change the draft message.
// ...import { generateText } from 'ai';
export enum MessageTones { POSITIVE = 'positive', NEGATIVE = 'negative', CRINGE = 'cringe',};
export const changeMessageTone = async( message: string = '', tone: MessageTones = MessageTones.POSITIVE, lng: string = 'English'): Promise<string> => { const draft = message.trim(); const prompt = `Rewrite the text \"${draft}\" in ${tone} tone. Use its original language, or ${lng} if unclear. Avoid using italicized emotional interjections. Instead, express the same emotions directly using plain text or appropriate emojis. Keep all meaning. Output only the rewritten text.`
try { const result = await generateText({ model: googleModelAI, prompt }); return result.text; } catch (error) { console.error('Change message tone failed', error) throw error; }}React usage example
Section titled “React usage example”// ...import type { Dialogs } from 'connectycube';import ConnectyCube, { ChatType, DialogType } from 'connectycube';import React, { useState, useCallback } from 'react';
type ChatInputProps = { dialog: Dialogs.dialog, currentUserId: number, lng?: string}
const ChatInput: React.FC<ChatInputProps> = ({ dialog, currentUserId, lng = 'English' }) => { // ... const [text, setText] = useState<string>(''); const [loading, setLoading] = useState<boolean>(false);
const sendMessage = useCallback(() => { const message = { type: dialog.type === DialogType.PRIVATE ? ChatType.CHAT : ChatType.GROUPCHAT, body: text, extension: { save_to_history: 1, dialog_id: dialog._id } }; const to = dialog.type === DialogType.PRIVATE ? dialog.occupants_ids.find((occupantId) => occupantId !== currentUserId) : dialog._id
ConnectyCube.chat.send(to, message) }, [dialog, text]);
const handleTone = async (tone: MessageTones): Promise<void> => { setLoading(true);
try { const changedText = await changeMessageTone(text, tone, lng);
setText(changedText); } catch (error) { // show friendly UI error if needed } finally { setLoading(false); } };
return ( <div> <textarea value={text} onChange={(e) => setText(e.target.value)} /> <button onClick={sendMessage} disabled={loading}>Send</button> <div> <button onClick={() => handleTone(MessageTones.POSITIVE)} disabled={loading}>Positive</button> <button onClick={() => handleTone(MessageTones.NEGATIVE)} disabled={loading}>Negative</button> <button onClick={() => handleTone(MessageTones.CRINGE)} disabled={loading}>Cringe</button> </div> </div> );}
export default ChatInput;Notes & tips
Section titled “Notes & tips”- Debounce API calls: prevent sending multiple concurrent requests if the user clicks fast.
- Limit message count: sending too many messages in one summarization will slow down responses and increase cost.
- Cache summaries: reuse them unless new messages arrive.
- Respect privacy: don’t send private or sensitive content to external APIs.