Introduction
Why You Need a Knowledge Base
In today's world, you can get information about almost anything online. As a product developer, you want to control the quality of your product's information, and the best way to do this is by creating a Knowledge Base. This is a place where users can seek information regarding your project.
What We’ll Build
In this article, you will learn how to create a Knowledge Base using React Native and Strapi 5, as well as how to create a search functionality using AI.
Prerequisites
- Basic knowledge of React Native
- Node.js
- Visual studio code
- Basic Knowledge of Strapi - get started here!
- Knowledge of LangChain
- Basic knowledge of Python
Application Architecture
Given that we want to create an application that spans multiple applications, we should ideally have an architecture to guide us when building the application.
So, we have to decouple all the applications that ultimately make up our application and also point out how they communicate.
Here is an overview of the application's architecture:
Strapi 5 API
This application will use Strapi's REST API to expose the Data stored by the user utilizing Strapi CMS. In our case, we will be using local development, but you can easily exchange the endpoints to suit your requirements.
Once a user publishes entries to Strapi, it creates custom APIs and exposes the items via it's API. This API will serve our React Native application with Article data published by the user, and which in turn serves filtered and transfomed data to Flask + LangChain application.
React Native App
We will use React Native to create the frontend application. React Native is a framework used to develop cross-platform mobile applications.
The Knowledge Base app needs to render Strapi's API data on its user interface using React Native.
Flask and LangChain App
The Knowledge Base app uses LangChain, which is a framework to develop applications powered by Large Language Models (LLMs) to retrieve data from Strapi and transform the data before it is stored in vector stores.
A vector store is a database that can store vectors (fixed-length lists of numbers) along with other data items.
The Knowledge Base app also retrieves data from the user's input on the React Native App and uses similarity search and the chat model to give responses and refer to original sources.
Flask is used to add routing to LangChain and makes it possible for the other applications to communicate with LangChain reliably and fast.
Setting Up Strapi 5 Backend
Install Strapi 5
To start creating your Strapi 5 application using NPM, open your terminal and add the following code:
npx create-strapi@latest
# 'npx' runs a command from an npm package
# 'create-strapi' is the Strapi package
# '@latest' indicates that the latest version of Strapi is used
# note that the --quick-start flag has been deprecated in Strapi5
During installation process, you will have the following prompts:
Prompt | Choose option | Explanation |
---|---|---|
do you want to use the default database | Yes | initializing the app with a sqlite database. |
start with an example structure & data | Yes | this will pre-populate your app with content-types data. |
install dependencies with npm | Yes | installs all dependencies. |
Please log in or sign up. | Skip | not deploying to cloud. development stage. |
When the installation is done, you can start up a Strapi 5 development server using the following npm command:
npm run develop
Strapi will also redirect you to a browser sign-in page as an admin:
After logging in, follow the next steps to set up your backend.
Creating Article Content-type
Strapi 5's admin panel offers sample data structures if you agreed to the "start with an example structure and data" prompt we set previously and we will use these provided collections to build our application.
You can learn how to create custom content types using Strapi 5's admin content-type builder.
These content types or any custom collections you create automatically get a default api endpoint.
NOTE : During Strapi installation we said Yes to "start with an example structure & data". This means we have already automatically created the Article content type.
Publish Article Entries
Since we created our app with the example data, you should be able to navigate to your Article collection and see the data that was created for us.
Now, let's make sure that all of the data is published. If not, you can select all items via the checkbox and then click the Publish button.
Generate Strapi API Token for Authentication
Navigate to Settings on the sidebar, click on API tokens on the settings menu, and click on the Add new API Token button:
Strapi API tokens allow executing a request on REST API or GraphQL API endpoints as an authenticated user.
This will lead you to a page where you can add your API name, duration, and type:
Building the React Native Frontend
In this section, you will setup an environment for the React Native application and build the application following the next steps.
Step 1: Create a React Native Application
Start by creating your React Native application. Create a new folder outside your Strapi root folder and run the following command to create a new React Native application:
npx create-expo-app kb-react-native --template blank
After that, install the following dependencies on your application's root folder in order to run the application on your web browser:
- React-DOM: This is a React package that serves as a bridge between React Native components and the DOM (Document Object Model), and you can install it using the following npm command:
npx expo install react-dom react-native-web @expo/metro-runtime
- React-navigation/native and stack: This manages the application's navigation, and you can install it using the following npm command:
npm install @react-navigation/native @react-navigation/stack
- Axios: This package is used to make API requests using the HTTP/HTTPS protocol. you can install it using the following npm command:
npm install axios
- React Native Modal: This is an extension of the original React Native's Modal.
npm i react-native-modal
Step 2: Run the React Native Application
After the installation process above, run the following command to run your application:
npx expo start
This will open a page on http://localhost/8081
by default.
Step 3: Creating the Main API File
Now that you have confirmed your expo React Native application is running, it's time to do some editing.
First, create a file named api.js
in the root folder or React Native application to handle your API calls:
1import axios from 'axios';
2
3const API_URL = 'http://localhost:1337/api';
4const API_KEY = '<your strapi api>';
5
6const headers = {
7 Authorization: `Bearer ${API_KEY}`,
8};
9
10// Fetch all articles
11const getArticles = async () => {
12 try {
13 const response = await axios.get(`${API_URL}/articles?populate=*`, { headers });
14 return response.data.data; // Direct access to flattened data
15 } catch (error) {
16 console.error('Error fetching articles:', error);
17 throw error;
18 }
19};
20
21// Fetch all authors
22const getAuthors = async () => {
23 try {
24 const response = await axios.get(`${API_URL}/authors?populate=*`, { headers });
25 return response.data.data;
26 } catch (error) {
27 console.error('Error fetching authors:', error);
28 throw error;
29 }
30};
31
32// Fetch all categories
33const getCategories = async () => {
34 try {
35 const response = await axios.get(`${API_URL}/categories?populate=*`, { headers });
36 return response.data.data;
37 } catch (error) {
38 console.error('Error fetching categories:', error);
39 throw error;
40 }
41};
42
43// Fetch a specific article by ID
44const getArticleById = async (id) => {
45 try {
46 const response = await axios.get(`${API_URL}/articles/${id}?populate=*`, { headers });
47 return response.data.data;
48 } catch (error) {
49 console.error(`Error fetching article with ID ${id}:`, error);
50 throw error;
51 }
52};
53
54// Fetch a specific author by ID
55const getAuthorById = async (id) => {
56 try {
57 const response = await axios.get(`${API_URL}/authors/${id}?populate=*`, { headers });
58 return response.data.data;
59 } catch (error) {
60 console.error(`Error fetching author with ID ${id}:`, error);
61 throw error;
62 }
63};
64
65// Fetch a specific category by ID
66const getCategoryById = async (id) => {
67 try {
68 const response = await axios.get(`${API_URL}/categories/${id}?populate=*`, { headers });
69 return response.data.data;
70 } catch (error) {
71 console.error(`Error fetching category with ID ${id}:`, error);
72 throw error;
73 }
74};
75
76export { getArticles, getAuthors, getCategories, getArticleById, getAuthorById, getCategoryById };
The code above is resposible for making the main API request from Strapi API. It uses Axios to make the request and returns the getArticles
function which contains the API's response.
Step 4: Create Components
Now, we have to create components that we will use as guides or templates to manage the individual application component's state, data flow, and user interface.
Article Card Component
In your root folder, create a folder named components
. Inside the new folder components
, create a file article_card.js
and add the following code:
1// ./components/full_article.js
2
3import React, { useState } from 'react';
4import { View, Text, StyleSheet, Image, Pressable } from 'react-native';
5import { useNavigation } from '@react-navigation/native';
6
7const ArticleCard = ({ article }) => {
8 const navigation = useNavigation();
9 const API_URL = 'http://localhost:1337';
10 console.log(article);
11 return (
12 <View style={styles.card}>
13
14 <Pressable onPress={() => navigation.navigate('FullArticle', { article:article })}>
15 <Text style={styles.title}>{article.title}</Text>
16 <Image
17 source={{ uri: API_URL + article.cover.formats.thumbnail.url }}
18 style={styles.cover}
19 />
20
21 <Text style={styles.summary}>{article.description}</Text>
22 </Pressable>
23 </View>
24 );
25};
26
27const styles = StyleSheet.create({
28 card: {
29 padding: 20,
30 flexGrow: 1,
31 margin: 10,
32 backgroundColor: '#fff',
33 borderRadius: 10,
34 shadowColor: '#000',
35 shadowOffset: {
36 width: 0,
37 height: 2,
38 },
39 shadowOpacity: 0.25,
40 shadowRadius: 3.84,
41 elevation: 5,
42 width: '40%',
43 alignSelf:'center'
44
45 },
46 title: {
47 fontSize: 18,
48 fontWeight: 'bold',
49 width: '90%',
50 textAlign:'center'
51 },
52 summary:{
53 fontSize: 14,
54 width: '90%',
55 padding:10,
56 textAlign:'center'
57 },
58
59 cover: {
60 width: 250,
61 height:150,
62 backgroundColor:'black',
63 alignSelf:'center',
64 margin:10
65
66 }
67
68});
69
70export default ArticleCard;
71
The code above provides a structure for the article's clickable modal, which shows users the article's important attributes and summary before they opt to open the full article.
Full Article Component
Create another file named full_article.js
inside the components
folder and add the following code:
1// ./components/full_article.js
2
3import React from 'react';
4import { View, Text, ScrollView, StyleSheet, Image } from 'react-native';
5
6const FullArticle = ({ route }) => {
7 const { article } = route.params;
8 const API_URL = 'http://localhost:1337';
9
10 if (!article) {
11 return (
12 <View style={styles.container}>
13 <Text>Article details not available.</Text>
14 </View>
15 );
16 }
17
18
19 const title = article.title;
20 const cover = article.cover;
21 const body = article.blocks[0].body;
22 const description = article.description;
23
24 return (
25 <ScrollView contentContainerStyle={styles.container}>
26 <Text style={styles.title}>{title}</Text>
27 <Image
28 source={{ uri: API_URL + cover.url }}
29 style={styles.cover}
30 />
31
32 <Text style={styles.description}>{description}</Text>
33
34 <Text>{body}</Text>
35 </ScrollView>
36 );
37};
38
39const styles = StyleSheet.create({
40 container: {
41 flexGrow: 1,
42 backgroundColor: '#fff',
43 padding: 15,
44 width:'65%',
45 textAlign:'center',
46 alignSelf:'center',
47 height:1500,
48 },
49 title: {
50 fontSize: 44,
51 fontWeight: 'bold',
52 marginBottom: 16,
53 textAlign:'center'
54 },
55 description:{
56 fontSize: 16,
57
58 margin: 16,
59 textAlign:'center'
60 },
61 cover: {
62 width: '90%',
63 height:500,
64 borderRadius: 8,
65 marginBottom: 16,
66 textAlign:'center',
67 alignSelf:'center'
68 },
69 heading1: {
70 fontSize: 22,
71 fontWeight: 'bold',
72 marginBottom: 8,
73 },
74 heading2: {
75 fontSize: 20,
76 fontWeight: 'bold',
77 marginBottom: 8,
78 },
79 heading3: {
80 fontSize: 18,
81 fontWeight: 'bold',
82 marginBottom: 8,
83 },
84 heading4: {
85 fontSize: 16,
86 fontWeight: 'bold',
87 marginBottom: 8,
88 },
89 heading5: {
90 fontSize: 14,
91 fontWeight: 'bold',
92 marginBottom: 8,
93 },
94 heading6: {
95 fontSize: 12,
96 fontWeight: 'bold',
97 marginBottom: 8,
98 },
99 body: {
100 fontSize: 16,
101 lineHeight: 24,
102 marginBottom: 10,
103 },
104 list: {
105 marginBottom: 10,
106 },
107 listItem: {
108 fontSize: 16,
109 lineHeight: 24,
110 marginLeft: 20,
111 },
112});
113
114export default FullArticle;
The code above creates a FullArticle component which will render the full article for the user. This component is triggered wwhen the user clicking on the article modal from the ArticleCard component.
This trigger is accompanied by the route parameter, which passes the selected article's data.
Step 4: Creating React Native screens
After creating the components, you need to create the screens for your application.
By default, React Native references its app.js
file for the App's screens. So, navigate to the app.js
file of your React Native application folder and add the following code:
1// ./app.js
2
3import React, { useEffect, useState } from 'react';
4import { Button, View, FlatList, StyleSheet, ScrollView } from 'react-native';
5import { NavigationContainer } from '@react-navigation/native';
6import { createStackNavigator } from '@react-navigation/stack';
7import { getArticles } from './api';
8import ArticleCard from './components/article_card';
9import FullArticle from './components/full_article';
10import Modal from "react-native-modal";
11import Searchbox from './components/search_box';
12
13const Stack = createStackNavigator();
14
15const ArticleList = () => {
16 const [articles, setArticles] = useState([]);
17 const [isModalVisible, setModalVisible] = useState(false);
18
19 const toggleModal = () => {
20 setModalVisible(!isModalVisible);
21 };
22
23
24 useEffect(() => {
25 const fetchArticles = async () => {
26 try {
27 const data = await getArticles();
28 setArticles(data);
29 console.log(data);
30 console.log('reloaded');
31 } catch (error) {
32 console.error('Error fetching articles:', error);
33 }
34 };
35
36 fetchArticles();
37 }, []);
38
39 return (
40 <ScrollView style={styles.container}>
41 <Button title="search the knowledgebase" onPress={toggleModal} style={styles.btn} />
42 <Modal isVisible={isModalVisible} hasBackdrop={true} backdropColor='white' backdropOpacity={0.94}>
43 <View style={{ flex: 1 }}>
44 <Searchbox article={articles} />
45
46 <Button title="close" onPress={toggleModal} />
47 </View>
48 </Modal>
49 <FlatList
50 data={articles}
51 renderItem={({ item }) => <ArticleCard article={item} />}
52 keyExtractor={(item) => item.id.toString()}
53 />
54 </ScrollView>
55 );
56};
57
58export default function App() {
59 return (
60 <NavigationContainer>
61 <Stack.Navigator initialRouteName="ArticleList">
62 <Stack.Screen name="ArticleList" component={ArticleList} options={{ title: 'Articles' }} />
63 <Stack.Screen name="FullArticle" component={FullArticle} options={{ title: 'Full article'}} />
64 </Stack.Navigator>
65 </NavigationContainer>
66 );
67}
68
69const styles = StyleSheet.create({
70 container: {
71 flexGrow: 1,
72 backgroundColor: '#fff',
73 paddingTop: 50,
74 minHeight:1700
75 },
76 btn:{
77 margin:20,
78 width: 200
79 }
80});
The above code creates two screens for your application using createStackNavigator()
.
The first screen is the ArticleList screen, which will render a list of the articles. The second screen is the FullArticle screen to render an entire article.
Great work! You have covered the core of your front-end code. Next, we have to implement the search functionality and its corresponding UI.
Creating the Search Functionality With its UI
In this section, you use AI to search your Knowledge Base. You will use LangChain as the AI tool and Python to interact with your LLM model.
The LLM model will use Facebook AI Similarity Search (FAISS) as the vector store. Lastly, you will create a UI component for this functionality in your React Native application.
Creating Python Code to Fetch and Convert Content from Strapi Backend
For your Python code, you have to ensure you have the following installed or install them using pip in your project folder:
1pip install Flask[async]
2pip install faiss-cpu
3pip install flask-cors
4pip install langchain_cohere
5pip install langchain_community
Here is what we installed:
- Flask is a micro web framework written in Python.
- faiss-cpu: A library for efficient similarity search and clustering of dense vectors.
- flask-cors: A Flask extension simplifying CORS support.
- langchain-cohere: This package contains the LangChain integrations for Cohere.
- langchain-community: LangChain Community contains third-party integrations that implement the base interfaces defined in LangChain Core, making them ready-to-use in any LangChain application.
After installing all the requirements, create a Python file named llm_backend.py
in your project root folder and add the following code:
NOTE: We are using an example Cohere API key in the code below. Do get yours using the Cohere docs.
1from flask import Flask, request, jsonify
2from dotenv import load_dotenv
3import os
4from flask_cors import CORS
5import requests
6from langchain.indexes import VectorstoreIndexCreator
7from langchain_community.docstore.document import Document
8from langchain_community.utilities import ApifyWrapper
9from langchain_cohere import CohereEmbeddings, CohereRagRetriever, ChatCohere
10from langchain_text_splitters import CharacterTextSplitter
11from langchain_community.vectorstores import FAISS
12from langchain_community.document_loaders import TextLoader
13from langchain_core.messages import HumanMessage, SystemMessage
14
15load_dotenv()
16
17app = Flask(__name__)
18CORS(app) # Allow CORS for all routes
19# Load environment variables
20cohere_api_key = os.getenv('COHERE_API_KEY')
21API_KEY = '67434e2309b53788868178aff01bec9a28a074336bf567c33ef3b0eaf30bf53fa57623c6c0cc288ac7cc8d79a89e834caddce879559e28fb55fa0da02357814c69fcaadfae4db91d48595ea6cc548fb3da27aed85693bda1b3c0ce667b1747cabd1c4ad8f716b64789527b945672cdec8b5c455908541cd2583769a48279af61'
22# Check if environment variables are loaded properly
23if not cohere_api_key:
24 raise ValueError("COHERE_API_KEY environment variable not set.")
25
26# Initialize Apify client wrapper (if needed)
27# apify = ApifyWrapper()
28
29# Function to fetch articles from API endpoint and map to Document objects
30def fetch_articles_and_map_to_documents():
31 try:
32 api_url = 'http://localhost:1337/api/articles?populate=*'
33 headers = {'Authorization': f'Bearer {API_KEY}'}
34
35 # Fetch data from API endpoint
36 response = requests.get(api_url, headers=headers)
37 data = response.json().get('data', [])
38
39 # Map data to Document objects
40 documents = []
41 for item in data:
42 document = Document(
43 page_content=format_content(item.get('body', [])),
44 metadata={"source": item.get('title', '')}
45 )
46 documents.append(document)
47
48 return documents
49
50 except Exception as e:
51 print('Error fetching articles from API endpoint:', e)
52 raise
53
54# Function to format content from API response
55def format_content(content):
56 # Customize as per your content structure
57 formatted_content = []
58 for item in content:
59 if item.get('type') == 'paragraph':
60 formatted_content.append(item.get('children')[0].get('text'))
61 elif item.get('type') == 'list':
62 # Handle list formatting if needed
63 pass
64 # Add more conditions as per your content structure
65
66 return '\n\n'.join(formatted_content)
67
68# Define the embedding function using Cohere
69embedding_function = CohereEmbeddings(cohere_api_key=cohere_api_key)
70
71# Route to handle RAG QA queries
72@app.route('/rag-qa', methods=['POST'])
73async def rag_qa():
74 data = request.get_json()
75 user_query = data['question']
76 chat_llm = ChatCohere(model="command-r")
77 print(user_query)
78 try:
79 # Fetch articles from API endpoint and map to Document objects
80 print("fetchting documents")
81 documents = fetch_articles_and_map_to_documents()
82 print("got the documents")
83
84 print("Faissing documents")
85 try:
86 db = FAISS.from_documents(documents, embedding_function)
87 print("similarity search")
88 docs = db.similarity_search(user_query)
89 # Query the vector store index for relevant documents
90 results = docs[0].page_content
91
92 results_metadata = docs[0].metadata['source']
93
94 messages = [
95 SystemMessage(content=f'please keep the response very short. {results}'),
96 HumanMessage(content=user_query),
97 ]
98 llm_response = chat_llm.invoke(messages)
99 print(f'llm_response: {llm_response}')
100 print(results_metadata)
101 except Exception as e:
102 print(e)
103
104
105 results = results[:200]
106 return jsonify({'response': llm_response.content, 'metadata_title': results_metadata})
107
108 except Exception as e:
109 return jsonify({'error': str(e)}), 500
110
111
112if __name__ == '__main__':
113 app.run(debug=True)
The code above contains the following:
fetch_articles_and_map_to_documents()
: This function fetches articles from the Strapi API endpointhttp://localhost:1337/api/articles?populate=*
and maps the response data to the Document object.format_content()
: This function takes the response data from Strapi and formats.- A route
'/rag-qa'
that will handlePOST
requests containing queries.
In summary, the code above uses LangChain to store Strapi's data in a vector store as documents and responds to the user's question by using a similarity search against the vector store.
Environment Variables
Ensure you have a .env
file with the following values:
1LANGCHAIN_TRACING_V2=true
2LANGCHAIN_API_KEY= ""
3OPENAPI_API_KEY=""
4COHERE_API_KEY=""
Obtain your keys using the resources below:
Run Python Code
Once done, use the following code to run your Python application:
python llm_backend.py
Create React Native Search Box UI
Create a React native component to handle the search UI.
To do this, create a file named search_box.js
inside your components
folder and add the following code:
1import React, { useState, useEffect } from 'react';
2import { View, Text, TextInput, Button, StyleSheet, FlatList, ScrollView } from 'react-native';
3import axios from 'axios';
4import ArticleCard from './article_card';
5
6const API_URL = 'http://localhost:5000'; // Replace with your Flask server URL
7
8const Searchbox = ({article}) => {
9 const [question, setQuestion] = useState('');
10 const [response, setResponse] = useState('');
11 const [sourceTitle, setSourceTitle] = useState('');
12
13 const handleQuery = async () => {
14 try {
15 const response = await axios.post(`${API_URL}/rag-qa`, { question: question,});
16 console.log(response.data);
17 setResponse(response.data.response);
18 setSourceTitle(response.data.metadata_title);
19 console.log(sourceTitle)
20 } catch (error) {
21 console.error('Error querying Cohere RAG QA:', error.message);
22 setResponse('Error querying Cohere RAG QA');
23 }
24 };
25
26 return (
27 <View style={styles.container}>
28 <Text style={styles.title}>Search with AI</Text>
29 <TextInput
30 style={styles.input}
31 placeholder="Enter your question"
32 value={question}
33 onChangeText={text => setQuestion(text)}
34 />
35 <Button title="Ask" onPress={handleQuery} />
36
37
38 {response ? (
39 <View style={styles.responseContainer}>
40 <Text style={styles.responseTitle}>AI Response:</Text>
41 <Text style={styles.responseText}>{response}</Text>
42 <Text style={styles.articlesTitle}>Source Articles:</Text>
43 <FlatList
44 data={article.filter(article => article.title === sourceTitle)}
45 renderItem={({ item }) => <ArticleCard article={item} />}
46 keyExtractor={(item) => item.id.toString()}
47 />
48 </View>
49 ) : null}
50
51
52 </View>
53 );
54};
55
56const styles = StyleSheet.create({
57 container: {
58 flexGrow: 1,
59 justifyContent: 'center',
60 padding: 20,
61 alignItems: 'center',
62 fontSize:10
63 },
64 title: {
65 fontSize: 24,
66 fontWeight: 'bold',
67 marginBottom: 20,
68 },
69 input: {
70 borderWidth: 1,
71 borderColor: '#ccc',
72 padding: 10,
73 marginBottom: 10,
74 width: '100%',
75 },
76 articlesTitle: {
77 fontSize: 18,
78 fontWeight: 'bold',
79 marginTop: 20,
80 marginBottom: 10,
81 },
82 articleItem: {
83 padding: 10,
84 borderWidth: 1,
85 borderColor: '#ccc',
86 marginBottom: 10,
87 width: '100%',
88 },
89 responseContainer: {
90 marginTop: 20,
91 alignItems: 'center',
92
93 },
94 responseTitle: {
95 fontWeight: 'bold',
96 marginBottom: 10,
97 },
98 responseText: {
99 fontSize: 16,
100 },
101});
102
103export default Searchbox;
The code above does the following:
- It takes the user's question using the TextInput
onChangeText
event handler. - Using the
axios.post()
method, it sends the question as a paramter or query to the Python LLM's server route we created in the previous section using flask. - It then returns the AI answer as well as the related article.
This is a demo of how the application works:
GitHub Source Code
- React Native application: https://github.com/leviOnNet/strapi5ReactNative
- Strapi 5 application: https://github.com/leviOnNet/strapi5Kb
- Python Ai search application: https://github.com/leviOnNet/Strapi5PythonAi
Conclusion
Well done for making it to the end of this tutorial. As you can see from the results above, Strapi enables you create API endpoints that you can integrate into any technology of yours. In this case, we integrated Strapi with React Native and LangChain seamlessly.
We created a Knowledge Base application that first renders the main screen which is a list of articles created on the Strapi backend. A user can click on the article card which opens the full article or click on the search button which will enable the user to query the LLM's vector store.
The search function returns the LLMs response along with the related article card for the user to open if they wish to dive deeper.
Learn more about using Strapi with React Native in this integration guide.
Thanks for reading!
Join us in Paris
Levis Masonde is a full-stack developer fascinated by new, emerging software technologies and their real-world applications. He enjoys writing technical articles about these technologies as he believes in raising awareness for newcomers and veterans in this fast-paced field.