Your First Service
Get started with building a DAIN Service by understanding and running the auto-generated code sample.
Now that you've got your working environment set up, let's dive into the auto-generated code a little bit starting with src/index.ts.
Imports
import { z } from "zod";
import axios from "axios";
import {
defineDAINService,
ToolConfig,
} from "@dainprotocol/service-sdk";
import { CardUIBuilder, TableUIBuilder, MapUIBuilder } from "@dainprotocol/utils";
The DAIN Service SDK uses Zod for handling the data being passed into various config data structures and any library for handling API requests (in this case, axios).
- The
ToolConfig
type is used to define an individual tool that the service provides. - The
defineDAINService
type is used to define the service metadata for the DAIN network.
The default generated service is a working weather data service that requests data from the OpenMeteo Weather API.
CardUIBuilder, TableUIBuilder, and MapUIBuilder are used to build the UI for the service.
Tool Config
A Tool is the most primitive major object in the Service SDK.
const getWeatherConfig: ToolConfig = {
id: "get-weather",
name: "Get Weather",
description: "Fetches current weather for a city",
input: z
.object({
locationName: z.string().describe("Location name"),
latitude: z.number().describe("Latitude coordinate"),
longitude: z.number().describe("Longitude coordinate"),
})
.describe("Input parameters for the weather request"),
output: z
.object({
temperature: z.number().describe("Current temperature in Celsius"),
windSpeed: z.number().describe("Current wind speed in km/h"),
})
.describe("Current weather information"),
pricing: { pricePerUse: 0, currency: "USD" },
handler: async ({ locationName, latitude, longitude }, agentInfo, context) => {
console.log(
`User / Agent ${agentInfo.id} requested weather at ${locationName} (${latitude},${longitude})`
);
const response = await axios.get(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,wind_speed_10m`
);
const { temperature_2m, wind_speed_10m } = response.data.current;
const weatherEmoji = getWeatherEmoji(temperature_2m);
return {
text: `The current temperature in ${locationName} is ${temperature_2m}°C with wind speed of ${wind_speed_10m} km/h`,
data: {
temperature: temperature_2m,
windSpeed: wind_speed_10m,
},
ui: new CardUIBuilder()
.setRenderMode("page")
.title(`Current Weather in ${locationName} ${weatherEmoji}`)
.addChild(new MapUIBuilder()
.setInitialView(latitude, longitude, 10)
.setMapStyle('mapbox://styles/mapbox/streets-v12')
.addMarkers([
{
latitude,
longitude,
title: locationName,
description: `Temperature: ${temperature_2m}°C\nWind: ${wind_speed_10m} km/h`,
text: `${locationName} ${weatherEmoji}`,
}
])
.build())
.content(`Temperature: ${temperature_2m}°C\nWind Speed: ${wind_speed_10m} km/h`)
.build(),
};
},
};
The following parameters are involved:
- The
id
parameter is used for identifying the tool. - The
name
parameter is the name of the tool. - The
description
parameter is a short description of what the tool does. - The
input
parameter is used to define what kind of specific input would be extracted from the natural language input. - The
output
parameter is used to define what kind of output would be produced by the tool. - The
pricing
parameter is irrelevant for now, but it defines how much your service would earn per usage of this tool. - The
handler
part includes the logic for the tool. See Tool Handler Returns for details on what the handler must return.
DAIN Service
Every Service will have one dainService object that looks like this:
const dainService = defineDAINService({
metadata: {
title: "Weather DAIN Service",
description:
"A DAIN service for current weather and forecasts using Open-Meteo API",
version: "1.0.0",
author: "Your Name",
tags: ["weather", "forecast", "dain"],
logo: "https://cdn-icons-png.flaticon.com/512/252/252035.png"
},
identity: {
apiKey: process.env.DAIN_API_KEY,
},
tools: [getWeatherConfig, getWeatherForecastConfig],
});
The following parameters are involved:
- The
metadata
parameter contains the metadata involved in deploying the service to the network. This includes the title of the service, a description, the version that is deployed, the author of the service and tags used in routing to the service. - The
identity
parameter contains the API key for the service that you got in the previous section. - The
tools
parameter contains the Tool config objects of the tools to be deployed with the service.
Starting the Service
Now all that is left is to start the service.
dainService.startNode().then(({ address }) => {
console.log("DAIN Service is running at :" + address().port);
});
This runs the Service on a port, which is 2022 here.
Then, run this command in the terminal:
npm run dev
or with pnpm:
pnpm run dev
Running this command should generate a tunnel URL for the service that you would need for testing.