Publish Docker image (Multi-arch) / Build & push (amd64) (push) Failing after 1m40s
Release (Linux, macOS, Windows) / Linux Release (push) Failing after 42m16s
Publish Docker image (Multi-arch) / Build & push (arm64) (push) Canceled after 0s
Release (Linux, macOS, Windows) / macOS Release (push) Canceled after 0s
Release (Linux, macOS, Windows) / Windows Release (push) Canceled after 0s
Publish Docker image (Multi-arch) / Create multi-arch manifests (push) Canceled after 0s
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
97 lines
3.0 KiB
Go
97 lines
3.0 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"github.com/QuantumNous/new-api/common"
|
|
"github.com/QuantumNous/new-api/model"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/tidwall/gjson"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
)
|
|
|
|
var errDetectionServiceUnavailable = errors.New("detection service unreachable")
|
|
|
|
const localPelicanID = "local-pelican"
|
|
const pelicanPrompt = "Create a complete self-contained HTML page showing a pelican riding a bicycle. Draw the pelican and bicycle with inline SVG and animate pedaling and rotating wheels using CSS. Make the scene visually polished. Do not load external resources or use JavaScript. Return only the complete HTML document."
|
|
|
|
func detectionHTML(raw []byte, contentType string) string {
|
|
result := gjson.ParseBytes(raw)
|
|
if strings.Contains(contentType, "text/event-stream") {
|
|
result = gjson.Result{}
|
|
for line := range strings.SplitSeq(string(raw), "\n") {
|
|
if strings.HasPrefix(line, "data:") {
|
|
event := gjson.Parse(strings.TrimSpace(strings.TrimPrefix(line, "data:")))
|
|
if event.Get("type").String() == "response.completed" {
|
|
result = event.Get("response")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if result.Get("status").String() != "completed" {
|
|
return ""
|
|
}
|
|
var output strings.Builder
|
|
for _, item := range result.Get("output").Array() {
|
|
if item.Get("type").String() != "message" {
|
|
continue
|
|
}
|
|
for _, part := range item.Get("content").Array() {
|
|
if part.Get("type").String() == "output_text" {
|
|
output.WriteString(part.Get("text").String())
|
|
}
|
|
}
|
|
}
|
|
html := strings.TrimSpace(output.String())
|
|
lower := strings.ToLower(html)
|
|
start := strings.Index(lower, "<!doctype html")
|
|
if start < 0 {
|
|
start = strings.Index(lower, "<html")
|
|
}
|
|
end := strings.LastIndex(lower, "</html>")
|
|
if start < 0 || end < start || len(html) > 2<<20 {
|
|
return ""
|
|
}
|
|
return html[start : end+7]
|
|
}
|
|
|
|
func processLocalPelican(ctx context.Context, run model.DetectionRun) {
|
|
if ctx.Err() != nil {
|
|
return
|
|
}
|
|
if model.DB.Model(&model.DetectionRun{}).Where("id = ?", run.ID).Updates(map[string]any{"remote_id": localPelicanID, "quality": "unknown", "result": ""}).Error != nil {
|
|
return
|
|
}
|
|
var call model.DetectionCall
|
|
if model.DB.First(&call, "id = ?", run.ID).Error != nil {
|
|
return
|
|
}
|
|
if call.State == "running" {
|
|
return
|
|
}
|
|
if call.State == "ready" {
|
|
payload, _ := common.Marshal(map[string]any{"model": "gpt-6-astra", "input": pelicanPrompt})
|
|
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
|
c.Request = httptest.NewRequestWithContext(ctx, http.MethodPost, "/api/detection-proxy/v1/responses", bytes.NewReader(payload))
|
|
c.Request.Header.Set("Authorization", "Bearer "+pelicanCredential(run.ID))
|
|
DetectionProxy(c)
|
|
if model.DB.First(&call, "id = ?", run.ID).Error != nil {
|
|
return
|
|
}
|
|
}
|
|
if call.State != "finished" {
|
|
return
|
|
}
|
|
if model.DB.First(&run, "id = ?", run.ID).Error != nil {
|
|
return
|
|
}
|
|
if run.HTML != "" {
|
|
finishDetection(run, "succeeded", "")
|
|
} else {
|
|
finishDetection(run, "failed", "local_generation_failed")
|
|
}
|
|
}
|