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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user