From f43dbd22bbb6a74a29c1e5645e49026ce2179ff8 Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Wed, 17 Jul 2024 19:47:03 +0800 Subject: [PATCH 1/7] feat(cache): add cache message --- api_context_cache_content.go | 59 +++++++++++++++++++++++++++++++ api_context_cache_content_test.go | 44 +++++++++++++++++++++++ chat_completions_builder.go | 22 ++++++++++++ enum_chat_completions.go | 9 ++--- 4 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 api_context_cache_content.go create mode 100644 api_context_cache_content_test.go diff --git a/api_context_cache_content.go b/api_context_cache_content.go new file mode 100644 index 0000000..fd7484b --- /dev/null +++ b/api_context_cache_content.go @@ -0,0 +1,59 @@ +package moonshot + +import ( + "fmt" + "strings" +) + +const ( + ResetTTLNever = -1 // ResetTTLNever is the value for never reset ttl + ResetTTLImmediate = 0 // ResetTTLImmediate is the value for immediate reset ttl +) + +// ContextCacheContent is the content for the context cache +type ContextCacheContent struct { + CacheId string `json:"cache_id"` + Tag string `json:"tag"` + ResetTTL int64 `json:"reset_ttl"` + DryRun bool `json:"dry_run"` +} + +func NewContextCacheContentWithId(cacheId string) *ContextCacheContent { + return &ContextCacheContent{CacheId: cacheId, ResetTTL: ResetTTLNever} +} + +func NewContextCacheContentWithTag(tag string) *ContextCacheContent { + return &ContextCacheContent{Tag: tag, ResetTTL: ResetTTLNever} +} + +// WithResetTTL set the reset ttl for the context cache +func (c *ContextCacheContent) WithResetTTL(resetTTL int64) *ContextCacheContent { + c.ResetTTL = resetTTL + return c +} + +// WithDryRun set the dry run for the context cache +func (c *ContextCacheContent) WithDryRun(dryRun bool) *ContextCacheContent { + c.DryRun = dryRun + return c +} + +func (c *ContextCacheContent) Content() string { + var slice []string + + if c.CacheId != "" { + slice = append(slice, fmt.Sprintf("cache_id=%s", c.CacheId)) + } else if c.Tag != "" { + slice = append(slice, fmt.Sprintf("tag=%s", c.Tag)) + } + + if c.ResetTTL >= 0 { + slice = append(slice, fmt.Sprintf("reset_ttl=%d", c.ResetTTL)) + } + + if c.DryRun { + slice = append(slice, "dry_run=1") + } + + return strings.Join(slice, ";") +} diff --git a/api_context_cache_content_test.go b/api_context_cache_content_test.go new file mode 100644 index 0000000..f56bfd9 --- /dev/null +++ b/api_context_cache_content_test.go @@ -0,0 +1,44 @@ +package moonshot + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNewContextCacheContentWithId(t *testing.T) { + const cacheId = "my_cache_id" + expected := &ContextCacheContent{ + CacheId: cacheId, + ResetTTL: ResetTTLNever, + } + actual := NewContextCacheContentWithId(cacheId) + assert.Equal(t, expected, actual) + + const resetTTL = 3600 + expected = &ContextCacheContent{ + CacheId: cacheId, + ResetTTL: resetTTL, + } + actual = NewContextCacheContentWithId(cacheId). + WithResetTTL(resetTTL) + assert.Equal(t, expected, actual) + + const dryRun = true + expected = &ContextCacheContent{ + CacheId: cacheId, + ResetTTL: resetTTL, + DryRun: dryRun, + } + actual = NewContextCacheContentWithId(cacheId). + WithResetTTL(resetTTL). + WithDryRun(dryRun) + assert.Equal(t, expected, actual) + + const tag = "my_tag" + expected = &ContextCacheContent{ + Tag: tag, + ResetTTL: ResetTTLNever, + } + actual = NewContextCacheContentWithTag(tag) + assert.Equal(t, expected, actual) +} diff --git a/chat_completions_builder.go b/chat_completions_builder.go index 01780f0..b99b52f 100644 --- a/chat_completions_builder.go +++ b/chat_completions_builder.go @@ -20,6 +20,7 @@ type IChatCompletionsBuilder interface { SetStop(stop []string) IChatCompletionsBuilder SetTool(tool *ChatCompletionsTool) IChatCompletionsBuilder SetTools(tools []*ChatCompletionsTool) IChatCompletionsBuilder + SetContextCacheContent(content *ContextCacheContent) IChatCompletionsBuilder ToRequest() *ChatCompletionsRequest } @@ -192,6 +193,27 @@ func (c *chatCompletionsBuilder) SetTools(tools []*ChatCompletionsTool) IChatCom return c } +func (c *chatCompletionsBuilder) SetContextCacheContent(content *ContextCacheContent) IChatCompletionsBuilder { + // 如果 content 为 nil,则不做任何操作 + if content == nil { + return c + } + // 你必须把这个消息放在 messages 列表的第一位 + if len(c.req.Messages) > 0 && c.req.Messages[0].Role == RoleContextCache { + // Update the cache message + c.req.Messages[0].Content = content.Content() + } else { + // Add a new cache message to the first + c.req.Messages = append([]*ChatCompletionsMessage{{ + Role: RoleContextCache, + Content: content.Content(), + }}, c.req.Messages...) + } + // tools 参数必须为 null(空数组也将视为有值) + c.req.Tools = nil + return c +} + // ToRequest returns the ChatCompletionsRequest func (c *chatCompletionsBuilder) ToRequest() *ChatCompletionsRequest { return c.req diff --git a/enum_chat_completions.go b/enum_chat_completions.go index da7106d..291dff6 100644 --- a/enum_chat_completions.go +++ b/enum_chat_completions.go @@ -3,10 +3,11 @@ package moonshot type ChatCompletionsMessageRole string const ( - RoleSystem ChatCompletionsMessageRole = "system" - RoleUser ChatCompletionsMessageRole = "user" - RoleAssistant ChatCompletionsMessageRole = "assistant" - RoleTool ChatCompletionsMessageRole = "tool" + RoleSystem ChatCompletionsMessageRole = "system" + RoleUser ChatCompletionsMessageRole = "user" + RoleAssistant ChatCompletionsMessageRole = "assistant" + RoleTool ChatCompletionsMessageRole = "tool" + RoleContextCache ChatCompletionsMessageRole = "cache" ) func (c ChatCompletionsMessageRole) String() string { From c00f008619beb944da1d15c95a44d325baeeafb7 Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Wed, 17 Jul 2024 19:47:38 +0800 Subject: [PATCH 2/7] test(builder): add test messages --- chat_completions_builder_test.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/chat_completions_builder_test.go b/chat_completions_builder_test.go index f83a6a4..cd9b053 100644 --- a/chat_completions_builder_test.go +++ b/chat_completions_builder_test.go @@ -23,6 +23,10 @@ func TestNewChatCompletionsBuilder(t *testing.T) { wantedReq := &moonshot.ChatCompletionsRequest{ Messages: []*moonshot.ChatCompletionsMessage{ + { + Role: moonshot.RoleContextCache, + Content: "tag=tag1;reset_ttl=3600;dry_run=1", + }, { Role: moonshot.RoleSystem, Content: promptContent, @@ -69,7 +73,11 @@ func TestNewChatCompletionsBuilder(t *testing.T) { }}, } - builder.AddPrompt(promptContent). + builder.SetContextCacheContent( + moonshot.NewContextCacheContentWithTag("tag1"). + WithResetTTL(3600). + WithDryRun(true)). + AddPrompt(promptContent). AddUserContent(userContent). AddAssistantContent(assistantContent). AddMessage(&moonshot.ChatCompletionsMessage{ From 2c623f315504fe121b11270dbc2885e44462a735 Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Wed, 17 Jul 2024 19:50:24 +0800 Subject: [PATCH 3/7] test(cache): add test content --- api_context_cache_content_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api_context_cache_content_test.go b/api_context_cache_content_test.go index f56bfd9..0428125 100644 --- a/api_context_cache_content_test.go +++ b/api_context_cache_content_test.go @@ -13,6 +13,8 @@ func TestNewContextCacheContentWithId(t *testing.T) { } actual := NewContextCacheContentWithId(cacheId) assert.Equal(t, expected, actual) + content := "cache_id=my_cache_id" + assert.Equal(t, content, actual.Content()) const resetTTL = 3600 expected = &ContextCacheContent{ @@ -22,6 +24,8 @@ func TestNewContextCacheContentWithId(t *testing.T) { actual = NewContextCacheContentWithId(cacheId). WithResetTTL(resetTTL) assert.Equal(t, expected, actual) + content = "cache_id=my_cache_id;reset_ttl=3600" + assert.Equal(t, content, actual.Content()) const dryRun = true expected = &ContextCacheContent{ @@ -33,6 +37,8 @@ func TestNewContextCacheContentWithId(t *testing.T) { WithResetTTL(resetTTL). WithDryRun(dryRun) assert.Equal(t, expected, actual) + content = "cache_id=my_cache_id;reset_ttl=3600;dry_run=1" + assert.Equal(t, content, actual.Content()) const tag = "my_tag" expected = &ContextCacheContent{ @@ -41,4 +47,6 @@ func TestNewContextCacheContentWithId(t *testing.T) { } actual = NewContextCacheContentWithTag(tag) assert.Equal(t, expected, actual) + content = "tag=my_tag" + assert.Equal(t, content, actual.Content()) } From 0a56e25fe6d147d99f3dcda0f30fc61d2dacc368 Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Thu, 18 Jul 2024 10:20:59 +0800 Subject: [PATCH 4/7] feat(cache): add context cache api --- api_context_cache.go | 377 ++++++++++++++++++++++++++++++++++++++ api_context_cache_test.go | 23 +++ enum_context_cache.go | 25 +++ 3 files changed, 425 insertions(+) create mode 100644 api_context_cache.go create mode 100644 api_context_cache_test.go create mode 100644 enum_context_cache.go diff --git a/api_context_cache.go b/api_context_cache.go new file mode 100644 index 0000000..05e5503 --- /dev/null +++ b/api_context_cache.go @@ -0,0 +1,377 @@ +package moonshot + +import ( + "context" + "fmt" + "net/url" + "strconv" +) + +type IContextCache interface { + Create(ctx context.Context, req *ContextCacheCreateRequest) (*ContextCacheCreateResponse, error) + List(ctx context.Context, req *ContextCacheListRequest) (*ContextCacheListResponse, error) + Delete(ctx context.Context, req *ContextCacheDeleteRequest) (*ContextCacheDeleteResponse, error) + Update(ctx context.Context, req *ContextCacheUpdateRequest) (*ContextCacheUpdateResponse, error) + Get(ctx context.Context, req *ContextCacheGetRequest) (*ContextCacheGetResponse, error) + + CreateTag(ctx context.Context, req *ContextCacheCreateTagRequest) (*ContextCacheCreateTagResponse, error) + ListTag(ctx context.Context, req *ContextCacheListTagRequest) (*ContextCacheListTagResponse, error) + DeleteTag(ctx context.Context, req *ContextCacheDeleteTagRequest) (*ContextCacheDeleteTagResponse, error) + GetTag(ctx context.Context, req *ContextCacheGetTagRequest) (*ContextCacheGetTagResponse, error) + GetTagContent(ctx context.Context, req *ContextCacheGetTagContentRequest) (*ContextCacheGetTagContentResponse, error) +} + +type contextCache struct { + client *Client +} + +// ContextCache returns a new context cache controller +func (c *Client) ContextCache() IContextCache { + return &contextCache{ + client: c, + } +} + +// ContextCache is the cache of the context +type ContextCache struct { + Id string `json:"id"` // 缓存的唯一标识 + Status ContextCacheStatus `json:"status"` // 缓存的状态 + Object string `json:"object"` // 缓存的类型 + CreatedAt int64 `json:"created_at"` // 缓存的创建时间 + ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 + Tokens int `json:"tokens"` // 缓存的 Token 数量 + Model ChatCompletionsModelID `json:"model"` // 缓存的模型组名称 + Messages []ChatCompletionsMessage `json:"messages"` // 缓存的消息内容 + Tools []ChatCompletionsTool `json:"tools"` // 缓存使用的工具 + Name string `json:"name"` // 缓存的名称 + Description string `json:"description"` // 缓存的描述信息 + Metadata map[string]string `json:"metadata"` // 缓存的元信息 +} + +// ContextCacheCreateRequest is the request for creating a context cache +type ContextCacheCreateRequest struct { + Model ChatCompletionsModelID `json:"model"` // 模型组(model family)名称 + Messages []ChatCompletionsMessage `json:"messages"` // 消息内容 + Tools []ChatCompletionsTool `json:"tools,omitempty"` // 使用的工具 + Name string `json:"name,omitempty"` // 缓存名称 + Description string `json:"description,omitempty"` // 缓存描述信息 + Metadata map[string]string `json:"metadata,omitempty"` // 缓存的元信息 + ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 + TTL int64 `json:"ttl,omitempty"` // 缓存的有效期 +} + +// ContextCacheCreateResponse is the response for creating a context cache +type ContextCacheCreateResponse ContextCache + +// ContextCacheListRequest is the request for listing context caches +type ContextCacheListRequest struct { + Limit int `json:"limit,omitempty"` // 当前请求单页返回的缓存数量 + Order ContextCacheOrder `json:"order,omitempty"` // 当前请求时查询缓存的排序规则 + After string `json:"after,omitempty"` // 当前请求时,应该从哪一个缓存开始进行查找 + Before string `json:"before,omitempty"` // 当前请求时,应该查询到哪一个缓存为止 + Metadata map[string]string `json:"metadata,omitempty"` // 用于筛选缓存的 metadata 信息 +} + +// ContextCacheListResponse is the response for listing context caches +type ContextCacheListResponse struct { + Object string `json:"object"` // 返回的数据类型 + Data []ContextCache `json:"data"` // 返回的缓存列表 +} + +// ContextCacheDeleteRequest is the request for deleting a context cache +type ContextCacheDeleteRequest struct { + Id string `json:"id"` // 缓存的唯一标识 +} + +// ContextCacheDeleteResponse is the response for deleting a context cache +type ContextCacheDeleteResponse struct { + Deleted bool `json:"deleted"` // 缓存是否被删除 + Id string `json:"id"` // 被删除的缓存的唯一标识 + Object string `json:"object"` // 返回的数据类型 +} + +// ContextCacheUpdateRequest is the request for updating a context cache +type ContextCacheUpdateRequest struct { + Id string `json:"_"` // 缓存的唯一标识 + Metadata map[string]string `json:"metadata,omitempty"` // 缓存的元信息 + ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 + TTL int64 `json:"ttl,omitempty"` // 缓存的有效期 +} + +// ContextCacheUpdateResponse is the response for updating a context cache +type ContextCacheUpdateResponse ContextCache + +// ContextCacheGetRequest is the request for getting a context cache +type ContextCacheGetRequest struct { + Id string `json:"_"` // 缓存的唯一标识 +} + +// ContextCacheGetResponse is the response for getting a context cache +type ContextCacheGetResponse ContextCache + +// ContextCacheTag is the tag of the context cache +type ContextCacheTag struct { + Tag string `json:"tag"` // 缓存的标签 + CacheId string `json:"cache_id"` // 缓存的唯一标识 + Object string `json:"object"` // 缓存的类型 + OwnedBy string `json:"owned_by"` // 缓存的拥有者 + CreatedAt int `json:"created_at"` // 缓存的创建时间 +} + +// ContextCacheCreateTagRequest is the request for creating a context cache tag +type ContextCacheCreateTagRequest struct { + Tag string `json:"tag"` // 缓存的标签 + CacheId string `json:"cache_id"` // 缓存的唯一标识 +} + +// ContextCacheCreateTagResponse is the response for creating a context cache tag +type ContextCacheCreateTagResponse ContextCacheTag + +// ContextCacheListTagRequest is the request for listing context cache tags +type ContextCacheListTagRequest struct { + Limit int `json:"limit,omitempty"` // 当前请求单页返回的缓存数量 + Order ContextCacheOrder `json:"order,omitempty"` // 当前请求时查询缓存的排序规则 + After string `json:"after,omitempty"` // 当前请求时,应该从哪一个缓存开始进行查找 + Before string `json:"before,omitempty"` // 当前请求时,应该查询到哪一个缓存为止 +} + +// ContextCacheListTagResponse is the response for listing context cache tags +type ContextCacheListTagResponse struct { + Object string `json:"object"` // 返回的数据类型 + Data []ContextCacheTag `json:"data"` // 返回的缓存标签列表 +} + +// ContextCacheDeleteTagRequest is the request for deleting a context cache tag +type ContextCacheDeleteTagRequest struct { + Tag string `json:"_"` // 缓存的标签 +} + +// ContextCacheDeleteTagResponse is the response for deleting a context cache tag +type ContextCacheDeleteTagResponse struct { + Deleted bool `json:"deleted"` // 缓存是否被删除 + Object string `json:"object"` // 返回的数据类型 + Tag string `json:"tag"` // 被删除的缓存的标签 +} + +// ContextCacheGetTagRequest is the request for getting a context cache tag +type ContextCacheGetTagRequest struct { + Tag string `json:"_"` // 缓存的标签 +} + +// ContextCacheGetTagResponse is the response for getting a context cache tag +type ContextCacheGetTagResponse ContextCacheTag + +// ContextCacheGetTagContentRequest is the request for getting a context cache tag content +type ContextCacheGetTagContentRequest struct { + Tag string `json:"_"` // 缓存的标签 +} + +// ContextCacheGetTagContentResponse is the response for getting a context cache tag content +type ContextCacheGetTagContentResponse ContextCache + +func (c *contextCache) Create(ctx context.Context, req *ContextCacheCreateRequest) (*ContextCacheCreateResponse, error) { + const path = "/v1/caching" + contextCacheCreateResp := new(ContextCacheCreateResponse) + resp, err := c.client.HTTPClient().SetPath(path).SetBody(req).Post(ctx) + if err != nil { + return contextCacheCreateResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheCreateResp) + if err != nil { + return nil, err + } + return contextCacheCreateResp, nil +} + +func (c *contextCache) List(ctx context.Context, req *ContextCacheListRequest) (*ContextCacheListResponse, error) { + path := "/v1/caching" + params := url.Values{} + if req.Limit > 0 { + params.Add("limit", strconv.Itoa(req.Limit)) + } + if req.Order != "" { + params.Add("order", req.Order.String()) + } + if req.After != "" { + params.Add("after", req.After) + } + if req.Before != "" { + params.Add("before", req.Before) + } + if len(req.Metadata) > 0 { + for k, v := range req.Metadata { + params.Add(fmt.Sprintf("metadata[%s]", k), v) + } + } + if len(params) > 0 { + path = fmt.Sprintf("%s?%s", path, params.Encode()) + } + contextCacheListResp := new(ContextCacheListResponse) + resp, err := c.client.HTTPClient().SetPath(path).Get(ctx) + if err != nil { + return contextCacheListResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheListResp) + if err != nil { + return nil, err + } + return contextCacheListResp, nil +} + +func (c *contextCache) Delete(ctx context.Context, req *ContextCacheDeleteRequest) (*ContextCacheDeleteResponse, error) { + path := fmt.Sprintf("/v1/caching/%s", req.Id) + contextCacheDeleteResp := new(ContextCacheDeleteResponse) + resp, err := c.client.HTTPClient().SetPath(path).Delete(ctx) + if err != nil { + return contextCacheDeleteResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheDeleteResp) + if err != nil { + return nil, err + } + return contextCacheDeleteResp, nil +} + +func (c *contextCache) Update(ctx context.Context, req *ContextCacheUpdateRequest) (*ContextCacheUpdateResponse, error) { + path := fmt.Sprintf("/v1/caching/%s", req.Id) + contextCacheUpdateResp := new(ContextCacheUpdateResponse) + resp, err := c.client.HTTPClient().SetPath(path).SetBody(req).Put(ctx) + if err != nil { + return contextCacheUpdateResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheUpdateResp) + if err != nil { + return nil, err + } + return contextCacheUpdateResp, nil +} + +func (c *contextCache) Get(ctx context.Context, req *ContextCacheGetRequest) (*ContextCacheGetResponse, error) { + path := fmt.Sprintf("/v1/caching/%s", req.Id) + contextCacheGetResp := new(ContextCacheGetResponse) + resp, err := c.client.HTTPClient().SetPath(path).Get(ctx) + if err != nil { + return contextCacheGetResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheGetResp) + if err != nil { + return nil, err + } + return contextCacheGetResp, nil +} + +func (c *contextCache) CreateTag(ctx context.Context, req *ContextCacheCreateTagRequest) (*ContextCacheCreateTagResponse, error) { + const path = "/v1/caching/refs/tags" + contextCacheCreateTagResp := new(ContextCacheCreateTagResponse) + resp, err := c.client.HTTPClient().SetPath(path).SetBody(req).Post(ctx) + if err != nil { + return contextCacheCreateTagResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheCreateTagResp) + if err != nil { + return nil, err + } + return contextCacheCreateTagResp, nil +} + +func (c *contextCache) ListTag(ctx context.Context, req *ContextCacheListTagRequest) (*ContextCacheListTagResponse, error) { + path := "/v1/caching/refs/tags" + params := url.Values{} + if req.Limit > 0 { + params.Add("limit", strconv.Itoa(req.Limit)) + } + if req.Order != "" { + params.Add("order", req.Order.String()) + } + if req.After != "" { + params.Add("after", req.After) + } + if req.Before != "" { + params.Add("before", req.Before) + } + if len(params) > 0 { + path = fmt.Sprintf("%s?%s", path, params.Encode()) + } + contextCacheListTagResp := new(ContextCacheListTagResponse) + resp, err := c.client.HTTPClient().SetPath(path).Get(ctx) + if err != nil { + return contextCacheListTagResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheListTagResp) + if err != nil { + return nil, err + } + return contextCacheListTagResp, nil +} + +func (c *contextCache) DeleteTag(ctx context.Context, req *ContextCacheDeleteTagRequest) (*ContextCacheDeleteTagResponse, error) { + path := fmt.Sprintf("/v1/caching/refs/tags/%s", req.Tag) + contextCacheDeleteTagResp := new(ContextCacheDeleteTagResponse) + resp, err := c.client.HTTPClient().SetPath(path).Delete(ctx) + if err != nil { + return contextCacheDeleteTagResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheDeleteTagResp) + if err != nil { + return nil, err + } + return contextCacheDeleteTagResp, nil +} + +func (c *contextCache) GetTag(ctx context.Context, req *ContextCacheGetTagRequest) (*ContextCacheGetTagResponse, error) { + path := fmt.Sprintf("/v1/caching/refs/tags/%s", req.Tag) + contextCacheGetTagResp := new(ContextCacheGetTagResponse) + resp, err := c.client.HTTPClient().SetPath(path).Get(ctx) + if err != nil { + return contextCacheGetTagResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheGetTagResp) + if err != nil { + return nil, err + } + return contextCacheGetTagResp, nil +} + +func (c *contextCache) GetTagContent(ctx context.Context, req *ContextCacheGetTagContentRequest) (*ContextCacheGetTagContentResponse, error) { + path := fmt.Sprintf("/v1/caching/refs/tags/%s/content", req.Tag) + contextCacheGetTagContentResp := new(ContextCacheGetTagContentResponse) + resp, err := c.client.HTTPClient().SetPath(path).Get(ctx) + if err != nil { + return contextCacheGetTagContentResp, err + } + if !resp.StatusOK() { + return nil, ResponseToError(resp) + } + err = resp.Unmarshal(contextCacheGetTagContentResp) + if err != nil { + return nil, err + } + return contextCacheGetTagContentResp, nil +} diff --git a/api_context_cache_test.go b/api_context_cache_test.go new file mode 100644 index 0000000..97829ad --- /dev/null +++ b/api_context_cache_test.go @@ -0,0 +1,23 @@ +package moonshot_test + +import ( + "context" + "github.com/northes/go-moonshot" + "github.com/northes/go-moonshot/test" + "testing" +) + +func TestContextCache_Create(t *testing.T) { + cli, err := NewTestClient() + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + + response, err := cli.ContextCache().Create(ctx, &moonshot.ContextCacheCreateRequest{}) + if err != nil { + t.Fatal(err) + } + + t.Log(test.MarshalJsonToStringX(response)) +} diff --git a/enum_context_cache.go b/enum_context_cache.go new file mode 100644 index 0000000..b5d6f89 --- /dev/null +++ b/enum_context_cache.go @@ -0,0 +1,25 @@ +package moonshot + +type ContextCacheStatus string + +const ( + ContextCacheStatusPending ContextCacheStatus = "pending" // 当缓存被初次创建时,其初始状态为 pending + ContextCacheStatusReady ContextCacheStatus = "ready" // 如果参数合法,缓存创建成功,其状态变更为 ready + ContextCacheStatusError ContextCacheStatus = "error" // 如果参数不合法,或因其他原因缓存创建失败,其状态变更为 error + ContextCacheStatusInactive ContextCacheStatus = "inactive" // 对于已过期的缓存,其状态变更为 inactive +) + +func (c ContextCacheStatus) String() string { + return string(c) +} + +type ContextCacheOrder string + +const ( + ContextCacheOrderAsc ContextCacheOrder = "asc" // 升序 + ContextCacheOrderDesc ContextCacheOrder = "desc" // 降序 +) + +func (c ContextCacheOrder) String() string { + return string(c) +} From dfb5583d323747728e0cac088561dfb321bb716a Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Tue, 23 Jul 2024 10:01:55 +0800 Subject: [PATCH 5/7] feat(chat): add ChatCompletionsModelFamily --- api_context_cache.go | 40 ++++++++++++++++++++-------------------- enum_chat_completions.go | 10 ++++++++++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/api_context_cache.go b/api_context_cache.go index 05e5503..7dc11dc 100644 --- a/api_context_cache.go +++ b/api_context_cache.go @@ -34,30 +34,30 @@ func (c *Client) ContextCache() IContextCache { // ContextCache is the cache of the context type ContextCache struct { - Id string `json:"id"` // 缓存的唯一标识 - Status ContextCacheStatus `json:"status"` // 缓存的状态 - Object string `json:"object"` // 缓存的类型 - CreatedAt int64 `json:"created_at"` // 缓存的创建时间 - ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 - Tokens int `json:"tokens"` // 缓存的 Token 数量 - Model ChatCompletionsModelID `json:"model"` // 缓存的模型组名称 - Messages []ChatCompletionsMessage `json:"messages"` // 缓存的消息内容 - Tools []ChatCompletionsTool `json:"tools"` // 缓存使用的工具 - Name string `json:"name"` // 缓存的名称 - Description string `json:"description"` // 缓存的描述信息 - Metadata map[string]string `json:"metadata"` // 缓存的元信息 + Id string `json:"id"` // 缓存的唯一标识 + Status ContextCacheStatus `json:"status"` // 缓存的状态 + Object string `json:"object"` // 缓存的类型 + CreatedAt int64 `json:"created_at"` // 缓存的创建时间 + ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 + Tokens int `json:"tokens"` // 缓存的 Token 数量 + Model ChatCompletionsModelFamily `json:"model"` // 缓存的模型组名称 + Messages []ChatCompletionsMessage `json:"messages"` // 缓存的消息内容 + Tools []ChatCompletionsTool `json:"tools"` // 缓存使用的工具 + Name string `json:"name"` // 缓存的名称 + Description string `json:"description"` // 缓存的描述信息 + Metadata map[string]string `json:"metadata"` // 缓存的元信息 } // ContextCacheCreateRequest is the request for creating a context cache type ContextCacheCreateRequest struct { - Model ChatCompletionsModelID `json:"model"` // 模型组(model family)名称 - Messages []ChatCompletionsMessage `json:"messages"` // 消息内容 - Tools []ChatCompletionsTool `json:"tools,omitempty"` // 使用的工具 - Name string `json:"name,omitempty"` // 缓存名称 - Description string `json:"description,omitempty"` // 缓存描述信息 - Metadata map[string]string `json:"metadata,omitempty"` // 缓存的元信息 - ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 - TTL int64 `json:"ttl,omitempty"` // 缓存的有效期 + Model ChatCompletionsModelFamily `json:"model"` // 模型组(model family)名称 + Messages []ChatCompletionsMessage `json:"messages"` // 消息内容 + Tools []ChatCompletionsTool `json:"tools,omitempty"` // 使用的工具 + Name string `json:"name,omitempty"` // 缓存名称 + Description string `json:"description,omitempty"` // 缓存描述信息 + Metadata map[string]string `json:"metadata,omitempty"` // 缓存的元信息 + ExpiredAt int64 `json:"expired_at"` // 缓存的过期时间 + TTL int64 `json:"ttl,omitempty"` // 缓存的有效期 } // ContextCacheCreateResponse is the response for creating a context cache diff --git a/enum_chat_completions.go b/enum_chat_completions.go index 291dff6..21fff69 100644 --- a/enum_chat_completions.go +++ b/enum_chat_completions.go @@ -26,6 +26,16 @@ func (c ChatCompletionsModelID) String() string { return string(c) } +type ChatCompletionsModelFamily string + +const ( + ModelFamilyMoonshotV1 ChatCompletionsModelFamily = "moonshot-v1" +) + +func (c ChatCompletionsModelFamily) String() string { + return string(c) +} + type ChatCompletionsFinishReason string const ( From ddbd10da91d547bb9c1c193188f456e34c8d9f55 Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Tue, 23 Jul 2024 10:46:25 +0800 Subject: [PATCH 6/7] test(chat): update test example --- api_context_cache_test.go | 122 +++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/api_context_cache_test.go b/api_context_cache_test.go index 97829ad..86b930a 100644 --- a/api_context_cache_test.go +++ b/api_context_cache_test.go @@ -4,9 +4,84 @@ import ( "context" "github.com/northes/go-moonshot" "github.com/northes/go-moonshot/test" + "github.com/stretchr/testify/assert" "testing" + "time" ) +func TestContextCache(t *testing.T) { + cli, err := NewTestClient() + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + + // Create + var createResponse *moonshot.ContextCacheCreateResponse + createResponse, err = cli.ContextCache().Create(ctx, &moonshot.ContextCacheCreateRequest{ + Model: "moonshot-v1", + Messages: []moonshot.ChatCompletionsMessage{ + { + Role: moonshot.RoleSystem, + Content: "你是一个翻译机器人,我会告诉你一些英文,请帮我翻译成中文。", + }, + }, + ExpiredAt: -1, + TTL: 60, + }) + if err != nil { + t.Fatal(err) + } + id := createResponse.Id + assert.Equal(t, time.Now().Unix()+60, createResponse.ExpiredAt) + + // Get + var getResponse *moonshot.ContextCacheGetResponse + getResponse, err = cli.ContextCache().Get(ctx, &moonshot.ContextCacheGetRequest{ + Id: id, + }) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, id, getResponse.Id) + + // Update + var updateResponse *moonshot.ContextCacheUpdateResponse + updateResponse, err = cli.ContextCache().Update(ctx, &moonshot.ContextCacheUpdateRequest{ + Id: id, + ExpiredAt: -1, + TTL: 120, + }) + if err != nil { + t.Fatal(err) + } + _ = updateResponse + //assert.Equal(t, time.Now().Unix()+120, updateResponse.ExpiredAt) + + // List + var listResponse *moonshot.ContextCacheListResponse + listResponse, err = cli.ContextCache().List(ctx, &moonshot.ContextCacheListRequest{ + //Limit: 10, + //Order: moonshot.ContextCacheOrderAsc, + //After: "", + //Before: "", + }) + if err != nil { + t.Fatal(err) + } + assert.GreaterOrEqual(t, len(listResponse.Data), 1) + + // Delete + var deleteResponse *moonshot.ContextCacheDeleteResponse + deleteResponse, err = cli.ContextCache().Delete(ctx, &moonshot.ContextCacheDeleteRequest{ + Id: id, + }) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, id, deleteResponse.Id) +} + func TestContextCache_Create(t *testing.T) { cli, err := NewTestClient() if err != nil { @@ -14,7 +89,52 @@ func TestContextCache_Create(t *testing.T) { } ctx := context.Background() - response, err := cli.ContextCache().Create(ctx, &moonshot.ContextCacheCreateRequest{}) + response, err := cli.ContextCache().Create(ctx, &moonshot.ContextCacheCreateRequest{ + Model: "moonshot-v1", + Messages: []moonshot.ChatCompletionsMessage{ + { + Role: moonshot.RoleSystem, + Content: "你是一个翻译机器人,我会告诉你一些英文,请帮我翻译成中文。", + }, + }, + Tools: nil, + Description: "这是一个测试的描述", + Metadata: nil, + ExpiredAt: -1, + TTL: 60, + }) + if err != nil { + t.Fatal(err) + } + + t.Log(test.MarshalJsonToStringX(response)) +} + +func TestContextCache_Delete(t *testing.T) { + cli, err := NewTestClient() + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + + response, err := cli.ContextCache().Delete(ctx, &moonshot.ContextCacheDeleteRequest{ + Id: "cache-xxxx", + }) + if err != nil { + t.Fatal(err) + } + + t.Log(test.MarshalJsonToStringX(response)) +} + +func TestContextCache_List(t *testing.T) { + cli, err := NewTestClient() + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + + response, err := cli.ContextCache().List(ctx, &moonshot.ContextCacheListRequest{}) if err != nil { t.Fatal(err) } From 7e323841e48578ff33110af69e97424a45ff23fb Mon Sep 17 00:00:00 2001 From: Summer-lights <1067088037@qq.com> Date: Tue, 23 Jul 2024 10:53:15 +0800 Subject: [PATCH 7/7] test(chat): update test example --- api_context_cache_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/api_context_cache_test.go b/api_context_cache_test.go index 86b930a..dd86d99 100644 --- a/api_context_cache_test.go +++ b/api_context_cache_test.go @@ -141,3 +141,22 @@ func TestContextCache_List(t *testing.T) { t.Log(test.MarshalJsonToStringX(response)) } + +func TestContextCache_CreateTag(t *testing.T) { + cli, err := NewTestClient() + if err != nil { + t.Fatal(err) + } + ctx := context.Background() + + // Create + var createResponse *moonshot.ContextCacheCreateTagResponse + createResponse, err = cli.ContextCache().CreateTag(ctx, &moonshot.ContextCacheCreateTagRequest{ + Tag: "MyCacheTag", + CacheId: "cache-", + }) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, "MyCacheTag", createResponse.Tag) +}