Skip to content

Commit e7290a8

Browse files
committed
init
1 parent 4678f08 commit e7290a8

File tree

7 files changed

+188
-1
lines changed

7 files changed

+188
-1
lines changed

.env.example

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
YOMO_SFN_NAME=llm_fn_get_weather
2+
YOMO_SFN_ZIPPER=localhost:9000
3+
YOMO_SFN_CREDENTIAL=SECRET
4+
OPENWEATHERMAP_API_KEY=

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919

2020
# Go workspace file
2121
go.work
22+
.env
23+
*.yomo

README.md

+60-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,61 @@
11
# llm-function-get-weather
2-
OpenAI Function Calling RAG - get weather from API
2+
3+
This example demostrates how to implement OpenAI Function Calling in Strong-typed language, easy to write and maintain. follow the instructions below, you will extend OpenAI gpt-4o with openweathermap.org API.
4+
5+
## Development on local
6+
7+
### Install YoMo
8+
9+
```sh
10+
curl -fsSL "https://get.yomo.run" | sh
11+
```
12+
13+
### Add your OpenAI SK to configuration
14+
15+
```sh
16+
vim yomo.yml
17+
```
18+
19+
> [!TIP]
20+
> If you do not have an OpenAI API Key, you can try [vivgrid.com](https://vivgrid.com), it's free for developers with generous OpenAI Token every month.
21+
22+
### Start YoMo
23+
24+
```sh
25+
yomo serve -c yomo.yml
26+
```
27+
28+
### Get your api-key from OpenWeatherMap.org
29+
30+
grab your api-key from [openweathermap.org](https://openweathermap.org) free, and add it to your `.env` file:
31+
32+
```sh
33+
YOMO_SFN_NAME=llm_fn_get_weather
34+
YOMO_SFN_ZIPPER=localhost:9000
35+
YOMO_SFN_CREDENTIAL=SECRET
36+
OPENWEATHERMAP_API_KEY=<ADD_HERE>
37+
```
38+
39+
### Run your function calling
40+
41+
```sh
42+
yomo run app.go
43+
```
44+
45+
### Try it!
46+
47+
```sh
48+
curl -X POST -H "Content-Type: application/json" -d '{"prompt":"Hows the weather like in Paris today?"}' http://127.0.0.1:9000/invoke |jq
49+
{
50+
"Content": "The weather in Paris today is clear with a clear sky. Here are the detailed conditions:\n\n- **Temperature:** 9.89°C (feels like 9.02°C)\n- **Humidity:** 91%\n- **Pressure:** 1020 hPa\n- **Wind:** 2.06 m/s coming from the southwest (210°)\n- **Visibility:** 10 km\n- **Cloudiness:** 0% (clear sky)\n- **Sunrise:** 05:27 AM\n- **Sunset:** 08:41 PM\n\nOverall, it's a cool and clear day in Paris.",
51+
"ToolCalls": null,
52+
"ToolMessages": null,
53+
"FinishReason": "stop",
54+
"TokenUsage": {
55+
"prompt_tokens": 274,
56+
"completion_tokens": 125
57+
},
58+
"AssistantMessage": null
59+
}
60+
```
61+

app.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log/slog"
7+
"net/http"
8+
"os"
9+
10+
"github.com/yomorun/yomo/serverless"
11+
)
12+
13+
// Description defines the Function Calling, this will be combine to prompt automatically. As openweathermap.org does not support request api by `city_name`, we have ask LLM to translate it to Latitude and Longitude.
14+
func Description() string {
15+
return `Get current weather for a giving city. If no city is provided, you should ask to clarify the city.
16+
If the city name is given, you should convert city name to Latitude and Longitude geo coordinates,
17+
keep Latitude and Longitude in decimal format.`
18+
}
19+
20+
// Param defines the input parameters of the Function Calling, this will be combine to prompt automatically
21+
type Param struct {
22+
City string `json:"city" jsonschema:"description=The city name to get the weather for"`
23+
Latitude float64 `json:"latitude" jsonschema:"description=The latitude of the city, in decimal format, range should be in (-90, 90)"`
24+
Longitude float64 `json:"longitude" jsonschema:"description=The longitude of the city, in decimal format, range should be in (-180, 180)"`
25+
}
26+
27+
// InputSchema decalares the type of Function Calling Parameter, required by YoMo
28+
func InputSchema() any {
29+
return &Param{}
30+
}
31+
32+
// DataTags declares the type of data this stateful serverless observe, required by YoMo
33+
func DataTags() []uint32 {
34+
return []uint32{0x30}
35+
}
36+
37+
// Handler is the main entry point of the Function Calling when LLM response with `tool_call`
38+
func Handler(ctx serverless.Context) {
39+
var p Param
40+
// deserilize the parameters from llm tool_call response
41+
ctx.ReadLLMArguments(&p)
42+
43+
// call the openweathermap api and write the result back to LLM
44+
result := requestOpenWeatherMap(p.Latitude, p.Longitude)
45+
ctx.WriteLLMResult(result)
46+
47+
slog.Info("get-weather", "city", p.City, "rag", result)
48+
}
49+
50+
func requestOpenWeatherMap(lat, lon float64) string {
51+
const apiURL = "https://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&appid=%s&units=metric"
52+
apiKey := os.Getenv("OPENWEATHERMAP_API_KEY")
53+
url := fmt.Sprintf(apiURL, lat, lon, apiKey)
54+
// send api request to openweathermap.org
55+
resp, err := http.Get(url)
56+
if err != nil {
57+
fmt.Println(err)
58+
return "can not get the weather information at the moment"
59+
}
60+
defer resp.Body.Close()
61+
62+
body, err := io.ReadAll(resp.Body)
63+
if err != nil {
64+
fmt.Println(err)
65+
return "can not get the weather information at the moment"
66+
}
67+
68+
return string(body)
69+
}

go.mod

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module llm-fn-get-weather
2+
3+
go 1.22.3
4+
5+
require (
6+
github.com/stretchr/testify v1.9.0
7+
github.com/yomorun/yomo v1.18.9
8+
)
9+
10+
require (
11+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
12+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
13+
github.com/stretchr/objx v0.5.2 // indirect
14+
gopkg.in/yaml.v3 v3.0.1 // indirect
15+
)

go.sum

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
2+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
4+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
6+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
7+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
8+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9+
github.com/yomorun/yomo v1.18.9 h1:azxCLHYa0bE2odQzKgM7nHm93L359BIJCFxuJbRERZk=
10+
github.com/yomorun/yomo v1.18.9/go.mod h1:DwomD9J+U7vNgRnqFWoilQCbqlR4X9fBpIiDUX33jO0=
11+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
12+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
13+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
14+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

yomo.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: ai-zipper
2+
host: 0.0.0.0
3+
port: 9000
4+
5+
auth:
6+
type: token
7+
token: SECRET
8+
9+
bridge:
10+
ai:
11+
server:
12+
addr: localhost:9000
13+
provider: openai
14+
15+
providers:
16+
azopenai:
17+
api_endpoint: https://<DEPLOYMENT_NAME>.openai.azure.com
18+
deployment_id: <MODEL_NAME>
19+
api_key: <API_KEY>
20+
api_version: 2024-02-15-preview
21+
22+
openai:
23+
api_key: sk-
24+
model: gpt-4o

0 commit comments

Comments
 (0)