feat: implement AI gateway phase one runtime
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/easyai/easyai-ai-gateway/apps/api/internal/clients"
|
||||
)
|
||||
|
||||
func (s *Service) uploadGeneratedAssets(ctx context.Context, result map[string]any) (map[string]any, error) {
|
||||
if s.cfg.ServerMainBaseURL == "" || s.cfg.ServerMainInternalToken == "" {
|
||||
return result, nil
|
||||
}
|
||||
data, _ := result["data"].([]any)
|
||||
if len(data) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
next := map[string]any{}
|
||||
for key, value := range result {
|
||||
next[key] = value
|
||||
}
|
||||
nextData := make([]any, 0, len(data))
|
||||
for index, rawItem := range data {
|
||||
item, _ := rawItem.(map[string]any)
|
||||
if item == nil {
|
||||
nextData = append(nextData, rawItem)
|
||||
continue
|
||||
}
|
||||
b64 := stringFromMap(item, "b64_json")
|
||||
if b64 == "" {
|
||||
nextData = append(nextData, rawItem)
|
||||
continue
|
||||
}
|
||||
upload, err := s.uploadBase64Image(ctx, b64, index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
merged := map[string]any{}
|
||||
for key, value := range item {
|
||||
if key != "b64_json" {
|
||||
merged[key] = value
|
||||
}
|
||||
}
|
||||
merged["upload"] = upload
|
||||
if urlValue, ok := upload["url"].(string); ok && urlValue != "" {
|
||||
merged["url"] = urlValue
|
||||
}
|
||||
nextData = append(nextData, merged)
|
||||
}
|
||||
next["data"] = nextData
|
||||
return next, nil
|
||||
}
|
||||
|
||||
func (s *Service) uploadBase64Image(ctx context.Context, b64 string, index int) (map[string]any, error) {
|
||||
payload, err := base64.StdEncoding.DecodeString(stripDataURLPrefix(b64))
|
||||
if err != nil {
|
||||
return nil, &clients.ClientError{Code: "upload_decode_failed", Message: err.Error(), Retryable: false}
|
||||
}
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
fileWriter, err := writer.CreateFormFile("file", fmt.Sprintf("gateway-result-%d.png", index+1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := fileWriter.Write(payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = writer.WriteField("source", "ai-gateway")
|
||||
if err := writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, strings.TrimRight(s.cfg.ServerMainBaseURL, "/")+"/v1/files/upload", &body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.Header.Set("Authorization", "Bearer "+s.cfg.ServerMainInternalToken)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, &clients.ClientError{Code: "upload_network", Message: err.Error(), Retryable: true}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var decoded map[string]any
|
||||
if err := json.NewDecoder(resp.Body).Decode(&decoded); err != nil {
|
||||
return nil, &clients.ClientError{Code: "upload_invalid_response", Message: err.Error(), Retryable: false}
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return nil, &clients.ClientError{Code: "upload_failed", Message: "server-main upload failed", StatusCode: resp.StatusCode, Retryable: resp.StatusCode >= 500}
|
||||
}
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
func stripDataURLPrefix(value string) string {
|
||||
if index := strings.Index(value, ","); strings.HasPrefix(value, "data:") && index >= 0 {
|
||||
return value[index+1:]
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user