Implementing ChatGPT in React Native & Handling Streaming Response

ChatGPT, an AI model developed by OpenAI, has gained popularity for its ability to generate human-like text responses based on the input it receives. Integrating ChatGPT into a React Native application can enhance user interactions by providing intelligent responses to user queries or messages. In this guide, we’ll walk through the process of implementing ChatGPT in a React Native application and handling streaming responses for real-time interactions.

Prerequisites

Before we begin, make sure you have the following installed:

  • Node.js and npm
  • React Native CLI
  • Text editor or IDE of your choice

Step 1: Set Up a React Native Project

If you haven’t already, create a new React Native project using the following command:

npx react-native init ChatGPTApp

Navigate to the project directory:

cd ChatGPTApp

Step 2: Install Dependencies

Installing required dependencies Next, we need to install the required dependencies. We will use the EventSource library to handle streaming responses. You can install it using the following command:

yarn add react-native-sse @react-native-clipboard/clipboard

Step 3: Implement ChatGPT

Integrating the ChatGPT model To integrate the ChatGPT model, we need to make an API request to the OpenAI API. First, you need to sign up for an API key from the OpenAI website. Once you have the API key, you can use the following code to make an API request:

const handleGetChatGPTResponse = (seletedIndex, list) => { 
  try { 
   setCurrentIndex(seletedIndex); 
   setConversationList([...list]); 

   const params = JSON.stringify({ model: 'gpt-3.5-turbo', 
   messages: [...list], 
   max_tokens: 600, 
   n: 1, 
   temperature: 0.8, 
   stream: true, }); 
  } catch (error) { 
  console.log('Error', error); 
 } 
};

In the above code, we are making an API request to the OpenAI API with the model, messages, max_tokens, n, temperature, and stream parameters. You can also adjust more parameters and configurations as given in OpenAI Doc. We can also send previous responses to chat gpt as history so chatgpt can give replies based on it. We also add an event listener for the open event, triggered when the connection is established. We are also adding an event listener for the message event, which is triggered when a new message is received.

Step 4: Handle Streaming Response

To handle streaming responses, we are using the EventSource API using react-native-sse sdk. The EventSource API allows us to receive real-time updates from the server. In the above code, we are adding an event listener for the message event, which is triggered when a new message is received. We are then parsing the JSON data and updating the conversationList state with the new message. You can follow the below code to request a streaming response.

const handleGetChatGPTResponse = (selectedIndex, list) => {
    try {
       setCurrentIndex(selectedIndex);
       setConversationList([...list]);

      const params = JSON.stringify({
          model: 'gpt-3.5-turbo',
          messages: [...list],
          max_tokens: 600,
          n: 1,
          temperature: 0.8,
          stream: true,
      });

       setShowActionButtons(false);

       const es = new EventSource(Endpoints.chatGptUrl, {
            headers: {
                 'Content-Type': 'application/json',
                Authorization: `Bearer ${OPENAI_API_KEY}`,
            },
            method: 'POST',
            body: params,
            pollingInterval: 0,
         });

         es.addEventListener('open', () => {
            console.log('Open ');
         });


        es.addEventListener('message', (event) => {
            console.log('Test Message', event);
            let temp = conversationList;
            if (event.data !== '[DONE]') {
               const data = JSON.parse(event.data);
               console.log('Test Message', data);
               if (data?.choices[0]?.delta?.content !== undefined) {
                 let value = temp[selectedIndex]?.content;
                 let newValue = value + data.choices[0].delta.content;
                 temp[selectedIndex].content = newValue;
                 console.log('temp', temp);
                }
            } else {
               setShowActionButtons(true);
            }
            setConversationList([...temp]);
            setTimeout(() => {
                flatListRef?.current?.scrollToEnd();
            }, 1000);
            setSearch('');
         });

         return () => {
             es.close();
             es.removeAllEventListeners();
         };
      } catch (error) {
         console.log('Error', error);
      }
};

Seamless ChatGPT Implementation - Hire Our Experts and Get Started Today!

Step 5: Combline Code

import  {
     FlatList,
     Keyboard,
     KeyboardAvoidingView,
     SafeAreaView,
     StyleSheet,
     Text,
     TextInput,
     TouchableOpacity,
     View,
}    from "react-native";
import React, { useEffect, useRef, useState } from "react";
import Colors from "../theme/Colors";
import { Header, SvgIcon } from "../components";
import Strings from "../utils/Strings";
import SvgIcons from "../utils/SvgIcons";
import { FontFamily, FontSize } from "../utils/Fonts";
import { isAndroid, isIos } from "../utils/Metrics";
import stylesCommon from "../utils/stylesCommon";
import Clipboard from "@react-native-clipboard/clipboard";
import { showSuccessToast } from "../components/FlashMessage";
import EventSource from "react-native-sse";
import { Endpoints, OPENAI_API_KEY } from "../networkConfig/Endpoints";

const EditWithChatGpt = () => {
    const [search, setSearch] = useState("");
    const [keyboardOffset, setKeyboardOffset] = useState(0);

    const [conversationList, setConversationList] = useState([]);

    const [currentIndex, setCurrentIndex] = useState(0);

    const flatListRef = useRef();
    const [showActionButtons, setShowActionButtons] = useState(false);

    useEffect(() => {
         const keyboardDidShowListener = Keyboard.addListener(
              isAndroid ? "keyboardDidShow" : "keyboardWillShow",
              (e) => {
                  setKeyboardOffset(e.endCoordinates.height);
              }
         );

         const keyboardDidHideListener = Keyboard.addListener(
              isAndroid ? "keyboardDidHide" : "keyboardWillHide",
              () => {
                 setKeyboardOffset(0);
              }
          );
          return () => {
              keyboardDidShowListener.remove();
              keyboardDidHideListener.remove();
          };
        }, []);
        const onPressRefresh = (item, index) => {
             let selectedIndex = index;
             let list = conversationList || [];
             list[index].content = "";
             setCurrentIndex(selectedIndex);
             setConversationList([...list]);

             handleGetChatGPTResponse(selectedIndex, list);
        };
        const onPressSend = () => {
            try {
               let selectedIndex = currentIndex;
               let list = conversationList || [];
               let queObj = {
                  role: "user",
                  content: search?.trim(),
               };
               let ansObj = {
                  role: "system",
                  content: "",
               };
               list.push(queObj);
               list.push(ansObj);
               selectedIndex = list.length - 1;
               setCurrentIndex(selectedIndex);
               setConversationList([...list]);
               handleGetChatGPTResponse(selectedIndex, list);
            } catch (error) {
               console.log("Error", error);
            }
        };

        const handleGetChatGPTResponse = (selectedIndex, list) => {
             try {
                 setCurrentIndex(selectedIndex);
                 setConversationList([...list]);

                 const params = JSON.stringify({
                     model: "gpt-3.5-turbo",
                     messages: [...list],
                     max_tokens: 600,
                     n: 1,
                     temperature: 0.8,
                     stream: true,
                });
                setShowActionButtons(false);

                const es = new EventSource(Endpoints.chatGptUrl, {
                headers: {
                     "Content-Type": "application/json",
                    Authorization: `Bearer ${OPENAI_API_KEY}`,
                },
                method: "POST",
                body: params,
                pollingInterval: 0,
            });

            es.addEventListener("open", () => {
                console.log("Open ");
            });

            es.addEventListener("message", (event) => {
                console.log("Test Message", event);
                let temp = conversationList;
                if (event.data !== "[DONE]") {
                   const data = JSON.parse(event.data);
                   console.log("Test Message", data);

                   if (data?.choices[0]?.delta?.content !== undefined) {
                      let value = temp[selectedIndex]?.content;
                      let newValue = value + data.choices[0].delta.content;
                      temp[selectedIndex].content = newValue;
                      console.log("temp", temp);
                    } else {
                    }
             } else {
                setShowActionButtons(true);
             }
                setConversationList([...temp]);
                setTimeout(() => {
                flatListRef?.current?.scrollToEnd();
                }, 1000);
             });
                 setSearch("");
                 return () => {
                 es.close();
                 es.removeAllEventListeners();
             };
                } catch (error) {
                    console.log("Error", error);
                }
             };

                const renderConversation = ({ item, index }) => {
                       let isUser = item?.role == "user";
                       return (
                         <View style={styles.itemWrap}>
                          <View style={styles.topNameWrap}>
                           <Text style={styles.userStyle}>
                              {isUser ? Strings.you : Strings.bMAIAssistant}
                           </Text>
                          </View>
                          <Text style={styles.content}>{item?.content}</Text>
                         {showActionButtons ? (
                           <View style={styles.iconListWrap}>
                             <TouchableOpacity
                              style={styles.iconWrap}
                              onPress={() => onPressClipboard(item)}
                              >
                                <SvgIcon name={SvgIcons.copyIcon} height={15} width={15} />
                              </TouchableOpacity>
                              {!isUser && index == conversationList.length - 1 ? (
                                <TouchableOpacity
                                 style={[styles.iconWrap, styles.refreshIcon]}
                                 onPress={() => onPressRefresh(item, index)}
                               >
                                 <SvgIcon name={SvgIcons.refreshIcon} height={15} width={15} />
                                </TouchableOpacity>
                               ) : null}
                             </View>
                            ) : null}
                         </View>
                       );
                     };


                     const onPressClipboard = (item) => {
                        let { content } = item;
                        try {
                          Clipboard.setString(content);
                          showSuccessToast(Strings.copiedSuccessMsg);
                       } catch (error) {}
                     };
                     return (
                       <View style={styles.container}>
                          <Header backButton middleText={Strings.editWithAiAssistant} />
                          <View style={styles.mainWrap}>
                       <View style={stylesCommon.flex}>
                         {conversationList.length ? (
                           <FlatList
                              data={conversationList}
                              extraData={conversationList}
                              renderItem={renderConversation}
                              ref={flatListRef}
                              showsVerticalScrollIndicator={false}
                              bounces={false}
                              contentContainerStyle={styles.contentContainerStyle}
                            />
                         ) : (
                            <View style={styles.topWrap}>
                              <Text style={styles.howCanIHelpYou}>
                                 {Strings.howCanIHelpYou}
                              </Text>
                            </View>
                           )}
                        </View>
                        <KeyboardAvoidingView
                           behavior={isIos ? "padding" : null}
                           enabled
                           contentContainerStyle={[
                              stylesCommon.flexGrow,
                              { paddingBottom: keyboardOffset },
                            ]}
                            keyboardVerticalOffset={100}
                          >
                           <View style={styles.bottomWrapper}>
                             <Text>{Strings.content}</Text>
                             <View style={styles.inputBackground}>
                               <View style={styles.inputWrapper}>
                                <TextInput
                                   placeholder={Strings.sendMessage}
                                   autoCorrect={false}
                                   placeholderTextColor={Colors.disable}
                                   blurOnSubmit={false}
                                   cursorColor={Colors.tabActive}
                                   selectionColor={Colors.tabActive}
                                   underlineColorAndroid={Colors.transparent}
                                   value={search}
                                   onChangeText={(text) => setSearch(text)}
                                   multiline
                                   style={styles.inputStyle}
                                 />
                              </View>
                              <View style={styles.lastWrap}>
                                <TouchableOpacity
                                   style={[
                                    styles.sendWrap,
                                    {
                                      backgroundColor: search?.trim()?.length
                                         ? Colors.green2
                                        : Colors.disable,
                                     },
                                  ]}
                                  onPress={onPressSend}
                                >
                               <SvgIcon name={SvgIcons.sendIcon} height={20} width={20} />
                              </TouchableOpacity>
                             </View>
                            </View>
                           </View>
                          </KeyboardAvoidingView>
                         </View>
                        <SafeAreaView />
                       </View>
                     );
                  };
                  export default EditWithChatGpt;

                  const styles = StyleSheet.create({
                    container: {
                    flex: 1,
                    backgroundColor: Colors.white,
                  },
                  mainWrap: {
                     flex: 1,
                     paddingTop: 15,
                     paddingHorizontal: 20,
                  },
                  topWrap: {
                    alignItems: "center",
                    paddingTop: 20,
                    flex: 1,
                  },
                  howCanIHelpYou: {
                    color: Colors.primaryText,
                    marginTop: 15,
                  },
                  inputBackground: {
                    backgroundColor: Colors.background,
                    borderWidth: 1,
                    borderColor: Colors.divider,
                    marginTop: 10,
                    paddingVertical: 10,
                    borderRadius: 8,
                    paddingHorizontal: 10,
                    maxHeight: 300,
                    alignItems: "center",
                    justifyContent: "space-between",
                    flexDirection: "row",
                  },
                  inputStyle: {
                    fontSize: FontSize.F14,
                    padding: 0,
                    fontFamily: FontFamily.regular,
                    color: Colors.primaryText,
                    maxHeight: 250,
                    paddingBottom: isIos ? 5 : 3,
                  },
                  bottomWrapper: {
                    paddingBottom: 20,
                    paddingHorizontal: 2,
                    paddingTop: 10,
                  },
                  sendWrap: {
                    height: 35,
                    width: 35,
                    borderRadius: 5,
                    alignItems: "center",
                    justifyContent: "center",
                  },
                  lastWrap: {
                    justifyContent: "flex-end",
                    paddingLeft: 5,
                    alignSelf: "flex-end",
                  },
                  topNameWrap: {
                    flexDirection: "row",
                    alignItems: "center",
                  },
                  nameInitialWrap: {
                    height: 25,
                    width: 25,
                    backgroundColor: Colors.tabActive,
                    borderRadius: 50,
                    alignItems: "center",
                    justifyContent: "center",
                    marginRight: 10,
                   },
                   itemWrap: {
                     paddingVertical: 10,
                   },
                   iconListWrap: {
                     flexDirection: "row",
                     alignItems: "center",
                     marginTop: 20,
                   },
                   iconWrap: {
                     height: 30,
                     width: 30,
                     backgroundColor: Colors.lightGray,
                     borderRadius: 60,
                     alignItems: "center",
                     justifyContent: "center",
                   },
                   refreshIcon: {
                      marginLeft: 10,
                   },
                   disabledButtonContainerStyle: {
                      backgroundColor: Colors.white,
                      borderWidth: 1,
                      borderColor: Colors.border,
                      flex: 0.5,
                      marginLeft: 10,
                    },
                    inputWrapper: {
                      maxHeight: 250,
                      flex: 0.99,
                      width: "90%",
                    },
                    contentContainerStyle: {
                      flexGrow: 1,
                      paddingBottom: 20,
                    },
                    content: {
                      fontSize: 14,
                      fontWeight: "600",
                      color: "gray",
                    },
                    userStyle: {
                      fontSize: 16,
                      color: "Black",
                      fontWeight: "bold",
                     },
                });
coma

Conclusion

This blog post explains how to implement the ChatGPT model in a React Native application and handle streaming responses using the EventSource API. It covers project setup, model integration, and streaming response handling to create an interactive chat experience. By leveraging ChatGPT, you can enhance user engagement and provide valuable assistance in various applications. Experiment with different configurations to customize the chat interface to your needs.

!! Enjoy, Keep, and Do Delicious Coding !!

Keep Reading

Keep Reading

  • Service
  • Career
  • Let's create something together!

  • We’re looking for the best. Are you in?