Skip to content

Commit 133017d

Browse files
authored
feat: add example to send mail (#7)
1 parent 035d7b9 commit 133017d

File tree

21 files changed

+683
-0
lines changed

21 files changed

+683
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ YoMo support multiple LLM providers, like Ollama, Mistral, Llama, Azure OpenAI,
1414
- [node-tool-currency-converter](./node-tool-currency-converter): Currency Calculator by 3rd party API.
1515
- [node-tool-get-utc-time](./node-tool-get-utc-time): Get the UTC time by city name.
1616
- [node-tool-get-ip-and-latency](./node-tool-get-ip-and-latency): Get IP and Latency by give website name like "Nike" and "Amazone" by `ping` command.
17+
- [node-tool-send-mail-smtp](./node-tool-send-mail-smtp): Send email by `nodemailer` and `maildev`.
18+
- [node-tool-send-mail-resend](./node-tool-send-mail-resend): Send email by `resend`.
19+
- [node-tool-web-search](./node-tool-web-search): Search the web by Google Custom Search Engine.
1720

1821
### Golang
1922

@@ -22,6 +25,8 @@ YoMo support multiple LLM providers, like Ollama, Mistral, Llama, Azure OpenAI,
2225
- [golang-tool-get-utc-time](./golang-tool-get-utc-time): Get the UTC time by city name.
2326
- [golang-tool-timezone-calculator](./golang-tool-timezone-calculator): Calculate the timezone for a specific time.
2427
- [golang-tool-get-ip-and-latency](./golang-tool-get-ip-and-latency): Get IP and Latency by give website name like "Nike" and "Amazone" by `ping` command.
28+
- [golang-tool-send-mail-smtp](./golang-tool-send-mail-smtp): Send email by smtp.
29+
- [golang-tool-send-mail-resend](./golang-tool-send-mail-resend): Send email by `resend`.
2530

2631
## Self Hosting
2732

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
YOMO_SFN_NAME=my_first_llm_function_tool
2+
YOMO_SFN_ZIPPER="zipper.vivgrid.com:9000"
3+
YOMO_SFN_CREDENTIAL=<your-yomo-sfn-credential>
4+
5+
RESEND_API_KEY=<your-resend-api-key>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# LLM Function Calling - Send Email with Resend (Go)
2+
3+
This is a serverless function for sending emails using Resend, implemented in Go.
4+
5+
## Prerequisites
6+
7+
### 1. Environment Variables
8+
9+
```sh
10+
YOMO_SFN_NAME=my_first_llm_function_tool
11+
YOMO_SFN_ZIPPER=zipper.vivgrid.com:9000
12+
YOMO_SFN_CREDENTIAL=<your-yomo-sfn-credential>
13+
```
14+
15+
You can find other environment variables in the serverless page of [vivgrid dashboard](https://dashboard.vivgrid.com/).
16+
17+
### 2. Resend API Key
18+
19+
1. Sign up for a [Resend](https://resend.com) account
20+
2. Get your API key
21+
3. Add the API key to your `.env` file:
22+
23+
```bash
24+
25+
RESEND_API_KEY=<your-resend-api-key>
26+
```
27+
28+
## Development
29+
30+
### 1. Install YoMo CLI
31+
32+
```bash
33+
curl -fsSL https://get.yomo.run | sh
34+
```
35+
36+
For detailed CLI usage, check [Doc: YoMo CLI](https://yomo.run/docs/cli).
37+
38+
### 2. Install Dependencies
39+
40+
```bash
41+
go mod download
42+
```
43+
44+
### 3. Test the Function
45+
46+
You can test the email sending functionality with the following curl command:
47+
48+
```bash
49+
curl --request POST \
50+
--url https://api.vivgrid.com/v1/chat/completions \
51+
--header 'Authorization: Bearer <token>' \
52+
--header 'content-type: application/json' \
53+
--data '{
54+
"messages": [
55+
{
56+
"role": "assistant",
57+
"content": "send an email to [email protected], tell him I will attend the meeting"
58+
}
59+
]
60+
}'
61+
```
62+
63+
### 4. Connect Function to LLM Bridge
64+
65+
```bash
66+
yomo run main.go -n my_first_llm_function_tool
67+
```

golang-tool-send-mail-resend/app.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"log/slog"
7+
"os"
8+
9+
"github.com/joho/godotenv"
10+
"github.com/resend/resend-go/v2"
11+
"github.com/yomorun/yomo/serverless"
12+
)
13+
14+
// Description outlines the functionality for the LLM Function Calling feature.
15+
func Description() string {
16+
return `Generate and send emails. Please provide the recipient's email address, and you should help generate appropriate subject and content. If no recipient address is provided, You should ask to add one. When you generate the subject and content, you should send it through the email sending function.`
17+
}
18+
19+
// InputSchema defines the argument structure for LLM Function Calling
20+
func InputSchema() any {
21+
return &Parameter{}
22+
}
23+
24+
var client *resend.Client
25+
26+
// Init is an optional function invoked during the initialization phase of the
27+
// sfn instance. It's designed for setup tasks like global variable
28+
// initialization, establishing database connections, or loading models into
29+
// GPU memory. If initialization fails, the sfn instance will halt and
30+
// terminate. This function can be omitted if no initialization tasks are
31+
// needed.
32+
func Init() error {
33+
if _, ok := os.LookupEnv("RESEND_API_KEY"); !ok {
34+
err := godotenv.Load()
35+
if err != nil {
36+
log.Fatal("You have to set RESEND_API_KEY in ENV or .env file")
37+
os.Exit(-1)
38+
}
39+
}
40+
41+
client = resend.NewClient(os.Getenv("RESEND_API_KEY"))
42+
return nil
43+
}
44+
45+
// Parameter defines the arguments for the LLM Function Calling
46+
type Parameter struct {
47+
To string `json:"to" jsonschema:"description=The recipient's email address"`
48+
Subject string `json:"subject" jsonschema:"description=The subject of the email"`
49+
Body string `json:"body" jsonschema:"description=The content of the email"`
50+
}
51+
52+
// Handler orchestrates the core processing logic of this function
53+
func Handler(ctx serverless.Context) {
54+
var args Parameter
55+
ctx.ReadLLMArguments(&args)
56+
57+
result, err := sendEmail(args)
58+
if err != nil {
59+
ctx.WriteLLMResult(fmt.Sprintf("Failed to send email: %v", err))
60+
return
61+
}
62+
63+
ctx.WriteLLMResult(result)
64+
slog.Info("send-email", "to", args.To, "result", result)
65+
}
66+
67+
func sendEmail(args Parameter) (string, error) {
68+
if err := godotenv.Load(); err != nil {
69+
slog.Warn("Error loading .env file", "error", err)
70+
}
71+
72+
slog.Info("send-email", "args", args)
73+
74+
params := &resend.SendEmailRequest{
75+
From: os.Getenv("FROM_EMAIL"),
76+
To: []string{args.To},
77+
Subject: args.Subject,
78+
Html: fmt.Sprintf("<p>%s</p>", args.Body),
79+
}
80+
81+
resp, err := client.Emails.Send(params)
82+
if err != nil {
83+
return "", fmt.Errorf("failed to send email: %w", err)
84+
}
85+
86+
return fmt.Sprintf("Email has been successfully sent to %s with ID: %s", args.To, resp.Id), nil
87+
}
88+
89+
// DataTags specifies the data tags to which this serverless function subscribes
90+
func DataTags() []uint32 {
91+
return []uint32{0x67}
92+
}

golang-tool-send-mail-resend/go.mod

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module github.com/yomo-mqtt/llm-function-calling/examples/golang-tool-send-mail-resend
2+
3+
go 1.21
4+
5+
require github.com/yomorun/yomo v1.18.11
6+
7+
require (
8+
github.com/joho/godotenv v1.5.1
9+
github.com/resend/resend-go/v2 v2.5.0
10+
)
11+
12+
require (
13+
github.com/caarlos0/env/v6 v6.10.1 // indirect
14+
github.com/lmittmann/tint v1.0.4 // indirect
15+
github.com/sashabaranov/go-openai v1.27.0 // indirect
16+
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
17+
)

golang-tool-send-mail-resend/go.sum

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II=
2+
github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
3+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
4+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
6+
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
7+
github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=
8+
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
9+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
10+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
11+
github.com/resend/resend-go/v2 v2.5.0 h1:XzTtzQ9YB2LlGHWjS5AVyUqV9cVbDU+6Z4XgCKsJh4g=
12+
github.com/resend/resend-go/v2 v2.5.0/go.mod h1:ihnxc7wPpSgans8RV8d8dIF4hYWVsqMK5KxXAr9LIos=
13+
github.com/sashabaranov/go-openai v1.27.0 h1:L3hO6650YUbKrbGUC6yCjsUluhKZ9h1/jcgbTItI8Mo=
14+
github.com/sashabaranov/go-openai v1.27.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
15+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
16+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
17+
github.com/yomorun/yomo v1.18.11 h1:lWA+YtRnm/ppQKPztoV2XekmCcQVRHJajyYSFu49h+g=
18+
github.com/yomorun/yomo v1.18.11/go.mod h1:aDnZBSmXMCBH/73jnqtUdYvzVDeqGx25Z87y80cOU34=
19+
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
20+
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
21+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
22+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
YOMO_SFN_NAME=my_first_llm_function_tool
2+
YOMO_SFN_ZIPPER="zipper.vivgrid.com:9000"
3+
YOMO_SFN_CREDENTIAL=<your-yomo-sfn-credential>
4+
SMTP_HOST=localhost
5+
SMTP_PORT=1025
6+

golang-tool-send-mail-smtp/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# LLM Function Calling - Send Email with SMTP
2+
3+
This is a serverless function for sending emails with SMTP.
4+
5+
## Prerequisites
6+
7+
### 1. Environment Variables
8+
9+
```sh
10+
YOMO_SFN_NAME=my_first_llm_function_tool
11+
YOMO_SFN_ZIPPER=zipper.vivgrid.com:9000
12+
YOMO_SFN_CREDENTIAL=<your-yomo-sfn-credential>
13+
```
14+
15+
You can find other environment variables in the serverless page of [vivgrid dashboard](https://dashboard.vivgrid.com/).
16+
17+
## Development
18+
19+
### 1. Install YoMo CLI
20+
21+
```bash
22+
curl -fsSL https://get.yomo.run | sh
23+
```
24+
25+
For detailed CLI usage, check [Doc: YoMo CLI](https://yomo.run/docs/cli).
26+
27+
### 2. Start Mail Development Server
28+
29+
```bash
30+
docker run -p 1080:1080 -p 1025:1025 maildev/maildev
31+
```
32+
33+
### 3. Add Environment Variables
34+
35+
Add the following environment variables to your `.env` file:
36+
37+
```bash
38+
SMTP_HOST=localhost
39+
SMTP_PORT=1025
40+
41+
```
42+
43+
### 4. Test the Function
44+
45+
You can test the email sending functionality with the following curl command:
46+
47+
```bash
48+
curl --request POST \
49+
--url https://api.vivgrid.com/v1/chat/completions \
50+
--header 'Authorization: Bearer <token>' \
51+
--header 'content-type: application/json' \
52+
--data '{
53+
"messages": [
54+
{
55+
"role": "assistant",
56+
"content": "send an email to [email protected], tell him I will attend the meeting"
57+
}
58+
]
59+
}'
60+
```
61+
62+
### 4. Connect this Function to Your LLM Bridge
63+
64+
```bash
65+
yomo run app.go -n my_first_llm_function_tool
66+
```
67+
68+
## Web Interface
69+
70+
After starting the mail development server, you can access the web interface at `http://localhost:1080` to view sent emails.

golang-tool-send-mail-smtp/app.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"net/smtp"
7+
"os"
8+
9+
"github.com/yomorun/yomo/serverless"
10+
)
11+
12+
// Description describes the functionality of this Function Calling
13+
func Description() string {
14+
return `Generate and send emails. Please provide the recipient's email address, and you should help generate appropriate subject and content. If no recipient address is provided, You should ask to add one. When you generate the subject and content, you should send it through the email sending function.`
15+
}
16+
17+
// Parameter defines the required parameters for sending emails
18+
type Parameter struct {
19+
To string `json:"to" jsonschema:"description=Recipient's email address,[email protected]"`
20+
Subject string `json:"subject" jsonschema:"description=Email subject"`
21+
Body string `json:"body" jsonschema:"description=Email content"`
22+
}
23+
24+
func InputSchema() any {
25+
return &Parameter{}
26+
}
27+
28+
// Handler processes the email sending logic
29+
func Handler(ctx serverless.Context) {
30+
var msg Parameter
31+
ctx.ReadLLMArguments(&msg)
32+
33+
slog.Info("send-mail", "msg", msg)
34+
35+
// Get email configuration from environment variables
36+
smtpHost := os.Getenv("SMTP_HOST")
37+
smtpPort := os.Getenv("SMTP_PORT")
38+
fromEmail := os.Getenv("FROM_EMAIL")
39+
40+
// Construct email content
41+
emailBody := fmt.Sprintf("Subject: %s\r\n\r\n%s", msg.Subject, msg.Body)
42+
43+
// Send email
44+
err := smtp.SendMail(
45+
smtpHost+":"+smtpPort,
46+
nil,
47+
fromEmail,
48+
[]string{msg.To},
49+
[]byte(emailBody),
50+
)
51+
52+
if err != nil {
53+
slog.Error("Failed to send email", "error", err)
54+
ctx.WriteLLMResult("Failed to send email, please try again later")
55+
return
56+
}
57+
58+
ctx.WriteLLMResult(fmt.Sprintf("Email has been successfully sent to %s", msg.To))
59+
}
60+
61+
// DataTags specifies the data tags to which this serverless function
62+
// subscribes, essential for data reception. Upon receiving data with these
63+
// tags, the Handler function is triggered.
64+
func DataTags() []uint32 {
65+
return []uint32{0x65}
66+
}

golang-tool-send-mail-smtp/go.mod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module llm-fn-get-weather
2+
3+
go 1.22.3
4+
5+
require github.com/yomorun/yomo v1.18.11
6+
7+
require (
8+
github.com/caarlos0/env/v6 v6.10.1 // indirect
9+
github.com/lmittmann/tint v1.0.4 // indirect
10+
github.com/sashabaranov/go-openai v1.27.0 // indirect
11+
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
12+
)

0 commit comments

Comments
 (0)