Syncfusion AI Assistant

How can I help you?

Integrate Gemini AI With React Inline AI Assist component

19 Mar 202624 minutes to read

The Inline AI Assist component integrates with Google’s Gemini API to deliver intelligent conversational interfaces. It leverages advanced natural language understanding to interpret user input, maintain context throughout interactions, and provide accurate, relevant responses. By configuring secure authentication and data handling, developers can unlock powerful AI-driven communication features that elevate user engagement and streamline support experiences.

Prerequisites

Before starting, ensure you have the following:

  • Node.js: Version 16 or higher with npm.

  • Google Account: For generating a Gemini API key.

  • Syncfusion Inline AI Assist: Package @syncfusion/ej2-react-interactive-chat installed.

  • Marked Library: For parsing Markdown responses (npm install marked --save).

Set Up the Environment

Follow the Getting Started guide to configure and render the Inline AI Assist component in your application.

Install Dependencies

Install the required packages:

  • Google Generative AI SDK:
npm install @google/generative-ai
  • Marked Library:
npm install marked --save

Generate API Key

  1. Access Google AI Studio: Instructs users to sign into Google AI Studio with a Google account or create a new account if needed.

  2. Navigate to API Key Creation: Go to the Get API Key option in the left-hand menu or top-right corner of the dashboard. Click the Create API Key button.

  3. Project Selection: Choose an existing Google Cloud project or create a new one.

  4. API Key Generation: After project selection, the API key is generated. Users are instructed to copy and store the key securely, as it is shown only once.

Security Note: Advises against committing the API key to version control and recommends using environment variables or a secret manager in production.

Configure Gemini AI with Inline AI Assist

Modify the index.tsx file to integrate the Gemini API with the Inline AI Assist component.

  • Add your Gemini API key securely in the configuration:
const geminiApiKey = 'Place your API key here';
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { GoogleGenerativeAI } from '@google/generative-ai';
import { marked } from 'marked';
import * as React from 'react';
import * as ReactDOM from 'react-dom';

function App() {
    const assistRef = React.useRef(null);
    const editableRef = React.useRef(null);
    const [stopStreaming, setStopStreaming] = React.useState(false);

    // Initialize Gemini API
    const geminiApiKey = ''; // Replace with your Gemini API key
    const genAI = new GoogleGenerativeAI(geminiApiKey);

    const handleSummarizeBtnClick = () => {
        if (assistRef.current && typeof assistRef.current.showPopup === 'function') {
            assistRef.current.showPopup();
        }
    };

    // Stream AI response in chunks
    const streamResponse = async (response) => {
        let lastResponse = "";
        const responseUpdateRate = 10;
        let i = 0;
        const responseLength = response.length;
        while (i < responseLength && !stopStreaming) {
            lastResponse += response[i];
            i++;
            if (i % responseUpdateRate === 0 || i === responseLength) {
                const htmlResponse = await marked.parse(lastResponse);
                if (assistRef.current && typeof assistRef.current.addResponse === 'function') {
                    assistRef.current.addResponse(htmlResponse, i === responseLength);
                }
            }
            await new Promise(resolve => setTimeout(resolve, 15));
        }
    };

    // Handle user prompt: call Gemini model
    const handlePromptRequest = async (args) => {
        try {
            setStopStreaming(false);
            const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' }); // Select the Gemini model
            const result = await model.generateContent(args.prompt);
            const response = result.response.text();
            await streamResponse(response);
        } catch (error) {
            if (assistRef.current && typeof assistRef.current.addResponse === 'function') {
                assistRef.current.addResponse(
                    '⚠️ Something went wrong while connecting to the AI service. Please check your API key or try again later.'
                );
            }
            setStopStreaming(true);
        }
    };

    const handleResponseItemSelect = (args) => {
        if (args.command.label === 'Accept') {
            if (editableRef.current && assistRef.current) {
                const lastResponse = assistRef.current.prompts && assistRef.current.prompts.length > 0
                    ? assistRef.current.prompts[assistRef.current.prompts.length - 1].response
                    : '';
                if (lastResponse) {
                    editableRef.current.innerHTML = '<p>' + lastResponse + '</p>';
                }
            }
            if (assistRef.current && typeof assistRef.current.hidePopup === 'function') {
                assistRef.current.hidePopup();
            }
        } else if (args.command.label === 'Discard') {
            if (assistRef.current && typeof assistRef.current.hidePopup === 'function') {
                assistRef.current.hidePopup();
            }
        }
    };

    const handleToolbarItemClick = (args) => {
        if (args.item.iconCss === 'e-icons e-inline-stop') {
            setStopStreaming(true);
        }
    };

    return (
        <div>
            <button 
                id="summarizeBtn" 
                className="e-btn e-primary" 
                style=
                onClick={handleSummarizeBtnClick}
            >
                Content Summarize
            </button>
            <div 
                id="editableText" 
                contentEditable="true" 
                ref={editableRef}
            >
                <p>Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity. It leverages advanced natural language processing to understand context and deliver precise suggestions. Users can seamlessly integrate AI-powered features into their applications.</p>
                <p>With real-time response streaming and customizable prompts, developers can create interactive experiences. The component supports multiple response modes including inline editing and popup-based interactions.</p>
            </div>
            <InlineAIAssistComponent
                id="defaultInlineAssist"
                ref={assistRef}
                relateTo="#summarizeBtn"
                promptRequest={handlePromptRequest}
                responseSettings=
                inlineToolbarSettings=
                popupWidth="500px"
            />
        </div>
    );
}

ReactDOM.render(<App />, document.getElementById('container'));
import { InlineAIAssistComponent, ResponseItemSelectEventArgs, InlinePromptRequestEventArgs, ToolbarItemClickEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import { GoogleGenerativeAI } from '@google/generative-ai';
import { marked } from 'marked';
import * as React from 'react';

const App: React.FC = () => {
    const assistRef = React.useRef<InlineAIAssistComponent>(null);
    const editableRef = React.useRef<HTMLDivElement>(null);
    const [stopStreaming, setStopStreaming] = React.useState(false);

    // Initialize Gemini API
    const geminiApiKey = ''; // Replace with your Gemini API key
    const genAI = new GoogleGenerativeAI(geminiApiKey);

    const handleSummarizeBtnClick = (): void => {
        if (assistRef.current && typeof assistRef.current.showPopup === 'function') {
            assistRef.current.showPopup();
        }
    };

    // Stream AI response in chunks
    const streamResponse = async (response: string): Promise<void> => {
        let lastResponse = "";
        const responseUpdateRate = 10;
        let i = 0;
        const responseLength = response.length;
        while (i < responseLength && !stopStreaming) {
            lastResponse += response[i];
            i++;
            if (i % responseUpdateRate === 0 || i === responseLength) {
                const htmlResponse = await marked.parse(lastResponse);
                if (assistRef.current && typeof assistRef.current.addResponse === 'function') {
                    assistRef.current.addResponse(htmlResponse, i === responseLength);
                }
            }
            await new Promise(resolve => setTimeout(resolve, 15));
        }
    };

    // Handle user prompt: call Gemini model
    const handlePromptRequest = async (args: InlinePromptRequestEventArgs): Promise<void> => {
        try {
            setStopStreaming(false);
            const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' }); // Select the Gemini model
            const result = await model.generateContent((args.prompt) as string);
            const response = result.response.text();
            await streamResponse(response);
        } catch (error) {
            if (assistRef.current && typeof assistRef.current.addResponse === 'function') {
                assistRef.current.addResponse(
                    '⚠️ Something went wrong while connecting to the AI service. Please check your API key or try again later.'
                );
            }
            setStopStreaming(true);
        }
    };

    const handleResponseItemSelect = (args: ResponseItemSelectEventArgs): void => {
        if (args.command.label === 'Accept') {
            if (editableRef.current && assistRef.current) {
                const lastResponse = assistRef.current.prompts && assistRef.current.prompts.length > 0
                    ? assistRef.current.prompts[assistRef.current.prompts.length - 1].response
                    : '';
                if (lastResponse) {
                    editableRef.current.innerHTML = '<p>' + lastResponse + '</p>';
                }
            }
            if (assistRef.current && typeof assistRef.current.hidePopup === 'function') {
                assistRef.current.hidePopup();
            }
        } else if (args.command.label === 'Discard') {
            if (assistRef.current && typeof assistRef.current.hidePopup === 'function') {
                assistRef.current.hidePopup();
            }
        }
    };

    const handleToolbarItemClick = (args: ToolbarItemClickEventArgs): void => {
        if (args.item && args.item.iconCss === 'e-icons e-inline-stop') {
            setStopStreaming(true);
        }
    };

    return (
        <div>
            <button 
                id="summarizeBtn" 
                className="e-btn e-primary" 
                style=
                onClick={handleSummarizeBtnClick}
            >
                Content Summarize
            </button>
            <div 
                id="editableText" 
                contentEditable="true" 
                ref={editableRef}
            >
                <p>Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity. It leverages advanced natural language processing to understand context and deliver precise suggestions. Users can seamlessly integrate AI-powered features into their applications.</p>
                <p>With real-time response streaming and customizable prompts, developers can create interactive experiences. The component supports multiple response modes including inline editing and popup-based interactions.</p>
            </div>
            <InlineAIAssistComponent
                id="defaultInlineAssist"
                ref={assistRef}
                relateTo="#summarizeBtn"
                promptRequest={handlePromptRequest}
                responseSettings=
                inlineToolbarSettings=
                popupWidth="500px"
            />
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById('container'));
#loader {
    color: #008cff;
    height: 40px;
    left: 45%;
    position: absolute;
    top: 45%;
    width: 30%;
}

#container {
    margin: 20px auto;
}

#editableText {
    width: 100%;
    min-height: 120px;
    max-height: 300px;
    overflow-y: auto;
    font-size: 16px;
    padding: 12px;
    border-radius: 4px;
    border: 1px solid;
}