Skip to content

Commit

Permalink
Merge pull request #495 from trheyi/main
Browse files Browse the repository at this point in the history
[add] moapi process and api
  • Loading branch information
trheyi authored Nov 9, 2023
2 parents 9ed6b26 + 5137f99 commit 213111a
Show file tree
Hide file tree
Showing 17 changed files with 570 additions and 18 deletions.
8 changes: 8 additions & 0 deletions engine/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/yaoapp/yao/fs"
"github.com/yaoapp/yao/i18n"
"github.com/yaoapp/yao/importer"
"github.com/yaoapp/yao/moapi"
"github.com/yaoapp/yao/model"
"github.com/yaoapp/yao/neo"
"github.com/yaoapp/yao/pack"
Expand Down Expand Up @@ -203,6 +204,12 @@ func Load(cfg config.Config) (err error) {
printErr(cfg.Mode, "SUI", err)
}

// Load Moapi
err = moapi.Load(cfg)
if err != nil {
printErr(cfg.Mode, "Moapi", err)
}

return nil
}

Expand Down Expand Up @@ -445,6 +452,7 @@ func loadApp(root string) error {

var appData []byte
var appFile string

// Read app setting
if has, _ := application.App.Exists("app.yao"); has {
appFile = "app.yao"
Expand Down
27 changes: 27 additions & 0 deletions moapi/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package moapi

import "github.com/yaoapp/gou/api"

var dsl = []byte(`
{
"name": "Moapi API",
"description": "The API for Moapi",
"version": "1.0.0",
"guard": "bearer-jwt",
"group": "__moapi/v1",
"paths": [
{
"path": "/images/generations",
"method": "POST",
"process": "moapi.images.Generations",
"in": ["$payload.model", "$payload.prompt", ":payload"],
"out": { "status": 200, "type": "application/json" }
}
]
}
`)

func registerAPI() error {
_, err := api.LoadSource("<moapi.v1>.yao", dsl, "moapi.v1")
return err
}
169 changes: 169 additions & 0 deletions moapi/moapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package moapi

// *** WARNING ***
// Temporarily: change after the moapi is open source
//

import (
"fmt"

jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/http"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/share"
)

// Mirrors list all the mirrors
var cacheMirrors = []*Mirror{}
var cacheApps = []*App{}
var cacheMirrorsMap = map[string]*Mirror{}

// Models list all the models
var Models = []string{
"gpt-4-1106-preview",
"gpt-4-1106-vision-preview",
"gpt-4",
"gpt-4-32k",

"gpt-3.5-turbo",
"gpt-3.5-turbo-1106",
"gpt-3.5-turbo-instruct",

"dall-e-3",
"dall-e-2",

"tts-1",
"tts-1-hd",

"text-moderation-latest",
"text-moderation-stable",

"text-embedding-ada-002",
"whisper-1",
}

// Load load the moapi
func Load(cfg config.Config) error {
return registerAPI()
}

// Mirrors list all the mirrors
func Mirrors(cache bool) ([]*Mirror, error) {
if cache && len(cacheMirrors) > 0 {
return cacheMirrors, nil
}

bytes, err := httpGet("/api/moapi/mirrors")
if err != nil {
return nil, err
}

err = jsoniter.Unmarshal(bytes, &cacheMirrors)
if err != nil {
return nil, err
}

for _, mirror := range cacheMirrors {
cacheMirrorsMap[mirror.Host] = mirror
}

return cacheMirrors, nil
}

// Apps list all the apps
func Apps(cache bool) ([]*App, error) {
if cache && len(cacheApps) > 0 {
return cacheApps, nil
}

mirrors := SelectMirrors()
bytes, err := httpGet("/api/moapi/apps", mirrors...)
if err != nil {
return nil, err
}

err = jsoniter.Unmarshal(bytes, &cacheApps)
if err != nil {
return nil, err
}

channel := Channel()
if channel != "" {
for i := range cacheApps {
cacheApps[i].Homepage = cacheApps[i].Homepage + "?channel=" + channel
}
}

return cacheApps, nil
}

// Homepage get the home page url with the invite code
func Homepage() string {
channel := Channel()
if channel == "" {
return "https://store.moapi.ai"
}
return "https://store.moapi.ai" + "?channel=" + channel
}

// Channel get the channel
func Channel() string {

return share.App.Moapi.Channel
}

// SelectMirrors select the mirrors
func SelectMirrors() []*Mirror {

if share.App.Moapi.Mirrors == nil || len(share.App.Moapi.Mirrors) == 0 {
return []*Mirror{}
}

_, err := Mirrors(true)
if err != nil {
return []*Mirror{}
}

// pick the mirrors
var result []*Mirror
for _, host := range share.App.Moapi.Mirrors {
if mirror, ok := cacheMirrorsMap[host]; ok {
if mirror.Status == "on" {
result = append(result, mirror)
}
}
}

return result
}

// httpGet get the data from the api
func httpGet(api string, mirrors ...*Mirror) ([]byte, error) {
return httpGetRetry(api, mirrors, 0)
}

func httpGetRetry(api string, mirrors []*Mirror, retryTimes int) ([]byte, error) {

url := "https://" + share.MoapiHosts[retryTimes] + api
if len(mirrors) > retryTimes {
url = "https://" + mirrors[retryTimes].Host + api
}

secret := share.App.Moapi.Secret
organization := share.App.Moapi.Organization

http := http.New(url)
http.SetHeader("Authorization", "Bearer "+secret)
http.SetHeader("Content-Type", "application/json")
http.SetHeader("Moapi-Organization", organization)

resp := http.Get()
if resp.Code >= 500 {
if retryTimes > 3 {
return nil, fmt.Errorf("Moapi Server Error: %s", resp.Data)
}
return httpGetRetry(api, mirrors, retryTimes+1)
}

return jsoniter.Marshal(resp.Data)
}
48 changes: 48 additions & 0 deletions moapi/process.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package moapi

import (
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/utils"
"github.com/yaoapp/yao/openai"
)

func init() {
process.RegisterGroup("moapi", map[string]process.Handler{
"images.generations": ImagesGenerations,
})
}

// ImagesGenerations Generate images
func ImagesGenerations(process *process.Process) interface{} {

process.ValidateArgNums(2)
model := process.ArgsString(0)
prompt := process.ArgsString(1)
option := process.ArgsMap(2, map[string]interface{}{})

if model == "" {
exception.New("ImagesGenerations error: model is required", 400).Throw()
}

if prompt == "" {
exception.New("ImagesGenerations error: prompt is required", 400).Throw()
}

ai, err := openai.NewMoapi(model)
if err != nil {
exception.New("ImagesGenerations error: %s", 400, err).Throw()
}

option["prompt"] = prompt
option["model"] = model
option["response_format"] = "url"

res, ex := ai.ImagesGenerations(prompt, option)
if ex != nil {
utils.Dump(ex)
ex.Throw()
}

return res
}
34 changes: 34 additions & 0 deletions moapi/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package moapi

// Mirror is the mirror info
type Mirror struct {
Name string `json:"name"`
Host string `json:"host"`
Area string `json:"area"` // area code
Latency int `json:"latency"` // ms
Status string `json:"status"` // on, slow, off,
}

// App is the app info
type App struct {
Name string `json:"name"`
UpdatedAt int64 `json:"updated_at"`
CreatedAt int64 `json:"created_at"`
Country string `json:"country"`
Creator string `json:"creator"`
Description string `json:"description"`
Version string `json:"version"`
Short string `json:"short"`
Icon string `json:"icon"`
Homepage string `json:"homepage"`
Images []string `json:"images,omitempty"`
Videos []string `json:"videos,omitempty"`
Stat AppStat `json:"stat,omitempty"`
Languages []string `json:"languages"`
}

// AppStat is the app stat info
type AppStat struct {
Downloads int `json:"downloads"`
Stars int `json:"stars"`
}
7 changes: 6 additions & 1 deletion neo/neo.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,12 @@ func (neo *DSL) getGuardHandlers() ([]gin.HandlerFunc, error) {
func (neo *DSL) newAI() error {

if neo.Connector == "" {
return fmt.Errorf("%s connector is required", neo.ID)
ai, err := openai.NewMoapi("gpt-3.5-turbo")
if err != nil {
return err
}
neo.AI = ai
return nil
}

conn, err := connector.Select(neo.Connector)
Expand Down
Loading

0 comments on commit 213111a

Please sign in to comment.