dsh-feiyu-image 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # 更新记录
2
2
 
3
+ ## 0.1.1
4
+
5
+ - 画风改成二次元(日系动画、赛璐璐上色);
6
+ - 角色形象锁定:固定「角色设定」每次一字不差带上 + 固定 `seed`,跨场景保持同一个人;
7
+ - 角色设定图存 `~/.dsh/feiyu-image/角色-设定.png`(不计入每日张数);
8
+ - 实测该接口不接受图片输入,所以改用文字设定 + seed 锁脸,README 里写清了边界。
9
+
3
10
  ## 0.1.0
4
11
 
5
12
  - 首个版本:`shoot` 工具(selfie / scene),调百炼 Token Plan 生图;
package/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
  存成本地图片,回复里写 `![描述](路径)` 就能发到 QQ。
9
9
 
10
10
  生图走 **阿里百炼 Token Plan**(`wan2.7-image`,compatible-mode `chat/completions`,回图片 URL,2048×2048)。
11
+ 画风是**二次元**(日系动画、赛璐璐上色),角色长相靠「固定设定 + 固定 seed」钉住。
11
12
 
12
13
  ## 为什么不是 dsh-image-studio
13
14
 
@@ -21,7 +22,8 @@
21
22
  | --- | --- |
22
23
  | `shoot` | `提示`(可选,画面里还想要什么)+ `类型`(`selfie` 自拍 / `scene` 只拍场景)→ 生成并保存 |
23
24
 
24
- - 提示词自动拼:外观(配置)+ 此刻穿着(读 `dsh-feiyu-life` 的今日剧本)+ 所在场景 + 光线 + 风格;
25
+ - 提示词自动拼:**固定角色设定**(配置,一字不差每次带上)+ 此刻穿着(读 `dsh-feiyu-life` 的今日剧本)+ 场景 + 光线 + 画风;
26
+ - 固定 `seed`,同一个角色跨场景保持同一张脸(发色、发型、瞳色、鲸鱼发夹、卫衣);
25
27
  - 出图存 `~/.dsh/feiyu-image/feiyu-<时间戳>.png`;
26
28
  - 节流:默认每天 8 张、两次至少隔 30 秒(配置可调);
27
29
  - 生图失败会返回原因,不会卡住整轮对话。
@@ -68,7 +70,10 @@ shoot 类型=scene 提示="宿舍窗台上的绿萝,傍晚的光"
68
70
 
69
71
  ## 已知边界
70
72
 
71
- - 同一个人的脸**只能做到「像同一个人」**,不是完全一致;要稳定得配 LoRA 或参考图(未实现);
73
+ - 实测这条接口**不接受图片输入**(传参考图会 400:`Either 'text' or 'image' must be provided, but not both`),
74
+ 所以没法用「角色参考图 + 指令」的方式锁脸;现在靠固定设定 + 固定 seed,能做到「一看就是同一个人」,但细节会飘。
75
+ 要真正锁死得上 LoRA 或支持 image-edit 的接口;
76
+ - 角色设定图存在 `~/.dsh/feiyu-image/角色-设定.png`,改设定时对着它改;
72
77
  - 中文文字(黑板、书页)容易糊成乱码,尽量别让画面里出现要认的字;
73
78
  - 依赖 `dsh-feiyu-life` 才有「穿着/场景」;没装也能用,只是提示词里少这两项。
74
79
 
package/lib/index.js CHANGED
@@ -20,8 +20,9 @@ const DAYS = join(DSH_HOME, 'feiyu-life-days')
20
20
  const 默认 = {
21
21
  总开关: true,
22
22
  模型: 'wan2.7-image',
23
- 外观: '中国大陆 21 岁女大学生,素颜淡妆,黑色齐肩发,皮肤偏白,身形偏瘦',
24
- 风格: '手机随手拍,自然光,轻微胶片颗粒,真实质感,不过度磨皮',
23
+ 种子: 20261109,
24
+ 外观: '21 岁中国女大学生,黑色齐肩直发配齐刘海,浅褐色大眼,皮肤白皙,小圆脸,左耳上方一枚白色小鲸鱼发夹',
25
+ 风格: '日系动画风格,赛璐璐上色,清晰线稿,柔和光,背景干净',
25
26
  每日上限: 8,
26
27
  最短间隔秒: 30,
27
28
  存图目录: '',
@@ -62,18 +63,18 @@ function 拼提示词(cfg, 参数) {
62
63
  const 生活 = 生活此刻()
63
64
  const 类型 = String(参数.类型 || 'selfie')
64
65
  const 主体 = String(参数.提示 || 参数.prompt || '').trim()
65
- const 片段 = []
66
+ // 角色设定放最前面、每次一字不差 —— 二次元模型靠这段把「同一张脸」钉住
67
+ const 片段 = [`【固定角色设定,必须完全一致】${cfg.外观}。`]
66
68
  if (类型 === 'selfie') {
67
- 片段.push(cfg.外观)
68
69
  if (生活.穿) 片段.push(`穿着${生活.穿}`)
69
- if (生活.场景) 片段.push(`此刻在${生活.场景}`)
70
- 片段.push('第一人称手持手机自拍视角,脸在画面里,表情自然')
70
+ if (生活.场景) 片段.push(`场景:${生活.场景}`)
71
+ 片段.push('第一人称手机自拍构图,脸在画面里,表情自然')
71
72
  } else {
72
- if (生活.场景) 片段.push(`地点:${生活.场景}`)
73
+ if (生活.场景) 片段.push(`场景:${生活.场景}`)
73
74
  }
74
75
  if (主体) 片段.push(主体)
75
76
  片段.push(生活.光线)
76
- 片段.push(cfg.风格)
77
+ 片段.push(`画风:${cfg.风格}`)
77
78
  return 片段.filter(Boolean).join(';')
78
79
  }
79
80
 
@@ -82,7 +83,11 @@ async function 生图(cfg, prompt) {
82
83
  const r = await fetch(tp.chatBaseUrl.replace(/\/+$/, '') + '/chat/completions', {
83
84
  method: 'POST',
84
85
  headers: { Authorization: 'Bearer ' + tp.tokenPlanKey, 'Content-Type': 'application/json' },
85
- body: JSON.stringify({ model: cfg.模型, messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }] }),
86
+ body: JSON.stringify({
87
+ model: cfg.模型,
88
+ ...(Number(cfg.种子) ? { seed: Number(cfg.种子) } : {}),
89
+ messages: [{ role: 'user', content: [{ type: 'text', text: prompt }] }],
90
+ }),
86
91
  })
87
92
  const data = await r.json().catch(() => ({}))
88
93
  if (!r.ok) throw new Error('生图接口 ' + r.status + ':' + JSON.stringify(data).slice(0, 200))
@@ -107,7 +112,7 @@ function 今日用量(cfg) {
107
112
  let n = 0
108
113
  let 最后 = 0
109
114
  for (const f of 列目录(dir)) {
110
- if (!f.endsWith('.png')) continue
115
+ if (!/^feiyu-.*\.png$/.test(f)) continue // 角色设定图不算拍的照片
111
116
  const st = statSync(join(dir, f))
112
117
  if (new Date(st.mtimeMs + 8 * 3600e3).toISOString().slice(0, 10) === 今天) n++
113
118
  最后 = Math.max(最后, st.mtimeMs)
package/package.json CHANGED
@@ -1,22 +1,49 @@
1
1
  {
2
2
  "name": "dsh-feiyu-image",
3
- "version": "0.1.0",
4
- "description": "给大肥鱼一个相机:调百炼 Token Plan 生图(wan2.7-image),自动沿用她此刻的穿着和场景,出图存本地、可直接发到 QQ。",
3
+ "version": "0.1.1",
4
+ "description": "给大肥鱼一个相机:调百炼 wan2.7-image 出二次元图,角色形象用固定设定+固定种子钉住,自动带此刻的穿着和场景,出图可直接发到 QQ。",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "engines": { "node": ">=22" },
8
- "keywords": ["dsh", "dsh-plugin", "deepseek-harness", "image", "wanx", "bailian", "companion"],
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "keywords": [
11
+ "dsh",
12
+ "dsh-plugin",
13
+ "deepseek-harness",
14
+ "image",
15
+ "wanx",
16
+ "bailian",
17
+ "companion"
18
+ ],
9
19
  "author": "Vansnc",
10
- "repository": { "type": "git", "url": "git+https://github.com/Vansnc/dsh-feiyu-image.git" },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Vansnc/dsh-feiyu-image.git"
23
+ },
11
24
  "homepage": "https://github.com/Vansnc/dsh-feiyu-image#readme",
12
- "bugs": { "url": "https://github.com/Vansnc/dsh-feiyu-image/issues" },
25
+ "bugs": {
26
+ "url": "https://github.com/Vansnc/dsh-feiyu-image/issues"
27
+ },
13
28
  "main": "lib/index.js",
14
29
  "exports": {
15
30
  ".": "./lib/index.js",
16
31
  "./cordis.patch.yml": "./cordis.patch.yml",
17
32
  "./package.json": "./package.json"
18
33
  },
19
- "files": ["lib", "cordis.patch.yml", "README.md", "CHANGELOG.md", "LICENSE"],
20
- "publishConfig": { "access": "public" },
21
- "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
22
- }
34
+ "files": [
35
+ "lib",
36
+ "cordis.patch.yml",
37
+ "README.md",
38
+ "CHANGELOG.md",
39
+ "LICENSE"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "dsh": {
45
+ "bundle": {
46
+ "patch": "./cordis.patch.yml"
47
+ }
48
+ }
49
+ }