DEV Community

Cover image for TrackNChat - Look up your tracking numbers in one place
Rad Ghost
Rad Ghost

Posted on

TrackNChat - Look up your tracking numbers in one place

This is a submission for the The AWS Amplify Fullstack TypeScript Challenge

What We Built

Many businesses often require a solution to notify customers about the tracking status of their packages (i.e. whether the package has arrived, where the package is in transit, and how long until the package arrives). We offer an easy-to-use web app that allows users to query information about tracking numbers and get the data they need in a single place. This is useful for some businesses that may not have an automated system in place to send tracking status to their customers, but want a quick and easy way to check the tracking status of their customers' packages in one place. This can also be used by customers to check their package tracking status as well. To use the app, you ask the chatbot information about your tracking number, and it'll respond back with relevant information about the tracking status.

Demo

Try the live app here!

Chat interface

Image description

View previous sessions

Image description

Check out the code here!

Journey

Our team consisted of 2 members, and we spent a single day working on the project (actually on the same day the project was to be turned in for the hackathon) from the idea to submission. It was a fun sprint to see how much we could get done in a short time and to learn/try new technologies we hadn't used before. We used AWS Amplify to power our full-stack application and AWS Lex to power the chatbot. While working on our project, we discovered how easy it was to follow the Amplify docs to get started and incorporate all their components including frontend, backend, hosting, data storage, and automated CI/CD. In regards to the chatbot, at first we considered developing a custom AI agent/tool, but realized that it would take too much time, and so in our search for something simpler, we came across AWS Lex which already had documenation on how to connect it with AWS Amplify. We found that using AWS Lex worked surprisingly well, and we could ask the chatbot in human language, and it'd be able to understand our intent and parse out the tracking number from the query. We weren't able to accomplish all the things that we'd like to implement, but we were proud that we got a chance to learn new technologies and build a fun and useful tool.

These are some of the things we'd like to incorporate into our app in the future:

  • Interact with the UPS, USPS, FedEx, DHL, etc. APIs to could get direct access to the tracking information rather than using an NPM package that provides basic details on a tracking number. We would've implemented this, but we found out that when we signed up for the USPS API, they require an approval process that we simply didn't have time to wait for.
  • Allow uploading of CSVs/Excel files in bulk to process many tracking numbers and the chatbot would provide the status of all tracking numbers

Connected Components and/or Feature Full

This is an architecture of how our system works.

Image description

When an user interacts with our NextJS web app, they can ask information about their tracking number, and it'll send a request to AWS Lex which forwards the request to AWS Lambda which can make a request to the shipping provider APIs to provide information on the tracking number. It turns out AWS Lex works very similar to Amazon Alexa and you can optionally add in generative AI support with AWS Bedrock for even better customer interaction.

AWS Lex chatbot configuration

Image description

AWS Lambda handler to process chatbot events that match the QueryTracking intent

export const handler: Handler = async (event, context) => {
  console.log(JSON.stringify(event, null, 2));

  const sessionState = event.sessionState;
  sessionState.intent.state = 'Fulfilled';
  sessionState.dialogAction = {
    type: 'Close'
  };

  const trackingNumber =
    event.interpretations[0].intent.slots.TrackingNumber.value
      .interpretedValue;
  const tracking = getTracking(trackingNumber); // <-- returns tracking details in this object

  return {
    sessionState,
    messages: [
      {
        contentType: 'PlainText',
        content: JSON.stringify(tracking)
      }
    ]
  };
}
Enter fullscreen mode Exit fullscreen mode

NextJS interaction with chatbot (triggered every time user enters a chat message)

async function submitMsg(userInput: string) {
  await Interactions.send({
    botName,
    message: userInput
  });
}
Enter fullscreen mode Exit fullscreen mode

NextJS callback for chatbot responses

Interactions.onComplete({
  botName,
  callback: async (error?: Error, response?: {[key: string]: any}) => {
    if (error) {
          alert('bot conversation failed');
    } else if (response) {
          // <process chatbot response here (e.g. display to user)>
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

All users are assigned a guest user id, provided by the AWS Cognito service. We use this id to store chat sessions and all the chat content so that users can refer back to their previous chat histories. Users can also optionally sign in to save their chat sessions to their accounts instead. This is similar to ChatGPT's website where you can view all your chat history. The data is read from/written to DynamoDB via AppSync GraphQL. And all of this is abstracted with the AWS Amplify typescript SDK!

Authentication component

<Authenticator>
    {({ signOut, user }) => (
        <main>
            <h1>Hello {user?.username}</h1>
            <button onClick={signOut}>Sign out</button>
        </main>
    )}
</Authenticator>
Enter fullscreen mode Exit fullscreen mode

Data schema

const schema = a.schema({
    ChatSession: a
        .model({
            userId: a.string().required(),
            chatContents: a.hasMany('ChatContent', 'chatSessionId')
        })
        .authorization((allow) => [allow.publicApiKey()]),
    ChatContent: a
        .model({
            content: a.string().required(),
            source: a.enum(['USER', 'BOT']),
            chatSessionId: a.id().required(),
            chatSession: a.belongsTo('ChatSession', 'chatSessionId')
        })
        .authorization((allow) => [allow.publicApiKey()])
});
Enter fullscreen mode Exit fullscreen mode

One of the issues we currently still encounter is when we create a new ChatSession record in the database and try to get the data back with a query like this.

GraphQL query

query MyQuery {
  getChatContent(id: "8f525820-8132-42ca-82e6-fa49116d3e2b") {
    id
    content
    chatSessionId
  }
  listChatContents(
    filter: {chatSessionId: {eq: "b56b034e-3cb5-479b-92fa-cebe1bd74e9c"}}
  ) {
    items {
      id
      content
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The data returned ends up being like this. For some reason listChatContents is empty even though it should contain the same data as getChatContent. If anyone has an answer to this problem, please let us know in the comments.

JSON output

{
  "data": {
    "getChatContent": {
      "id": "8f525820-8132-42ca-82e6-fa49116d3e2b",
      "content": "Some content",
      "chatSessionId": "b56b034e-3cb5-479b-92fa-cebe1bd74e9c"
    },
    "listChatContents": {
      "items": []
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Continuing on, the NextJS app is styled with tailwindss and shadcn, and it is hosted on AWS Amplify. Every time we push new code changes to our GitHub repo, AWS Amplify will automatically build and deploy the new version of our app to the live site.

Conclusion

And, that wraps up our project. We had a lot of fun working on this project and participating in this hackathon. It gave us a chance to apply our skills as well as explore the new AWS Amplify gen 2 platform and other AWS services as well.

Team

Top comments (0)