commit
68d274b93d
9 changed files with 121 additions and 89 deletions
|
|
@ -17,6 +17,23 @@ func SetStore(store Store) {
|
|||
DefaultStore = store
|
||||
}
|
||||
|
||||
// Match the command from the content
|
||||
func Match(sid string, query driver.Query, input string) (string, error) {
|
||||
|
||||
if DefaultStore == nil {
|
||||
return "", fmt.Errorf("command store is not set")
|
||||
}
|
||||
|
||||
// Check the command from the store
|
||||
if id, cid, has := DefaultStore.GetRequest(sid); has {
|
||||
fmt.Println("Match Requst:", id)
|
||||
return cid, nil
|
||||
}
|
||||
|
||||
return DefaultStore.Match(query, input)
|
||||
}
|
||||
|
||||
// save the command to the store
|
||||
func (cmd *Command) save() error {
|
||||
if DefaultStore == nil {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -51,13 +51,13 @@ func TestMemoryMatch(t *testing.T) {
|
|||
defer test.Clean()
|
||||
|
||||
mem := prepare(t)
|
||||
id, err := mem.Match(Query{}, "Generate table test data")
|
||||
id, err := mem.Match(Query{Stack: "Table.Page.pet"}, "Generate table test data")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "table.data", id)
|
||||
|
||||
id, err = mem.Match(Query{Stack: "Form"}, "Generate table test data")
|
||||
id, err = mem.Match(Query{Stack: "Form.Page.pet", Path: "/Form/pet"}, "Generate table test data")
|
||||
assert.ErrorContains(t, err, "no related command found")
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ func prepare(t *testing.T) *Memory {
|
|||
Name: "Generate test data for the table",
|
||||
Description: "Generate test data for the table",
|
||||
Stack: "Table.*",
|
||||
Path: "*",
|
||||
Path: "Table.*",
|
||||
Args: []map[string]interface{}{
|
||||
{
|
||||
"name": "data",
|
||||
|
|
|
|||
|
|
@ -8,39 +8,40 @@ import (
|
|||
// MatchStack match the stack
|
||||
func (query Query) MatchStack(stack string) bool {
|
||||
|
||||
if query.Stack == "" || query.Stack == "*" || stack == "" {
|
||||
if stack == "" || stack == "*" || query.Stack == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if query.Stack == stack {
|
||||
if stack == query.Stack {
|
||||
return true
|
||||
}
|
||||
|
||||
matched, _ := regexp.MatchString(strings.ReplaceAll(query.Stack, "*", ".*"), stack)
|
||||
matched, _ := regexp.MatchString(strings.ReplaceAll(stack, "*", ".*"), query.Stack)
|
||||
return matched
|
||||
}
|
||||
|
||||
// MatchPath match the path
|
||||
func (query Query) MatchPath(path string) bool {
|
||||
if query.Path == "" || query.Path == "*" || path == "" {
|
||||
if path == "" || path == "*" || query.Path == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if query.Path == path {
|
||||
if path == query.Path {
|
||||
return true
|
||||
}
|
||||
|
||||
matched, _ := regexp.MatchString(strings.ReplaceAll(query.Path, "*", ".*"), path)
|
||||
matched, _ := regexp.MatchString(strings.ReplaceAll(path, "*", ".*"), query.Path)
|
||||
return matched
|
||||
}
|
||||
|
||||
// MatchAny match the stack or path
|
||||
func (query Query) MatchAny(stack, path string) bool {
|
||||
if query.Path == "" || query.Path == "-" {
|
||||
|
||||
if path == "" || path == "-" {
|
||||
return query.MatchStack(stack)
|
||||
}
|
||||
|
||||
if query.Stack == "" || query.Stack == "-" {
|
||||
if stack == "" || stack == "-" {
|
||||
return query.MatchPath(path)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,84 +1,76 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
)
|
||||
|
||||
var requests = sync.Map{}
|
||||
func output(format string, args ...interface{}) []byte {
|
||||
content := fmt.Sprintf(format, args...)
|
||||
return []byte(fmt.Sprintf(`{"id":"chatcmpl-7Atx502nGBuYcvoZfIaWU4FREI1mT","object":"chat.completion.chunk","created":1682832715,"model":"gpt-3.5-turbo-0301","choices":[{"delta":{"content":"%s"},"index":0,"finish_reason":null}]}`, content))
|
||||
}
|
||||
|
||||
// Run the command
|
||||
func (req *Request) Run(cb func(data []byte) int) (interface{}, error) {
|
||||
func (req *Request) Run(messages []map[string]interface{}, cb func(data []byte) int) (interface{}, error) {
|
||||
|
||||
cb(output("- Command: %s\\n", req.Command.ID))
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
cb(output("- Session: %s\\n", req.sid))
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
cb(output("- Request: %s\\n", req.id))
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
cb([]byte(`[DONE]`))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewRequest create a new request
|
||||
func (cmd *Command) NewRequest(ctx Context, messages []map[string]interface{}) (*Request, error) {
|
||||
func (cmd *Command) NewRequest(ctx Context) (*Request, error) {
|
||||
|
||||
v, ok := requests.Load(ctx.Sid)
|
||||
if !ok {
|
||||
v = map[string]string{
|
||||
"id": uuid.New().String(),
|
||||
"cmd": cmd.ID,
|
||||
if DefaultStore == nil {
|
||||
return nil, fmt.Errorf("command store is not set")
|
||||
}
|
||||
|
||||
if ctx.Sid == "" {
|
||||
return nil, fmt.Errorf("context sid is request")
|
||||
}
|
||||
|
||||
// continue the request
|
||||
id, cid, has := DefaultStore.GetRequest(ctx.Sid)
|
||||
if has {
|
||||
if cid != cmd.ID {
|
||||
return nil, fmt.Errorf("request id is not match")
|
||||
}
|
||||
return &Request{
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
req, ok := v.(map[string]string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("request id is not string")
|
||||
}
|
||||
|
||||
if req["id"] == "" {
|
||||
return nil, fmt.Errorf("request id is request")
|
||||
}
|
||||
|
||||
if req["cmd"] != cmd.ID {
|
||||
defer requests.Delete(ctx.Sid)
|
||||
return nil, fmt.Errorf("request id is not match")
|
||||
// create a new request
|
||||
id = uuid.New().String()
|
||||
err := DefaultStore.SetRequest(ctx.Sid, id, cmd.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Request{
|
||||
Command: cmd,
|
||||
messages: messages,
|
||||
sid: ctx.Sid,
|
||||
id: req["id"],
|
||||
ctx: ctx,
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Done the request done
|
||||
func (req *Request) Done() {
|
||||
requests.Delete(req.sid)
|
||||
}
|
||||
|
||||
// prepare the command
|
||||
func (req *Request) prepare(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (int, *exception.Exception) {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// before the process
|
||||
func (req *Request) before(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (interface{}, *exception.Exception) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// after the process
|
||||
func (req *Request) after(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (interface{}, *exception.Exception) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// run the process
|
||||
func (req *Request) process(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (interface{}, *exception.Exception) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (req *Request) saveConversation(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (interface{}, *exception.Exception) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (req *Request) saveData(ctx context.Context, data []map[string]interface{}, messages []map[string]interface{}, option map[string]interface{}, cb func(data []byte) int) (interface{}, *exception.Exception) {
|
||||
return nil, nil
|
||||
if DefaultStore == nil {
|
||||
DefaultStore.DelRequest(req.sid)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ import (
|
|||
|
||||
// Request the command request
|
||||
type Request struct {
|
||||
id string
|
||||
sid string
|
||||
ctx Context
|
||||
messages []map[string]interface{}
|
||||
id string
|
||||
sid string
|
||||
ctx Context
|
||||
*Command
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +65,7 @@ type Optional struct {
|
|||
type Context struct {
|
||||
Sid string `json:"-" yaml:"-"`
|
||||
Stack string `json:"stack,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Path string `json:"pathname,omitempty"`
|
||||
context.Context `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
|
|
|
|||
22
neo/load.go
22
neo/load.go
|
|
@ -4,8 +4,11 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/yaoapp/gou/application"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/aigc"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/neo/command"
|
||||
"github.com/yaoapp/yao/neo/command/driver"
|
||||
"github.com/yaoapp/yao/neo/conversation"
|
||||
)
|
||||
|
||||
|
|
@ -41,18 +44,31 @@ func Load(cfg config.Config) error {
|
|||
}
|
||||
|
||||
Neo = &setting
|
||||
|
||||
// AI Setting
|
||||
err = Neo.newAI()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Conversation Setting
|
||||
err = Neo.newConversation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Command Setting
|
||||
store, err := driver.NewMemory("gpt-3_5-turbo", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
command.SetStore(store)
|
||||
|
||||
// Load the commands
|
||||
err = command.Load(cfg)
|
||||
if err != nil {
|
||||
log.Error("Command Load Error: %s", err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadCommands load the commands
|
||||
func (neo *DSL) LoadCommands() {}
|
||||
|
|
|
|||
18
neo/neo.go
18
neo/neo.go
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
"github.com/yaoapp/yao/neo/command"
|
||||
"github.com/yaoapp/yao/neo/command/driver"
|
||||
"github.com/yaoapp/yao/neo/conversation"
|
||||
"github.com/yaoapp/yao/openai"
|
||||
)
|
||||
|
|
@ -66,7 +67,7 @@ func (neo *DSL) API(router *gin.Engine, path string) error {
|
|||
// utils.Dump(messages)
|
||||
|
||||
// set the context
|
||||
ctx, cancel := command.NewContextWithCancel(sid, c.GetString("context"))
|
||||
ctx, cancel := command.NewContextWithCancel(sid, c.Query("context"))
|
||||
defer cancel()
|
||||
|
||||
err = neo.Answer(ctx, c, messages)
|
||||
|
|
@ -87,9 +88,13 @@ func (neo *DSL) Answer(ctx command.Context, answer Answer, messages []map[string
|
|||
chanError := make(chan error, 1)
|
||||
|
||||
// check the command
|
||||
// cmd, isCommand := neo.Command.Match(ctx, messages)
|
||||
isCommand := false
|
||||
cmd := command.Command{}
|
||||
var cmd *command.Command
|
||||
var isCommand = false
|
||||
input := messages[len(messages)-1]["content"].(string)
|
||||
name, err := command.Match(ctx.Sid, driver.Query{Stack: ctx.Stack, Path: ctx.Path}, input)
|
||||
if err == nil && name != "" {
|
||||
cmd, isCommand = command.Commands[name]
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
|
|
@ -100,13 +105,13 @@ func (neo *DSL) Answer(ctx command.Context, answer Answer, messages []map[string
|
|||
// execute the command
|
||||
if isCommand {
|
||||
|
||||
req, err := cmd.NewRequest(ctx, messages)
|
||||
req, err := cmd.NewRequest(ctx)
|
||||
if err != nil {
|
||||
chanError <- err
|
||||
return
|
||||
}
|
||||
|
||||
_, err = req.Run(func(data []byte) int {
|
||||
_, err = req.Run(messages, func(data []byte) int {
|
||||
chanStream <- data
|
||||
return 1
|
||||
})
|
||||
|
|
@ -114,6 +119,7 @@ func (neo *DSL) Answer(ctx command.Context, answer Answer, messages []map[string
|
|||
if err != nil {
|
||||
chanError <- err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
httpTest "github.com/yaoapp/gou/http"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/helper"
|
||||
"github.com/yaoapp/yao/neo/command"
|
||||
"github.com/yaoapp/yao/test"
|
||||
_ "github.com/yaoapp/yao/utils"
|
||||
)
|
||||
|
|
@ -104,11 +105,18 @@ func testServer(t *testing.T, router *gin.Engine) (string, func()) {
|
|||
|
||||
func testRouter(t *testing.T) *gin.Engine {
|
||||
|
||||
// Load Config
|
||||
err := Load(config.Conf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Load Commands
|
||||
err = command.Load(config.Conf)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
router := gin.New()
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
return router
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/yaoapp/yao/aigc"
|
||||
"github.com/yaoapp/yao/neo/command"
|
||||
"github.com/yaoapp/yao/neo/conversation"
|
||||
)
|
||||
|
||||
|
|
@ -20,7 +19,6 @@ type DSL struct {
|
|||
Allows []string `json:"allows,omitempty"`
|
||||
AI aigc.AI `json:"-" yaml:"-"`
|
||||
Conversation Conversation `json:"-" yaml:"-"`
|
||||
Command Command `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// Conversation the store interface
|
||||
|
|
@ -29,11 +27,6 @@ type Conversation interface {
|
|||
SaveHistory(sid string, messages []map[string]interface{}) error
|
||||
}
|
||||
|
||||
// Command the command interface
|
||||
type Command interface {
|
||||
Match(ctx command.Context, messages []map[string]interface{}) (*command.Command, bool)
|
||||
}
|
||||
|
||||
// Answer the answer interface
|
||||
type Answer interface {
|
||||
GetString(key string) (s string)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue