feat: 前端搭建-未完成
This commit is contained in:
14
internal/channel/channel.go
Normal file
14
internal/channel/channel.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"gpt-load/internal/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ChannelProxy defines the interface for different API channel proxies.
|
||||
type ChannelProxy interface {
|
||||
// Handle takes a context, an API key, and the original request,
|
||||
// then forwards the request to the upstream service.
|
||||
Handle(c *gin.Context, apiKey *models.APIKey, group *models.Group)
|
||||
}
|
18
internal/channel/factory.go
Normal file
18
internal/channel/factory.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gpt-load/internal/models"
|
||||
)
|
||||
|
||||
// GetChannel returns a channel proxy based on the group's channel type.
|
||||
func GetChannel(group *models.Group) (ChannelProxy, error) {
|
||||
switch group.ChannelType {
|
||||
case "openai":
|
||||
return NewOpenAIChannel(group)
|
||||
case "gemini":
|
||||
return NewGeminiChannel(group)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported channel type: %s", group.ChannelType)
|
||||
}
|
||||
}
|
55
internal/channel/gemini_channel.go
Normal file
55
internal/channel/gemini_channel.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gpt-load/internal/models"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const GeminiBaseURL = "https://generativelanguage.googleapis.com"
|
||||
|
||||
type GeminiChannel struct {
|
||||
BaseURL *url.URL
|
||||
}
|
||||
|
||||
func NewGeminiChannel(group *models.Group) (*GeminiChannel, error) {
|
||||
baseURL, err := url.Parse(GeminiBaseURL)
|
||||
if err != nil {
|
||||
return nil, err // Should not happen with a constant
|
||||
}
|
||||
return &GeminiChannel{BaseURL: baseURL}, nil
|
||||
}
|
||||
|
||||
func (ch *GeminiChannel) Handle(c *gin.Context, apiKey *models.APIKey, group *models.Group) {
|
||||
proxy := httputil.NewSingleHostReverseProxy(ch.BaseURL)
|
||||
|
||||
proxy.Director = func(req *http.Request) {
|
||||
// Gemini API key is passed as a query parameter
|
||||
originalPath := c.Param("path")
|
||||
newPath := fmt.Sprintf("%s?key=%s", originalPath, apiKey.KeyValue)
|
||||
|
||||
req.URL.Scheme = ch.BaseURL.Scheme
|
||||
req.URL.Host = ch.BaseURL.Host
|
||||
req.URL.Path = newPath
|
||||
req.Host = ch.BaseURL.Host
|
||||
// Remove the Authorization header if it was passed by the client
|
||||
req.Header.Del("Authorization")
|
||||
}
|
||||
|
||||
proxy.ModifyResponse = func(resp *http.Response) error {
|
||||
// Log the response, etc.
|
||||
return nil
|
||||
}
|
||||
|
||||
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
logrus.Errorf("Proxy error to Gemini: %v", err)
|
||||
// Handle error, maybe update key status
|
||||
}
|
||||
|
||||
proxy.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
55
internal/channel/openai_channel.go
Normal file
55
internal/channel/openai_channel.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gpt-load/internal/models"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type OpenAIChannel struct {
|
||||
BaseURL *url.URL
|
||||
}
|
||||
|
||||
type OpenAIChannelConfig struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
}
|
||||
|
||||
func NewOpenAIChannel(group *models.Group) (*OpenAIChannel, error) {
|
||||
var config OpenAIChannelConfig
|
||||
if err := json.Unmarshal([]byte(group.Config), &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baseURL, err := url.Parse(config.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &OpenAIChannel{BaseURL: baseURL}, nil
|
||||
}
|
||||
|
||||
func (ch *OpenAIChannel) Handle(c *gin.Context, apiKey *models.APIKey, group *models.Group) {
|
||||
proxy := httputil.NewSingleHostReverseProxy(ch.BaseURL)
|
||||
proxy.Director = func(req *http.Request) {
|
||||
req.URL.Scheme = ch.BaseURL.Scheme
|
||||
req.URL.Host = ch.BaseURL.Host
|
||||
req.URL.Path = c.Param("path")
|
||||
req.Host = ch.BaseURL.Host
|
||||
req.Header.Set("Authorization", "Bearer "+apiKey.KeyValue)
|
||||
}
|
||||
|
||||
proxy.ModifyResponse = func(resp *http.Response) error {
|
||||
// Log the response, etc.
|
||||
return nil
|
||||
}
|
||||
|
||||
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
logrus.Errorf("Proxy error: %v", err)
|
||||
// Handle error, maybe update key status
|
||||
}
|
||||
|
||||
proxy.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
Reference in New Issue
Block a user