feat: support vision

- Added new dependencies: `github.com/fsnotify/fsnotify v1.4.9`, `github.com/go-playground/assert/v2 v2.2.0`, `github.com/nxadm/tail v1.4.8`, `github.com/onsi/ginkgo v1.16.5`, `github.com/onsi/gomega v1.18.1`, `golang.org/x/net v0.10.0`, `gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7`
- Updated dependencies: `github.com/gin-gonic/gin` from v1.9.0 to v2.0.0, `golang.org/x/net` from v0.17.0 to v0.10.0
- Removed dependencies: `github.com/golang-jwt/jwt v3.2.2+incompatible`, `github.com/gorilla/websocket v1.5.1`
- Updated Go version from `1.18` to `1.21`
- Made various modifications and refactoring in the code:
  - Added new struct `VisionMessage` with fields `Role`, `Content`, and `Name`
  - Added constants for certain types
  - Added methods and error handling to handle different message types
  - Modified existing struct and methods to accommodate changes
  - Removed unused imports
This commit is contained in:
Laisky.Cai
2023-11-17 01:59:11 +00:00
parent b2e46a33ac
commit b58bd7e3ab
13 changed files with 2051 additions and 1916 deletions

View File

@@ -1,6 +1,7 @@
package controller
import (
"errors"
"fmt"
"net/http"
"one-api/common"
@@ -16,6 +17,44 @@ type Message struct {
Name *string `json:"name,omitempty"`
}
type VisionMessage struct {
Role string `json:"role"`
Content OpenaiVisionMessageContent `json:"content"`
Name *string `json:"name,omitempty"`
}
// OpenaiVisionMessageContentType vision message content type
type OpenaiVisionMessageContentType string
const (
// OpenaiVisionMessageContentTypeText text
OpenaiVisionMessageContentTypeText OpenaiVisionMessageContentType = "text"
// OpenaiVisionMessageContentTypeImageUrl image url
OpenaiVisionMessageContentTypeImageUrl OpenaiVisionMessageContentType = "image_url"
)
// OpenaiVisionMessageContent vision message content
type OpenaiVisionMessageContent struct {
Type OpenaiVisionMessageContentType `json:"type"`
Text string `json:"text,omitempty"`
ImageUrl OpenaiVisionMessageContentImageUrl `json:"image_url,omitempty"`
}
// VisionImageResolution image resolution
type VisionImageResolution string
const (
// VisionImageResolutionLow low resolution
VisionImageResolutionLow VisionImageResolution = "low"
// VisionImageResolutionHigh high resolution
VisionImageResolutionHigh VisionImageResolution = "high"
)
type OpenaiVisionMessageContentImageUrl struct {
URL string `json:"url"`
Detail VisionImageResolution `json:"detail,omitempty"`
}
const (
RelayModeUnknown = iota
RelayModeChatCompletions
@@ -30,18 +69,76 @@ const (
// https://platform.openai.com/docs/api-reference/chat
type GeneralOpenAIRequest struct {
Model string `json:"model,omitempty"`
Messages []Message `json:"messages,omitempty"`
Prompt any `json:"prompt,omitempty"`
Stream bool `json:"stream,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
N int `json:"n,omitempty"`
Input any `json:"input,omitempty"`
Instruction string `json:"instruction,omitempty"`
Size string `json:"size,omitempty"`
Functions any `json:"functions,omitempty"`
Model string `json:"model,omitempty"`
// Messages maybe []Message or []VisionMessage
Messages any `json:"messages,omitempty"`
Prompt any `json:"prompt,omitempty"`
Stream bool `json:"stream,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
Temperature float64 `json:"temperature,omitempty"`
TopP float64 `json:"top_p,omitempty"`
N int `json:"n,omitempty"`
Input any `json:"input,omitempty"`
Instruction string `json:"instruction,omitempty"`
Size string `json:"size,omitempty"`
Functions any `json:"functions,omitempty"`
}
func (r *GeneralOpenAIRequest) MessagesLen() int {
switch msgs := r.Messages.(type) {
case []any:
return len(msgs)
case []Message:
return len(msgs)
case []VisionMessage:
return len(msgs)
default:
return 0
}
}
// TextMessages returns messages as []Message
func (r *GeneralOpenAIRequest) TextMessages() (messages []Message, err error) {
switch msgs := r.Messages.(type) {
case []any:
messages = make([]Message, 0, len(msgs))
for _, msg := range msgs {
if m, ok := msg.(Message); ok {
messages = append(messages, m)
} else {
err = fmt.Errorf("invalid message type")
return
}
}
case []Message:
messages = msgs
default:
return nil, errors.New("invalid message type")
}
return
}
// VisionMessages returns messages as []VisionMessage
func (r *GeneralOpenAIRequest) VisionMessages() (messages []VisionMessage, err error) {
switch msgs := r.Messages.(type) {
case []any:
messages = make([]VisionMessage, 0, len(msgs))
for _, msg := range msgs {
if m, ok := msg.(VisionMessage); ok {
messages = append(messages, m)
} else {
err = fmt.Errorf("invalid message type")
return
}
}
case []VisionMessage:
messages = msgs
default:
return nil, errors.New("invalid message type")
}
return
}
func (r GeneralOpenAIRequest) ParseInput() []string {