-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
149 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log/slog" | ||
|
||
"github.com/yomorun/yomo/serverless" | ||
) | ||
|
||
// Init is an optional function invoked during the initialization phase of the | ||
// sfn instance. It's designed for setup tasks like global variable | ||
// initialization, establishing database connections, or loading models into | ||
// GPU memory. If initialization fails, the sfn instance will halt and terminate. | ||
// This function can be omitted if no initialization tasks are needed. | ||
func Init() error { | ||
return nil | ||
} | ||
|
||
// Description outlines the functionality for the LLM Function Calling feature. | ||
// It provides a detailed description of the function's purpose, essential for | ||
// integration with LLM Function Calling. The presence of this function and its | ||
// return value make the function discoverable and callable within the LLM | ||
// ecosystem. For more information on Function Calling, refer to the OpenAI | ||
// documentation at: https://platform.openai.com/docs/guides/function-calling | ||
func Description() string { | ||
return `Get current weather for a given city. If no city is provided, you | ||
should ask to clarify the city. If the city name is given, you should | ||
convert the city name to Latitude and Longitude geo coordinates, keeping | ||
Latitude and Longitude in decimal format.` | ||
} | ||
|
||
// InputSchema defines the argument structure for LLM Function Calling. It | ||
// utilizes jsonschema tags to detail the definition. For jsonschema in Go, | ||
// see https://github.com/invopop/jsonschema. | ||
func InputSchema() any { | ||
return &LLMArguments{} | ||
} | ||
|
||
// LLMArguments defines the arguments for the LLM Function Calling. These | ||
// arguments are combined to form a prompt automatically. | ||
type LLMArguments struct { | ||
City string `json:"city" jsonschema:"description=The city name to get the weather for,required"` | ||
Latitude float64 `json:"latitude" jsonschema:"description=The latitude of the city, in decimal format, range should be in (-90, 90)"` | ||
Longitude float64 `json:"longitude" jsonschema:"description=The longitude of the city, in decimal format, range should be in (-180, 180)"` | ||
} | ||
|
||
// DataTags specifies the data tags to which this serverless function | ||
// subscribes, essential for data reception. Upon receiving data with these | ||
// tags, the Handler function is triggered. | ||
func DataTags() []uint32 { | ||
return []uint32{0x30} | ||
} | ||
|
||
// Handler orchestrates the core processing logic of this function. | ||
// - ctx.ReadLLMArguments() parses LLM Function Calling Arguments (skip if none). | ||
// - ctx.WriteLLMResult() sends the retrieval result back to LLM. | ||
// - ctx.Tag() identifies the tag of the incoming data. | ||
// - ctx.Data() accesses the raw data. | ||
// - ctx.Write() forwards processed data downstream. | ||
func Handler(ctx serverless.Context) { | ||
var p LLMArguments | ||
// deserilize the arguments from llm tool_call response | ||
ctx.ReadLLMArguments(&p) | ||
|
||
// invoke the open weather map api and return the result back to LLM | ||
result := fmt.Sprintf("The current weather in %s (%f,%f) is sunny", p.City, p.Latitude, p.Longitude) | ||
ctx.WriteLLMResult(result) | ||
|
||
slog.Info("get-weather", "city", p.City, "rag", result) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/yomorun/yomo/ai" | ||
"github.com/yomorun/yomo/serverless/mock" | ||
) | ||
|
||
func TestHandler(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
ctx *mock.MockContext | ||
// want is the expected data and tag that be written by ctx.Write | ||
want []mock.WriteRecord | ||
}{ | ||
{ | ||
name: "get weather", | ||
ctx: mock.NewMockContext([]byte(`{"arguments":"{\"city\":\"New York\",\"latitude\":40.7128,\"longitude\":-74.0060}"}`), 0x33), | ||
want: []mock.WriteRecord{ | ||
{Data: []byte(`{"result":"The current weather in New York (40.712800,-74.006000) is sunny","arguments":"{\"city\":\"New York\",\"latitude\":40.7128,\"longitude\":-74.0060}","is_ok":true}`), Tag: ai.ReducerTag}, | ||
}, | ||
}, | ||
// TODO: add more test cases. | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
Handler(tt.ctx) | ||
got := tt.ctx.RecordsWritten() | ||
|
||
fmt.Println(string(got[0].Data)) | ||
|
||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("TestHandler got: %v, want: %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters