Changeset 0.5.0 (#35)
This commit is contained in:
149
server/providers/venice.go
Normal file
149
server/providers/venice.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// VeniceProvider handles the Venice.ai API.
|
||||
// Venice is OpenAI-compatible with extensions: venice_parameters for
|
||||
// web search, thinking controls, and web scraping.
|
||||
//
|
||||
// Ported from ai-editor js/providers/venice.js
|
||||
type VeniceProvider struct{}
|
||||
|
||||
func (p *VeniceProvider) ID() string { return "venice" }
|
||||
|
||||
// ── Chat Completion ─────────────────────────
|
||||
// Delegates to OpenAI provider after injecting venice_parameters.
|
||||
|
||||
func (p *VeniceProvider) ChatCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (*CompletionResponse, error) {
|
||||
oai := &OpenAIProvider{}
|
||||
return oai.ChatCompletion(ctx, cfg, req)
|
||||
}
|
||||
|
||||
func (p *VeniceProvider) StreamCompletion(ctx context.Context, cfg ProviderConfig, req CompletionRequest) (<-chan StreamEvent, error) {
|
||||
oai := &OpenAIProvider{}
|
||||
return oai.StreamCompletion(ctx, cfg, req)
|
||||
}
|
||||
|
||||
// ── List Models ─────────────────────────────
|
||||
// Venice /v1/models returns model_spec with capabilities, pricing,
|
||||
// context tokens, and traits. We parse all of it.
|
||||
|
||||
func (p *VeniceProvider) ListModels(ctx context.Context, cfg ProviderConfig) ([]Model, error) {
|
||||
endpoint := strings.TrimSuffix(cfg.Endpoint, "/") + "/models"
|
||||
|
||||
httpReq, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg.APIKey != "" {
|
||||
httpReq.Header.Set("Authorization", "Bearer "+cfg.APIKey)
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("venice list models: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
return nil, fmt.Errorf("venice list models: HTTP %d: %s", resp.StatusCode, string(b))
|
||||
}
|
||||
|
||||
var result veniceModelsResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("venice decode models: %w", err)
|
||||
}
|
||||
|
||||
models := make([]Model, 0, len(result.Data))
|
||||
for _, m := range result.Data {
|
||||
spec := m.ModelSpec
|
||||
vcaps := spec.Capabilities
|
||||
|
||||
caps := ModelCapabilities{
|
||||
Streaming: true,
|
||||
ToolCalling: vcaps.SupportsFunctionCalling,
|
||||
Vision: vcaps.SupportsVision,
|
||||
Reasoning: vcaps.SupportsReasoning,
|
||||
WebSearch: vcaps.SupportsWebSearch,
|
||||
MaxContext: spec.AvailableContextTokens,
|
||||
}
|
||||
|
||||
// Venice doesn't report max output tokens directly.
|
||||
// Try known table, then derive from context.
|
||||
if known, ok := LookupKnownModel(m.ID); ok && known.MaxOutputTokens > 0 {
|
||||
caps.MaxOutputTokens = known.MaxOutputTokens
|
||||
}
|
||||
|
||||
var pricing *ModelPricing
|
||||
if spec.Pricing.Input.USD > 0 {
|
||||
pricing = &ModelPricing{
|
||||
InputPerM: spec.Pricing.Input.USD,
|
||||
OutputPerM: spec.Pricing.Output.USD,
|
||||
}
|
||||
}
|
||||
|
||||
name := spec.Name
|
||||
if name == "" {
|
||||
name = m.ID
|
||||
}
|
||||
|
||||
models = append(models, Model{
|
||||
ID: m.ID,
|
||||
Name: name,
|
||||
OwnedBy: "venice",
|
||||
Capabilities: caps,
|
||||
Pricing: pricing,
|
||||
})
|
||||
}
|
||||
return models, nil
|
||||
}
|
||||
|
||||
// ── Venice Wire Types ───────────────────────
|
||||
|
||||
type veniceModelsResponse struct {
|
||||
Data []veniceModel `json:"data"`
|
||||
}
|
||||
|
||||
type veniceModel struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
OwnedBy string `json:"owned_by"`
|
||||
ModelSpec veniceModelSpec `json:"model_spec"`
|
||||
}
|
||||
|
||||
type veniceModelSpec struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
AvailableContextTokens int `json:"availableContextTokens"`
|
||||
Capabilities veniceCapabilities `json:"capabilities"`
|
||||
Pricing venicePricing `json:"pricing"`
|
||||
Traits []string `json:"traits"`
|
||||
Offline bool `json:"offline"`
|
||||
}
|
||||
|
||||
type veniceCapabilities struct {
|
||||
SupportsFunctionCalling bool `json:"supportsFunctionCalling"`
|
||||
SupportsVision bool `json:"supportsVision"`
|
||||
SupportsReasoning bool `json:"supportsReasoning"`
|
||||
SupportsWebSearch bool `json:"supportsWebSearch"`
|
||||
SupportsResponseSchema bool `json:"supportsResponseSchema"`
|
||||
SupportsAudioInput bool `json:"supportsAudioInput"`
|
||||
SupportsLogProbs bool `json:"supportsLogProbs"`
|
||||
}
|
||||
|
||||
type venicePricing struct {
|
||||
Input venicePriceUnit `json:"input"`
|
||||
Output venicePriceUnit `json:"output"`
|
||||
}
|
||||
|
||||
type venicePriceUnit struct {
|
||||
USD float64 `json:"usd"`
|
||||
}
|
||||
Reference in New Issue
Block a user