feat: 添加基础通道实现和请求处理逻辑

This commit is contained in:
tbphp
2025-07-02 09:46:08 +08:00
parent 5818c3cb1d
commit 762dfe48e8
5 changed files with 185 additions and 68 deletions

View File

@@ -1,55 +1,50 @@
package channel
import (
"encoding/json"
"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
BaseChannel
}
type GeminiChannelConfig struct {
BaseURL string `json:"base_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
var config GeminiChannelConfig
if err := json.Unmarshal([]byte(group.Config), &config); err != nil {
return nil, fmt.Errorf("failed to unmarshal channel config: %w", err)
}
return &GeminiChannel{BaseURL: baseURL}, nil
if config.BaseURL == "" {
return nil, fmt.Errorf("base_url is required for gemini channel")
}
baseURL, err := url.Parse(config.BaseURL)
if err != nil {
return nil, fmt.Errorf("failed to parse base_url: %w", err)
}
return &GeminiChannel{
BaseChannel: BaseChannel{
Name: "gemini",
BaseURL: baseURL,
HTTPClient: &http.Client{},
},
}, 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")
func (ch *GeminiChannel) Handle(c *gin.Context, apiKey *models.APIKey, group *models.Group) error {
modifier := func(req *http.Request, key *models.APIKey) {
q := req.URL.Query()
q.Set("key", key.KeyValue)
req.URL.RawQuery = q.Encode()
}
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)
return ch.ProcessRequest(c, apiKey, modifier)
}