thread-master/internal/model/ai/usecase/usecase.go

119 lines
2.9 KiB
Go

package usecase
import (
"context"
app "haixun-backend/internal/library/errors"
"haixun-backend/internal/library/errors/code"
"haixun-backend/internal/model/ai/domain/enum"
domai "haixun-backend/internal/model/ai/domain/usecase"
"haixun-backend/internal/model/ai/provider"
)
type UseCase = domai.UseCase
type providerMeta struct {
ID string
Label string
Streams bool
}
type aiUseCase struct {
providers map[enum.ProviderID]domai.Provider
catalog []providerMeta
}
func NewUseCase() UseCase {
providers := map[enum.ProviderID]domai.Provider{
enum.ProviderOpenCode: provider.NewOpenAICompatible(enum.ProviderOpenCode, "https://opencode.ai/zen/go/v1"),
enum.ProviderXAI: provider.NewOpenAICompatible(enum.ProviderXAI, "https://api.x.ai/v1"),
}
return &aiUseCase{
providers: providers,
catalog: []providerMeta{
{ID: string(enum.ProviderOpenCode), Label: "OpenCode Go", Streams: true},
{ID: string(enum.ProviderXAI), Label: "Grok (xAI)", Streams: true},
},
}
}
func (u *aiUseCase) ListProviders(ctx context.Context) []domai.ProviderOption {
options := make([]domai.ProviderOption, 0, len(u.catalog))
for _, meta := range u.catalog {
options = append(options, domai.ProviderOption{
ID: meta.ID,
Label: meta.Label,
Streams: meta.Streams,
})
}
return options
}
func (u *aiUseCase) ListProviderModels(ctx context.Context, providerID enum.ProviderID, credential domai.Credential) domai.ProviderModels {
meta, ok := u.meta(providerID)
if !ok {
return domai.ProviderModels{
Error: app.For(code.AI).InputInvalidFormat("unsupported AI provider").Error(),
}
}
result := domai.ProviderModels{
ID: meta.ID,
Label: meta.Label,
Models: []string{},
Streams: meta.Streams,
}
p, ok := u.providers[providerID]
if !ok {
result.Error = app.For(code.AI).InputInvalidFormat("unsupported AI provider").Error()
return result
}
models, err := p.ListModels(ctx, credential)
if err != nil {
if appErr := app.FromError(err); appErr != nil {
result.Error = appErr.Error()
} else {
result.Error = err.Error()
}
return result
}
result.Models = models
return result
}
func (u *aiUseCase) GenerateText(ctx context.Context, req domai.GenerateRequest) (*domai.GenerateResult, error) {
p, err := u.resolve(req.Provider)
if err != nil {
return nil, err
}
return p.GenerateText(ctx, req)
}
func (u *aiUseCase) StreamText(ctx context.Context, req domai.GenerateRequest) (<-chan domai.StreamEvent, error) {
p, err := u.resolve(req.Provider)
if err != nil {
return nil, err
}
return p.StreamText(ctx, req)
}
func (u *aiUseCase) meta(id enum.ProviderID) (providerMeta, bool) {
for _, meta := range u.catalog {
if meta.ID == string(id) {
return meta, true
}
}
return providerMeta{}, false
}
func (u *aiUseCase) resolve(id enum.ProviderID) (domai.Provider, error) {
p, ok := u.providers[id]
if !ok {
return nil, app.For(code.AI).InputInvalidFormat("unsupported AI provider")
}
return p, nil
}