Skip to content

Commit

Permalink
完善流程
Browse files Browse the repository at this point in the history
  • Loading branch information
shitiandmw committed Nov 23, 2023
1 parent e39a463 commit 70cc910
Show file tree
Hide file tree
Showing 24 changed files with 465 additions and 217 deletions.
53 changes: 47 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
sd-pics-hub
sd-pics-hub (圆梦照相馆)
===============


<div style="font-size: 1.5rem;">
<a href="./README.md">English</a> |
<a href="./README_ZH.md">中文</a>
<a href="./README_EN.md">English</a> |
<a href="./README.md">中文</a>
</div>
</br>

这是一个利用stable diffusion生成个人AI写真的应用,你只需要上传一张清晰的自拍照,就可以生成多种风格的AI写真

This is an application that utilizes stable diffusion to create personalized AI portraits. You simply need to upload a clear selfie, and the application will generate AI portraits in various styles.
## 目录结构

## Copyright Information
总体目录结构如下

sd-pics-hub is released under the [Apache License 2.0]() open-source license and is available for free use.
```
├─sd-pics-hub
│ ├─api (数据接口部分,使用Egg.js框架)
│ ├─client 客户端,暂定使用hbuild+vue构建,支持多端发布)
│ ├─doc (文档、资料等)
│ │ ├─database.md (数据结构)
│ ├─worker (应用和stable-diffusion沟通的中间件)
│ ├─docker-compose.yml (用于一键启动docker-compose容器编排配置文件)
│ ├─README.md (项目说明文档)
│ ├─README_ZH.md (项目说明文档-中文)
```
## 功能规划

**1.0 版本**

1. 通过roop处理的写真
2. 通过lora模型处理的写真
3. 通过人为干预精修处理的写真,做高级AI摄影作品

## 目前功能

如下图所示,目前可实现使用stable-diffusion生成各种场景的写真照,用roop二次处理后形成自己的写真照

![demo](./demo.png)

## 用到的技术

+ 前端 `uni`,`vue`,`vuex`,`taiwind`...
+ 后端 `nodejs`,`eggjs`,`socket.io`,`redis`,`mongo`,`cos`...
+ 其他 `stable-diffusion`,`nginx`,`mongodb-express`...

## 启动方式

docker-compose up -d

## 你需要关注或修改的配置
...

## 版权信息

sd-pics-hub 遵循 [Apache License 2.0]() 开源协议发布,并提供免费使用。

Copyright © 2023 by EMart
40 changes: 0 additions & 40 deletions README_ZH.md

This file was deleted.

2 changes: 1 addition & 1 deletion api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ RUN npm i --production --registry=https://registry.npmmirror.com
# 拷贝所有源代码到工作目录
COPY . /app

RUN cd /app/lib/plugins/egg-lu-redis && npm i --registry=https://registry.npmmirror.com
# RUN cd /app/lib/plugins/egg-lu-redis && npm i --registry=https://registry.npmmirror.com


WORKDIR /app
Expand Down
2 changes: 2 additions & 0 deletions api/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class AppBootHook {
// // 可以做一些数据初始化等操作,这些操作成功才会启动应用
// // 例如:从数据库加载数据到内存缓存
// this.app.cacheData = await this.app.model.query(QUERY_CACHE_SQL);
const ctx = this.app.createAnonymousContext();
ctx.service.template.init();
}

async didReady() {
Expand Down
49 changes: 47 additions & 2 deletions api/app/controller/doppelganger.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,55 @@ class DoppelgangerController extends Controller {
}

async getList() {
const { ctx } = this;
let list = await ctx.service.doppelganger.getList(ctx.user.id);
const { ctx, app } = this;
const input = ctx.request.query;
// 验证参数合法性
const errors = app.validator.validate(
{
last_id: { type: "string", required: false, max: 24, min: 24 },
},
input
);
if (errors && errors.length > 0)
throw ctx.ltool.err(`"${errors[0].field}"${errors[0].message}`, 40011);
let list = await ctx.service.doppelganger.getList(
ctx.user.id,
input.last_id
);
ctx.body = list;
}
/**
* 删除某个数字分身
*/
async del() {
const { ctx, app } = this;
const input = ctx.request.body;
// 验证参数合法性
const errors = app.validator.validate(
{
id: { type: "string", required: false, max: 24, min: 24 },
},
input
);
if (errors && errors.length > 0)
throw ctx.ltool.err(`"${errors[0].field}"${errors[0].message}`, 40011);
let doppelganger = await ctx.service.doppelganger.getInfo(input.id);
if (!doppelganger || doppelganger.user_id != ctx.user.id)
throw ctx.ltool.err("删除数字分身失败", 40012);

await ctx.service.doppelganger.del(input.id);

ctx.body = "success";
}

/**
* 获得用户可用分身的数量
*/
async getUserCount(){
const { ctx, app } = this;
let count = await ctx.service.doppelganger.getUserCount(ctx.user.id);
ctx.body = count;
}

async getCosToken() {
const { ctx, app } = this;
Expand Down
2 changes: 2 additions & 0 deletions api/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ module.exports = app => {
router.post('/doppelganger/create', controller.doppelganger.create); // 创建数字分身
router.get('/doppelganger/list', controller.doppelganger.getList); // 查看数字分身列表
router.get('/doppelganger/getcostoken', controller.doppelganger.getCosToken);
router.post('/doppelganger/del', controller.doppelganger.del);
router.get('/doppelganger/count', controller.doppelganger.getUserCount);

/**---------------- 任务相关 ----------------**/
router.post('/task/generate_portrait', controller.task.generatePortrait); // 创建任务写真任务
Expand Down
53 changes: 34 additions & 19 deletions api/app/service/doppelganger.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ class DoppelgangerSevice extends Service {
* 下载图片并压缩上传,获得压缩的图片地址
* @param {*} url 远程图片地址(不带域名时默认使用cos域名)
* @param {*} cos_path cos上传路径(不要带图片名称)
* @param {*} width
* @param {*} height
* @param {*} quality
* @returns
* @param {*} width
* @param {*} height
* @param {*} quality
* @returns
*/
async compressUploadImg(url,cos_path,width, height, quality) {
let {ctx,app} = this;
async compressUploadImg(url, cos_path, width, height, quality) {
let { ctx, app } = this;
// 系统文件分割符
let __ = path.sep;
let day = ctx.ltool.formatTime2(new Date().valueOf(), "YYYYMMDD");
Expand All @@ -25,21 +25,24 @@ class DoppelgangerSevice extends Service {
// 若不存在,则创建此目录
if (!fs.existsSync(download_path))
fs.mkdirSync(download_path, { recursive: true });
if (!url.startsWith('http://') && !url.startsWith('https://'))
if (!url.startsWith("http://") && !url.startsWith("https://"))
url = app.config.tencent.cos.host + url;
// 下载图片到指定的目录(1分钟内不重复下载)
let downloadFileName = await this.app.redis.sGet('download:' + ctx.ltool.md5(url), async () => {
return await ctx.ltool.downloadImg(
url,
download_path
);
});
let downloadFileName = await this.app.redis.sGet(
"download:" + ctx.ltool.md5(url),
async () => {
return await ctx.ltool.downloadImg(url, download_path);
}
);
let compress_img = `${cos_path}${downloadFileName}`;
let system_img = `${download_path}${__}${downloadFileName}`;
await ctx.service.tencentCos.uploadImage(
system_img,
compress_img,
width,height,quality);
width,
height,
quality
);
return compress_img;
}

Expand Down Expand Up @@ -79,11 +82,23 @@ class DoppelgangerSevice extends Service {
* 获得用户的数字分身列表
* @param {*} user_id
*/
async getList(user_id) {
return await this.ctx.model.Doppelganger.find(
{ user_id: user_id, is_delete: 0 },
"name type train_imgs train_status"
);
async getList(user_id, last_id = "", page_size = 10) {
let query = { user_id: user_id, is_delete: 0 };
if (last_id != "") query._id = { $lt: last_id };
let list = await this.ctx.model.Doppelganger.find(
query,
"name type train_imgs train_status create_time"
)
.sort({ _id: -1 })
.limit(page_size);
if (!list) return [];
let res_list=[];
for (let index = 0; index < list.length; index++) {
let item = list[index].toJSON();
item.create_time_format = this.ctx.ltool.formatTime(item.create_time,2);
res_list.push(item);
}
return res_list;
}

/**
Expand Down
Loading

0 comments on commit 70cc910

Please sign in to comment.