dsh-pictor 0.1.0 → 0.2.0
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/README.md +47 -50
- package/README.zh-cn.md +78 -0
- package/docs/screenshot-empty.png +0 -0
- package/docs/screenshot-workbench.png +0 -0
- package/lib/client.js +54 -13
- package/lib/image-providers.js +1 -1
- package/package.json +1 -1
- package/references/domain/base-prompt.md +11 -13
- package/references/domain/styles/bandung-circuit.md +9 -16
package/README.md
CHANGED
|
@@ -1,81 +1,78 @@
|
|
|
1
|
-
# Pictor —
|
|
1
|
+
# Pictor — Document-to-Infographic Workbench
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[ EN | [中文](./README.zh-cn.md) ]
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
Pictor turns a document into a set of infographics. It is a [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) plugin published to npm as [`dsh-pictor`](https://www.npmjs.com/package/dsh-pictor), with source at [github.com/bandung-circuits/pictor](https://github.com/bandung-circuits/pictor). Each project is one coherent agent session that carries the whole extract → advise → render flow; the GUI is a thin layer that only shows file-fact state and shapes your input. Design decisions live in [docs/DESIGN.zh.md](docs/DESIGN.zh.md) (Chinese).
|
|
6
6
|
|
|
7
|
-
Pictor
|
|
7
|
+

|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Installation
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- 唯一入口是 dsh 左下角 footer 按钮「Pictor」,打开 shell.overlay 工作台:左栏列项目,右栏显示当前项目。
|
|
13
|
-
- 项目步骤固定三步:提取结构 → 方案设计 → 渲染出图。每步由你做决定后,会话在同一会话里接着执行(agent-loop 的 resume 语义),不重跑已有阶段。
|
|
14
|
-
- 项目名取文档首行,信息条内随时可改名,只动 index.json。
|
|
15
|
-
- 状态只由文件事实驱动;运行中判定以 dsh agent 注册表为权威;把你对 orchestration 的关心都留给会话。
|
|
11
|
+
Pictor is published to npm as `dsh-pictor`:
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
```bash
|
|
14
|
+
dsh plugin --profile <profile> add dsh-pictor
|
|
15
|
+
```
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
- 画图模型:在工作台「设置」里配置(seedream / gemini / openai-compatible / mock)。密钥经 dsh 凭据子系统保存,配置只留引用。
|
|
17
|
+
Replace `<profile>` with the target profile name (e.g. `desktop`, `web`) and start that profile. A **Pictor** button appears at the bottom-left of the dsh footer. On first use a `~/.pictor` home is provisioned and registered as a DSH workspace; project sessions group under "Pictor" in the sidebar. For development installs (local link, live-reload while editing source) see [docs/DESIGN.zh.md](docs/DESIGN.zh.md).
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
**For non-technical users**: install [DSH Desktop](https://dshdesktop.com/en/) (a community project, not an official DeepSeek product; it bundles the DeepSeek Harness runtime as a ready-to-run desktop app) and let the agent install the plugin for you — just send this one message in dsh:
|
|
23
20
|
|
|
24
|
-
Pictor
|
|
21
|
+
> Install the Pictor plugin from the npm package `dsh-pictor` into the current profile, restart if needed, and confirm when a Pictor button appears at the bottom left.
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
dsh plugin --profile <profile> add dsh-pictor
|
|
28
|
-
```
|
|
23
|
+
## Usage
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
1. Open the workbench via the **Pictor** footer button and click **New project**: upload a file (`md` / `txt` / `docx` / `pdf` / image) or paste content (from Word or the web; formatting is kept, stored as sanitised HTML).
|
|
26
|
+
2. The session reads and normalises the source (`docx` / `pdf` / image / HTML → `document.md` via DSH tooling) and proposes candidate structures.
|
|
27
|
+
3. Tick the structures and confirm; the session moves to proposal design. Tick a proposal, pick an aspect ratio, and click **Render selected**.
|
|
28
|
+
4. Preview and download from the result grid; open the discussion panel to talk to the session at any point, or use the step bar to go back and redo existing artifacts.
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+

|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
2. 会话读取并规整来源(docx/pdf/图片/HTML → document.md 由会话用 dsh 工具完成),提取候选结构。
|
|
36
|
-
3. 勾选结构,确认,会话进入方案设计;勾选方案,设画面比例,点「渲染所选方案」。
|
|
37
|
-
4. 结果网格里预览、下载;随时可展开讨论面板对会话说话,或点步骤条回到已有产物的步骤重做。
|
|
32
|
+
## Form
|
|
38
33
|
|
|
39
|
-
|
|
34
|
+
- A `~/.pictor` home is created on first use (registered as a DSH workspace; sidebar shows "Pictor").
|
|
35
|
+
- The only entry point is the bottom-left **Pictor** footer button, which toggles a `shell.overlay` workbench: projects on the left, the selected project on the right.
|
|
36
|
+
- Every project has three fixed steps: extract structures → design proposals → render images. After each human decision the **same session resumes** (agent-loop resume semantics); existing artifacts are never re-derived.
|
|
37
|
+
- The project name is taken from the document's first line and can be renamed any time in the info bar (touches only `index.json`).
|
|
38
|
+
- State is driven purely by file facts; running status is authoritative via the DSH agent registry; orchestration concerns are left to the session.
|
|
39
|
+
|
|
40
|
+
## Two models
|
|
41
|
+
|
|
42
|
+
- **Reasoner**: extract and advise run on DSH's current default model — no Pictor configuration needed.
|
|
43
|
+
- **Image model**: configured in the workbench Settings (`seedream` / `gemini` / `openai-compatible` / `mock`). API keys go through DSH's credential subsystem; the configuration stores only a reference.
|
|
44
|
+
|
|
45
|
+
## Development & verification
|
|
40
46
|
|
|
41
47
|
```bash
|
|
42
|
-
npm run build
|
|
43
|
-
npm run verify
|
|
44
|
-
npm run verify:integration # L3 transport
|
|
45
|
-
npm run test:e2e
|
|
48
|
+
npm run build # esbuild build of host + bundled client
|
|
49
|
+
npm run verify # L1 unit + L2 host integration (mock ctx, 15 items)
|
|
50
|
+
npm run verify:integration # L3 transport smoke against a real dsh web
|
|
51
|
+
npm run test:e2e # L4a browser e2e (fixture data, deterministic)
|
|
46
52
|
```
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
Test-layer definitions and rationale: [docs/DESIGN.zh.md](docs/DESIGN.zh.md) §7.
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
### Layout
|
|
51
57
|
|
|
52
58
|
```
|
|
53
59
|
pictor/
|
|
54
|
-
├── agents/ #
|
|
60
|
+
├── agents/ # declarative blueprints (orchestrator/extractor/advisor/renderer)
|
|
55
61
|
├── references/domain/ # base-prompt + layouts/ + styles/ + diagram-types/ + visual-principles
|
|
56
|
-
├── src/host/ #
|
|
57
|
-
├── src/client/ #
|
|
62
|
+
├── src/host/ # plugin host: ~/.pictor, project sessions, /pictor RPC, image generation
|
|
63
|
+
├── src/client/ # workbench UI (React.createElement + theme variables)
|
|
58
64
|
├── e2e/ # L4a Playwright
|
|
59
|
-
├── verify.mjs # L1+L2
|
|
65
|
+
├── verify.mjs # L1+L2 offline smoke
|
|
60
66
|
└── scripts/ # build + transport-smoke
|
|
61
67
|
```
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
## 许可证
|
|
66
|
-
|
|
67
|
-
MIT,见 [LICENSE](LICENSE)。
|
|
68
|
-
|
|
69
|
-
---
|
|
69
|
+
Data home `~/.pictor/`: `index.json` (project index), `pictor-config.json` (image-model configuration), `<project-id>/` (self-contained: agents/references snapshot + `10.input` + `11.extraction` + `12.advice` + `output`).
|
|
70
70
|
|
|
71
|
-
##
|
|
71
|
+
## Documents
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
- Design decisions: [docs/DESIGN.zh.md](docs/DESIGN.zh.md) (Chinese)
|
|
74
|
+
- Verification checklist: [docs/verification-checklist.zh.md](docs/verification-checklist.zh.md) (Chinese)
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
- The only entry point is the bottom-left "Pictor" footer button, which toggles a `shell.overlay` workbench: projects on the left, the selected project on the right.
|
|
77
|
-
- Every project has three fixed steps: extract structures → design proposals → render images. After each human decision the **same session resumes** to keep working; existing artifacts are never re-derived (file facts are the source of truth).
|
|
78
|
-
- Reasoner: DSH's default model (no Pictor config). Image model: configured in the workbench Settings (seedream / gemini / openai-compatible / mock); the API key goes through DSH's credentials subsystem.
|
|
79
|
-
- Tests: L1 unit + L2 host integration (`npm run verify`), L3 real-dsh transport smoke (`npm run verify:integration`), L4a browser e2e against a seeded fixture (`npm run test:e2e`).
|
|
76
|
+
## License
|
|
80
77
|
|
|
81
|
-
MIT
|
|
78
|
+
MIT — see [LICENSE](LICENSE). Third-party content notices: [NOTICE.md](NOTICE.md).
|
package/README.zh-cn.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Pictor — 文档转信息图工作台
|
|
2
|
+
|
|
3
|
+
[ [English](./README.md) | 中文 ]
|
|
4
|
+
|
|
5
|
+
Pictor 把一份文档变成一组信息图。它是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)的插件,已发布到 npm 包 [`dsh-pictor`](https://www.npmjs.com/package/dsh-pictor),源码仓库在 [github.com/bandung-circuits/pictor](https://github.com/bandung-circuits/pictor)。每新建一个项目,宿主创建一个连贯的会话作为项目会话,整个「提取 → 方案 → 渲染」流程都在这个会话里推进,GUI 只做两件事:查看信息、规整输入。设计文档见 [docs/DESIGN.zh.md](docs/DESIGN.zh.md)。
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
已发布到 npm,安装即一行命令:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
dsh plugin --profile <profile> add dsh-pictor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
把 `<profile>` 换成目标 profile 名(如 `desktop`、`web`),然后启动该 profile,dsh 左下角会出现「Pictor」按钮。首次使用自动生成 `~/.pictor` 工作区(注册为 dsh 工作区,侧栏归组见「Pictor」)。开发安装(改动源码实时联调)见 [docs/DESIGN.zh.md](docs/DESIGN.zh.md)。
|
|
18
|
+
|
|
19
|
+
非技术用户可安装 [DSH Desktop](https://dshdesktop.com/en/)(社区维护项目,非 DeepSeek 官方产品,把 DeepSeek Harness 运行封装成可直接打开的桌面应用),然后让 dsh 里的 AI 帮装,发这一句即可:
|
|
20
|
+
|
|
21
|
+
> 帮我把 Pictor 插件装上,从 npm 包 dsh-pictor 装到当前 profile,需要的话重启,装好告诉我左下角有没有 Pictor 入口。
|
|
22
|
+
|
|
23
|
+
## 使用
|
|
24
|
+
|
|
25
|
+
1. 打开工作台,点「新建项目」:上传文件(md/txt/docx/pdf/图片)或粘贴内容(从 Word/网页粘贴,格式保留,落盘为消毒 HTML)。
|
|
26
|
+
2. 会话读取并规整来源(docx/pdf/图片/HTML → document.md 由会话用 dsh 工具完成),提取候选结构。
|
|
27
|
+
3. 勾选结构,确认,会话进入方案设计;勾选方案,设画面比例,点「渲染所选方案」。
|
|
28
|
+
4. 结果网格里预览、下载;随时可展开讨论面板对会话说话,或点步骤条回到已有产物的步骤重做。
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
## 形态
|
|
33
|
+
|
|
34
|
+
- 安装后首次使用自动生成 `~/.pictor` 工作区(注册为 dsh 工作区,侧栏归组见「Pictor」)。
|
|
35
|
+
- 唯一入口是 dsh 左下角 footer 按钮「Pictor」,打开 shell.overlay 工作台:左栏列项目,右栏显示当前项目。
|
|
36
|
+
- 项目步骤固定三步:提取结构 → 方案设计 → 渲染出图。每步由你做决定后,会话在同一会话里接着执行(agent-loop 的 resume 语义),不重跑已有阶段。
|
|
37
|
+
- 项目名取文档首行,信息条内随时可改名,只动 index.json。
|
|
38
|
+
- 状态只由文件事实驱动;运行中判定以 dsh agent 注册表为权威;把你对 orchestration 的关心都留给会话。
|
|
39
|
+
|
|
40
|
+
## 两个模型
|
|
41
|
+
|
|
42
|
+
- 推理模型:extract 与 advise 用 dsh 当前默认模型,无需在 Pictor 配置。
|
|
43
|
+
- 画图模型:在工作台「设置」里配置(seedream / gemini / openai-compatible / mock)。密钥经 dsh 凭据子系统保存,配置只留引用。
|
|
44
|
+
|
|
45
|
+
## 开发与验证
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run build # esbuild 构建 host + 拼接 client
|
|
49
|
+
npm run verify # L1 单元 + L2 host 集成(mock ctx,15 项)
|
|
50
|
+
npm run verify:integration # L3 transport 冒烟(真实 dsh web)
|
|
51
|
+
npm run test:e2e # L4a 浏览器 e2e(fixture 数据,确定性)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
测试分层的定义与理由见 [docs/DESIGN.zh.md](docs/DESIGN.zh.md) 第 7 节。
|
|
55
|
+
|
|
56
|
+
## 目录
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
pictor/
|
|
60
|
+
├── agents/ # 声明式蓝图(orchestrator/extractor/advisor/renderer)
|
|
61
|
+
├── references/domain/ # base-prompt + layouts/ + styles/ + diagram-types/ + visual-principles
|
|
62
|
+
├── src/host/ # 插件宿主:~/.pictor、项目会话、/pictor RPC、生图
|
|
63
|
+
├── src/client/ # 工作台 UI(React.createElement + 主题变量)
|
|
64
|
+
├── e2e/ # L4a Playwright
|
|
65
|
+
├── verify.mjs # L1+L2 离线冒烟
|
|
66
|
+
└── scripts/ # build + transport-smoke
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
数据目录 `~/.pictor/`:`index.json`(项目索引)、`pictor-config.json`(画图模型配置)、`<项目 id>/`(自包含:agents/references 快照 + 10.input + 11.extraction + 12.advice + output)。
|
|
70
|
+
|
|
71
|
+
## 文档
|
|
72
|
+
|
|
73
|
+
- 设计与决策:[docs/DESIGN.zh.md](docs/DESIGN.zh.md)
|
|
74
|
+
- 验证清单:[docs/verification-checklist.zh.md](docs/verification-checklist.zh.md)
|
|
75
|
+
|
|
76
|
+
## 许可证
|
|
77
|
+
|
|
78
|
+
MIT,见 [LICENSE](LICENSE)。第三方内容声明见 [NOTICE.md](NOTICE.md)。
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -303,6 +303,7 @@ const I18N = {
|
|
|
303
303
|
layoutLabel: '布局', styleLabel: '风格', metaConfirmedHint: '确认后作为项目名与提取依据,可编辑。',
|
|
304
304
|
chooseLayout: '选择布局', chooseStyle: '选择风格', resetToAi: '回到 AI 推荐',
|
|
305
305
|
layoutChanged: '·已改', aiSuggestion: 'AI 推荐',
|
|
306
|
+
batchStyleLabel: '批量设置风格', batchStyleHint: '为所选方案套用同一风格(未选则全部)',
|
|
306
307
|
close: '关闭',
|
|
307
308
|
discussion: '讨论', discussHint: '对项目会话自由说话:补充参考、要求搜索、调整方向。你的决定会在同一会话里接着执行。',
|
|
308
309
|
discussPlaceholder: '例如:先不要继续,帮我查一下这篇文章提到的背景…',
|
|
@@ -360,6 +361,7 @@ const I18N = {
|
|
|
360
361
|
layoutLabel: 'Layout', styleLabel: 'Style', metaConfirmedHint: 'Confirmed as the project name and extraction basis; editable.',
|
|
361
362
|
chooseLayout: 'Choose layout', chooseStyle: 'Choose style', resetToAi: 'Reset to AI',
|
|
362
363
|
layoutChanged: '· edited', aiSuggestion: 'AI',
|
|
364
|
+
batchStyleLabel: 'Batch style', batchStyleHint: 'Apply one style to all selected proposals (all if none selected)',
|
|
363
365
|
close: 'Close',
|
|
364
366
|
discussion: 'Discussion', discussHint: 'Talk to the project session: add context, ask for research, adjust direction. Your decisions continue it in the same session.',
|
|
365
367
|
discussPlaceholder: 'e.g. Hold on — research the background this article mentions…',
|
|
@@ -793,9 +795,17 @@ function ProposalsPanel({ stage, proposals, suggestedStyle, steps, selected, onT
|
|
|
793
795
|
const ratioFor = (id) => ratios[id] || '16:9'
|
|
794
796
|
const activePrompt = promptId ? proposals.find((x) => x.id === promptId) || null : null
|
|
795
797
|
|
|
798
|
+
function batchTargetIds() {
|
|
799
|
+
return selected.length ? selected : proposals.map((p) => p.id)
|
|
800
|
+
}
|
|
796
801
|
function pickOption(name) {
|
|
797
802
|
const cur = pick
|
|
798
803
|
if (!cur) return
|
|
804
|
+
if (cur.batch) {
|
|
805
|
+
batchTargetIds().forEach((id) => setSty(id, name))
|
|
806
|
+
setPick(null)
|
|
807
|
+
return
|
|
808
|
+
}
|
|
799
809
|
if (cur.kind === 'layout') setLay(cur.id, name)
|
|
800
810
|
else setSty(cur.id, name)
|
|
801
811
|
setPick(null)
|
|
@@ -803,6 +813,11 @@ function ProposalsPanel({ stage, proposals, suggestedStyle, steps, selected, onT
|
|
|
803
813
|
function resetCurrent() {
|
|
804
814
|
const cur = pick
|
|
805
815
|
if (!cur) return
|
|
816
|
+
if (cur.batch) {
|
|
817
|
+
batchTargetIds().forEach((id) => setSty(id, undefined))
|
|
818
|
+
setPick(null)
|
|
819
|
+
return
|
|
820
|
+
}
|
|
806
821
|
if (cur.kind === 'layout') setLay(cur.id, undefined)
|
|
807
822
|
else setSty(cur.id, undefined)
|
|
808
823
|
setPick(null)
|
|
@@ -859,34 +874,60 @@ function ProposalsPanel({ stage, proposals, suggestedStyle, steps, selected, onT
|
|
|
859
874
|
: null
|
|
860
875
|
|
|
861
876
|
const chooserModal = pick ? (function chooser() {
|
|
862
|
-
const p = proposals.find((x) => x.id === pick.id)
|
|
863
|
-
if (!p) return null
|
|
864
877
|
const kind = pick.kind
|
|
878
|
+
const batch = Boolean(pick.batch)
|
|
879
|
+
const p = batch ? null : proposals.find((x) => x.id === pick.id)
|
|
880
|
+
if (!batch && !p) return null
|
|
865
881
|
const list = kind === 'layout'
|
|
866
|
-
? (layouts && layouts.length ? layouts : [p.suggested_layout])
|
|
867
|
-
: (styles && styles.length ? styles : [p.suggested_style || suggestedStyle])
|
|
868
|
-
const base = kind === 'layout' ? p.suggested_layout : (p.suggested_style || suggestedStyle)
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
882
|
+
? (layouts && layouts.length ? layouts : (p ? [p.suggested_layout] : []))
|
|
883
|
+
: (styles && styles.length ? styles : (p ? [p.suggested_style || suggestedStyle] : (suggestedStyle ? [suggestedStyle] : [])))
|
|
884
|
+
const base = batch ? '' : (kind === 'layout' ? p.suggested_layout : (p.suggested_style || suggestedStyle))
|
|
885
|
+
// batch:高亮所有目标方案共享的同一风格(若有),否则不高亮
|
|
886
|
+
let current
|
|
887
|
+
if (batch) {
|
|
888
|
+
const ids = batchTargetIds()
|
|
889
|
+
const eff = ids.map((id) => {
|
|
890
|
+
const pp = proposals.find((x) => x.id === id)
|
|
891
|
+
return (pp ? (sty[id] || pp.suggested_style || suggestedStyle || '') : (sty[id] || ''))
|
|
892
|
+
})
|
|
893
|
+
current = eff.length && eff.every((s) => s === eff[0]) ? eff[0] : ''
|
|
894
|
+
} else {
|
|
895
|
+
current = kind === 'layout' ? (lay[pick.id] || p.suggested_layout) : (sty[pick.id] || p.suggested_style || suggestedStyle)
|
|
896
|
+
}
|
|
897
|
+
const changed = batch
|
|
898
|
+
? ids_haveAnyOverrideStyle()
|
|
899
|
+
: (kind === 'layout' ? Boolean(lay[pick.id] && lay[pick.id] !== base) : Boolean(sty[pick.id] && sty[pick.id] !== base))
|
|
900
|
+
function ids_haveAnyOverrideStyle() {
|
|
901
|
+
return batchTargetIds().some((id) => Boolean(sty[id]))
|
|
902
|
+
}
|
|
873
903
|
const items = list.map((n) => h('div', { key: n, className: 'pt-preview-item' + (n === current ? ' sel' : ''), onClick: () => pickOption(n) },
|
|
874
|
-
n === base ? h('span', { className: 'ai-chip' }, t('aiSuggestion')) : null,
|
|
904
|
+
(!batch && n === base) ? h('span', { className: 'ai-chip' }, t('aiSuggestion')) : null,
|
|
875
905
|
h('img', { src: '/pictor/preview/' + (kind === 'layout' ? 'layouts' : 'styles') + '/' + encodeURIComponent(n) + '.webp', alt: kind === 'layout' ? layoutLabel(n) : n }),
|
|
876
906
|
h('div', { className: 'nm' }, kind === 'layout' ? layoutLabel(n) : n)))
|
|
907
|
+
const title = batch ? t('batchStyleLabel') : (kind === 'layout' ? t('chooseLayout') : t('chooseStyle'))
|
|
908
|
+
const batchSub = batch ? h('p', { className: 'pt-meta', style: { margin: '0 0 10px' }, key: 'sub' },
|
|
909
|
+
t('batchStyleHint') + ' · ' + t('selectCount', { s: selected.length, t: proposals.length })) : null
|
|
877
910
|
return h('div', { className: 'pt-modal-backdrop', onClick: () => setPick(null) },
|
|
878
911
|
h('div', { className: 'pt-modal pt-modal-wide', onClick: (e) => e.stopPropagation() },
|
|
879
912
|
h('div', { className: 'pt-modal-head' },
|
|
880
|
-
h('h3', { className: 'pt-option-title', style: { margin: 0 } },
|
|
913
|
+
h('h3', { className: 'pt-option-title', style: { margin: 0 } }, title),
|
|
881
914
|
h('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
882
915
|
changed ? h('button', { className: 'pt-btn', style: { padding: '6px 12px', fontSize: 13 }, onClick: resetCurrent }, t('resetToAi')) : null,
|
|
883
916
|
h('button', { className: 'pt-modal-close', onClick: () => setPick(null), title: t('close'), 'aria-label': t('close') }, '×'))),
|
|
884
|
-
h('div', { className: 'pt-modal-body' }, h('div', { className: 'pt-preview-grid' }, items))))
|
|
917
|
+
h('div', { className: 'pt-modal-body' }, batchSub, h('div', { className: 'pt-preview-grid' }, items))))
|
|
885
918
|
})() : null
|
|
886
919
|
|
|
920
|
+
const styleList = (styles && styles.length ? styles : (suggestedStyle ? [suggestedStyle] : []))
|
|
921
|
+
const batchStyleBtn = styleList.length ? h('button', {
|
|
922
|
+
className: 'pt-btn', style: { padding: '4px 10px', fontSize: 13 }, disabled: proposals.length === 0,
|
|
923
|
+
onClick: () => setPick({ id: null, kind: 'style', batch: true }),
|
|
924
|
+
title: t('batchStyleHint'),
|
|
925
|
+
}, t('batchStyleLabel')) : null
|
|
926
|
+
|
|
887
927
|
const actionRow = h('div', { className: 'pt-card-row', style: { marginTop: 18 } },
|
|
888
|
-
h('div', { style: { display: 'flex', gap: 10, alignItems: 'center' } },
|
|
928
|
+
h('div', { style: { display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap' } },
|
|
889
929
|
h('button', { className: 'pt-btn', onClick: onToggleAll }, allSelected ? t('deselectAll') : t('selectAll')),
|
|
930
|
+
batchStyleBtn,
|
|
890
931
|
h('span', { className: 'pt-meta' }, t('selectCount', { s: selected.length, t: proposals.length }))),
|
|
891
932
|
hasImageKey === false
|
|
892
933
|
? h('p', { className: 'pt-warn', style: { margin: 0 } }, t('imgKeyHint'))
|
package/lib/image-providers.js
CHANGED
|
@@ -124,7 +124,7 @@ class DashScopeProvider {
|
|
|
124
124
|
const base = this.cfg.baseUrl || "https://dashscope.aliyuncs.com/api/v1";
|
|
125
125
|
const size = DASHSCOPE_SIZE_MAP[aspectRatio] || "1024*1024";
|
|
126
126
|
const url = base.replace(/\/$/, "") + "/services/aigc/multimodal-generation/generation";
|
|
127
|
-
const parameters = { size,
|
|
127
|
+
const parameters = { size, watermark: false };
|
|
128
128
|
const body = {
|
|
129
129
|
model,
|
|
130
130
|
input: { messages: [{ role: "user", content: [{ type: "text", text: prompt }] }] },
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Create a professional infographic
|
|
1
|
+
Create a professional infographic. This prompt separates what to render from how to render it: the Content section is the subject matter, data, and labels to put in the infographic; the Layout and Style sections are visual specifications (structure and aesthetic — they describe the look, not the subject). Put the content in first, then apply the layout and style to present it.
|
|
2
2
|
|
|
3
3
|
## Image Specifications
|
|
4
4
|
|
|
@@ -8,6 +8,13 @@ Create a professional infographic following these specifications:
|
|
|
8
8
|
- **Aspect Ratio**: {{ASPECT_RATIO}}
|
|
9
9
|
- **Language**: {{LANGUAGE}}
|
|
10
10
|
|
|
11
|
+
## Content — the subject matter, data, and labels to render
|
|
12
|
+
|
|
13
|
+
{{CONTENT}}
|
|
14
|
+
|
|
15
|
+
Text labels (in {{LANGUAGE}}):
|
|
16
|
+
{{TEXT_LABELS}}
|
|
17
|
+
|
|
11
18
|
## Core Principles
|
|
12
19
|
|
|
13
20
|
- Follow the layout structure precisely for information architecture
|
|
@@ -26,19 +33,10 @@ Create a professional infographic following these specifications:
|
|
|
26
33
|
- Labels should be clear and appropriately sized
|
|
27
34
|
- Use the specified language for all text content
|
|
28
35
|
|
|
29
|
-
## Layout Guidelines
|
|
36
|
+
## Layout Guidelines — visual structure (how to arrange; not content)
|
|
30
37
|
|
|
31
38
|
{{LAYOUT_GUIDELINES}}
|
|
32
39
|
|
|
33
|
-
## Style Guidelines
|
|
34
|
-
|
|
35
|
-
{{STYLE_GUIDELINES}}
|
|
40
|
+
## Style Guidelines — visual aesthetic (how it looks; not subject matter)
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Generate the infographic based on the content below:
|
|
40
|
-
|
|
41
|
-
{{CONTENT}}
|
|
42
|
-
|
|
43
|
-
Text labels (in {{LANGUAGE}}):
|
|
44
|
-
{{TEXT_LABELS}}
|
|
42
|
+
{{STYLE_GUIDELINES}}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# bandung-circuit
|
|
2
2
|
|
|
3
|
-
Editorial illustration style
|
|
3
|
+
Editorial illustration style — a muted, paper-printed aesthetic. Cream stock, duotone restraint, thin-line hand-drawn icons, and typography-led hierarchy. Reads as an interior print spread, not a marketing poster.
|
|
4
4
|
|
|
5
5
|
## Color Palette
|
|
6
6
|
|
|
@@ -25,10 +25,10 @@ Editorial illustration style of the Bandung Circuit column — a muted, paper-pr
|
|
|
25
25
|
|
|
26
26
|
## Typography
|
|
27
27
|
|
|
28
|
-
- **Font family: Poppins** — used as the single typeface across the entire composition (headlines, body, labels, captions, numerals). Poppins is a geometric sans with humanist warmth, which suits
|
|
28
|
+
- **Font family: Poppins** — used as the single typeface across the entire composition (headlines, body, labels, captions, numerals). Poppins is a geometric sans with humanist warmth, which suits an editorial-but-warm register; do not pair it with a second family.
|
|
29
29
|
- Headlines: Poppins SemiBold or Bold — uppercase or title case acceptable, tracking slightly opened
|
|
30
30
|
- Body text and labels: Poppins Regular or Medium — comfortable reading weight
|
|
31
|
-
- All-caps short labels for block headers
|
|
31
|
+
- All-caps short labels for block headers — Poppins Medium/SemiBold, set in cream on solid duotone bar
|
|
32
32
|
- Sub-captions and explanatory phrases beneath block titles: Poppins Italic or Light
|
|
33
33
|
- Numerals match the body face (Poppins lining figures) — no oversized statement numerals (this style trusts the layout, not hero stats)
|
|
34
34
|
|
|
@@ -49,13 +49,9 @@ Editorial illustration style of the Bandung Circuit column — a muted, paper-pr
|
|
|
49
49
|
- Use filled / solid icons (Material-style) — icons are line-art only
|
|
50
50
|
- Introduce a fourth or fifth color — composition must feel like a duotone with a single accent
|
|
51
51
|
- Use glossy or "tech product" iconography — keep icons modest and editorial
|
|
52
|
-
- Use heavy textures, parchment overlays, ink splatter, or cross-hatching (that is `aged-academia`, not
|
|
52
|
+
- Use heavy textures, parchment overlays, ink splatter, or cross-hatching (that is `aged-academia`, not this style)
|
|
53
53
|
- Use bold red blocks or full-bleed red panels (that is `tricon-infographic`, the poster sibling — not this)
|
|
54
|
-
- Crowd the canvas —
|
|
55
|
-
|
|
56
|
-
## Best For
|
|
57
|
-
|
|
58
|
-
Editorial illustrations for left-publishing journal articles, conceptual frameworks, multi-pillar architectures, theoretical model diagrams, methodology overviews, Global South research publications, long-form essay infographics, in-text figures (not standalone posters)
|
|
54
|
+
- Crowd the canvas — these pages always breathe
|
|
59
55
|
|
|
60
56
|
## Recommended Pairings
|
|
61
57
|
|
|
@@ -67,16 +63,13 @@ Editorial illustrations for left-publishing journal articles, conceptual framewo
|
|
|
67
63
|
|
|
68
64
|
## Distinction from Sibling Styles
|
|
69
65
|
|
|
70
|
-
- **vs `tricon-infographic`**: That style is
|
|
71
|
-
- **vs `aged-academia`**: That style is sepia parchment with cross-hatched scientific illustration.
|
|
72
|
-
- **vs `mckinsey-report`**: That style is white-background institutional consulting with serif/sans dual typography.
|
|
66
|
+
- **vs `tricon-infographic`**: That style is a poster voice — bold red on white, authoritative, full-bleed. `bandung-circuit` is an interior/essay voice — cream stock, duotone, quiet.
|
|
67
|
+
- **vs `aged-academia`**: That style is sepia parchment with cross-hatched scientific illustration. `bandung-circuit` is contemporary editorial print, not historical specimen plate.
|
|
68
|
+
- **vs `mckinsey-report`**: That style is white-background institutional consulting with serif/sans dual typography. `bandung-circuit` is a warm-paper aesthetic with a single sans family.
|
|
73
69
|
|
|
74
70
|
## Register
|
|
75
71
|
|
|
76
72
|
- formal-casual: formal but warm
|
|
77
73
|
- abstract-representational: slightly abstract
|
|
78
74
|
- bright-dark: bright (warm-bright, not white-bright)
|
|
79
|
-
- digital-handcrafted: leans handcrafted (digital execution with hand-drawn iconography)
|
|
80
|
-
- cultural-anchor: left publishing-house interior page design (Tricontinental, Verso, *New Left Review*, *Monthly Review*) — editorial register of the international left intellectual tradition
|
|
81
|
-
- best-for: in-text editorial illustrations for journal articles, conceptual diagrams in long-form essays, Global South research publications
|
|
82
|
-
- avoid-for: marketing posters, product UI, children's content, entertainment, corporate consulting decks, social-media graphics requiring stopping power
|
|
75
|
+
- digital-handcrafted: leans handcrafted (digital execution with hand-drawn iconography)
|