Skip to content

Commit

Permalink
refactor: break down json grammar parser in different files (#3004)
Browse files Browse the repository at this point in the history
* refactor: break down json grammar parser in different files

Signed-off-by: Ettore Di Giacinto <[email protected]>

* fix: patch to `refactor_grammars` - propagate errors (#3006)

propagate errors around

Signed-off-by: Dave Lee <[email protected]>

---------

Signed-off-by: Ettore Di Giacinto <[email protected]>
Signed-off-by: Dave Lee <[email protected]>
Co-authored-by: Dave <[email protected]>
  • Loading branch information
mudler and dave-gray101 authored Jul 25, 2024
1 parent 717cc6f commit 5eda7f5
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 153 deletions.
10 changes: 8 additions & 2 deletions core/http/endpoints/openai/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,15 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, startup

// Update input grammar
jsStruct := funcs.ToJSONStructure(config.FunctionsConfig.FunctionNameKey, config.FunctionsConfig.FunctionNameKey)
config.Grammar = jsStruct.Grammar(config.FunctionsConfig.GrammarConfig.Options()...)
g, err := jsStruct.Grammar(config.FunctionsConfig.GrammarConfig.Options()...)
if err == nil {
config.Grammar = g
}
case input.JSONFunctionGrammarObject != nil:
config.Grammar = input.JSONFunctionGrammarObject.Grammar(config.FunctionsConfig.GrammarConfig.Options()...)
g, err := input.JSONFunctionGrammarObject.Grammar(config.FunctionsConfig.GrammarConfig.Options()...)
if err == nil {
config.Grammar = g
}
default:
// Force picking one of the functions by the request
if config.FunctionToCall() != "" {
Expand Down
47 changes: 47 additions & 0 deletions pkg/functions/bnf_rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package functions

import "regexp"

var (
PRIMITIVE_RULES = map[string]string{
"boolean": `("true" | "false") space`,
"number": `("-"? ([0-9] | [1-9] [0-9]*)) ("." [0-9]+)? ([eE] [-+]? [0-9]+)? space`,
"integer": `("-"? ([0-9] | [1-9] [0-9]*)) space`,
"string": `"\"" (
[^"\\] |
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
)* "\"" space`,
// TODO: we shouldn't forbid \" and \\ or all unicode and have this branch here,
// however, if we don't have it, the grammar will be ambiguous and
// empirically results are way worse.
"freestring": `(
[^\x00] |
"\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F])
)* space`,
"null": `"null" space`,
}

INVALID_RULE_CHARS_RE = regexp.MustCompile(`[^a-zA-Z0-9-]+`)
GRAMMAR_LITERAL_ESCAPE_RE = regexp.MustCompile(`[\r\n"]`)
GRAMMAR_LITERAL_ESCAPES = map[string]string{
"\r": `\r`,
"\n": `\n`,
`"`: `\"`,
}
)

const (
SPACE_RULE = `" "?`

arrayNewLines = `arr ::=
"[\n" (
realvalue
(",\n" realvalue)*
)? "]"`

array = `arr ::=
"[" (
realvalue
("," realvalue)*
)? "]"`
)
25 changes: 25 additions & 0 deletions pkg/functions/function_structure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package functions

import "encoding/json"

type Item struct {
Type string `json:"type"`
Properties map[string]interface{} `json:"properties"`
}

type JSONFunctionStructure struct {
OneOf []Item `json:"oneOf,omitempty"`
AnyOf []Item `json:"anyOf,omitempty"`
Defs map[string]interface{} `json:"$defs,omitempty"`
}

func (j JSONFunctionStructure) Grammar(options ...func(*GrammarOption)) (string, error) {
grammarOpts := &GrammarOption{}
grammarOpts.Apply(options...)

dat, err := json.Marshal(j)
if err != nil {
return "", err
}
return NewJSONSchemaConverter(grammarOpts.PropOrder).GrammarFromBytes(dat, options...)
}
17 changes: 17 additions & 0 deletions pkg/functions/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ type Function struct {
}
type Functions []Function

type FunctionName struct {
Const string `json:"const"`
}

type Argument struct {
Type string `json:"type"`
Properties map[string]interface{} `json:"properties"`
}

type Tool struct {
Type string `json:"type"`
Function Function `json:"function,omitempty"`
Expand Down Expand Up @@ -86,3 +95,11 @@ func (f Functions) Select(name string) Functions {

return funcs
}

func jsonString(v interface{}) (string, error) {
b, err := json.Marshal(v)
if err != nil {
return "", err
}
return string(b), nil
}
14 changes: 13 additions & 1 deletion pkg/functions/functions_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package functions
package functions_test

import (
"testing"

. "github.com/mudler/LocalAI/pkg/functions"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
Expand All @@ -11,3 +13,13 @@ func TestGrammar(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Grammar test suite")
}

func createFunction(field1 string, field2 string, name string, properties map[string]interface{}) map[string]interface{} {
property := map[string]interface{}{}
property[field1] = FunctionName{Const: name}
property[field2] = Argument{
Type: "object",
Properties: properties,
}
return property
}
Loading

0 comments on commit 5eda7f5

Please sign in to comment.