new version for apigo.cc/ai
This commit is contained in:
parent
ee2775d7fa
commit
db308fe42b
57
README.md
57
README.md
@ -1,3 +1,56 @@
|
|||||||
# huoshan
|
# 火山引擎AI能力
|
||||||
|
|
||||||
To know about js functions, go to [huoshan.ts](https://apigo.cc/ai/huoshan/src/branch/master/huoshan.ts)
|
### 配置 Access Key ID & Secret Access Key
|
||||||
|
|
||||||
|
在火山引擎的[控制台中](https://console.volcengine.com/iam/keymanage/),获取Access Key ID & Secret Access Key(建议使用子账号)
|
||||||
|
|
||||||
|
将 AK 和 SK 以逗号分隔的形式填入 ai.yml 或 env.yml 中
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ai:
|
||||||
|
huoshan:
|
||||||
|
apiKey: AK,SK
|
||||||
|
```
|
||||||
|
|
||||||
|
建议将 AK&SK 加密,使用工具[sskey](https://github.com/ssgo/tool)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sskey -e 'AK,SK'
|
||||||
|
```
|
||||||
|
|
||||||
|
复制url base64编码后的字符串填入 ai.yml 或 env.yml 中
|
||||||
|
|
||||||
|
|
||||||
|
## 火山方舟大模型
|
||||||
|
|
||||||
|
在[控制台](https://console.volcengine.com/ark/)的在线推理中创建接入点,使用接入点ID(ep-开头)作为模型名称配置到chat中并赋予一个名称
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ai:
|
||||||
|
huoshan:
|
||||||
|
chat:
|
||||||
|
fastAsk:
|
||||||
|
model: ep-20241030164919-wql26
|
||||||
|
```
|
||||||
|
|
||||||
|
调用时的代码为:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import co from 'apigo.cc/gojs/console'
|
||||||
|
import ai from 'apigo.cc/ai'
|
||||||
|
|
||||||
|
return ai.huoshan.fastAsk('用一句话介绍一下你的主人', co.info, {
|
||||||
|
systemPrompt: '你的主人叫张三,是个程序员'
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 图片生成
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import co from 'apigo.cc/gojs/console'
|
||||||
|
import ai from 'apigo.cc/ai'
|
||||||
|
|
||||||
|
return ai.huoshan.makeImage({
|
||||||
|
prompt: '在山顶,一位美丽的主人,头戴精致帽子,优雅地坐在藤椅上,手中端着一杯香浓的咖啡,身旁是云雾缭绕的美景,阳光洒在她身上,仿佛一幅宁静而美好的画面'
|
||||||
|
})
|
||||||
|
```
|
||||||
|
20
ai_test.go
Normal file
20
ai_test.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package huoshan_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
_ "apigo.cc/ai"
|
||||||
|
_ "apigo.cc/ai/huoshan"
|
||||||
|
"apigo.cc/gojs"
|
||||||
|
_ "apigo.cc/gojs/console"
|
||||||
|
"github.com/ssgo/u"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAI(t *testing.T) {
|
||||||
|
gojs.ExportForDev()
|
||||||
|
r, err := gojs.RunFile("ai_test.js")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
println(u.Cyan(u.JsonP(r)))
|
||||||
|
}
|
24
ai_test.js
Normal file
24
ai_test.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import co from 'apigo.cc/gojs/console'
|
||||||
|
import ai from 'apigo.cc/ai'
|
||||||
|
|
||||||
|
let r = ai.huoshan.fastAsk('用一句话为你的主人写一段生成在山顶喝咖啡的图片的提示词', co.print, {
|
||||||
|
systemPrompt: '你的主人很美丽,喜欢戴帽子'
|
||||||
|
})
|
||||||
|
co.println()
|
||||||
|
co.info('生成的提示词:', r.result)
|
||||||
|
|
||||||
|
let r2 = ai.huoshan.makeImage({
|
||||||
|
prompt: r.result,
|
||||||
|
systemPrompt: '3D卡通,高清,4K,',
|
||||||
|
width: 1280,
|
||||||
|
height: 720,
|
||||||
|
})
|
||||||
|
co.info('生成的图片:', r2.results[0])
|
||||||
|
|
||||||
|
let r3 = ai.huoshan.makeImageKeepIP({
|
||||||
|
prompt: '女孩,骑马在草原上狂奔,天上的云朵,有太阳,有小鸟',
|
||||||
|
width: 1280,
|
||||||
|
height: 720,
|
||||||
|
ref: [r2.results[0]],
|
||||||
|
})
|
||||||
|
co.info('生成角色一致的图片:', r3.results[0])
|
198
chat.go
Normal file
198
chat.go
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
package huoshan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"apigo.cc/ai"
|
||||||
|
"github.com/ssgo/u"
|
||||||
|
"github.com/volcengine/volcengine-go-sdk/service/arkruntime"
|
||||||
|
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getAKSK(aiConf *ai.AIConfig) (string, string) {
|
||||||
|
keys := strings.SplitN(aiConf.ApiKey, ",", 2)
|
||||||
|
if len(keys) == 1 {
|
||||||
|
keys = append(keys, "")
|
||||||
|
}
|
||||||
|
return keys[0], keys[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChatClient(aiConf *ai.AIConfig) *arkruntime.Client {
|
||||||
|
opt := make([]arkruntime.ConfigOption, 0)
|
||||||
|
if aiConf.Endpoint != "" {
|
||||||
|
opt = append(opt, arkruntime.WithBaseUrl(aiConf.Endpoint))
|
||||||
|
}
|
||||||
|
if aiConf.Extra["region"] != nil {
|
||||||
|
opt = append(opt, arkruntime.WithRegion(u.String(aiConf.Extra["region"])))
|
||||||
|
}
|
||||||
|
ak, sk := getAKSK(aiConf)
|
||||||
|
return arkruntime.NewClientWithAkSk(ak, sk, opt...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Chat(aiConf *ai.AIConfig, messages []ai.ChatMessage, callback func(string), conf ai.ChatConfig) (ai.ChatResult, error) {
|
||||||
|
req := model.ChatCompletionRequest{
|
||||||
|
Model: conf.Model,
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Messages = make([]*model.ChatCompletionMessage, len(messages))
|
||||||
|
for i, msg := range messages {
|
||||||
|
var contents []*model.ChatCompletionMessageContentPart
|
||||||
|
if msg.Contents != nil {
|
||||||
|
contents = make([]*model.ChatCompletionMessageContentPart, len(msg.Contents))
|
||||||
|
for j, inPart := range msg.Contents {
|
||||||
|
part := model.ChatCompletionMessageContentPart{}
|
||||||
|
part.Type = model.ChatCompletionMessageContentPartType(inPart.Type)
|
||||||
|
switch inPart.Type {
|
||||||
|
case ai.TypeText:
|
||||||
|
part.Text = inPart.Content
|
||||||
|
case ai.TypeImage:
|
||||||
|
part.ImageURL = &model.ChatMessageImageURL{URL: inPart.Content}
|
||||||
|
//case ai.TypeVideo:
|
||||||
|
// part.VideoURL = &model.URLItem{URL: inPart.Content}
|
||||||
|
}
|
||||||
|
contents[j] = &part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(contents) == 1 && contents[0].Type == ai.TypeText {
|
||||||
|
req.Messages[i] = &model.ChatCompletionMessage{
|
||||||
|
Role: msg.Role,
|
||||||
|
Content: &model.ChatCompletionMessageContent{
|
||||||
|
StringValue: &contents[0].Text,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req.Messages[i] = &model.ChatCompletionMessage{
|
||||||
|
Role: msg.Role,
|
||||||
|
Content: &model.ChatCompletionMessageContent{
|
||||||
|
ListValue: contents,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conf.SystemPrompt != "" {
|
||||||
|
req.Messages = append([]*model.ChatCompletionMessage{{
|
||||||
|
Role: ai.RoleSystem,
|
||||||
|
Content: &model.ChatCompletionMessageContent{
|
||||||
|
StringValue: &conf.SystemPrompt,
|
||||||
|
},
|
||||||
|
}}, req.Messages...)
|
||||||
|
}
|
||||||
|
|
||||||
|
tools := conf.Tools
|
||||||
|
if len(tools) > 0 {
|
||||||
|
req.Tools = make([]*model.Tool, 0)
|
||||||
|
for name, toolConf := range tools {
|
||||||
|
switch name {
|
||||||
|
case ai.ToolFunction:
|
||||||
|
conf := model.FunctionDefinition{}
|
||||||
|
u.Convert(toolConf, &conf)
|
||||||
|
req.Tools = append(req.Tools, &model.Tool{
|
||||||
|
Type: model.ToolTypeFunction,
|
||||||
|
Function: &conf,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conf.MaxTokens != 0 {
|
||||||
|
req.MaxTokens = conf.MaxTokens
|
||||||
|
}
|
||||||
|
if conf.Temperature != 0 {
|
||||||
|
req.Temperature = float32(conf.Temperature)
|
||||||
|
}
|
||||||
|
if conf.TopP != 0 {
|
||||||
|
req.TopP = float32(conf.TopP)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := getChatClient(aiConf)
|
||||||
|
t1 := time.Now().UnixMilli()
|
||||||
|
if callback != nil {
|
||||||
|
stream, err := c.CreateChatCompletionStream(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
return ai.ChatResult{}, err
|
||||||
|
}
|
||||||
|
results := make([]string, 0)
|
||||||
|
var outErr error
|
||||||
|
out := ai.ChatResult{}
|
||||||
|
for {
|
||||||
|
recv, err := stream.Recv()
|
||||||
|
if recv.Usage != nil {
|
||||||
|
out.AskTokens += int64(recv.Usage.PromptTokens)
|
||||||
|
out.AnswerTokens += int64(recv.Usage.CompletionTokens)
|
||||||
|
out.TotalTokens += int64(recv.Usage.TotalTokens)
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
outErr = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(recv.Choices) > 0 {
|
||||||
|
for _, ch := range recv.Choices {
|
||||||
|
text := ch.Delta.Content
|
||||||
|
results = append(results, text)
|
||||||
|
callback(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.Close()
|
||||||
|
out.UsedTime = time.Now().UnixMilli() - t1
|
||||||
|
out.Result = strings.Join(results, "")
|
||||||
|
return out, outErr
|
||||||
|
} else {
|
||||||
|
r, err := c.CreateChatCompletion(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
return ai.ChatResult{}, err
|
||||||
|
}
|
||||||
|
t2 := time.Now().UnixMilli() - t1
|
||||||
|
results := make([]string, 0)
|
||||||
|
if r.Choices != nil {
|
||||||
|
for _, ch := range r.Choices {
|
||||||
|
results = append(results, *ch.Message.Content.StringValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ai.ChatResult{
|
||||||
|
Result: strings.Join(results, ""),
|
||||||
|
AskTokens: int64(r.Usage.PromptTokens),
|
||||||
|
AnswerTokens: int64(r.Usage.CompletionTokens),
|
||||||
|
TotalTokens: int64(r.Usage.TotalTokens),
|
||||||
|
UsedTime: t2,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Embedding(aiConf *ai.AIConfig, text string, embeddingConf ai.EmbeddingConfig) (ai.EmbeddingResult, error) {
|
||||||
|
c := getChatClient(aiConf)
|
||||||
|
req := model.EmbeddingRequestStrings{
|
||||||
|
Input: []string{text},
|
||||||
|
Model: embeddingConf.Model,
|
||||||
|
}
|
||||||
|
t1 := time.Now().UnixMilli()
|
||||||
|
if r, err := c.CreateEmbeddings(context.Background(), req); err == nil {
|
||||||
|
t2 := time.Now().UnixMilli() - t1
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if r.Data != nil {
|
||||||
|
for _, ch := range r.Data {
|
||||||
|
for _, v := range ch.Embedding {
|
||||||
|
_ = binary.Write(buf, binary.LittleEndian, float32(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ai.EmbeddingResult{
|
||||||
|
Result: buf.Bytes(),
|
||||||
|
AskTokens: int64(r.Usage.PromptTokens),
|
||||||
|
AnswerTokens: int64(r.Usage.CompletionTokens),
|
||||||
|
TotalTokens: int64(r.Usage.TotalTokens),
|
||||||
|
UsedTime: t2,
|
||||||
|
}, nil
|
||||||
|
} else {
|
||||||
|
return ai.EmbeddingResult{}, err
|
||||||
|
}
|
||||||
|
}
|
27
config.go
Normal file
27
config.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package huoshan
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"apigo.cc/ai"
|
||||||
|
"github.com/ssgo/u"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed default.yml
|
||||||
|
var defaultYml string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
defaultConf := ai.AILoadConfig{}
|
||||||
|
u.Convert(u.UnYamlMap(defaultYml), &defaultConf)
|
||||||
|
ai.Register("huoshan", &ai.Agent{
|
||||||
|
ChatConfigs: defaultConf.Chat,
|
||||||
|
EmbeddingConfigs: defaultConf.Embedding,
|
||||||
|
ImageConfigs: defaultConf.Image,
|
||||||
|
VideoConfigs: defaultConf.Video,
|
||||||
|
Chat: Chat,
|
||||||
|
Embedding: Embedding,
|
||||||
|
MakeImage: MakeImage,
|
||||||
|
// MakeVideo: MakeVideo,
|
||||||
|
// GetVideoResult: GetVideoResult,
|
||||||
|
})
|
||||||
|
}
|
63
default.yml
Normal file
63
default.yml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
chat:
|
||||||
|
embedding:
|
||||||
|
image:
|
||||||
|
makeImage:
|
||||||
|
model: t2i_xl_sft
|
||||||
|
width: 1024
|
||||||
|
height: 1024
|
||||||
|
makeImageHD:
|
||||||
|
model: "high_aes_general_v20_L:general_v2.0_L"
|
||||||
|
width: 512
|
||||||
|
height: 512
|
||||||
|
extra:
|
||||||
|
req_schedule_conf: general_v20_9B_rephraser
|
||||||
|
use_sr: true
|
||||||
|
use_pre_llm: true
|
||||||
|
makeImageKeepIP:
|
||||||
|
model: "high_aes_general_v14_ip_keep:general_v1.4_ip"
|
||||||
|
width: 1024
|
||||||
|
height: 1024
|
||||||
|
makeAmericanComics:
|
||||||
|
model: "img2img_photoverse_american_comics"
|
||||||
|
make3DWeird:
|
||||||
|
model: "img2img_photoverse_3d_weird"
|
||||||
|
makeCyberpunk:
|
||||||
|
model: "img2img_photoverse_cyberpunk"
|
||||||
|
makeBabi:
|
||||||
|
model: "img2img_xiezhen_babi_niuzai"
|
||||||
|
extra:
|
||||||
|
beautify_info:
|
||||||
|
whitening: 2
|
||||||
|
dermabrasion: 2
|
||||||
|
makeIDPhoto:
|
||||||
|
model: "img2img_photoverse_executive_ID_photo"
|
||||||
|
# ModelDoubaoLite4k = "Doubao-lite-4k"
|
||||||
|
# ModelDoubaoLite32k = "Doubao-lite-32k"
|
||||||
|
# ModelDoubaoLite128k = "Doubao-lite-128k"
|
||||||
|
# ModelDoubaoPro4k = "Doubao-pro-4k"
|
||||||
|
# ModelDoubaoPro32k = "Doubao-pro-32k"
|
||||||
|
# ModelDoubaoPro128k = "Doubao-pro-128k"
|
||||||
|
# ModelDoubaoPro256k = "Doubao-pro-256k"
|
||||||
|
# ModelDoubaoEmbedding = "Doubao-embedding"
|
||||||
|
# ModelDoubaoEmbeddingLarge = "Doubao-embedding-large"
|
||||||
|
# ModelT2I2L = "high_aes_general_v20_L:general_v2.0_L"
|
||||||
|
# ModelT2I2S = "high_aes_general_v20:general_v2.0"
|
||||||
|
# ModelT2IXL = "t2i_xl_sft"
|
||||||
|
# ModelI2IXL = "i2i_xl_sft"
|
||||||
|
# ModelT2I14 = "high_aes_general_v14"
|
||||||
|
# ModelI2I14IP = "high_aes_general_v14_ip_keep"
|
||||||
|
# ModelAnime13 = "high_aes:anime_v1.3"
|
||||||
|
# ModelAnime131 = "high_aes:anime_v1.3.1"
|
||||||
|
# ModelPhotoverseAmericanComics = "img2img_photoverse_american_comics" // 美漫风格
|
||||||
|
# ModelPhotoverseExecutiveIDPhoto = "img2img_photoverse_executive_ID_photo" // 商务证件照
|
||||||
|
# ModelPhotoverse3dWeird = "img2img_photoverse_3d_weird" // 3d人偶
|
||||||
|
# ModelPhotoverseCyberpunk = "img2img_photoverse_cyberpunk" // 赛博朋克
|
||||||
|
# ModelXiezhenGubao = "img2img_xiezhen_gubao" // 古堡
|
||||||
|
# ModelXiezhenBabiNiuzai = "img2img_xiezhen_babi_niuzai" // 芭比牛仔
|
||||||
|
# ModelXiezhenBathrobe = "img2img_xiezhen_bathrobe" // 浴袍风格
|
||||||
|
# ModelXiezhenButterflyMachin = "img2img_xiezhen_butterfly_machin" // 蝴蝶机械
|
||||||
|
# ModelXiezhenZhichangzhengjianzhao = "img2img_xiezhen_zhichangzhengjianzhao" // 职场证件照
|
||||||
|
# ModelXiezhenChristmas = "img2img_xiezhen_christmas" // 圣诞
|
||||||
|
# ModelXiezhenDessert = "img2img_xiezhen_dessert" // 美式甜点师
|
||||||
|
# ModelXiezhenOldMoney = "img2img_xiezhen_old_money" // old money
|
||||||
|
# ModelXiezhenSchool = "img2img_xiezhen_school" // 最美校园
|
127
gc.go
Normal file
127
gc.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package huoshan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"apigo.cc/ai"
|
||||||
|
"github.com/ssgo/u"
|
||||||
|
"github.com/volcengine/volc-sdk-golang/service/visual"
|
||||||
|
"github.com/volcengine/volc-sdk-golang/service/visual/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getVisualClient(aiConf *ai.AIConfig) *visual.Visual {
|
||||||
|
ak, sk := getAKSK(aiConf)
|
||||||
|
vis := visual.NewInstance()
|
||||||
|
vis.Client.SetAccessKey(ak)
|
||||||
|
vis.Client.SetSecretKey(sk)
|
||||||
|
if aiConf.Extra["region"] != nil {
|
||||||
|
vis.SetRegion(u.String(aiConf.Extra["region"]))
|
||||||
|
}
|
||||||
|
if aiConf.Extra["host"] != nil {
|
||||||
|
vis.SetHost(u.String(aiConf.Extra["host"]))
|
||||||
|
}
|
||||||
|
return vis
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeImage(aiConf *ai.AIConfig, conf ai.ImageConfig) (ai.ImageResult, error) {
|
||||||
|
modelA := strings.SplitN(conf.Model, ":", 2)
|
||||||
|
data := map[string]any{
|
||||||
|
"req_key": modelA[0],
|
||||||
|
"prompt": conf.SystemPrompt + conf.Prompt,
|
||||||
|
"return_url": true,
|
||||||
|
}
|
||||||
|
if len(modelA) > 1 {
|
||||||
|
data["model_version"] = modelA[1]
|
||||||
|
}
|
||||||
|
if conf.NegativePrompt != "" {
|
||||||
|
data["negative_prompt"] = conf.NegativePrompt
|
||||||
|
}
|
||||||
|
if conf.Width > 0 {
|
||||||
|
data["width"] = conf.Width
|
||||||
|
}
|
||||||
|
if conf.Height > 0 {
|
||||||
|
data["height"] = conf.Height
|
||||||
|
}
|
||||||
|
if conf.Scale > 0 {
|
||||||
|
if conf.Scale < 1 {
|
||||||
|
// 取值 0-1 放大到 1-30
|
||||||
|
data["scale"] = conf.Scale * 30
|
||||||
|
} else {
|
||||||
|
data["scale"] = conf.Scale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conf.Steps > 0 {
|
||||||
|
data["ddim_steps"] = conf.Steps
|
||||||
|
}
|
||||||
|
if len(conf.Ref) > 0 {
|
||||||
|
// 如果有参考图,自动切换到图生图模型
|
||||||
|
if strings.Contains(modelA[0], "t2i") {
|
||||||
|
data["req_key"] = strings.ReplaceAll(modelA[0], "t2i", "i2i")
|
||||||
|
}
|
||||||
|
// 根据参考图类型设置(url和base64只能2选1)
|
||||||
|
image_url := make([]string, 0)
|
||||||
|
binary_data_base64 := make([]string, 0)
|
||||||
|
for _, ref := range conf.Ref {
|
||||||
|
if strings.Contains(ref, "://") {
|
||||||
|
image_url = append(image_url, ref)
|
||||||
|
} else {
|
||||||
|
binary_data_base64 = append(binary_data_base64, ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(image_url) > 0 {
|
||||||
|
data["image_urls"] = conf.Ref
|
||||||
|
} else {
|
||||||
|
data["binary_data_base64"] = binary_data_base64
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参考图权重设置
|
||||||
|
if conf.Cref > 0 || conf.Sref > 0 {
|
||||||
|
if strings.Contains(conf.Model, "ip_keep") {
|
||||||
|
// 人脸保持模型
|
||||||
|
if conf.Cref > 0 {
|
||||||
|
data["ref_id_weight"] = conf.Cref
|
||||||
|
}
|
||||||
|
if conf.Sref > 0 {
|
||||||
|
data["ref_ip_weight"] = conf.Sref
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 图生图模型
|
||||||
|
style_reference_args := map[string]any{"binary_data_index": 0}
|
||||||
|
if conf.Cref > 0 {
|
||||||
|
style_reference_args["id_weight"] = conf.Cref
|
||||||
|
}
|
||||||
|
if conf.Sref > 0 {
|
||||||
|
style_reference_args["style_weight"] = conf.Sref
|
||||||
|
}
|
||||||
|
data["style_reference_args"] = style_reference_args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他参数
|
||||||
|
for k, v := range conf.Extra {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Println(u.BMagenta(u.JsonP(data)), 111)
|
||||||
|
t1 := time.Now().UnixMilli()
|
||||||
|
c := getVisualClient(aiConf)
|
||||||
|
respMap, status, err := c.CVProcess(data)
|
||||||
|
// fmt.Println(u.BCyan(u.JsonP(respMap)), 222)
|
||||||
|
resp := &model.VisualPubResult{}
|
||||||
|
u.Convert(respMap, resp)
|
||||||
|
t2 := time.Now().UnixMilli() - t1
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ai.ImageResult{}, err
|
||||||
|
}
|
||||||
|
if status != 200 {
|
||||||
|
return ai.ImageResult{}, errors.New(u.String(resp.Message))
|
||||||
|
}
|
||||||
|
return ai.ImageResult{
|
||||||
|
Results: resp.Data.ImageUrls,
|
||||||
|
UsedTime: t2,
|
||||||
|
}, nil
|
||||||
|
}
|
20
go.mod
20
go.mod
@ -1,13 +1,16 @@
|
|||||||
module apigo.cc/ai/huoshan
|
module apigo.cc/ai/huoshan
|
||||||
|
|
||||||
go 1.18
|
go 1.22
|
||||||
|
|
||||||
|
toolchain go1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/gojs v0.0.1
|
apigo.cc/ai v0.0.1
|
||||||
github.com/ssgo/config v1.7.7
|
apigo.cc/gojs v0.0.4
|
||||||
github.com/ssgo/log v1.7.7
|
apigo.cc/gojs/console v0.0.1
|
||||||
github.com/ssgo/u v1.7.9
|
github.com/ssgo/u v1.7.9
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.178
|
github.com/volcengine/volc-sdk-golang v1.0.182
|
||||||
|
github.com/volcengine/volcengine-go-sdk v1.0.162
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -17,12 +20,15 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/ssgo/config v1.7.8 // indirect
|
||||||
|
github.com/ssgo/log v1.7.7 // indirect
|
||||||
github.com/ssgo/standard v1.7.7 // indirect
|
github.com/ssgo/standard v1.7.7 // indirect
|
||||||
github.com/ssgo/tool v0.4.27 // indirect
|
github.com/ssgo/tool v0.4.27 // indirect
|
||||||
golang.org/x/sys v0.26.0 // indirect
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
|
45
huoshan.go
45
huoshan.go
@ -1,45 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"apigo.cc/gojs"
|
|
||||||
_ "embed"
|
|
||||||
"github.com/ssgo/config"
|
|
||||||
"github.com/ssgo/log"
|
|
||||||
"github.com/ssgo/u"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed huoshan.ts
|
|
||||||
var huoshanTS string
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
AKey string
|
|
||||||
SKey string
|
|
||||||
}
|
|
||||||
|
|
||||||
var conf = Conf{}
|
|
||||||
|
|
||||||
var confAes = u.NewAes([]byte("?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV"), []byte("VFs7@sK61cj^f?HZ"))
|
|
||||||
var keysIsSet = false
|
|
||||||
|
|
||||||
func SetSSKey(key, iv []byte) {
|
|
||||||
if !keysIsSet {
|
|
||||||
confAes = u.NewAes(key, iv)
|
|
||||||
keysIsSet = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
obj := gojs.Map{
|
|
||||||
"name": "huoshan",
|
|
||||||
"image": RequireImage(),
|
|
||||||
}
|
|
||||||
config.LoadConfig("huoshan", &conf)
|
|
||||||
conf.AKey = confAes.DecryptUrlBase64ToString(conf.AKey)
|
|
||||||
conf.SKey = confAes.DecryptUrlBase64ToString(conf.SKey)
|
|
||||||
log.DefaultLogger.Info("Conf", "", conf)
|
|
||||||
gojs.Register("apigo.cc/ai/huoshan", gojs.Module{
|
|
||||||
Object: obj,
|
|
||||||
TsCode: huoshanTS,
|
|
||||||
Example: "",
|
|
||||||
})
|
|
||||||
}
|
|
20
huoshan.ts
20
huoshan.ts
@ -1,20 +0,0 @@
|
|||||||
export default {
|
|
||||||
image: {
|
|
||||||
text2image,
|
|
||||||
image2image,
|
|
||||||
readImage,
|
|
||||||
base64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//about image
|
|
||||||
function text2image(prompt:string, option?:Object):string {return ""}
|
|
||||||
// image2image
|
|
||||||
// image able with base64, bin(byte[], what you get from "readImage"), url(url must be written in an array like ["your url"])
|
|
||||||
function image2image(image, prompt:string, option?:Object):string {return ""}
|
|
||||||
function readImage(path:string):string {return ""}
|
|
||||||
// base64 written-in base64 function,you can use what you want
|
|
||||||
// data give what you want to give
|
|
||||||
function base64(data):string {return ""}
|
|
||||||
|
|
||||||
|
|
119
image.go
119
image.go
@ -1,119 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"apigo.cc/gojs"
|
|
||||||
"apigo.cc/gojs/goja"
|
|
||||||
"errors"
|
|
||||||
"github.com/ssgo/log"
|
|
||||||
"github.com/ssgo/u"
|
|
||||||
"github.com/volcengine/volc-sdk-golang/service/visual"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RequireImage() gojs.Map {
|
|
||||||
return map[string]interface{}{
|
|
||||||
"text2image": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
||||||
return vm.ToValue(T2IXL(args.Str(0), args.Map(1), vm))
|
|
||||||
},
|
|
||||||
"image2image": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(2)
|
|
||||||
v := u.FinalValue(reflect.ValueOf(args.Arguments[0].Export()))
|
|
||||||
switch v.Type().Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
option := args.Map(2)
|
|
||||||
if option == nil {
|
|
||||||
option = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
option["binary_data_base64"] = []string{
|
|
||||||
args.Str(0),
|
|
||||||
}
|
|
||||||
return vm.ToValue(I2IXLbyUrl(nil, args.Str(1), option, vm))
|
|
||||||
case reflect.Slice:
|
|
||||||
vv := u.FinalValue(v.Index(0))
|
|
||||||
if vv.Type().Kind() == reflect.Uint8 {
|
|
||||||
option := args.Map(2)
|
|
||||||
if option == nil {
|
|
||||||
option = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
option["binary_data_base64"] = []string{
|
|
||||||
u.Base64(args.Bytes(0)),
|
|
||||||
}
|
|
||||||
return vm.ToValue(I2IXLbyUrl(nil, args.Str(1), option, vm))
|
|
||||||
} else if vv.Type().Kind() == reflect.String {
|
|
||||||
arr := make([]string, 0)
|
|
||||||
u.Convert(args.Any(0), &arr)
|
|
||||||
return vm.ToValue(I2IXLbyUrl(arr, args.Str(1), args.Map(2), vm))
|
|
||||||
} else {
|
|
||||||
log.DefaultLogger.Error("image type is slice but not supported", "type", args.Arguments[0].ExportType().Kind().String(), "elemType", vv.Type().Kind().String())
|
|
||||||
panic(vm.NewGoError(errors.New(u.Red("image type is slice but not supported"))))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.DefaultLogger.Error("image type not supported", "type", args.Arguments[0].ExportType().Kind().String())
|
|
||||||
panic(vm.NewGoError(errors.New(u.Red("image type not supported"))))
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
"readImage": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
||||||
args := gojs.MakeArgs(&argsIn, vm).Check(1)
|
|
||||||
if r, err := u.ReadFileBytes(args.Path(0)); err == nil {
|
|
||||||
return vm.ToValue(r)
|
|
||||||
} else {
|
|
||||||
panic(vm.NewGoError(err))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"base64": func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
|
||||||
return vm.ToValue(u.Base64(u.Bytes(gojs.MakeArgs(&argsIn, vm).Check(1).Any(0))))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// T2IXL used t2i_xl_sft
|
|
||||||
//
|
|
||||||
// option 会覆盖已有参数,可传空,return_url不可更改
|
|
||||||
func T2IXL(prompt string, option map[string]interface{}, vm *goja.Runtime) []string {
|
|
||||||
vis := visual.NewInstance()
|
|
||||||
vis.Client.SetAccessKey(conf.AKey)
|
|
||||||
vis.Client.SetSecretKey(conf.SKey)
|
|
||||||
data := map[string]interface{}{
|
|
||||||
"req_key": "t2i_xl_sft",
|
|
||||||
"prompt": prompt,
|
|
||||||
}
|
|
||||||
if option != nil {
|
|
||||||
u.Convert(option, &data)
|
|
||||||
}
|
|
||||||
data["return_url"] = true
|
|
||||||
resp, status, err := vis.Text2ImgXLSft(data)
|
|
||||||
if status != 200 || err != nil {
|
|
||||||
log.DefaultLogger.Error("request error", status, err)
|
|
||||||
panic(vm.NewGoError(err))
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return resp.Data.ImageUrls
|
|
||||||
}
|
|
||||||
|
|
||||||
// I2IXLbyUrl used t2i_xl_sft
|
|
||||||
// option 会覆盖已有参数,可传空,return_url不可更改
|
|
||||||
func I2IXLbyUrl(imageUrls []string, prompt string, option map[string]interface{}, vm *goja.Runtime) []string {
|
|
||||||
vis := visual.NewInstance()
|
|
||||||
vis.Client.SetAccessKey(conf.AKey)
|
|
||||||
vis.Client.SetSecretKey(conf.SKey)
|
|
||||||
data := map[string]interface{}{
|
|
||||||
"req_key": "i2i_xl_sft",
|
|
||||||
"prompt": prompt,
|
|
||||||
}
|
|
||||||
if imageUrls != nil {
|
|
||||||
data["image_urls"] = imageUrls
|
|
||||||
}
|
|
||||||
if option != nil {
|
|
||||||
u.Convert(option, &data)
|
|
||||||
}
|
|
||||||
data["return_url"] = true
|
|
||||||
resp, status, err := vis.Img2ImgXLSft(data)
|
|
||||||
if status != 200 || err != nil {
|
|
||||||
log.DefaultLogger.Error("request error", "status", status, "err", err, "resp", resp)
|
|
||||||
panic(vm.NewGoError(err))
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return resp.Data.ImageUrls
|
|
||||||
}
|
|
@ -1,224 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"apigo.cc/ai/llm/llm"
|
|
||||||
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (lm *LLM) FastAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoLite32k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) LongAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro256k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BatterAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro32k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BestAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro256k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) MultiAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoLite32k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BestMultiAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro32k,
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) CodeInterpreterAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro32k,
|
|
||||||
Tools: map[string]any{llm.ToolCodeInterpreter: nil},
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) WebSearchAsk(messages []llm.ChatMessage, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
return lm.Ask(messages, llm.ChatConfig{
|
|
||||||
Model: ModelDoubaoPro32k,
|
|
||||||
Tools: map[string]any{llm.ToolWebSearch: nil},
|
|
||||||
}, callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) Ask(messages []llm.ChatMessage, config llm.ChatConfig, callback func(answer string)) (string, llm.Usage, error) {
|
|
||||||
config.SetDefault(&lm.config.ChatConfig)
|
|
||||||
|
|
||||||
req := model.ChatCompletionRequest{
|
|
||||||
Model: config.GetModel(),
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Messages = make([]*model.ChatCompletionMessage, len(messages))
|
|
||||||
for i, msg := range messages {
|
|
||||||
var contents []*model.ChatCompletionMessageContentPart
|
|
||||||
if msg.Contents != nil {
|
|
||||||
contents = make([]*model.ChatCompletionMessageContentPart, len(msg.Contents))
|
|
||||||
for j, inPart := range msg.Contents {
|
|
||||||
part := model.ChatCompletionMessageContentPart{}
|
|
||||||
part.Type = model.ChatCompletionMessageContentPartType(NameMap[inPart.Type])
|
|
||||||
switch inPart.Type {
|
|
||||||
case llm.TypeText:
|
|
||||||
part.Text = inPart.Content
|
|
||||||
case llm.TypeImage:
|
|
||||||
part.ImageURL = &model.ChatMessageImageURL{URL: inPart.Content}
|
|
||||||
//case llm.TypeVideo:
|
|
||||||
// part.VideoURL = &model.URLItem{URL: inPart.Content}
|
|
||||||
}
|
|
||||||
contents[j] = &part
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(contents) == 1 && contents[0].Type == llm.TypeText {
|
|
||||||
req.Messages[i] = &model.ChatCompletionMessage{
|
|
||||||
Role: NameMap[msg.Role],
|
|
||||||
Content: &model.ChatCompletionMessageContent{
|
|
||||||
StringValue: &contents[0].Text,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
req.Messages[i] = &model.ChatCompletionMessage{
|
|
||||||
Role: NameMap[msg.Role],
|
|
||||||
Content: &model.ChatCompletionMessageContent{
|
|
||||||
ListValue: contents,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tools := config.GetTools()
|
|
||||||
// if len(tools) > 0 {
|
|
||||||
// req.Tools = make([]*model.Tool, 0)
|
|
||||||
// for name := range tools {
|
|
||||||
// switch name {
|
|
||||||
// case llm.ToolCodeInterpreter:
|
|
||||||
// req.Tools = append(req.Tools, &model.Tool{
|
|
||||||
// Type: ,
|
|
||||||
// })
|
|
||||||
// // cc.AddTool(zhipu.ChatCompletionToolCodeInterpreter{})
|
|
||||||
// case llm.ToolWebSearch:
|
|
||||||
// // cc.AddTool(zhipu.ChatCompletionToolWebBrowser{})
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
if config.GetMaxTokens() != 0 {
|
|
||||||
req.MaxTokens = config.GetMaxTokens()
|
|
||||||
}
|
|
||||||
if config.GetTemperature() != 0 {
|
|
||||||
req.Temperature = float32(config.GetTemperature())
|
|
||||||
}
|
|
||||||
if config.GetTopP() != 0 {
|
|
||||||
req.TopP = float32(config.GetTopP())
|
|
||||||
}
|
|
||||||
|
|
||||||
c := lm.getChatClient()
|
|
||||||
t1 := time.Now().UnixMilli()
|
|
||||||
if callback != nil {
|
|
||||||
stream, err := c.CreateChatCompletionStream(context.Background(), req)
|
|
||||||
if err != nil {
|
|
||||||
return "", llm.Usage{}, err
|
|
||||||
}
|
|
||||||
out := make([]string, 0)
|
|
||||||
var outErr error
|
|
||||||
usage := llm.Usage{}
|
|
||||||
for {
|
|
||||||
recv, err := stream.Recv()
|
|
||||||
usage.AskTokens += int64(recv.Usage.PromptTokens)
|
|
||||||
usage.AnswerTokens += int64(recv.Usage.CompletionTokens)
|
|
||||||
usage.TotalTokens += int64(recv.Usage.TotalTokens)
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
outErr = err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(recv.Choices) > 0 {
|
|
||||||
for _, ch := range recv.Choices {
|
|
||||||
text := ch.Delta.Content
|
|
||||||
out = append(out, text)
|
|
||||||
callback(text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream.Close()
|
|
||||||
usage.UsedTime = time.Now().UnixMilli() - t1
|
|
||||||
return strings.Join(out, ""), usage, outErr
|
|
||||||
} else {
|
|
||||||
r, err := c.CreateChatCompletion(context.Background(), req)
|
|
||||||
if err != nil {
|
|
||||||
return "", llm.Usage{}, err
|
|
||||||
}
|
|
||||||
t2 := time.Now().UnixMilli() - t1
|
|
||||||
results := make([]string, 0)
|
|
||||||
if r.Choices != nil {
|
|
||||||
for _, ch := range r.Choices {
|
|
||||||
results = append(results, *ch.Message.Content.StringValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(results, ""), llm.Usage{
|
|
||||||
AskTokens: int64(r.Usage.PromptTokens),
|
|
||||||
AnswerTokens: int64(r.Usage.CompletionTokens),
|
|
||||||
TotalTokens: int64(r.Usage.TotalTokens),
|
|
||||||
UsedTime: t2,
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) FastEmbedding(text string) ([]byte, llm.Usage, error) {
|
|
||||||
return lm.Embedding(text, ModelDoubaoEmbedding)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BestEmbedding(text string) ([]byte, llm.Usage, error) {
|
|
||||||
return lm.Embedding(text, ModelDoubaoEmbeddingLarge)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) Embedding(text, modelName string) ([]byte, llm.Usage, error) {
|
|
||||||
c := lm.getChatClient()
|
|
||||||
// cc := c.Embedding(modelName)
|
|
||||||
req := model.EmbeddingRequestStrings{
|
|
||||||
Input: []string{text},
|
|
||||||
Model: modelName,
|
|
||||||
}
|
|
||||||
t1 := time.Now().UnixMilli()
|
|
||||||
if r, err := c.CreateEmbeddings(context.Background(), req); err == nil {
|
|
||||||
t2 := time.Now().UnixMilli() - t1
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if r.Data != nil {
|
|
||||||
for _, ch := range r.Data {
|
|
||||||
for _, v := range ch.Embedding {
|
|
||||||
_ = binary.Write(buf, binary.LittleEndian, float32(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.Bytes(), llm.Usage{
|
|
||||||
AskTokens: int64(r.Usage.PromptTokens),
|
|
||||||
AnswerTokens: int64(r.Usage.CompletionTokens),
|
|
||||||
TotalTokens: int64(r.Usage.TotalTokens),
|
|
||||||
UsedTime: t2,
|
|
||||||
}, nil
|
|
||||||
} else {
|
|
||||||
return nil, llm.Usage{}, err
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"apigo.cc/ai/llm/llm"
|
|
||||||
"github.com/volcengine/volc-sdk-golang/service/visual"
|
|
||||||
"github.com/volcengine/volcengine-go-sdk/service/arkruntime"
|
|
||||||
"github.com/volcengine/volcengine-go-sdk/service/arkruntime/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LLM struct {
|
|
||||||
config llm.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
var NameMap = map[string]string{
|
|
||||||
llm.TypeText: string(model.ChatCompletionMessageContentPartTypeText),
|
|
||||||
llm.TypeImage: string(model.ChatCompletionMessageContentPartTypeImageURL),
|
|
||||||
//llm.TypeVideo: string(model.ChatCompletionMessageContentPartTypeVideoURL),
|
|
||||||
llm.RoleSystem: model.ChatMessageRoleSystem,
|
|
||||||
llm.RoleUser: model.ChatMessageRoleUser,
|
|
||||||
llm.RoleAssistant: model.ChatMessageRoleAssistant,
|
|
||||||
llm.RoleTool: model.ChatMessageRoleTool,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
ModelDoubaoLite4k = "Doubao-lite-4k"
|
|
||||||
ModelDoubaoLite32k = "Doubao-lite-32k"
|
|
||||||
ModelDoubaoLite128k = "Doubao-lite-128k"
|
|
||||||
ModelDoubaoPro4k = "Doubao-pro-4k"
|
|
||||||
ModelDoubaoPro32k = "Doubao-pro-32k"
|
|
||||||
ModelDoubaoPro128k = "Doubao-pro-128k"
|
|
||||||
ModelDoubaoPro256k = "Doubao-pro-256k"
|
|
||||||
ModelDoubaoEmbedding = "Doubao-embedding"
|
|
||||||
ModelDoubaoEmbeddingLarge = "Doubao-embedding-large"
|
|
||||||
ModelT2I2L = "high_aes_general_v20_L:general_v2.0_L"
|
|
||||||
ModelT2I2S = "high_aes_general_v20:general_v2.0"
|
|
||||||
ModelT2IXL = "t2i_xl_sft"
|
|
||||||
ModelI2IXL = "i2i_xl_sft"
|
|
||||||
ModelT2I14 = "high_aes_general_v14"
|
|
||||||
ModelI2I14IP = "high_aes_general_v14_ip_keep"
|
|
||||||
ModelAnime13 = "high_aes:anime_v1.3"
|
|
||||||
ModelAnime131 = "high_aes:anime_v1.3.1"
|
|
||||||
ModelPhotoverseAmericanComics = "img2img_photoverse_american_comics" // 美漫风格
|
|
||||||
ModelPhotoverseExecutiveIDPhoto = "img2img_photoverse_executive_ID_photo" // 商务证件照
|
|
||||||
ModelPhotoverse3dWeird = "img2img_photoverse_3d_weird" // 3d人偶
|
|
||||||
ModelPhotoverseCyberpunk = "img2img_photoverse_cyberpunk" // 赛博朋克
|
|
||||||
ModelXiezhenGubao = "img2img_xiezhen_gubao" // 古堡
|
|
||||||
ModelXiezhenBabiNiuzai = "img2img_xiezhen_babi_niuzai" // 芭比牛仔
|
|
||||||
ModelXiezhenBathrobe = "img2img_xiezhen_bathrobe" // 浴袍风格
|
|
||||||
ModelXiezhenButterflyMachin = "img2img_xiezhen_butterfly_machin" // 蝴蝶机械
|
|
||||||
ModelXiezhenZhichangzhengjianzhao = "img2img_xiezhen_zhichangzhengjianzhao" // 职场证件照
|
|
||||||
ModelXiezhenChristmas = "img2img_xiezhen_christmas" // 圣诞
|
|
||||||
ModelXiezhenDessert = "img2img_xiezhen_dessert" // 美式甜点师
|
|
||||||
ModelXiezhenOldMoney = "img2img_xiezhen_old_money" // old money
|
|
||||||
ModelXiezhenSchool = "img2img_xiezhen_school" // 最美校园
|
|
||||||
)
|
|
||||||
|
|
||||||
func (lm *LLM) Support() llm.Support {
|
|
||||||
return llm.Support{
|
|
||||||
Ask: true,
|
|
||||||
AskWithImage: true,
|
|
||||||
AskWithVideo: false,
|
|
||||||
AskWithCodeInterpreter: false,
|
|
||||||
AskWithWebSearch: false,
|
|
||||||
MakeImage: true,
|
|
||||||
MakeVideo: false,
|
|
||||||
Models: []string{ModelDoubaoLite4k, ModelDoubaoLite32k, ModelDoubaoLite128k, ModelDoubaoPro4k, ModelDoubaoPro32k, ModelDoubaoPro128k, ModelDoubaoPro256k, ModelDoubaoEmbedding, ModelDoubaoEmbeddingLarge, ModelT2I2L, ModelT2I2S, ModelT2IXL, ModelI2IXL, ModelT2I14, ModelI2I14IP, ModelAnime13, ModelAnime131, ModelPhotoverseAmericanComics, ModelPhotoverseExecutiveIDPhoto, ModelPhotoverse3dWeird, ModelPhotoverseCyberpunk, ModelXiezhenGubao, ModelXiezhenBabiNiuzai, ModelXiezhenBathrobe, ModelXiezhenButterflyMachin, ModelXiezhenZhichangzhengjianzhao, ModelXiezhenChristmas, ModelXiezhenDessert, ModelXiezhenOldMoney, ModelXiezhenSchool},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) getChatClient() *arkruntime.Client {
|
|
||||||
opt := make([]arkruntime.ConfigOption, 0)
|
|
||||||
if lm.config.Endpoint != "" {
|
|
||||||
opt = append(opt, arkruntime.WithBaseUrl(lm.config.Endpoint))
|
|
||||||
}
|
|
||||||
return arkruntime.NewClientWithAkSk(strings.SplitN(lm.config.ApiKey, ",", 2)[0], opt...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) getGCClient() *visual.Visual {
|
|
||||||
keys := strings.SplitN(lm.config.ApiKey, ",", 2)
|
|
||||||
if len(keys) == 1 {
|
|
||||||
keys = append(keys, "")
|
|
||||||
}
|
|
||||||
vis := visual.NewInstance()
|
|
||||||
vis.Client.SetAccessKey(keys[0])
|
|
||||||
vis.Client.SetSecretKey(keys[1])
|
|
||||||
return vis
|
|
||||||
}
|
|
||||||
|
|
||||||
// 因为火山平台的配置过于繁琐(每个模型都要创建单独的endpoint,所以暂时放弃对豆包大模型的支持)
|
|
||||||
// func init() {
|
|
||||||
// llm.Register("huoshan", func(config llm.Config) llm.LLM {
|
|
||||||
// return &LLM{config: config}
|
|
||||||
// })
|
|
||||||
// }
|
|
@ -1,87 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"apigo.cc/ai/llm/llm"
|
|
||||||
"github.com/ssgo/u"
|
|
||||||
"github.com/volcengine/volc-sdk-golang/service/visual/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (lm *LLM) FastMakeImage(prompt string, config llm.GCConfig) ([]string, llm.Usage, error) {
|
|
||||||
config.Model = ModelT2I14
|
|
||||||
if config.Ref != "" {
|
|
||||||
config.Model = ModelI2I14IP
|
|
||||||
}
|
|
||||||
return lm.MakeImage(prompt, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BestMakeImage(prompt string, config llm.GCConfig) ([]string, llm.Usage, error) {
|
|
||||||
config.Model = ModelT2IXL
|
|
||||||
if config.Ref != "" {
|
|
||||||
config.Model = ModelI2IXL
|
|
||||||
}
|
|
||||||
return lm.MakeImage(prompt, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) MakeImage(prompt string, config llm.GCConfig) ([]string, llm.Usage, error) {
|
|
||||||
config.SetDefault(&lm.config.GCConfig)
|
|
||||||
modelA := strings.SplitN(config.GetModel(), ":", 2)
|
|
||||||
sizeA := strings.SplitN(config.GetSize(), "x", 2)
|
|
||||||
if len(sizeA) == 1 {
|
|
||||||
sizeA = append(sizeA, sizeA[0])
|
|
||||||
}
|
|
||||||
ref := config.GetRef()
|
|
||||||
vis := lm.getGCClient()
|
|
||||||
data := map[string]any{
|
|
||||||
"req_key": modelA[0],
|
|
||||||
"prompt": prompt,
|
|
||||||
"width": u.Int(sizeA[0]),
|
|
||||||
"height": u.Int(sizeA[1]),
|
|
||||||
"return_url": true,
|
|
||||||
}
|
|
||||||
if len(modelA) > 1 {
|
|
||||||
data["model_version"] = modelA[1]
|
|
||||||
}
|
|
||||||
// TODO llm 支持动态额外参数
|
|
||||||
|
|
||||||
t1 := time.Now().UnixMilli()
|
|
||||||
var resp *model.VisualPubResult
|
|
||||||
var status int
|
|
||||||
var err error
|
|
||||||
if ref == "" {
|
|
||||||
resp, status, err = vis.Text2ImgXLSft(data)
|
|
||||||
} else {
|
|
||||||
if strings.Contains(ref, "://") {
|
|
||||||
data["image_url"] = []string{ref}
|
|
||||||
} else {
|
|
||||||
data["binary_data_base64"] = []string{ref}
|
|
||||||
}
|
|
||||||
resp, status, err = vis.Img2ImgXLSft(data)
|
|
||||||
}
|
|
||||||
t2 := time.Now().UnixMilli() - t1
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, llm.Usage{}, err
|
|
||||||
}
|
|
||||||
if status != 200 {
|
|
||||||
return nil, llm.Usage{}, errors.New(resp.Message)
|
|
||||||
}
|
|
||||||
return resp.Data.ImageUrls, llm.Usage{
|
|
||||||
UsedTime: t2,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) FastMakeVideo(prompt string, config llm.GCConfig) ([]string, []string, llm.Usage, error) {
|
|
||||||
return lm.MakeVideo(prompt, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) BestMakeVideo(prompt string, config llm.GCConfig) ([]string, []string, llm.Usage, error) {
|
|
||||||
return lm.MakeVideo(prompt, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lm *LLM) MakeVideo(prompt string, config llm.GCConfig) ([]string, []string, llm.Usage, error) {
|
|
||||||
return nil, nil, llm.Usage{}, errors.New("not support")
|
|
||||||
}
|
|
21
test.go
21
test.go
@ -1,21 +0,0 @@
|
|||||||
package huoshan
|
|
||||||
|
|
||||||
import (
|
|
||||||
"apigo.cc/gojs"
|
|
||||||
"fmt"
|
|
||||||
"github.com/ssgo/u"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestExport(t *testing.T) {
|
|
||||||
gojs.ExportForDev()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLLM(t *testing.T) {
|
|
||||||
r, err := gojs.RunFile("test.js")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
fmt.Println(u.JsonP(r))
|
|
||||||
}
|
|
24
test.js
24
test.js
@ -1,24 +0,0 @@
|
|||||||
import {image} from 'apigo.cc/ai/huoshan'
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
let a = image.image2image(image.base64(image.readImage("img_2.jpeg")), "在吃冰淇淋", {
|
|
||||||
style_reference_args: {
|
|
||||||
id_weight: 1.0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
let b = image.image2image(image.readImage("img_2.jpeg"), "在吃冰淇淋", {
|
|
||||||
style_reference_args: {
|
|
||||||
id_weight: 1.0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
let c = image.image2image(["一个url"], "在吃冰淇淋", {
|
|
||||||
style_reference_args: {
|
|
||||||
id_weight: 1.0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
a: a,
|
|
||||||
b: b,
|
|
||||||
c: c
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user