3c65189f30
后端从占位回显变为真实生成:管理员经控制面登记/激活模型,Gateway 经 NATS 下发,Dispatcher 热更新 LLM Pool,Eino 图用 OpenAI 兼容流式真实推理。 - shared: contract.ModelConfig(provider/base_url/api_key/model) + 配置 subjects; bus.RequestModelConfig/ServeModelConfig/Publish/Subscribe ModelConfigUpdated - gateway: store.LLMModel→sundynix_model(AutoMigrate,唯一激活) + admin REST (GET/POST/active/delete/test models, api_key 脱敏) + main ServeModelConfig + 变更广播; 路由 /api/v1/admin/models* - dispatcher: llm.Pool OpenAI 兼容 SSE 流式客户端(ChatStream) + 热更新配置 + 未配置则降级桩; poolModel.Ready()?真实流式:注入记忆的桩; main 取配置+订阅 - 开发期接在线 API 不拉本地模型(见 llm-provider-strategy memory) - 验证: 4 模块 build✓ + e2e PASS; mock OpenAI 服务 live 跑通——登记/测试连接✓/ 激活→NATS 热更新→提交→真实 SSE 流出 mock 回复, mock 日志证明端点被调用且 注入画像(老王)进了模型上下文 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
// Package store 封装 MainDB(PgSQL) 与 CacheDB(Redis) 的访问。
|
|
package store
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"log"
|
|
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/schema"
|
|
)
|
|
|
|
// errStoreDisabled 表示 Postgres 处于降级(未连接)模式,写操作无法进行。
|
|
var errStoreDisabled = errors.New("postgres store disabled")
|
|
|
|
// Postgres 持有 MainDB 连接(Users / Billing / DSL)。
|
|
// db 为 nil 表示降级模式(连接失败时仍允许网关启动)。
|
|
type Postgres struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// OpenPostgres 用 GORM 连接 MainDB 并自动迁移表结构。
|
|
// 表名统一 sundynix_ 前缀 + 单数(User→sundynix_user, Task→sundynix_task)。
|
|
// 连接失败不 fatal:返回降级实例,网关仍可启动(无 Docker 跑 demo 时即此路径)。
|
|
func OpenPostgres(dsn string) *Postgres {
|
|
db, err := gorm.Open(postgres.New(postgres.Config{DSN: dsn}), &gorm.Config{
|
|
NamingStrategy: schema.NamingStrategy{
|
|
TablePrefix: "sundynix_", // 所有表加前缀
|
|
SingularTable: true, // 单数表名
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Printf("[store] postgres 不可用,降级运行(不持久化): %v", err)
|
|
return &Postgres{}
|
|
}
|
|
if err := db.AutoMigrate(&User{}, &Task{}, &LLMModel{}); err != nil {
|
|
log.Printf("[store] postgres AutoMigrate 失败,降级运行: %v", err)
|
|
return &Postgres{}
|
|
}
|
|
log.Println("[store] postgres connected, migrated sundynix_user / sundynix_task")
|
|
return &Postgres{db: db}
|
|
}
|
|
|
|
// Enabled 报告是否处于真实持久化模式。
|
|
func (p *Postgres) Enabled() bool { return p.db != nil }
|
|
|
|
// SaveTask 持久化一次任务提交(best-effort:降级模式下静默跳过)。
|
|
func (p *Postgres) SaveTask(ctx context.Context, id, graph string) error {
|
|
if p.db == nil {
|
|
return nil
|
|
}
|
|
return p.db.WithContext(ctx).Create(&Task{ID: id, Graph: graph, Status: "submitted"}).Error
|
|
}
|
|
|
|
// CountTasks 返回已提交任务数(降级模式返回 0)。
|
|
func (p *Postgres) CountTasks(ctx context.Context) (int64, error) {
|
|
if p.db == nil {
|
|
return 0, nil
|
|
}
|
|
var n int64
|
|
err := p.db.WithContext(ctx).Model(&Task{}).Count(&n).Error
|
|
return n, err
|
|
}
|
|
|
|
// Close 释放底层连接。
|
|
func (p *Postgres) Close() {
|
|
if p.db == nil {
|
|
return
|
|
}
|
|
if sqlDB, err := p.db.DB(); err == nil {
|
|
_ = sqlDB.Close()
|
|
}
|
|
}
|