DEV Community

Denis Valášek
Denis Valášek

Posted on

Gemini in your Slack workspace using Firebase & Genkit

Ever wished you could just tag your custom AI model in Slack? With connection to your internal systems (and your safeguards), to get actually relevant data along with helpful monitoring of the usage and access?

Let's take a look how you can do that today using Slack Bolt API, Google Gemini and Firebase Genkit.

Slack setup

We need to create a Slack app that will handle all the Slack permissions, events, and interactions. It's fairly easy to do this for your local workspace if you are an admin, you might need additional permissions if you are not, or just create a new workspace for testing.

Head on to Slack Apps to create a new Slack app from scratch.

Create new Slack app from scratch

Make sure to pick some reasonable name, as it will be used to tag the bot later on and install it into the appropriate workspace.

Pick name and Workspace

After creating, you are presented with a bunch of secrets and values. You will need Signing Secret later on, but it's always available on this screen.

Go to OAuth & Permissions section in the left panel and pick 2 Bot Token Scopes:

  • app_mentions:read to get events when the bot was mentioned
  • chat:write to be able to reply to the mentions

OAuth & Permissions

Proceed to install the app into your workspace in OAuth Tokens, this will give you a bot token, with the permissions you set above.

Backend setup

For our backend we will be using Cloud Functions for Firebase and Firebase Genkit.

Cloud Functions will provide us with serverless webhook URL, that we can use for our Slack app and Genkit will make it easy for us to iterate on prompt design, switch models and get step-by-step logs of our AI requests.

Follow the README in the sample Gemini in Slack repository for this article to have the project setup.

Genkit

In the genkit.ts file, you can see several Genkit concepts being used, let's highlight a few:

enableFirebaseTelemetry();
Enter fullscreen mode Exit fullscreen mode

This single line gives us a complete overview & traces for each API call we make using Genkit, making it very easy to keep track of our spend, usage and how well the app works. You can find all the live calls in the Firebase dashboard in the Genkit section.

export const slackFlow = ai.defineFlow(
 {
   name: "slackFlow",
   inputSchema: z.string().describe("Slack message text"),
   outputSchema: z.string(),
 },
 async (subject) => {
   // Edit the prompt to fit your use case, make sure to experiment with the models and tools to get the best results.
   const prompt = `You are a helpful assistant that can answer questions about the number of customers and revenue for a given date. You can use the tools provided to you to get the information you need. You might also answer general questions about the workspace.

   Here is the user's message: ${subject}`;


   logger.info("slackFlow", { prompt });


   const response = await ai.generate({
     model: gemini20Flash,
     prompt: prompt,
     config: {
       temperature: 1,
     },
     tools: [getCustomersForDate, getRevenueForDate, getDate],
   });


   return response.text;
 }
);
Enter fullscreen mode Exit fullscreen mode

This code snippet represents a Genkit flow, which is like a Genkit function wrapper, which handles many internal tasks for one goal. Inside one flow, you might do several AI calls, call internal APIs or access the file system, but it makes it incredibly easy to access the function from the Genkit Dev Tools and to categorize it in Genkit Monitoring.

For simplicity, prompt is also defined right in the flow, but we could use Genkit Dotprompt if our prompt grows or we want to test multiple versions efficiently.

const getCustomersForDate = ai.defineTool(
 {
   name: "getCustomersForDate",
   description: "Gets the number of customers for a given date",
   inputSchema: z.object({
     date: z.string().describe("The date to get the number of customers for"),
   }),
   outputSchema: z.object({
     output: z
       .number()
       .describe("The number of customers for the given date")
       .optional(),
     error: z.string().describe("The error message text").optional(),
   }),
 },
 async (input) => {
   try {
     logger.info("getCustomersForDate", { input });
     checkIfFutureDate(input.date);
     // Here, we would typically make an API call or database query. For this
     // example, we just return a random value.
     return {
       output: Math.floor(Math.random() * 100),
     };
   } catch (error) {
     logger.error("getCustomersForDate", { error, input });
     return {
       error: "I cannot provide data for the future dates.",
     };
   }
 }
);
Enter fullscreen mode Exit fullscreen mode

This part showcases how tool calling works in Genkit. We define tools and their parameters, along with descriptions to be later on passed to the model itself. Recently, Genkit also started supporting dynamic tool creation at runtime, which might be interesting for some use cases.

In the sample code tool calling is used as an example to call your internal APIs to provide answers to various questions, like:

  • How many customers did we have yesterday?
  • What is our revenue today?

I also provided some examples on how to handle errors in tool calling and some potential logical errors as well, like asking for revenue in the future.

Local testing

Once you go through the codebase, set your own secrets in the .env file, you might want to play with the prompt itself and the tool calling, to better fit your use-case.

You can run:

npm run genkit:start
Enter fullscreen mode Exit fullscreen mode

To start the Genkit Dev UI, you will get a localhost URL as the output. In the left panel, select Flows and the slackFlow to start testing. You can treat the input field as whatever the Slack message would say and on the right side you can see step-by-step calls made inside the flows for easy debugging.

Genkit slackFlow

You can see that one of the tools handles transformation of dates like today or yesterday into date string

Date tool

And result of the date tool gets passed into the getCustomersForDate tool, which simulates an internal API call to return a random number of customers.

Simulated API call tool

And final output. Genkit debugging is super useful when dealing with complicated flows and tool calls, make sure to try it out.

Genkit output

Deployment

Now you can run $$npm run deploy$$ to deploy the function and get the URL.

Slack events setup

From the previous step, you should have a URL looking like this:

https://gemini-in-slack-{random-id}-uc.a.run.app
Enter fullscreen mode Exit fullscreen mode

Head to your newly created Slack app into the Event Subscriptions section and enable events. This will give you an option to paste your Firebase Function URL there, make sure to add /events to the end of the URL after pasting it, so the complete URL looks like this:

https://gemini-in-slack-{random-id}-uc.a.run.app/events
Enter fullscreen mode Exit fullscreen mode

Subscribe to events URL
URL verification

You should get a green checkmark once Slack verifies your endpoint. Below the URL, subscribe to the app_mention event, to start receiving event notifications.

URL verified

Testing

Now it all should be ready to test! Head on to your Slack workspace and choose a channel where you won't disturb anyone, making sure to tag the bot with your query. You should get an in-thread answer. If you didn't change the prompt or tool calls, here are some queries that should work just fine:

  • How many customers did we have today?
  • What was our revenue yesterday?

And to try the error handling, try asking: "What will be our revenue tomorrow?"

Sample conversation

Genkit Monitoring

After few conversations, head on to Firebase Genkit in the Firebase Console to see all the logs and traces for your conversations, where you can later debug new calls and see if the tool replies as it should.
You also have an overview of tokens consumed and if something isn't taking too long.
Firebase Genkit Monitoring

Troubleshooting

If you do not receive an answer within a few minutes, make sure to check the Firebase Cloud Function logs to get an idea what went wrong. You might be missing an API key or left out one of the permissions.

Conclusion

We went over the basics of how to set up a Slack bot, explained some Genkit concepts and put it all together. I hope you can modify the sample code to something actually useful for your organization and thanks for reading!

Google Cloud credits are provided for this project. #AISprint

Top comments (0)