48 lines
1.5 KiB
Go
48 lines
1.5 KiB
Go
|
|
package ai
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"fmt"
|
|||
|
|
"strings"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// Client is AI provider transport (real HTTP or fake).
|
|||
|
|
type Client interface {
|
|||
|
|
Complete(ctx context.Context, apiKey, model, prompt string) (string, error)
|
|||
|
|
// CompleteStream 串流 delta;onDelta 可為 nil。回傳完整正文。
|
|||
|
|
CompleteStream(ctx context.Context, apiKey, model, prompt string, onDelta func(chunk string) error) (string, error)
|
|||
|
|
ListModels(ctx context.Context, apiKey string) ([]string, error)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FakeClient for tests / when no real key path needed.
|
|||
|
|
type FakeClient struct {
|
|||
|
|
Fail bool
|
|||
|
|
Models []string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (f *FakeClient) Complete(ctx context.Context, apiKey, model, prompt string) (string, error) {
|
|||
|
|
if f.Fail || apiKey == "" {
|
|||
|
|
return "", fmt.Errorf("ai call failed: no key or forced fail")
|
|||
|
|
}
|
|||
|
|
_ = SystemPromptForLanguage(ResponseLanguageFrom(ctx)) // ensure always defined for real clients
|
|||
|
|
if len(prompt) > 200 {
|
|||
|
|
prompt = prompt[:200]
|
|||
|
|
}
|
|||
|
|
return fmt.Sprintf("[%s] %s", model, strings.TrimSpace(prompt)), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (f *FakeClient) ListModels(_ context.Context, apiKey string) ([]string, error) {
|
|||
|
|
if f.Fail || apiKey == "" {
|
|||
|
|
return nil, fmt.Errorf("list models failed: no key or forced fail")
|
|||
|
|
}
|
|||
|
|
if len(f.Models) > 0 {
|
|||
|
|
return append([]string(nil), f.Models...), nil
|
|||
|
|
}
|
|||
|
|
return []string{"grok-3", "grok-2", "grok-beta"}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ModelsForProvider — static catalog (fallback when live list fails).
|
|||
|
|
func ModelsForProvider(provider string) []string {
|
|||
|
|
return FallbackModels(provider)
|
|||
|
|
}
|