package openai import ( "context" "encoding/json" "fmt" "github.com/rose_cat707/luminary/internal/model" "github.com/rose_cat707/luminary/internal/provider" ) type Client struct { http *provider.HTTPClientWrapper } func New() *Client { return &Client{http: provider.NewHTTPClientWrapper()} } func (c *Client) Type() string { return "openai" } func (c *Client) cfg(baseURL string) provider.ProviderConfig { return provider.ProviderConfig{ Type: model.ProviderOpenAI, Category: model.CategoryLLM, BaseURL: provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI), } } func (c *Client) ListModels(ctx context.Context, apiKey, baseURL string) ([]provider.ModelInfo, error) { return c.ListModelsWithConfig(ctx, apiKey, provider.ProviderConfig{ Type: model.ProviderOpenAI, BaseURL: provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI), }) } func (c *Client) ListModelsWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig) ([]provider.ModelInfo, error) { cfg.Type = model.ProviderOpenAI cfg.BaseURL = provider.NormalizeBaseURL(cfg.BaseURL, model.ProviderOpenAI) url := cfg.ResolveEndpointURL(provider.EndpointListModels) resp, err := provider.ForwardHTTP(ctx, c.http.Client, "GET", url, apiKey, cfg.Type, nil, nil) if err != nil { return nil, err } if resp.StatusCode >= 400 { return nil, fmt.Errorf("list models: %s", string(resp.Body)) } var out struct { Data []struct { ID string `json:"id"` } `json:"data"` } if err := json.Unmarshal(resp.Body, &out); err != nil { return nil, err } models := make([]provider.ModelInfo, 0, len(out.Data)) for _, m := range out.Data { models = append(models, provider.ModelInfo{ID: m.ID, DisplayName: m.ID}) } return models, nil } func (c *Client) ChatCompletion(ctx context.Context, apiKey, baseURL string, req *provider.ChatRequest) (*provider.ChatResponse, error) { return c.ForwardWithConfig(ctx, apiKey, provider.ProviderConfig{ Type: model.ProviderOpenAI, BaseURL: provider.NormalizeBaseURL(baseURL, model.ProviderOpenAI), }, provider.EndpointChatCompletion, req.Raw) } func (c *Client) ForwardWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig, endpoint provider.EndpointType, body []byte) (*provider.ChatResponse, error) { cfg.Type = model.ProviderOpenAI cfg.BaseURL = provider.NormalizeBaseURL(cfg.BaseURL, model.ProviderOpenAI) url := cfg.ResolveEndpointURL(endpoint) resp, err := provider.ForwardHTTP(ctx, c.http.Client, "POST", url, apiKey, cfg.Type, body, nil) if err != nil { return nil, err } return &provider.ChatResponse{ StatusCode: resp.StatusCode, Body: resp.Body, TokensIn: resp.TokensIn, TokensOut: resp.TokensOut, }, nil } func (c *Client) HealthCheck(ctx context.Context, apiKey, baseURL string) error { _, err := c.ListModels(ctx, apiKey, baseURL) return err } func (c *Client) HealthCheckWithConfig(ctx context.Context, apiKey string, cfg provider.ProviderConfig) error { _, err := c.ListModelsWithConfig(ctx, apiKey, cfg) return err }