# Using MongoDB Atlas Triggers to Summarize Airbnb Reviews with OpenAI

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.

## Introduction

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:

```javascript
"reviews":  { "_id": "2663437", 
"date": { "$date": "2012-10-20T04:00:00.000Z" }, \
"listing_id": "664017",
 "reviewer_id": "633940", 
"reviewer_name": "Patricia", 
"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" },
 { "_id": "2741592", 
"date": { "$date": "2012-10-28T04:00:00.000Z" }, 
"listing_id": "664017",
 "reviewer_id": "3932440", 
"reviewer_name": "Carolina", 
"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." }, ... ]
```

## Prerequisites
- App Services application (e.g., application-0). Ensure linkage to the cluster with the Airbnb data.
- OpenAI account with API access. 

![Open AI Key

### Secrets and Values

1. Navigate to your App Services application.
2. Under "Values," create a secret named `openAIKey` with your OPEN AI API key.

3. Create a linked value named OpenAIKey and link to the secret.

## The trigger code

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:
```javascript
listingsAndReviews.updateOne({"_id" : "1129303"}, { $push : { "reviews" : new_review } , $set : { "process" : false" }});
```

### Sample reviews function
To prevent overloading the API with a large number of reviews, a function sampleReviews is defined to randomly sample up to 50 reviews:

```javscript
function sampleReviews(reviews) {
    if (reviews.length <= 50) {
        return reviews;
    }

    const sampledReviews = ];
    const seenIndices = new Set();

    while (sampledReviews.length < 50) {
        const randomIndex = Math.floor(Math.random() * reviews.length);
        if (!seenIndices.has(randomIndex)) {
            seenIndices.add(randomIndex);
            sampledReviews.push(reviews[randomIndex]);
        }
    }

    return sampledReviews;
}
```

### Main trigger logic

The main trigger logic is invoked when an update change event is detected with a `"process" : false` field.
```javascript
exports = async function(changeEvent) {
  // A Database Trigger will always call a function with a changeEvent.
  // Documentation on ChangeEvents: https://www.mongodb.com/docs/manual/reference/change-events

  // This sample function will listen for events and replicate them to a collection in a different Database
function sampleReviews(reviews) {
// Logic above...
   if (reviews.length <= 50) {
        return reviews;
    }
    const sampledReviews = [];
    const seenIndices = new Set();

    while (sampledReviews.length < 50) {
        const randomIndex = Math.floor(Math.random() * reviews.length);
        if (!seenIndices.has(randomIndex)) {
            seenIndices.add(randomIndex);
            sampledReviews.push(reviews[randomIndex]);
        }
    }

    return sampledReviews;
}

  // Access the _id of the changed document:
  const docId = changeEvent.documentKey._id;
  const doc= changeEvent.fullDocument;
  

  // Get the MongoDB service you want to use (see "Linked Data Sources" tab)
  const serviceName = "mongodb-atlas";
  const databaseName = "sample_airbnb";
  const collection = context.services.get(serviceName).db(databaseName).collection(changeEvent.ns.coll);

 // This function is the endpoint's request handler. 
    // URL to make the request to the OpenAI API.
    const url = 'https://api.openai.com/v1/chat/completions';

    // Fetch the OpenAI key stored in the context values.
    const openai_key = context.values.get("openAIKey");

    const reviews = doc.reviews.map((review) => {return {"comments" : review.comments}});
    
    const sampledReviews= sampleReviews(reviews);

    // Prepare the request string for the OpenAI API.
    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. `;
    console.log(`reqString: ${reqString}`);

    // Call OpenAI API to get the response.
    
    let resp = await context.http.post({
        url: url,
        headers: {
            'Authorization': [`Bearer ${openai_key}`],
            'Content-Type': ['application/json']
        },
        body: JSON.stringify({
            model: "gpt-4",
            temperature: 0,
            messages: [
                {
                    "role": "system",
                    "content": "Output json generator follow only provided example on the current reviews"
                },
                {
                    "role": "user",
                    "content": reqString
                }
            ]
        })
    });

    // Parse the JSON response
    let responseData = JSON.parse(resp.body.text());

    // Check the response status.
    if(resp.statusCode === 200) {
        console.log("Successfully received code.");
        console.log(JSON.stringify(responseData));

        const code = responseData.choices[0].message.content;
        // Get the required data to be added into the document
        const updateDoc = JSON.parse(code)
        // Set a flag that this document does not need further re-processing 
        updateDoc.process = true
        await collection.updateOne({_id : docId}, {$set : updateDoc});
      

    } else {
        console.error("Failed to generate filter JSON.");
        console.log(JSON.stringify(responseData));
        return {};
    }
};
```

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:
```
"process": true, 
"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.",
"neg_tags": [ "language barrier", "dog issues" ], 
"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:

```html

     Overall Review (ai based) : {{ listing.overall_review }}
      
          {{tag}}
      
      
        {{tag}}
      
  
```

## Conclusion
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.

Questions? Comments? Let’s continue the conversation over in our [community forums.