From 1c4932d005717918c702df287e13f14cd99c4298 Mon Sep 17 00:00:00 2001 From: Star Date: Sun, 3 Nov 2024 11:36:02 +0800 Subject: [PATCH] support some Edit Image --- ai_test.go | 2 + ai_test.js | 17 +++++++- config.go | 7 ++++ default.yml | 96 ++++++++++++++++++++++++++----------------- gc.go | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 10 ++--- 6 files changed, 202 insertions(+), 44 deletions(-) diff --git a/ai_test.go b/ai_test.go index 5d02d4a..af8f1d3 100644 --- a/ai_test.go +++ b/ai_test.go @@ -7,6 +7,8 @@ import ( _ "apigo.cc/ai/huoshan" "apigo.cc/gojs" _ "apigo.cc/gojs/console" + _ "apigo.cc/gojs/file" + _ "apigo.cc/gojs/util" "github.com/ssgo/u" ) diff --git a/ai_test.js b/ai_test.js index 32d4cda..ed8c8c6 100644 --- a/ai_test.js +++ b/ai_test.js @@ -1,8 +1,10 @@ import co from 'apigo.cc/gojs/console' +import file from 'apigo.cc/gojs/file' +import u from 'apigo.cc/gojs/util' import ai from 'apigo.cc/ai' let r = ai.huoshan.fastAsk('用一句话为你的主人写一段生成在山顶喝咖啡的图片的提示词', co.print, { - systemPrompt: '你的主人很美丽,喜欢戴帽子' + systemPrompt: '你的主人是个年轻姑娘,很美丽,喜欢戴帽子' }) co.println() co.info('生成的提示词:', r.result) @@ -16,9 +18,20 @@ let r2 = ai.huoshan.makeImage({ co.info('生成的图片:', r2.results[0]) let r3 = ai.huoshan.makeImageKeepIP({ - prompt: '女孩,骑马在草原上狂奔,天上的云朵,有太阳,有小鸟', + prompt: '年轻姑娘,表情悲伤,骑马在草原上狂奔,天上的云朵,有太阳,有小鸟', width: 1280, height: 720, ref: [r2.results[0]], }) co.info('生成角色一致的图片:', r3.results[0]) + +let r3s = ai.huoshan.changeEmotion(r3.results[0], { target_emotion: 'liwo' }) +co.info('梨涡笑:', r3s.result) + +let r3p = ai.huoshan.makeFacePretty(r3s.result) +file.write('test.jpg', u.unBase64(r3p.result)) +co.info('美颜后:', 'test.jpg') + +let r4 = ai.huoshan.getHumanSegment(r3p.result) +file.write('test_mask.jpg', u.unBase64(r4.result)) +co.info('角色主体:', 'test_mask.jpg') diff --git a/config.go b/config.go index 598bf1b..ca55a7c 100644 --- a/config.go +++ b/config.go @@ -18,10 +18,17 @@ func init() { EmbeddingConfigs: defaultConf.Embedding, ImageConfigs: defaultConf.Image, VideoConfigs: defaultConf.Video, + EditConfigs: defaultConf.Edit, + AsrConfigs: defaultConf.Asr, + TtsConfigs: defaultConf.Tts, Chat: Chat, Embedding: Embedding, MakeImage: MakeImage, // MakeVideo: MakeVideo, // GetVideoResult: GetVideoResult, + Edit: Edit, + // Scan: Scan, + // Asr: Asr, + // Tts: Tts, }) } diff --git a/default.yml b/default.yml index 01b5353..633e66b 100644 --- a/default.yml +++ b/default.yml @@ -6,58 +6,80 @@ image: width: 1024 height: 1024 makeImageHD: - model: "high_aes_general_v20_L:general_v2.0_L" + 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 + makeCartoon: + model: high_aes:anime_v1.3.1 + width: 1024 + height: 1024 + 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" + model: high_aes_general_v14_ip_keep:general_v1.4_ip width: 1024 height: 1024 makeAmericanComics: - model: "img2img_photoverse_american_comics" + model: img2img_photoverse_american_comics make3DWeird: - model: "img2img_photoverse_3d_weird" + model: img2img_photoverse_3d_weird makeCyberpunk: - model: "img2img_photoverse_cyberpunk" + model: img2img_photoverse_cyberpunk makeBabi: - model: "img2img_xiezhen_babi_niuzai" + 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" // 最美校园 + model: img2img_photoverse_executive_ID_photo + makeOutpainting: + model: i2i_outpainting + make3DStyle: + model: img2img_disney_3d_style + makeCartoonStyle: + model: img2img_cartoon_style +edit: + getHumanSegment: + action: HumanSegment + refine: 1 + return_foreground_image: 1 + changeEmotion: + action: EmotionPortrait + # jiuwo: 酒窝笑 + # liwo: 梨窝笑 + # big_smile_white_teeth: 露牙大笑 + # classic_white_teeth: 露牙标准笑 + # cool: 耍酷 + # sad: 悲伤 + # tight_smile: 勉强笑 + target_emotion: big_smile_white_teeth + changeHair: + action: EmotionPortrait + # 101: 刘海(默认) + # 201: 长发 + # 301: 刘海加长发 + # 401: 中程度增发 + # 402: 轻程度增发 + # 403: 重程度增发 + # 502: 轻程度卷发 + # 503: 重程度卷发 + # 603: 短发(要求输入尺寸<2048x2048,若输入大于2048x2048的图片,输出的图片会被resize成最长边2048;) + # 801: 金发 + # 901: 直发 + # 1001: 头发去油(轻微效果,原图中此问题建议较为明显) + # 1101: 补发际线(调整过高的发际线,轻微效果,原图中此问题建议较为明显) + # 1201: 头发柔顺 (轻微效果,原图需有较大发型区域,原图中此问题建议较为明显) + # 1301: 补发缝(轻微效果,填补头发区域中的头皮部分,原图中此问题建议较为明显) + hair_type: 101 + makeFacePretty: + action: FacePretty + do_risk: false + multi_face: 1 + beauty_level: 1 diff --git a/gc.go b/gc.go index ec492d5..ab31696 100644 --- a/gc.go +++ b/gc.go @@ -2,6 +2,7 @@ package huoshan import ( "errors" + "net/url" "strings" "time" @@ -86,6 +87,11 @@ func MakeImage(aiConf *ai.AIConfig, conf ai.ImageConfig) (ai.ImageResult, error) if conf.Sref > 0 { data["ref_ip_weight"] = conf.Sref } + } else if strings.Contains(conf.Model, ":anime_") { + // 动漫模型 + if conf.Sref > 0 { + data["strength"] = conf.Sref + } } else { // 图生图模型 style_reference_args := map[string]any{"binary_data_index": 0} @@ -125,3 +131,111 @@ func MakeImage(aiConf *ai.AIConfig, conf ai.ImageConfig) (ai.ImageResult, error) UsedTime: t2, }, nil } + +func Edit(aiConf *ai.AIConfig, from string, conf map[string]any) (ai.StringResult, error) { + action := u.String(conf["action"]) + c := getVisualClient(aiConf) + t1 := time.Now().UnixMilli() + switch action { + case "EmotionPortrait": + // 修改表情 + req := map[string]any{"req_key": "emotion_portrait", "return_url": true} + for k, v := range conf { + if k != "action" { + req[k] = v + } + } + if strings.Contains(from, "://") { + req["image_urls"] = []string{from} + } else { + req["binary_data_base64"] = []string{from} + } + resp, status, err := c.EmotionPortrait(req) + if err != nil { + return ai.StringResult{}, err + } + if status != 200 { + return ai.StringResult{}, errors.New(u.String(resp.Message)) + } + result := resp.Data.ImageUrls[0] + return ai.StringResult{ + Result: result, + UsedTime: time.Now().UnixMilli() - t1, + }, nil + case "HumanSegment": + // 抠出人像 + req := url.Values{ + "refine": {u.String(u.Int(conf["refine"]))}, + "return_foreground_image": {u.String(u.Int(conf["return_foreground_image"]))}, + } + if strings.Contains(from, "://") { + req["image_url"] = []string{from} + } else { + req["image_base64"] = []string{from} + } + resp, status, err := c.HumanSegment(req) + if err != nil { + return ai.StringResult{}, err + } + if status != 200 { + return ai.StringResult{}, errors.New(u.String(resp.Message)) + } + // u.WriteFileBytes("mask.jpg", u.UnBase64(resp.Data.Mask)) + // u.WriteFileBytes("body.jpg", u.UnBase64(resp.Data.ForegroundImage)) + result := resp.Data.ForegroundImage + if result == "" { + result = resp.Data.Mask + } + return ai.StringResult{ + Result: result, + UsedTime: time.Now().UnixMilli() - t1, + }, nil + case "FacePretty": + // 美颜 + req := url.Values{ + "do_risk": {u.GetUpperName(u.String(u.Bool(conf["do_risk"])))}, + "multi_face": {u.String(u.Int(conf["multi_face"]))}, + "beauty_level": {u.String(u.Float(conf["beauty_level"]))}, + } + if strings.Contains(from, "://") { + req["image_url"] = []string{from} + } else { + req["image_base64"] = []string{from} + } + resp, status, err := c.FacePretty(req) + if err != nil { + return ai.StringResult{}, err + } + if status != 200 { + return ai.StringResult{}, errors.New(u.String(resp.Message)) + } + return ai.StringResult{ + Result: resp.Data.Image, + UsedTime: time.Now().UnixMilli() - t1, + }, nil + case "HairStyle": + // 改变发型 + req := url.Values{ + "req_key": {"hair_style"}, + "return_url": {"true"}, + "hair_type": {u.String(conf["hair_type"])}, + } + if strings.Contains(from, "://") { + req["image_urls"] = []string{from} + } else { + req["binary_data_base64"] = []string{from} + } + resp, status, err := c.HairStyle(req) + if err != nil { + return ai.StringResult{}, err + } + if status != 200 { + return ai.StringResult{}, errors.New(u.String(resp.Message)) + } + return ai.StringResult{ + Result: resp.Data.Image, + UsedTime: time.Now().UnixMilli() - t1, + }, nil + } + return ai.StringResult{}, nil +} diff --git a/go.mod b/go.mod index c549ef9..0db5f94 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module apigo.cc/ai/huoshan -go 1.22 - -toolchain go1.22.1 +go 1.18 require ( - apigo.cc/ai v0.0.1 + apigo.cc/ai v0.0.2 apigo.cc/gojs v0.0.4 apigo.cc/gojs/console v0.0.1 + apigo.cc/gojs/file v0.0.2 + apigo.cc/gojs/util v0.0.3 github.com/ssgo/u v1.7.9 github.com/volcengine/volc-sdk-golang v1.0.182 github.com/volcengine/volcengine-go-sdk v1.0.162 @@ -24,7 +24,7 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // 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