feat(model): add model management module (#2303)

This commit is contained in:
Ryo
2025-10-21 16:44:29 +08:00
committed by GitHub
parent 6e02c861c7
commit 2b021a3d41
185 changed files with 27862 additions and 8142 deletions

View File

@ -0,0 +1,105 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package envkey
import (
"fmt"
"os"
"strconv"
)
func GetIntD(key string, defaultValue int) int {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return defaultValue
}
return int(i)
}
func GetI32D(key string, defaultValue int32) int32 {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
i, err := strconv.ParseInt(v, 10, 32)
if err != nil {
return defaultValue
}
return int32(i)
}
func GetI64(key string) (int64, error) {
v := os.Getenv(key)
if v == "" {
return 0, fmt.Errorf("env %s is empty", key)
}
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return 0, err
}
return i, nil
}
func GetI64D(key string, defaultValue int64) int64 {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
i, err := strconv.ParseInt(v, 10, 32)
if err != nil {
return defaultValue
}
return i
}
func GetString(key string) string {
return os.Getenv(key)
}
func GetStringD(key string, defaultValue string) string {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
return v
}
func GetBoolD(key string, defaultValue bool) bool {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
b, err := strconv.ParseBool(v)
if err != nil {
return defaultValue
}
return b
}

View File

@ -1,82 +0,0 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jsoncache
import (
"context"
"encoding/json"
"fmt"
"github.com/coze-dev/coze-studio/backend/infra/cache"
)
type JsonCache[T any] struct {
cache cache.Cmdable
prefix string
}
func New[T any](prefix string, cache cache.Cmdable) *JsonCache[T] {
return &JsonCache[T]{
prefix: prefix,
cache: cache,
}
}
func (g *JsonCache[T]) Save(ctx context.Context, k string, v *T) error {
if v == nil {
return fmt.Errorf("cannot save nil value for key: %s", k)
}
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("marshal failed for type %T: %w", *v, err)
}
key := g.prefix + k
if err := g.cache.Set(ctx, key, data, 0).Err(); err != nil {
return fmt.Errorf("redis set failed for key %s: %w", k, err)
}
return nil
}
// Get returns default T if key not found
func (g *JsonCache[T]) Get(ctx context.Context, k string) (*T, error) {
key := g.prefix + k
var obj T
data, err := g.cache.Get(ctx, key).Result()
if err == cache.Nil {
return &obj, nil
}
if err != nil {
return nil, fmt.Errorf("failed to get key %s: %w", k, err)
}
if err := json.Unmarshal([]byte(data), &obj); err != nil {
return nil, fmt.Errorf("failed to unmarshal json for key %s: %w", k, err)
}
return &obj, nil
}
func (g *JsonCache[T]) Delete(ctx context.Context, k string) error {
key := g.prefix + k
if err := g.cache.Del(ctx, key).Err(); err != nil {
return fmt.Errorf("failed to delete key %s: %w", k, err)
}
return nil
}

View File

@ -0,0 +1,118 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kvstore
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"gorm.io/gorm"
)
var ErrKeyNotFound = errors.New("key not found")
/*
CREATE TABLE IF NOT EXISTS `kv_entries` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`namespace` VARCHAR(255) NOT NULL,
`key_data` VARCHAR(255) NOT NULL,
`value_data` LONGBLOB NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_namespace_key` (`namespace`, `key_data`)
) ENGINE=InnoDB CHARSET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'kv data';
*/
type KVStore[T any] struct {
repo *gorm.DB
}
var defaultDB *gorm.DB
func SetDefault(db *gorm.DB) {
defaultDB = db
}
func New[T any](db *gorm.DB) *KVStore[T] {
return &KVStore[T]{
repo: db,
}
}
func (g *KVStore[T]) db(ctx context.Context) *gorm.DB {
if g.repo == nil {
return defaultDB.WithContext(ctx)
}
return g.repo.WithContext(ctx)
}
func (g *KVStore[T]) Save(ctx context.Context, namespace, k string, v *T) error {
if v == nil {
return fmt.Errorf("cannot save nil value for key: %s", k)
}
data, err := json.Marshal(v)
if err != nil {
return fmt.Errorf("marshal failed for key %s for type %T: %w", k, *v, err)
}
res := g.db(ctx).Exec(
"INSERT INTO `kv_entries` (`namespace`, `key_data`, `value_data`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `value_data` = ?",
namespace, k, data, data,
)
if res.Error != nil {
return fmt.Errorf("failed to save key %s: %w", k, res.Error)
}
return nil
}
func (g *KVStore[T]) Get(ctx context.Context, namespace, k string) (*T, error) {
var obj T
row := g.db(ctx).Raw(
"SELECT `value_data` FROM `kv_entries` WHERE `namespace` = ? AND `key_data` = ? LIMIT 1",
namespace, k,
).Row()
var value []byte
if err := row.Scan(&value); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrKeyNotFound
}
return nil, fmt.Errorf("failed to get key %s: %w", k, err)
}
if err := json.Unmarshal(value, &obj); err != nil {
return nil, fmt.Errorf("failed to unmarshal json for key %s: %w", k, err)
}
return &obj, nil
}
func (g *KVStore[T]) Delete(ctx context.Context, namespace, k string) error {
res := g.db(ctx).Exec(
"DELETE FROM `kv_entries` WHERE `namespace` = ? AND `key_data` = ?",
namespace, k,
)
return res.Error
}

View File

@ -33,6 +33,19 @@ func Int64ToStr(v int64) string {
return strconv.FormatInt(v, 10)
}
func StrToFloat64(v string) (float64, error) {
return strconv.ParseFloat(v, 64)
}
func StrToFloat64D(v string, defaultValue float64) float64 {
toV, err := strconv.ParseFloat(v, 64)
if err != nil {
return defaultValue
}
return toV
}
// StrToInt64 returns strconv.ParseInt(v, 10, 64)'s value.
// if error occurs, returns defaultValue as result.
func StrToInt64D(v string, defaultValue int64) int64 {

View File

@ -24,12 +24,11 @@ import (
"io"
"net/http"
"net/url"
"os"
"strconv"
"time"
"github.com/coze-dev/coze-studio/backend/bizpkg/config"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/types/consts"
)
// CozeAPIClient represents a client for coze.cn OpenAPI
@ -264,15 +263,21 @@ func (c *CozeAPIClient) requestWithQuery(ctx context.Context, method, path strin
// getEnvOrDefault returns environment variable value or default if not set
func getSaasOpenAPIUrl() string {
if value := os.Getenv(consts.CozeSaasAPIBaseURL); value != "" {
return value
baseConfig, err := config.Base().GetBaseConfig(context.Background())
if err != nil {
logs.CtxErrorf(context.Background(), "GetBaseConfig failed: %v", err)
return "https://api.coze.cn"
}
return "https://api.coze.cn"
return baseConfig.PluginConfiguration.CozeSaasAPIBaseURL
}
func getSaasOpenAPIKey() string {
if value := os.Getenv(consts.CozeSaasAPIKey); value != "" {
return value
baseConfig, err := config.Base().GetBaseConfig(context.Background())
if err != nil {
logs.CtxErrorf(context.Background(), "GetBaseConfig failed: %v", err)
return ""
}
return ""
return baseConfig.PluginConfiguration.CozeAPIToken
}