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 }