Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat add tools #201

Merged
merged 15 commits into from
May 29, 2024
24 changes: 12 additions & 12 deletions examples/llm/openai/thread/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package main

import (
"context"
"encoding/json"
"fmt"
"strings"

"github.com/henomis/lingoose/llm/openai"
"github.com/henomis/lingoose/thread"
"github.com/henomis/lingoose/tools/dalle"
"github.com/henomis/lingoose/transformer"
)

Expand All @@ -32,31 +33,30 @@ func newStr(str string) *string {

func main() {
openaillm := openai.New().WithModel(openai.GPT4o)
openaillm.WithToolChoice(newStr("auto"))
err := openaillm.BindFunction(
crateImage,
"createImage",
"use this function to create an image from a description",
)
if err != nil {
panic(err)
}
openaillm.WithToolChoice(newStr("auto")).WithTools(dalle.New())

t := thread.New().AddMessage(
thread.NewUserMessage().AddContent(
thread.NewTextContent("Please, create an image that inspires you"),
),
)

err = openaillm.Generate(context.Background(), t)
err := openaillm.Generate(context.Background(), t)
if err != nil {
panic(err)
}

if t.LastMessage().Role == thread.RoleTool {
var output dalle.Output

err = json.Unmarshal([]byte(t.LastMessage().Contents[0].AsToolResponseData().Result), &output)
if err != nil {
panic(err)
}

t.AddMessage(thread.NewUserMessage().AddContent(
thread.NewImageContentFromURL(
strings.ReplaceAll(t.LastMessage().Contents[0].AsToolResponseData().Result, `"`, ""),
output.ImageURL,
),
).AddContent(
thread.NewTextContent("can you describe the image?"),
Expand Down
32 changes: 32 additions & 0 deletions examples/llm/openai/tools/python/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"context"
"fmt"

"github.com/henomis/lingoose/llm/openai"
"github.com/henomis/lingoose/thread"
"github.com/henomis/lingoose/tools/python"
)

func main() {
newStr := func(str string) *string {
return &str
}
llm := openai.New().WithModel(openai.GPT3Dot5Turbo0613).WithToolChoice(newStr("auto")).WithTools(
python.New(),
)

t := thread.New().AddMessage(
thread.NewUserMessage().AddContent(
thread.NewTextContent("calculate reverse string of 'ailatiditalia', don't try to guess, let's use appropriate tool"),
),
)

llm.Generate(context.Background(), t)
if t.LastMessage().Role == thread.RoleTool {
llm.Generate(context.Background(), t)
}

fmt.Println(t)
}
66 changes: 66 additions & 0 deletions examples/llm/openai/tools/rag/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"context"
"fmt"
"os"

openaiembedder "github.com/henomis/lingoose/embedder/openai"
"github.com/henomis/lingoose/index"
"github.com/henomis/lingoose/index/vectordb/jsondb"
"github.com/henomis/lingoose/llm/openai"
"github.com/henomis/lingoose/rag"
"github.com/henomis/lingoose/thread"
ragtool "github.com/henomis/lingoose/tools/rag"
"github.com/henomis/lingoose/tools/serpapi"
"github.com/henomis/lingoose/tools/shell"
)

func main() {

rag := rag.New(
index.New(
jsondb.New().WithPersist("index.json"),
openaiembedder.New(openaiembedder.AdaEmbeddingV2),
),
).WithChunkSize(1000).WithChunkOverlap(0)

_, err := os.Stat("index.json")
if os.IsNotExist(err) {
err = rag.AddSources(context.Background(), "state_of_the_union.txt")
if err != nil {
panic(err)
}
}

newStr := func(str string) *string {
return &str
}
llm := openai.New().WithModel(openai.GPT4o).WithToolChoice(newStr("auto")).WithTools(
ragtool.New(rag, "US covid vaccines"),
serpapi.New(),
shell.New(),
)

topics := []string{
"how many covid vaccine doses US has donated to other countries.",
"who's the author of LinGoose github project.",
"which process is consuming the most memory.",
}

for _, topic := range topics {
t := thread.New().AddMessage(
thread.NewUserMessage().AddContent(
thread.NewTextContent("Please tell me " + topic),
),
)

llm.Generate(context.Background(), t)
if t.LastMessage().Role == thread.RoleTool {
llm.Generate(context.Background(), t)
}

fmt.Println(t)
}

}
15 changes: 15 additions & 0 deletions examples/tools/duckduckgo/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"fmt"

"github.com/henomis/lingoose/tools/duckduckgo"
)

func main() {

t := duckduckgo.New().WithMaxResults(5)
f := t.Fn().(duckduckgo.FnPrototype)

fmt.Println(f(duckduckgo.Input{Query: "Simone Vellei"}))
}
16 changes: 16 additions & 0 deletions examples/tools/python/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"fmt"

"github.com/henomis/lingoose/tools/python"
)

func main() {
t := python.New().WithPythonPath("python3")

pythonScript := `print("Hello from Python!")`
f := t.Fn().(python.FnPrototype)

fmt.Println(f(python.Input{PythonCode: pythonScript}))
}
15 changes: 15 additions & 0 deletions examples/tools/serpapi/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"fmt"

"github.com/henomis/lingoose/tools/serpapi"
)

func main() {

t := serpapi.New()
f := t.Fn().(serpapi.FnPrototype)

fmt.Println(f(serpapi.Input{Query: "Simone Vellei"}))
}
16 changes: 16 additions & 0 deletions examples/tools/shell/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"fmt"

"github.com/henomis/lingoose/tools/shell"
)

func main() {
t := shell.New()

bashScript := `echo "Hello from $SHELL!"`
f := t.Fn().(shell.FnPrototype)

fmt.Println(f(shell.Input{BashScript: bashScript}))
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/henomis/restclientgo v1.2.0
github.com/invopop/jsonschema v0.7.0
github.com/sashabaranov/go-openai v1.24.0
golang.org/x/net v0.25.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
19 changes: 19 additions & 0 deletions llm/openai/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,25 @@ func (o *OpenAI) BindFunction(
return nil
}

type Tool interface {
Description() string
Name() string
Fn() any
}

func (o OpenAI) WithTools(tools ...Tool) OpenAI {
for _, tool := range tools {
function, err := bindFunction(tool.Fn(), tool.Name(), tool.Description())
if err != nil {
fmt.Println(err)
}

o.functions[tool.Name()] = *function
}

return o
}

func (o *Legacy) getFunctions() []openai.FunctionDefinition {
var functions []openai.FunctionDefinition

Expand Down
56 changes: 56 additions & 0 deletions tools/dalle/dalle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dalle

import (
"context"
"fmt"
"time"

"github.com/henomis/lingoose/transformer"
)

const (
defaultTimeoutInSeconds = 60
)

type Tool struct {
}

type Input struct {
Description string `json:"description" jsonschema:"description=the description of the image that should be created"`
}

type Output struct {
Error string `json:"error,omitempty"`
ImageURL string `json:"imageURL,omitempty"`
}

type FnPrototype func(Input) Output

func New() *Tool {
return &Tool{}
}

func (t *Tool) Name() string {
return "dalle"
}

func (t *Tool) Description() string {
return "A tool that creates an image from a description."
}

func (t *Tool) Fn() any {
return t.fn
}

func (t *Tool) fn(i Input) Output {
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeoutInSeconds*time.Second)
defer cancel()

d := transformer.NewDallE().WithImageSize(transformer.DallEImageSize512x512)
imageURL, err := d.Transform(ctx, i.Description)
if err != nil {
return Output{Error: fmt.Sprintf("error creating image: %v", err)}
}

return Output{ImageURL: imageURL.(string)}
}
Loading
Loading