|
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"pplx2api/config"
|
|
"pplx2api/core"
|
|
"pplx2api/logger"
|
|
"pplx2api/utils"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type ChatCompletionRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []map[string]interface{} `json:"messages"`
|
|
Stream bool `json:"stream"`
|
|
Tools []map[string]interface{} `json:"tools,omitempty"`
|
|
}
|
|
|
|
type ErrorResponse struct {
|
|
Error string `json:"error"`
|
|
}
|
|
|
|
|
|
func HealthCheckHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": "ok",
|
|
})
|
|
}
|
|
|
|
|
|
func ChatCompletionsHandler(c *gin.Context) {
|
|
|
|
|
|
var req ChatCompletionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, ErrorResponse{
|
|
Error: fmt.Sprintf("Invalid request: %v", err),
|
|
})
|
|
return
|
|
}
|
|
|
|
|
|
if len(req.Messages) == 0 {
|
|
c.JSON(http.StatusBadRequest, ErrorResponse{
|
|
Error: "No messages provided",
|
|
})
|
|
return
|
|
}
|
|
|
|
|
|
model := req.Model
|
|
if model == "" {
|
|
model = "claude-3.7-sonnet"
|
|
}
|
|
openSearch := false
|
|
if strings.HasSuffix(model, "-search") {
|
|
openSearch = true
|
|
model = strings.TrimSuffix(model, "-search")
|
|
}
|
|
model = config.ModelMapGet(model, model)
|
|
var prompt strings.Builder
|
|
img_data_list := []string{}
|
|
|
|
for _, msg := range req.Messages {
|
|
role, roleOk := msg["role"].(string)
|
|
if !roleOk {
|
|
continue
|
|
}
|
|
|
|
content, exists := msg["content"]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
prompt.WriteString(utils.GetRolePrefix(role))
|
|
switch v := content.(type) {
|
|
case string:
|
|
prompt.WriteString(v + "\n\n")
|
|
case []interface{}:
|
|
for _, item := range v {
|
|
if itemMap, ok := item.(map[string]interface{}); ok {
|
|
if itemType, ok := itemMap["type"].(string); ok {
|
|
if itemType == "text" {
|
|
if text, ok := itemMap["text"].(string); ok {
|
|
prompt.WriteString(text + "\n\n")
|
|
}
|
|
} else if itemType == "image_url" {
|
|
if imageUrl, ok := itemMap["image_url"].(map[string]interface{}); ok {
|
|
if url, ok := imageUrl["url"].(string); ok {
|
|
if len(url) > 50 {
|
|
logger.Info(fmt.Sprintf("Image URL: %s ……", url[:50]))
|
|
}
|
|
if strings.HasPrefix(url, "data:image/") {
|
|
|
|
url = strings.Split(url, ",")[1]
|
|
}
|
|
img_data_list = append(img_data_list, url)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fmt.Println(prompt.String())
|
|
fmt.Println("img_data_list_length:", len(img_data_list))
|
|
var rootPrompt strings.Builder
|
|
rootPrompt.WriteString(prompt.String())
|
|
|
|
var pplxClient *core.Client
|
|
index := config.Sr.NextIndex()
|
|
for i := 0; i < config.ConfigInstance.RetryCount; i++ {
|
|
if i > 0 {
|
|
prompt.Reset()
|
|
prompt.WriteString(rootPrompt.String())
|
|
}
|
|
index = (index + 1) % len(config.ConfigInstance.Sessions)
|
|
session, err := config.ConfigInstance.GetSessionForModel(index)
|
|
logger.Info(fmt.Sprintf("Using session for model %s: %s", model, session.SessionKey))
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to get session for model %s: %v", model, err))
|
|
logger.Info("Retrying another session")
|
|
continue
|
|
}
|
|
|
|
pplxClient = core.NewClient(session.SessionKey, config.ConfigInstance.Proxy, model, openSearch)
|
|
if len(img_data_list) > 0 {
|
|
err := pplxClient.UploadImage(img_data_list)
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to upload file: %v", err))
|
|
logger.Info("Retrying another session")
|
|
|
|
continue
|
|
}
|
|
}
|
|
if prompt.Len() > config.ConfigInstance.MaxChatHistoryLength {
|
|
err := pplxClient.UploadText(prompt.String())
|
|
if err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to upload text: %v", err))
|
|
logger.Info("Retrying another session")
|
|
|
|
continue
|
|
}
|
|
prompt.Reset()
|
|
prompt.WriteString(config.ConfigInstance.PromptForFile)
|
|
}
|
|
if _, err := pplxClient.SendMessage(prompt.String(), req.Stream, config.ConfigInstance.IsIncognito, c); err != nil {
|
|
logger.Error(fmt.Sprintf("Failed to send message: %v", err))
|
|
logger.Info("Retrying another session")
|
|
|
|
continue
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
logger.Error("Failed for all retries")
|
|
c.JSON(http.StatusInternalServerError, ErrorResponse{
|
|
Error: "Failed to process request after multiple attempts"})
|
|
}
|
|
|
|
func MoudlesHandler(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"data": config.ResponseModles,
|
|
})
|
|
}
|
|
|