Using MongoDB Atlas Triggers to Summarize Airbnb Reviews with OpenAI
Pavel Duchovny4 min read • Published Oct 31, 2023 • Updated Oct 31, 2023
Rate this tutorial
In the realm of property rentals, reviews play a pivotal role. MongoDB Atlas triggers, combined with the power of OpenAI's models, can help summarize and analyze these reviews in real-time. In this article, we'll explore how to utilize MongoDB Atlas triggers to process Airbnb reviews, yielding concise summaries and relevant tags.
This article is an additional feature added to the hotels and apartment sentiment search application developed in Leveraging OpenAI and MongoDB Atlas for Improved Search Functionality.
MongoDB Atlas triggers allow users to define functions that execute in real-time in response to database operations. These triggers can be harnessed to enhance data processing and analysis capabilities. In this example, we aim to generate summarized reviews and tags for a sample Airbnb dataset.
Our original data model has each review embedded in the listing document as an array:
1 "reviews": [ { "_id": "2663437", 2 "date": { "$date": "2012-10-20T04:00:00.000Z" }, \ 3 "listing_id": "664017", 4 "reviewer_id": "633940", 5 "reviewer_name": "Patricia", 6 "comments": "I booked the room at Marinete's apartment for my husband. He was staying in Rio for a week because he was studying Portuguese. He loved the place. Marinete was very helpfull, the room was nice and clean. \r\nThe location is perfect. He loved the time there. \r\n\r\n" }, 7 { "_id": "2741592", 8 "date": { "$date": "2012-10-28T04:00:00.000Z" }, 9 "listing_id": "664017", 10 "reviewer_id": "3932440", 11 "reviewer_name": "Carolina", 12 "comments": "Es una muy buena anfitriona, preocupada de que te encuentres cómoda y te sugiere que actividades puedes realizar. Disfruté mucho la estancia durante esos días, el sector es central y seguro." }, ... ]
- App Services application (e.g., application-0). Ensure linkage to the cluster with the Airbnb data.
- OpenAI account with API access.
- Navigate to your App Services application.
- Under "Values," create a secret named
openAIKey
with your OPEN AI API key. - Create a linked value named OpenAIKey and link to the secret.
The provided trigger listens for changes in the sample_airbnb.listingsAndReviews collection. Upon detecting a new review, it samples up to 50 reviews, sends them to OpenAI's API for summarization, and updates the original document with the summarized content and tags.
Please notice that the trigger reacts to updates that were marked with
"process" : false
flag. This field indicates that there were no summary created for this batch of reviews yet.Example of a review update operation that will fire this trigger:
1 listingsAndReviews.updateOne({"_id" : "1129303"}, { $push : { "reviews" : new_review } , $set : { "process" : false" }});
To prevent overloading the API with a large number of reviews, a function sampleReviews is defined to randomly sample up to 50 reviews:
1 function sampleReviews(reviews) { 2 if (reviews.length <= 50) { 3 return reviews; 4 } 5 6 const sampledReviews = []; 7 const seenIndices = new Set(); 8 9 while (sampledReviews.length < 50) { 10 const randomIndex = Math.floor(Math.random() * reviews.length); 11 if (!seenIndices.has(randomIndex)) { 12 seenIndices.add(randomIndex); 13 sampledReviews.push(reviews[randomIndex]); 14 } 15 } 16 17 return sampledReviews; 18 }
The main trigger logic is invoked when an update change event is detected with a
"process" : false
field.1 exports = async function(changeEvent) { 2 // A Database Trigger will always call a function with a changeEvent. 3 // Documentation on ChangeEvents: https://mongodb.prakticum-team.ru/docs/manual/reference/change-events 4 5 // This sample function will listen for events and replicate them to a collection in a different Database 6 function sampleReviews(reviews) { 7 // Logic above... 8 if (reviews.length <= 50) { 9 return reviews; 10 } 11 const sampledReviews = []; 12 const seenIndices = new Set(); 13 14 while (sampledReviews.length < 50) { 15 const randomIndex = Math.floor(Math.random() * reviews.length); 16 if (!seenIndices.has(randomIndex)) { 17 seenIndices.add(randomIndex); 18 sampledReviews.push(reviews[randomIndex]); 19 } 20 } 21 22 return sampledReviews; 23 } 24 25 // Access the _id of the changed document: 26 const docId = changeEvent.documentKey._id; 27 const doc= changeEvent.fullDocument; 28 29 30 // Get the MongoDB service you want to use (see "Linked Data Sources" tab) 31 const serviceName = "mongodb-atlas"; 32 const databaseName = "sample_airbnb"; 33 const collection = context.services.get(serviceName).db(databaseName).collection(changeEvent.ns.coll); 34 35 // This function is the endpoint's request handler. 36 // URL to make the request to the OpenAI API. 37 const url = 'https://api.openai.com/v1/chat/completions'; 38 39 // Fetch the OpenAI key stored in the context values. 40 const openai_key = context.values.get("openAIKey"); 41 42 const reviews = doc.reviews.map((review) => {return {"comments" : review.comments}}); 43 44 const sampledReviews= sampleReviews(reviews); 45 46 // Prepare the request string for the OpenAI API. 47 const reqString = `Summerize the reviews provided here: ${JSON.stringify(sampledReviews)} | instructions example:\n\n [{"comment" : "Very Good bed"} ,{"comment" : "Very bad smell"} ] \nOutput: {"overall_review": "Overall good beds and bad smell" , "neg_tags" : ["bad smell"], pos_tags : ["good bed"]}. No explanation. No 'Output:' string in response. Valid JSON. `; 48 console.log(`reqString: ${reqString}`); 49 50 // Call OpenAI API to get the response. 51 52 let resp = await context.http.post({ 53 url: url, 54 headers: { 55 'Authorization': [`Bearer ${openai_key}`], 56 'Content-Type': ['application/json'] 57 }, 58 body: JSON.stringify({ 59 model: "gpt-4", 60 temperature: 0, 61 messages: [ 62 { 63 "role": "system", 64 "content": "Output json generator follow only provided example on the current reviews" 65 }, 66 { 67 "role": "user", 68 "content": reqString 69 } 70 ] 71 }) 72 }); 73 74 // Parse the JSON response 75 let responseData = JSON.parse(resp.body.text()); 76 77 // Check the response status. 78 if(resp.statusCode === 200) { 79 console.log("Successfully received code."); 80 console.log(JSON.stringify(responseData)); 81 82 const code = responseData.choices[0].message.content; 83 // Get the required data to be added into the document 84 const updateDoc = JSON.parse(code) 85 // Set a flag that this document does not need further re-processing 86 updateDoc.process = true 87 await collection.updateOne({_id : docId}, {$set : updateDoc}); 88 89 90 } else { 91 console.error("Failed to generate filter JSON."); 92 console.log(JSON.stringify(responseData)); 93 return {}; 94 } 95 };
Key steps include:
- API request preparation: Reviews from the changed document are sampled and prepared into a request string for the OpenAI API. The format and instructions are tailored to ensure the API returns a valid JSON with summarized content and tags.
- API interaction: Using the context.http.post method, the trigger sends the prepared data to the OpenAI API.
- Updating the original document: Upon a successful response from the API, the trigger updates the original document with the summarized content, negative tags (neg_tags), positive tags (pos_tags), and a process flag set to true.
Here is a sample result that is added to the processed listing document:
1 "process": true, 2 "overall_review": "Overall, guests had a positive experience at Marinete's apartment. They praised the location, cleanliness, and hospitality. However, some guests mentioned issues with the dog and language barrier.", 3 "neg_tags": [ "language barrier", "dog issues" ], 4 "pos_tags": [ "great location", "cleanliness", "hospitality" ]
Once the data is added to our documents, providing this information in our VUE application is as simple as adding this HTML template:
1 <div v-if="listing.overall_review" class="overall-review" > 2 <b>Overall Review (ai based) :</b> {{ listing.overall_review }} 3 <div v-for="tag in listing.pos_tags" > 4 <span class="badge-pos">{{tag}}</span> 5 </div> 6 <div v-for="tag in listing.neg_tags" > 7 <span class="badge-neg">{{tag}}</span> 8 </div> 9 </div>
By integrating MongoDB Atlas triggers with OpenAI's powerful models, we can efficiently process and analyze large volumes of reviews in real-time. This setup not only provides concise summaries of reviews but also categorizes them into positive and negative tags, offering valuable insights to property hosts and potential renters.