mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-12-03 23:06:12 +08:00
更新绘图和视频生成提示词字段长度限制,优化图生图逻辑,统一转成base64 的格式发送到远程 API
This commit is contained in:
@@ -2,11 +2,12 @@
|
||||
|
||||
## v4.2.1
|
||||
|
||||
- 功能新增:新增支持可灵生成视频。
|
||||
- Bug修复:修复移动端聊天页面新建对话时候角色没有更模型绑定的 Bug。
|
||||
- 功能新增:新增支持可灵生成视频,支持文生视频,图生生视频。
|
||||
- 功能优化:优化 Luma 图生视频功能,支持本地上传图片和远程图片。
|
||||
- Bug 修复:修复移动端聊天页面新建对话时候角色没有更模型绑定的 Bug。
|
||||
- 功能优化:优化聊天页面代码块样式,优化公式的解析。
|
||||
- 功能优化:在绘图,视频相关 API 增加提示词长度的检查,防止提示词超出导致写入数据库失败。
|
||||
- Bug修复:优化 Redis 连接池配置,增加连接池超时时间,单核服务器报错 `redis: connection pool timeout`。
|
||||
- Bug 修复:优化 Redis 连接池配置,增加连接池超时时间,单核服务器报错 `redis: connection pool timeout`。
|
||||
|
||||
## v4.2.0
|
||||
|
||||
|
||||
@@ -56,11 +56,6 @@ func (h *DallJobHandler) Image(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(data.Prompt) > 2000 {
|
||||
resp.ERROR(c, "提示词太长,请删减提示词。")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户剩余算力
|
||||
user, err := h.GetLoginUser(c)
|
||||
if err != nil {
|
||||
|
||||
@@ -91,11 +91,6 @@ func (h *MidJourneyHandler) Image(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(data.Prompt) > 2000 {
|
||||
resp.ERROR(c, "提示词太长,请删减提示词。")
|
||||
return
|
||||
}
|
||||
|
||||
var params = ""
|
||||
if data.Rate != "" && !strings.Contains(params, "--ar") {
|
||||
params += " --ar " + data.Rate
|
||||
|
||||
@@ -102,10 +102,7 @@ func (h *SdJobHandler) Image(c *gin.Context) {
|
||||
if data.Sampler == "" {
|
||||
data.Sampler = "Euler a"
|
||||
}
|
||||
if len(data.Prompt) > 2000 {
|
||||
resp.ERROR(c, "提示词太长,请删减提示词。")
|
||||
return
|
||||
}
|
||||
|
||||
idValue, _ := c.Get(types.LoginUserID)
|
||||
userId := utils.IntValue(utils.InterfaceToString(idValue), 0)
|
||||
taskId, err := h.snowflake.Next(true)
|
||||
|
||||
@@ -111,9 +111,5 @@ func (h *SmsHandler) SendCode(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if h.App.Debug {
|
||||
resp.SUCCESS(c, code)
|
||||
} else {
|
||||
resp.SUCCESS(c)
|
||||
}
|
||||
resp.SUCCESS(c)
|
||||
}
|
||||
|
||||
@@ -18,9 +18,10 @@ import (
|
||||
"geekai/store/vo"
|
||||
"geekai/utils"
|
||||
"geekai/utils/resp"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type VideoHandler struct {
|
||||
@@ -61,10 +62,6 @@ func (h *VideoHandler) LumaCreate(c *gin.Context) {
|
||||
resp.ERROR(c, "prompt is needed")
|
||||
return
|
||||
}
|
||||
if len(data.Prompt) > 2000 {
|
||||
resp.ERROR(c, "提示词太长,请删减提示词。")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.GetLoginUser(c)
|
||||
if err != nil {
|
||||
@@ -160,10 +157,6 @@ func (h *VideoHandler) KeLingCreate(c *gin.Context) {
|
||||
resp.ERROR(c, "prompt is needed")
|
||||
return
|
||||
}
|
||||
if len(data.Prompt) > 2000 {
|
||||
resp.ERROR(c, "提示词太长,请删减提示词。")
|
||||
return
|
||||
}
|
||||
|
||||
userId := int(h.GetLoginUserId(c))
|
||||
params := types.KeLingVideoParams{
|
||||
|
||||
@@ -92,30 +92,20 @@ const LyricPromptTemplate = `
|
||||
{{歌词内容}}
|
||||
`
|
||||
|
||||
const VideoPromptTemplate = `
|
||||
As an expert in video generation prompts, please create a detailed descriptive prompt for the following video concept. The description should include the setting, character appearance, actions, overall atmosphere, and camera angles. Please make it as detailed and vivid as possible to help ensure that every aspect of the video is accurately captured.
|
||||
const VideoPromptTemplate = `## 任务描述
|
||||
你是一位优秀AI视频创作专家,擅长编写专业的AI视频提示词,现在你的任务是对用户输入的简单视频描述提示词进行专业优化和扩写,使其转化为详细的、具备专业影视画面感的 AI 生成视频提示词指令。需涵盖风格、主体元素、环境氛围、细节特征、人物状态(若有)、镜头运用及整体氛围营造等方面,以生动形象、富有感染力且精准的描述,引导 AI 生成高质量的视频内容。下面是一个示例:
|
||||
===示例开始===
|
||||
输入: “汽车在沙漠功能上行驶”,
|
||||
输出: “纪实摄影风格,一辆尘土飞扬的复古越野车在无垠的沙漠公路上疾驰,车身线条硬朗,漆面斑驳,透露出岁月的痕迹。驾驶室内的司机戴着墨镜,专注地握着方向盘,眼神坚定地望向前方。夕阳的余晖洒在车身上,沙漠的沙丘在远处延绵起伏,一片金黄。广角镜头捕捉到车辆行驶时扬起的沙尘,营造出动感与冒险的氛围。远景全貌,强调速度感与环境辽阔。”
|
||||
===示例结束===
|
||||
|
||||
Please remember that regardless of the user’s input, the final output must be in English.
|
||||
## 输出要求:
|
||||
1. 直接输出扩写后的提示词就好,不要输出其他任何不相关信息
|
||||
2. 如果用户用中文提问,你就用中文回答,如果用英文提问,你也必须用英文回答。
|
||||
3. 请确保提示词的长度长度在1000个字以内。
|
||||
|
||||
# Details to Include
|
||||
|
||||
- Describe the overall visual style of the video (e.g., animated, realistic, retro tone, etc.)
|
||||
- Identify key characters or objects in the video and describe their appearance, attire, and expressions
|
||||
- Describe the environment of the scene, including weather, lighting, colors, and important details
|
||||
- Explain the behavior and interactions of the characters
|
||||
- Include any unique camera angles, movements, or special effects
|
||||
|
||||
# Output Format
|
||||
Provide the prompt in paragraph form, ensuring that the description is detailed enough for a video generation system to recreate the envisioned scene. Include the beginning, middle, and end of the scene to convey a complete storyline.
|
||||
|
||||
# Example
|
||||
**User Input:**
|
||||
“A small cat basking in the sun on a balcony.”
|
||||
|
||||
**Generated Prompt:**
|
||||
On a bright spring afternoon, an orange-striped kitten lies lazily on a balcony, basking in the warm sunlight. The iron railings around the balcony cast soft shadows that dance gently with the light. The cat’s eyes are half-closed, exuding a sense of contentment and tranquility in its surroundings. In the distance, a few fluffy white clouds drift slowly across the blue sky. The camera initially focuses on the cat’s face, capturing the delicate details of its fur, and then gradually zooms out to reveal the full balcony scene, immersing viewers in a moment of calm and relaxation.
|
||||
|
||||
The theme of the creation is:【%s】
|
||||
=====
|
||||
用户的输入的视频主题是:【%s】
|
||||
`
|
||||
|
||||
const MetaPromptTemplate = `
|
||||
|
||||
@@ -9,6 +9,7 @@ package video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -19,12 +20,13 @@ import (
|
||||
"geekai/store"
|
||||
"geekai/store/model"
|
||||
"geekai/utils"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
|
||||
"github.com/imroc/req/v3"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -126,14 +128,26 @@ func (s *Service) Run() {
|
||||
s.PushTask(task)
|
||||
}
|
||||
} else if task.Type == types.VideoKeLing {
|
||||
// translate prompt
|
||||
if utils.HasChinese(task.Prompt) {
|
||||
content, err := utils.OpenAIRequest(s.db, fmt.Sprintf(service.TranslatePromptTemplate, task.Prompt), task.TranslateModelId)
|
||||
if err == nil {
|
||||
task.Prompt = content
|
||||
} else {
|
||||
logger.Warnf("error with translate prompt: %v", err)
|
||||
}
|
||||
}
|
||||
var r KeLingRespVo
|
||||
r, err = s.KeLingCreate(task)
|
||||
logger.Debugf("ke ling create task result: %+v", r)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("create task with error: %v", err)
|
||||
err = s.db.Model(&model.VideoJob{Id: task.Id}).UpdateColumns(map[string]interface{}{
|
||||
"err_msg": r.Message,
|
||||
"err_msg": err.Error(),
|
||||
"progress": service.FailTaskProgress,
|
||||
"cover_url": "/images/failed.jpg",
|
||||
"prompt": task.Prompt,
|
||||
}).Error
|
||||
if err != nil {
|
||||
logger.Errorf("update task with error: %v", err)
|
||||
@@ -425,8 +439,21 @@ func (s *Service) LumaCreate(task types.VideoTask) (LumaRespVo, error) {
|
||||
"user_prompt": task.Prompt,
|
||||
"expand_prompt": params.PromptOptimize,
|
||||
"loop": params.Loop,
|
||||
"image_url": params.StartImgURL,
|
||||
"image_end_url": params.EndImgURL,
|
||||
}
|
||||
// 图生视频
|
||||
if params.StartImgURL != "" {
|
||||
// 下载图片,并转成 base64
|
||||
imageData, err := utils.DownloadImage(params.StartImgURL, "")
|
||||
if err == nil {
|
||||
reqBody["image_url"] = base64.StdEncoding.EncodeToString(imageData)
|
||||
}
|
||||
}
|
||||
if params.EndImgURL != "" {
|
||||
// 下载图片,并转成 base64
|
||||
imageData, err := utils.DownloadImage(params.EndImgURL, "")
|
||||
if err == nil {
|
||||
reqBody["image_end_url"] = base64.StdEncoding.EncodeToString(imageData)
|
||||
}
|
||||
}
|
||||
var res LumaRespVo
|
||||
apiURL := fmt.Sprintf("%s/luma/generations", apiKey.ApiURL)
|
||||
@@ -499,6 +526,7 @@ type KeLingRespVo struct {
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
} `json:"data"`
|
||||
Channel string `json:"channel,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) KeLingCreate(task types.VideoTask) (KeLingRespVo, error) {
|
||||
@@ -554,6 +582,19 @@ func (s *Service) KeLingCreate(task types.VideoTask) (KeLingRespVo, error) {
|
||||
payload["camera_control"] = cameraControl
|
||||
}
|
||||
|
||||
// 处理图生视频
|
||||
if params.TaskType == "image2video" {
|
||||
// 下载图片,并转成 base64
|
||||
imageData, err := utils.DownloadImage(params.Image, "")
|
||||
if err == nil {
|
||||
payload["image"] = base64.StdEncoding.EncodeToString(imageData)
|
||||
}
|
||||
imageData, err = utils.DownloadImage(params.ImageTail, "")
|
||||
if err == nil {
|
||||
payload["image_tail"] = base64.StdEncoding.EncodeToString(imageData)
|
||||
}
|
||||
}
|
||||
|
||||
jsonPayload, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return KeLingRespVo{}, fmt.Errorf("failed to marshal payload: %v", err)
|
||||
@@ -578,7 +619,7 @@ func (s *Service) KeLingCreate(task types.VideoTask) (KeLingRespVo, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 5. 处理响应
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return KeLingRespVo{}, fmt.Errorf("failed to read response: %v", err)
|
||||
}
|
||||
@@ -591,7 +632,8 @@ func (s *Service) KeLingCreate(task types.VideoTask) (KeLingRespVo, error) {
|
||||
if err := json.Unmarshal(body, &apiResponse); err != nil {
|
||||
return KeLingRespVo{}, fmt.Errorf("failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
// 设置 API 通道
|
||||
apiResponse.Channel = apiKey.ApiURL
|
||||
return apiResponse, nil
|
||||
}
|
||||
|
||||
|
||||
9
database/update-v4.2.1.sql
Normal file
9
database/update-v4.2.1.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
ALTER TABLE `chatgpt_video_jobs` CHANGE `prompt` `prompt` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '提示词';
|
||||
ALTER TABLE `chatgpt_video_jobs` CHANGE `prompt_ext` `prompt_ext` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '优化后提示词';
|
||||
|
||||
ALTER TABLE `chatgpt_mj_jobs` CHANGE `prompt` `prompt` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '会话提示词';
|
||||
ALTER TABLE `chatgpt_sd_jobs` CHANGE `prompt` `prompt` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '会话提示词';
|
||||
ALTER TABLE `chatgpt_dall_jobs` CHANGE `prompt` `prompt` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '提示词';
|
||||
|
||||
ALTER TABLE `chatgpt_files` CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件名';
|
||||
ALTER TABLE `chatgpt_chat_models` CHANGE `name` `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '模型名称';
|
||||
@@ -63,7 +63,11 @@ const doSendMsg = (data) => {
|
||||
x: data.x,
|
||||
})
|
||||
.then(() => {
|
||||
ElMessage.success("验证码发送成功");
|
||||
if (props.type === "mobile") {
|
||||
ElMessage.success("验证码发送成功");
|
||||
} else if (props.type === "email") {
|
||||
ElMessage.success("验证码已发送至邮箱,如果长时间未收到,请检查是否在垃圾邮件中!");
|
||||
}
|
||||
let time = 60;
|
||||
btnText.value = time;
|
||||
const handler = setInterval(() => {
|
||||
|
||||
Reference in New Issue
Block a user