@symerian/symi 3.0.17 → 3.0.18

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.
Files changed (146) hide show
  1. package/dist/{audio-preflight-CBDFctZN.js → audio-preflight-BfmZbg4Y.js} +4 -4
  2. package/dist/{audio-preflight-gsZSpG-6.js → audio-preflight-DcuC-liM.js} +4 -4
  3. package/dist/build-info.json +3 -3
  4. package/dist/bundled/boot-md/handler.js +8 -8
  5. package/dist/bundled/session-memory/handler.js +7 -7
  6. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  7. package/dist/{chrome-nPMY1XTJ.js → chrome-Bo7cbvFK.js} +5 -5
  8. package/dist/{chrome-BjVab8gM.js → chrome-DYp18Q0t.js} +5 -5
  9. package/dist/{deliver-D-QFqm31.js → deliver-ChSIbiMM.js} +1 -1
  10. package/dist/{deliver-B4-bcot9.js → deliver-DEgRQM4J.js} +1 -1
  11. package/dist/extensionAPI.js +7 -7
  12. package/dist/{image-CDwtQjmt.js → image-Bx-hvoNJ.js} +1 -1
  13. package/dist/{image-CcS-vzTA.js → image-CQl_mjWk.js} +1 -1
  14. package/dist/llm-slug-generator.js +7 -7
  15. package/dist/{manager-BnEdHzmO.js → manager-D_pn0urG.js} +1 -1
  16. package/dist/{manager-09r0qPze.js → manager-YQxK2t0C.js} +1 -1
  17. package/dist/{pi-embedded-CWsY69-4.js → pi-embedded-CLw_ZzEZ.js} +16 -16
  18. package/dist/{pi-embedded-helpers-BBMy-lqr.js → pi-embedded-helpers-B5I53aw6.js} +4 -4
  19. package/dist/{pi-embedded-helpers-ChEYbgVj.js → pi-embedded-helpers-sUAEIC9X.js} +4 -4
  20. package/dist/plugin-sdk/{accounts-BfyWsC_i.js → accounts-CWFytwbR.js} +3 -3
  21. package/dist/plugin-sdk/{active-listener-DcJW7xAT.js → active-listener-BkZ4jHrL.js} +2 -2
  22. package/dist/plugin-sdk/{agent-scope-ChbGV6of.js → agent-scope-C9gfY_Gk.js} +2 -2
  23. package/dist/plugin-sdk/{audio-preflight-D3GtNLqW.js → audio-preflight-HKbdzXLZ.js} +21 -21
  24. package/dist/plugin-sdk/{bindings-CN2Qmefj.js → bindings-BaKIqPPy.js} +2 -2
  25. package/dist/plugin-sdk/{channel-web-DTyqujjA.js → channel-web-D5nWiTH1.js} +18 -18
  26. package/dist/plugin-sdk/{chrome-BKzAKr3K.js → chrome-klTSnz-9.js} +3 -3
  27. package/dist/plugin-sdk/{chunk-DhDkBujV.js → chunk-BbrYSny_.js} +1 -1
  28. package/dist/plugin-sdk/{command-format-CVrYFyZS.js → command-format-BN6tyZt6.js} +1 -1
  29. package/dist/plugin-sdk/{commands-registry-17yfZkHZ.js → commands-registry-CTzKKtY6.js} +4 -4
  30. package/dist/plugin-sdk/{config-7wk65zKC.js → config-Crv2qEdJ.js} +9 -9
  31. package/dist/plugin-sdk/{consolidate-exbAW0ml.js → consolidate-DT1QH65Q.js} +2 -2
  32. package/dist/plugin-sdk/{deliver-TxAcw7J5.js → deliver-7rOvAlrc.js} +12 -12
  33. package/dist/plugin-sdk/{diagnostic-Debx4frd.js → diagnostic-0nsxhWp7.js} +1 -1
  34. package/dist/plugin-sdk/{fs-safe-wBYbAkJF.js → fs-safe-DfWYBeWF.js} +1 -1
  35. package/dist/plugin-sdk/{gemini-auth-7U2pm2Ky.js → gemini-auth-C0N0_u49.js} +1 -1
  36. package/dist/plugin-sdk/{image-BtDVmYA5.js → image-WOSl2apK.js} +4 -4
  37. package/dist/plugin-sdk/index.js +43 -43
  38. package/dist/plugin-sdk/{ir-CKMvRrGW.js → ir-9J84MTls.js} +4 -4
  39. package/dist/plugin-sdk/{local-roots-c_gaPs01.js → local-roots-OLRDbvyY.js} +3 -3
  40. package/dist/plugin-sdk/{login-DUym1Jy0.js → login-C7x4q0i2.js} +7 -7
  41. package/dist/plugin-sdk/{login-qr-B-WBdvrX.js → login-qr-Dv5_MoAW.js} +9 -9
  42. package/dist/plugin-sdk/{manager-B71SCzos.js → manager-C83tK17x.js} +8 -8
  43. package/dist/plugin-sdk/{manifest-registry-Dnic6Chh.js → manifest-registry-CJMV-PI7.js} +1 -1
  44. package/dist/plugin-sdk/{markdown-tables-Dur7OTlM.js → markdown-tables-DXNKz5y_.js} +1 -1
  45. package/dist/plugin-sdk/{message-channel-BrAhJJV_.js → message-channel-aGy1HbQQ.js} +1 -1
  46. package/dist/plugin-sdk/{model-selection-B9qaVQSJ.js → model-selection-C-3-tpe7.js} +4 -4
  47. package/dist/plugin-sdk/{outbound-DB1wDM8b.js → outbound-DquCeSy5.js} +6 -6
  48. package/dist/plugin-sdk/{pi-auth-json-ZO118hoy.js → pi-auth-json-D9PDCXGn.js} +1 -1
  49. package/dist/plugin-sdk/{pi-embedded-helpers-s_U0Un7j.js → pi-embedded-helpers-D3ygfH7l.js} +16 -16
  50. package/dist/plugin-sdk/{plugins-DF81oSaI.js → plugins-DOwnSg9D.js} +4 -4
  51. package/dist/plugin-sdk/{pw-ai-CTwP02uv.js → pw-ai-rlengLjb.js} +8 -8
  52. package/dist/plugin-sdk/{qmd-manager-CBaSGant.js → qmd-manager-BzxFjRFa.js} +4 -4
  53. package/dist/plugin-sdk/{registry-CZVURNhF.js → registry-5iFfixlB.js} +2 -2
  54. package/dist/plugin-sdk/{replies-hwRbkU3z.js → replies-BXOzO_H5.js} +7 -7
  55. package/dist/plugin-sdk/{reply-prefix-CaXmzZlx.js → reply-prefix-INAKTqCU.js} +1 -1
  56. package/dist/plugin-sdk/{resolve-outbound-target-fxVSOBmk.js → resolve-outbound-target-DvbxHtqp.js} +2 -2
  57. package/dist/plugin-sdk/{resolve-route-ClCyiOeu.js → resolve-route-URXlY3AK.js} +3 -3
  58. package/dist/plugin-sdk/{runner-Cq5jvwQ7.js → runner-Bv0_DWoH.js} +9 -9
  59. package/dist/plugin-sdk/{session-B_TkB65Y.js → session-C3r8l7ou.js} +4 -4
  60. package/dist/plugin-sdk/{skill-commands-0LF9HTGr.js → skill-commands-KjLUGIdZ.js} +5 -5
  61. package/dist/plugin-sdk/{skills-BIT_O7J0.js → skills-BrsD4L5c.js} +7 -7
  62. package/dist/plugin-sdk/{sqlite-Bx5Y5U5X.js → sqlite-CjW7ME1H.js} +1 -1
  63. package/dist/plugin-sdk/{subsystem-CXqYeDy-.js → subsystem-DcOg1xJr.js} +1 -1
  64. package/dist/plugin-sdk/{synthesis-DtsYAj1E.js → synthesis-CY7YAasV.js} +38 -38
  65. package/dist/plugin-sdk/{target-errors-B8mokOeH.js → target-errors-BVWJGWFq.js} +2 -2
  66. package/dist/plugin-sdk/{thinking-Ca0DhqzO.js → thinking-CtsTDPOi.js} +3 -3
  67. package/dist/plugin-sdk/{tokens-CvlONEqh.js → tokens-8lqOTZCB.js} +1 -1
  68. package/dist/plugin-sdk/{tool-images-DpBaWEHT.js → tool-images-Cl_rGIUZ.js} +2 -2
  69. package/dist/plugin-sdk/{tool-loop-detection-BOvUFa0f.js → tool-loop-detection-Da4WUT_P.js} +2 -2
  70. package/dist/plugin-sdk/{unified-runner-CnM7lyNd.js → unified-runner-nwMnsZyj.js} +60 -60
  71. package/dist/plugin-sdk/web-BlweOZDp.js +54 -0
  72. package/dist/plugin-sdk/{whatsapp-actions-CvnfsFJm.js → whatsapp-actions-DpfaGYs7.js} +21 -21
  73. package/dist/{pw-ai-BW8_KeDf.js → pw-ai-BqxJG-Wh.js} +1 -1
  74. package/dist/{pw-ai-j9IE1K0-.js → pw-ai-C-NSGye0.js} +1 -1
  75. package/dist/{runner-8ALr2UII.js → runner-COGFTeDw.js} +1 -1
  76. package/dist/{runner-C4-9kFdR.js → runner-DhCi2lT1.js} +1 -1
  77. package/dist/{synthesis-Cph3LhA1.js → synthesis-CXZu24Vx.js} +7 -7
  78. package/dist/{synthesis-Cus0A2dL.js → synthesis-DrPxcMlQ.js} +7 -7
  79. package/dist/{unified-runner-CX80YMTk.js → unified-runner-iByUazvW.js} +16 -16
  80. package/dist/{web-ChozvJ7I.js → web-EsMQBIYf.js} +7 -7
  81. package/dist/{web-DFlsbXmQ.js → web-PPg5y6xI.js} +7 -7
  82. package/package.json +1 -1
  83. package/dist/plugin-sdk/web-CIPJBHAU.js +0 -54
  84. package/skills/1password/SKILL.md +0 -71
  85. package/skills/1password/references/cli-examples.md +0 -29
  86. package/skills/1password/references/get-started.md +0 -17
  87. package/skills/apple-notes/SKILL.md +0 -78
  88. package/skills/apple-reminders/SKILL.md +0 -119
  89. package/skills/bear-notes/SKILL.md +0 -108
  90. package/skills/blogwatcher/SKILL.md +0 -70
  91. package/skills/blucli/SKILL.md +0 -48
  92. package/skills/bluebubbles/SKILL.md +0 -132
  93. package/skills/camsnap/SKILL.md +0 -46
  94. package/skills/canvas/SKILL.md +0 -204
  95. package/skills/connect-email/SKILL.md +0 -142
  96. package/skills/document-generation/SKILL.md +0 -83
  97. package/skills/eightctl/SKILL.md +0 -51
  98. package/skills/food-order/SKILL.md +0 -49
  99. package/skills/gemini/SKILL.md +0 -44
  100. package/skills/gh-issues/SKILL.md +0 -865
  101. package/skills/gifgrep/SKILL.md +0 -80
  102. package/skills/github/SKILL.md +0 -164
  103. package/skills/gog/SKILL.md +0 -117
  104. package/skills/goplaces/SKILL.md +0 -53
  105. package/skills/healthcheck/SKILL.md +0 -246
  106. package/skills/himalaya/SKILL.md +0 -258
  107. package/skills/himalaya/references/configuration.md +0 -184
  108. package/skills/himalaya/references/message-composition.md +0 -199
  109. package/skills/imsg/SKILL.md +0 -122
  110. package/skills/long-task/SKILL.md +0 -58
  111. package/skills/long-task/scripts/detach-task.sh +0 -187
  112. package/skills/nano-banana-pro/SKILL.md +0 -59
  113. package/skills/nano-banana-pro/scripts/generate_image.py +0 -184
  114. package/skills/nano-pdf/SKILL.md +0 -39
  115. package/skills/notion/SKILL.md +0 -173
  116. package/skills/obsidian/SKILL.md +0 -82
  117. package/skills/openai-image-gen/SKILL.md +0 -90
  118. package/skills/openai-image-gen/scripts/gen.py +0 -240
  119. package/skills/openai-whisper/SKILL.md +0 -39
  120. package/skills/openai-whisper-api/SKILL.md +0 -53
  121. package/skills/openai-whisper-api/scripts/transcribe.sh +0 -85
  122. package/skills/openhue/SKILL.md +0 -113
  123. package/skills/oracle/SKILL.md +0 -126
  124. package/skills/ordercli/SKILL.md +0 -79
  125. package/skills/peekaboo/SKILL.md +0 -191
  126. package/skills/reactions-extensive/SKILL.md +0 -30
  127. package/skills/reactions-minimal/SKILL.md +0 -31
  128. package/skills/safe-edit/SKILL.md +0 -51
  129. package/skills/sag/SKILL.md +0 -88
  130. package/skills/sherpa-onnx-tts/SKILL.md +0 -104
  131. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +0 -178
  132. package/skills/songsee/SKILL.md +0 -50
  133. package/skills/sonoscli/SKILL.md +0 -66
  134. package/skills/spotify-player/SKILL.md +0 -65
  135. package/skills/symihub/SKILL.md +0 -78
  136. package/skills/things-mac/SKILL.md +0 -87
  137. package/skills/tmux/SKILL.md +0 -153
  138. package/skills/tmux/scripts/find-sessions.sh +0 -112
  139. package/skills/tmux/scripts/wait-for-text.sh +0 -83
  140. package/skills/trello/SKILL.md +0 -96
  141. package/skills/video-frames/SKILL.md +0 -47
  142. package/skills/video-frames/scripts/frame.sh +0 -81
  143. package/skills/voice-call/SKILL.md +0 -46
  144. package/skills/wacli/SKILL.md +0 -73
  145. package/skills/weather/SKILL.md +0 -113
  146. package/skills/xurl/SKILL.md +0 -462
@@ -1,173 +0,0 @@
1
- ---
2
- name: notion
3
- description: Notion API for creating and managing pages, databases, and blocks.
4
- homepage: https://developers.notion.com
5
- metadata:
6
- {
7
- "symi":
8
- { "emoji": "📝", "requires": { "env": ["NOTION_API_KEY"] }, "primaryEnv": "NOTION_API_KEY" },
9
- }
10
- triggers: [notion]
11
- ---
12
-
13
- # notion
14
-
15
- Use the Notion API to create/read/update pages, data sources (databases), and blocks.
16
-
17
- ## Setup
18
-
19
- 1. Create an integration at https://notion.so/my-integrations
20
- 2. Copy the API key (starts with `ntn_` or `secret_`)
21
- 3. Store it:
22
-
23
- ```bash
24
- mkdir -p ~/.config/notion
25
- echo "ntn_your_key_here" > ~/.config/notion/api_key
26
- ```
27
-
28
- 4. Share target pages/databases with your integration (click "..." → "Connect to" → your integration name)
29
-
30
- ## API Basics
31
-
32
- All requests need:
33
-
34
- ```bash
35
- NOTION_KEY=$(cat ~/.config/notion/api_key)
36
- curl -X GET "https://api.notion.com/v1/..." \
37
- -H "Authorization: Bearer $NOTION_KEY" \
38
- -H "Notion-Version: 2025-09-03" \
39
- -H "Content-Type: application/json"
40
- ```
41
-
42
- > **Note:** The `Notion-Version` header is required. This skill uses `2025-09-03` (latest). In this version, databases are called "data sources" in the API.
43
-
44
- ## Common Operations
45
-
46
- **Search for pages and data sources:**
47
-
48
- ```bash
49
- curl -X POST "https://api.notion.com/v1/search" \
50
- -H "Authorization: Bearer $NOTION_KEY" \
51
- -H "Notion-Version: 2025-09-03" \
52
- -H "Content-Type: application/json" \
53
- -d '{"query": "page title"}'
54
- ```
55
-
56
- **Get page:**
57
-
58
- ```bash
59
- curl "https://api.notion.com/v1/pages/{page_id}" \
60
- -H "Authorization: Bearer $NOTION_KEY" \
61
- -H "Notion-Version: 2025-09-03"
62
- ```
63
-
64
- **Get page content (blocks):**
65
-
66
- ```bash
67
- curl "https://api.notion.com/v1/blocks/{page_id}/children" \
68
- -H "Authorization: Bearer $NOTION_KEY" \
69
- -H "Notion-Version: 2025-09-03"
70
- ```
71
-
72
- **Create page in a data source:**
73
-
74
- ```bash
75
- curl -X POST "https://api.notion.com/v1/pages" \
76
- -H "Authorization: Bearer $NOTION_KEY" \
77
- -H "Notion-Version: 2025-09-03" \
78
- -H "Content-Type: application/json" \
79
- -d '{
80
- "parent": {"database_id": "xxx"},
81
- "properties": {
82
- "Name": {"title": [{"text": {"content": "New Item"}}]},
83
- "Status": {"select": {"name": "Todo"}}
84
- }
85
- }'
86
- ```
87
-
88
- **Query a data source (database):**
89
-
90
- ```bash
91
- curl -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
92
- -H "Authorization: Bearer $NOTION_KEY" \
93
- -H "Notion-Version: 2025-09-03" \
94
- -H "Content-Type: application/json" \
95
- -d '{
96
- "filter": {"property": "Status", "select": {"equals": "Active"}},
97
- "sorts": [{"property": "Date", "direction": "descending"}]
98
- }'
99
- ```
100
-
101
- **Create a data source (database):**
102
-
103
- ```bash
104
- curl -X POST "https://api.notion.com/v1/data_sources" \
105
- -H "Authorization: Bearer $NOTION_KEY" \
106
- -H "Notion-Version: 2025-09-03" \
107
- -H "Content-Type: application/json" \
108
- -d '{
109
- "parent": {"page_id": "xxx"},
110
- "title": [{"text": {"content": "My Database"}}],
111
- "properties": {
112
- "Name": {"title": {}},
113
- "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
114
- "Date": {"date": {}}
115
- }
116
- }'
117
- ```
118
-
119
- **Update page properties:**
120
-
121
- ```bash
122
- curl -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
123
- -H "Authorization: Bearer $NOTION_KEY" \
124
- -H "Notion-Version: 2025-09-03" \
125
- -H "Content-Type: application/json" \
126
- -d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
127
- ```
128
-
129
- **Add blocks to page:**
130
-
131
- ```bash
132
- curl -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
133
- -H "Authorization: Bearer $NOTION_KEY" \
134
- -H "Notion-Version: 2025-09-03" \
135
- -H "Content-Type: application/json" \
136
- -d '{
137
- "children": [
138
- {"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello"}}]}}
139
- ]
140
- }'
141
- ```
142
-
143
- ## Property Types
144
-
145
- Common property formats for database items:
146
-
147
- - **Title:** `{"title": [{"text": {"content": "..."}}]}`
148
- - **Rich text:** `{"rich_text": [{"text": {"content": "..."}}]}`
149
- - **Select:** `{"select": {"name": "Option"}}`
150
- - **Multi-select:** `{"multi_select": [{"name": "A"}, {"name": "B"}]}`
151
- - **Date:** `{"date": {"start": "2024-01-15", "end": "2024-01-16"}}`
152
- - **Checkbox:** `{"checkbox": true}`
153
- - **Number:** `{"number": 42}`
154
- - **URL:** `{"url": "https://..."}`
155
- - **Email:** `{"email": "a@b.com"}`
156
- - **Relation:** `{"relation": [{"id": "page_id"}]}`
157
-
158
- ## Key Differences in 2025-09-03
159
-
160
- - **Databases → Data Sources:** Use `/data_sources/` endpoints for queries and retrieval
161
- - **Two IDs:** Each database now has both a `database_id` and a `data_source_id`
162
- - Use `database_id` when creating pages (`parent: {"database_id": "..."}`)
163
- - Use `data_source_id` when querying (`POST /v1/data_sources/{id}/query`)
164
- - **Search results:** Databases return as `"object": "data_source"` with their `data_source_id`
165
- - **Parent in responses:** Pages show `parent.data_source_id` alongside `parent.database_id`
166
- - **Finding the data_source_id:** Search for the database, or call `GET /v1/data_sources/{data_source_id}`
167
-
168
- ## Notes
169
-
170
- - Page/database IDs are UUIDs (with or without dashes)
171
- - The API cannot set database view filters — that's UI-only
172
- - Rate limit: ~3 requests/second average
173
- - Use `is_inline: true` when creating data sources to embed them in pages
@@ -1,82 +0,0 @@
1
- ---
2
- name: obsidian
3
- description: Work with Obsidian vaults (plain Markdown notes) and automate via obsidian-cli.
4
- homepage: https://help.obsidian.md
5
- metadata:
6
- {
7
- "symi":
8
- {
9
- "emoji": "💎",
10
- "requires": { "bins": ["obsidian-cli"] },
11
- "install":
12
- [
13
- {
14
- "id": "brew",
15
- "kind": "brew",
16
- "formula": "yakitrak/yakitrak/obsidian-cli",
17
- "bins": ["obsidian-cli"],
18
- "label": "Install obsidian-cli (brew)",
19
- },
20
- ],
21
- },
22
- }
23
- triggers: [obsidian]
24
- ---
25
-
26
- # Obsidian
27
-
28
- Obsidian vault = a normal folder on disk.
29
-
30
- Vault structure (typical)
31
-
32
- - Notes: `*.md` (plain text Markdown; edit with any editor)
33
- - Config: `.obsidian/` (workspace + plugin settings; usually don’t touch from scripts)
34
- - Canvases: `*.canvas` (JSON)
35
- - Attachments: whatever folder you chose in Obsidian settings (images/PDFs/etc.)
36
-
37
- ## Find the active vault(s)
38
-
39
- Obsidian desktop tracks vaults here (source of truth):
40
-
41
- - `~/Library/Application Support/obsidian/obsidian.json`
42
-
43
- `obsidian-cli` resolves vaults from that file; vault name is typically the **folder name** (path suffix).
44
-
45
- Fast “what vault is active / where are the notes?”
46
-
47
- - If you’ve already set a default: `obsidian-cli print-default --path-only`
48
- - Otherwise, read `~/Library/Application Support/obsidian/obsidian.json` and use the vault entry with `"open": true`.
49
-
50
- Notes
51
-
52
- - Multiple vaults common (iCloud vs `~/Documents`, work/personal, etc.). Don’t guess; read config.
53
- - Avoid writing hardcoded vault paths into scripts; prefer reading the config or using `print-default`.
54
-
55
- ## obsidian-cli quick start
56
-
57
- Pick a default vault (once):
58
-
59
- - `obsidian-cli set-default "<vault-folder-name>"`
60
- - `obsidian-cli print-default` / `obsidian-cli print-default --path-only`
61
-
62
- Search
63
-
64
- - `obsidian-cli search "query"` (note names)
65
- - `obsidian-cli search-content "query"` (inside notes; shows snippets + lines)
66
-
67
- Create
68
-
69
- - `obsidian-cli create "Folder/New note" --content "..." --open`
70
- - Requires Obsidian URI handler (`obsidian://…`) working (Obsidian installed).
71
- - Avoid creating notes under “hidden” dot-folders (e.g. `.something/...`) via URI; Obsidian may refuse.
72
-
73
- Move/rename (safe refactor)
74
-
75
- - `obsidian-cli move "old/path/note" "new/path/note"`
76
- - Updates `[[wikilinks]]` and common Markdown links across the vault (this is the main win vs `mv`).
77
-
78
- Delete
79
-
80
- - `obsidian-cli delete "path/note"`
81
-
82
- Prefer direct edits when appropriate: open the `.md` file and change it; Obsidian will pick it up.
@@ -1,90 +0,0 @@
1
- ---
2
- name: openai-image-gen
3
- description: Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
4
- homepage: https://platform.openai.com/docs/api-reference/images
5
- metadata:
6
- {
7
- "symi":
8
- {
9
- "emoji": "🖼️",
10
- "requires": { "bins": ["python3"], "env": ["OPENAI_API_KEY"] },
11
- "primaryEnv": "OPENAI_API_KEY",
12
- "install":
13
- [
14
- {
15
- "id": "python-brew",
16
- "kind": "brew",
17
- "formula": "python",
18
- "bins": ["python3"],
19
- "label": "Install Python (brew)",
20
- },
21
- ],
22
- },
23
- }
24
- triggers: [openai-image-gen, openai, image, gen]
25
- ---
26
-
27
- # OpenAI Image Gen
28
-
29
- Generate a handful of “random but structured” prompts and render them via the OpenAI Images API.
30
-
31
- ## Run
32
-
33
- ```bash
34
- python3 {baseDir}/scripts/gen.py
35
- open ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...
36
- ```
37
-
38
- Useful flags:
39
-
40
- ```bash
41
- # GPT image models with various options
42
- python3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1
43
- python3 {baseDir}/scripts/gen.py --prompt "ultra-detailed studio photo of a coral reef explorer" --count 4
44
- python3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images
45
- python3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp
46
-
47
- # DALL-E 3 (note: count is automatically limited to 1)
48
- python3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid
49
- python3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt "serene mountain landscape"
50
-
51
- # DALL-E 2
52
- python3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4
53
- ```
54
-
55
- ## Model-Specific Parameters
56
-
57
- Different models support different parameter values. The script automatically selects appropriate defaults based on the model.
58
-
59
- ### Size
60
-
61
- - **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`
62
- - Default: `1024x1024`
63
- - **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`
64
- - Default: `1024x1024`
65
- - **dall-e-2**: `256x256`, `512x512`, or `1024x1024`
66
- - Default: `1024x1024`
67
-
68
- ### Quality
69
-
70
- - **GPT image models**: `auto`, `high`, `medium`, or `low`
71
- - Default: `high`
72
- - **dall-e-3**: `hd` or `standard`
73
- - Default: `standard`
74
- - **dall-e-2**: `standard` only
75
- - Default: `standard`
76
-
77
- ### Other Notable Differences
78
-
79
- - **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.
80
- - **GPT image models** support additional parameters:
81
- - `--background`: `transparent`, `opaque`, or `auto` (default)
82
- - `--output-format`: `png` (default), `jpeg`, or `webp`
83
- - Note: `stream` and `moderation` are available via API but not yet implemented in this script
84
- - **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)
85
-
86
- ## Output
87
-
88
- - `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)
89
- - `prompts.json` (prompt → file mapping)
90
- - `index.html` (thumbnail gallery)
@@ -1,240 +0,0 @@
1
- #!/usr/bin/env python3
2
- import argparse
3
- import base64
4
- import datetime as dt
5
- import json
6
- import os
7
- import random
8
- import re
9
- import sys
10
- import urllib.error
11
- import urllib.request
12
- from pathlib import Path
13
-
14
-
15
- def slugify(text: str) -> str:
16
- text = text.lower().strip()
17
- text = re.sub(r"[^a-z0-9]+", "-", text)
18
- text = re.sub(r"-{2,}", "-", text).strip("-")
19
- return text or "image"
20
-
21
-
22
- def default_out_dir() -> Path:
23
- now = dt.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
24
- preferred = Path.home() / "Projects" / "tmp"
25
- base = preferred if preferred.is_dir() else Path("./tmp")
26
- base.mkdir(parents=True, exist_ok=True)
27
- return base / f"openai-image-gen-{now}"
28
-
29
-
30
- def pick_prompts(count: int) -> list[str]:
31
- subjects = [
32
- "a coral reef explorer",
33
- "a brutalist lighthouse",
34
- "a cozy reading nook",
35
- "a cyberpunk noodle shop",
36
- "a Vienna street at dusk",
37
- "a minimalist product photo",
38
- "a surreal underwater library",
39
- ]
40
- styles = [
41
- "ultra-detailed studio photo",
42
- "35mm film still",
43
- "isometric illustration",
44
- "editorial photography",
45
- "soft watercolor",
46
- "architectural render",
47
- "high-contrast monochrome",
48
- ]
49
- lighting = [
50
- "golden hour",
51
- "overcast soft light",
52
- "neon lighting",
53
- "dramatic rim light",
54
- "candlelight",
55
- "foggy atmosphere",
56
- ]
57
- prompts: list[str] = []
58
- for _ in range(count):
59
- prompts.append(
60
- f"{random.choice(styles)} of {random.choice(subjects)}, {random.choice(lighting)}"
61
- )
62
- return prompts
63
-
64
-
65
- def get_model_defaults(model: str) -> tuple[str, str]:
66
- """Return (default_size, default_quality) for the given model."""
67
- if model == "dall-e-2":
68
- # quality will be ignored
69
- return ("1024x1024", "standard")
70
- elif model == "dall-e-3":
71
- return ("1024x1024", "standard")
72
- else:
73
- # GPT image or future models
74
- return ("1024x1024", "high")
75
-
76
-
77
- def request_images(
78
- api_key: str,
79
- prompt: str,
80
- model: str,
81
- size: str,
82
- quality: str,
83
- background: str = "",
84
- output_format: str = "",
85
- style: str = "",
86
- ) -> dict:
87
- url = "https://api.openai.com/v1/images/generations"
88
- args = {
89
- "model": model,
90
- "prompt": prompt,
91
- "size": size,
92
- "n": 1,
93
- }
94
-
95
- # Quality parameter - dall-e-2 doesn't accept this parameter
96
- if model != "dall-e-2":
97
- args["quality"] = quality
98
-
99
- # Note: response_format no longer supported by OpenAI Images API
100
- # dall-e models now return URLs by default
101
-
102
- if model.startswith("gpt-image"):
103
- if background:
104
- args["background"] = background
105
- if output_format:
106
- args["output_format"] = output_format
107
-
108
- if model == "dall-e-3" and style:
109
- args["style"] = style
110
-
111
- body = json.dumps(args).encode("utf-8")
112
- req = urllib.request.Request(
113
- url,
114
- method="POST",
115
- headers={
116
- "Authorization": f"Bearer {api_key}",
117
- "Content-Type": "application/json",
118
- },
119
- data=body,
120
- )
121
- try:
122
- with urllib.request.urlopen(req, timeout=300) as resp:
123
- return json.loads(resp.read().decode("utf-8"))
124
- except urllib.error.HTTPError as e:
125
- payload = e.read().decode("utf-8", errors="replace")
126
- raise RuntimeError(f"OpenAI Images API failed ({e.code}): {payload}") from e
127
-
128
-
129
- def write_gallery(out_dir: Path, items: list[dict]) -> None:
130
- thumbs = "\n".join(
131
- [
132
- f"""
133
- <figure>
134
- <a href="{it["file"]}"><img src="{it["file"]}" loading="lazy" /></a>
135
- <figcaption>{it["prompt"]}</figcaption>
136
- </figure>
137
- """.strip()
138
- for it in items
139
- ]
140
- )
141
- html = f"""<!doctype html>
142
- <meta charset="utf-8" />
143
- <title>openai-image-gen</title>
144
- <style>
145
- :root {{ color-scheme: dark; }}
146
- body {{ margin: 24px; font: 14px/1.4 ui-sans-serif, system-ui; background: #0b0f14; color: #e8edf2; }}
147
- h1 {{ font-size: 18px; margin: 0 0 16px; }}
148
- .grid {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }}
149
- figure {{ margin: 0; padding: 12px; border: 1px solid #1e2a36; border-radius: 14px; background: #0f1620; }}
150
- img {{ width: 100%; height: auto; border-radius: 10px; display: block; }}
151
- figcaption {{ margin-top: 10px; color: #b7c2cc; }}
152
- code {{ color: #9cd1ff; }}
153
- </style>
154
- <h1>openai-image-gen</h1>
155
- <p>Output: <code>{out_dir.as_posix()}</code></p>
156
- <div class="grid">
157
- {thumbs}
158
- </div>
159
- """
160
- (out_dir / "index.html").write_text(html, encoding="utf-8")
161
-
162
-
163
- def main() -> int:
164
- ap = argparse.ArgumentParser(description="Generate images via OpenAI Images API.")
165
- ap.add_argument("--prompt", help="Single prompt. If omitted, random prompts are generated.")
166
- ap.add_argument("--count", type=int, default=8, help="How many images to generate.")
167
- ap.add_argument("--model", default="gpt-image-1", help="Image model id.")
168
- ap.add_argument("--size", default="", help="Image size (e.g. 1024x1024, 1536x1024). Defaults based on model if not specified.")
169
- ap.add_argument("--quality", default="", help="Image quality (e.g. high, standard). Defaults based on model if not specified.")
170
- ap.add_argument("--background", default="", help="Background transparency (GPT models only): transparent, opaque, or auto.")
171
- ap.add_argument("--output-format", default="", help="Output format (GPT models only): png, jpeg, or webp.")
172
- ap.add_argument("--style", default="", help="Image style (dall-e-3 only): vivid or natural.")
173
- ap.add_argument("--out-dir", default="", help="Output directory (default: ./tmp/openai-image-gen-<ts>).")
174
- args = ap.parse_args()
175
-
176
- api_key = (os.environ.get("OPENAI_API_KEY") or "").strip()
177
- if not api_key:
178
- print("Missing OPENAI_API_KEY", file=sys.stderr)
179
- return 2
180
-
181
- # Apply model-specific defaults if not specified
182
- default_size, default_quality = get_model_defaults(args.model)
183
- size = args.size or default_size
184
- quality = args.quality or default_quality
185
-
186
- count = args.count
187
- if args.model == "dall-e-3" and count > 1:
188
- print(f"Warning: dall-e-3 only supports generating 1 image at a time. Reducing count from {count} to 1.", file=sys.stderr)
189
- count = 1
190
-
191
- out_dir = Path(args.out_dir).expanduser() if args.out_dir else default_out_dir()
192
- out_dir.mkdir(parents=True, exist_ok=True)
193
-
194
- prompts = [args.prompt] * count if args.prompt else pick_prompts(count)
195
-
196
- # Determine file extension based on output format
197
- if args.model.startswith("gpt-image") and args.output_format:
198
- file_ext = args.output_format
199
- else:
200
- file_ext = "png"
201
-
202
- items: list[dict] = []
203
- for idx, prompt in enumerate(prompts, start=1):
204
- print(f"[{idx}/{len(prompts)}] {prompt}")
205
- res = request_images(
206
- api_key,
207
- prompt,
208
- args.model,
209
- size,
210
- quality,
211
- args.background,
212
- args.output_format,
213
- args.style,
214
- )
215
- data = res.get("data", [{}])[0]
216
- image_b64 = data.get("b64_json")
217
- image_url = data.get("url")
218
- if not image_b64 and not image_url:
219
- raise RuntimeError(f"Unexpected response: {json.dumps(res)[:400]}")
220
-
221
- filename = f"{idx:03d}-{slugify(prompt)[:40]}.{file_ext}"
222
- filepath = out_dir / filename
223
- if image_b64:
224
- filepath.write_bytes(base64.b64decode(image_b64))
225
- else:
226
- try:
227
- urllib.request.urlretrieve(image_url, filepath)
228
- except urllib.error.URLError as e:
229
- raise RuntimeError(f"Failed to download image from {image_url}: {e}") from e
230
-
231
- items.append({"prompt": prompt, "file": filename})
232
-
233
- (out_dir / "prompts.json").write_text(json.dumps(items, indent=2), encoding="utf-8")
234
- write_gallery(out_dir, items)
235
- print(f"\nWrote: {(out_dir / 'index.html').as_posix()}")
236
- return 0
237
-
238
-
239
- if __name__ == "__main__":
240
- raise SystemExit(main())
@@ -1,39 +0,0 @@
1
- ---
2
- name: openai-whisper
3
- description: Local speech-to-text with the Whisper CLI (no API key).
4
- homepage: https://openai.com/research/whisper
5
- metadata:
6
- {
7
- "symi":
8
- {
9
- "emoji": "🎙️",
10
- "requires": { "bins": ["whisper"] },
11
- "install":
12
- [
13
- {
14
- "id": "brew",
15
- "kind": "brew",
16
- "formula": "openai-whisper",
17
- "bins": ["whisper"],
18
- "label": "Install OpenAI Whisper (brew)",
19
- },
20
- ],
21
- },
22
- }
23
- triggers: [openai-whisper, openai, whisper]
24
- ---
25
-
26
- # Whisper (CLI)
27
-
28
- Use `whisper` to transcribe audio locally.
29
-
30
- Quick start
31
-
32
- - `whisper /path/audio.mp3 --model medium --output_format txt --output_dir .`
33
- - `whisper /path/audio.m4a --task translate --output_format srt`
34
-
35
- Notes
36
-
37
- - Models download to `~/.cache/whisper` on first run.
38
- - `--model` defaults to `turbo` on this install.
39
- - Use smaller models for speed, larger for accuracy.
@@ -1,53 +0,0 @@
1
- ---
2
- name: openai-whisper-api
3
- description: Transcribe audio via OpenAI Audio Transcriptions API (Whisper).
4
- homepage: https://platform.openai.com/docs/guides/speech-to-text
5
- metadata:
6
- {
7
- "symi":
8
- {
9
- "emoji": "☁️",
10
- "requires": { "bins": ["curl"], "env": ["OPENAI_API_KEY"] },
11
- "primaryEnv": "OPENAI_API_KEY",
12
- },
13
- }
14
- triggers: [openai-whisper-api, openai, whisper, api]
15
- ---
16
-
17
- # OpenAI Whisper API (curl)
18
-
19
- Transcribe an audio file via OpenAI’s `/v1/audio/transcriptions` endpoint.
20
-
21
- ## Quick start
22
-
23
- ```bash
24
- {baseDir}/scripts/transcribe.sh /path/to/audio.m4a
25
- ```
26
-
27
- Defaults:
28
-
29
- - Model: `whisper-1`
30
- - Output: `<input>.txt`
31
-
32
- ## Useful flags
33
-
34
- ```bash
35
- {baseDir}/scripts/transcribe.sh /path/to/audio.ogg --model whisper-1 --out /tmp/transcript.txt
36
- {baseDir}/scripts/transcribe.sh /path/to/audio.m4a --language en
37
- {baseDir}/scripts/transcribe.sh /path/to/audio.m4a --prompt "Speaker names: Peter, Daniel"
38
- {baseDir}/scripts/transcribe.sh /path/to/audio.m4a --json --out /tmp/transcript.json
39
- ```
40
-
41
- ## API key
42
-
43
- Set `OPENAI_API_KEY`, or configure it in `~/.symi/symi.json`:
44
-
45
- ```json5
46
- {
47
- skills: {
48
- "openai-whisper-api": {
49
- apiKey: "OPENAI_KEY_HERE",
50
- },
51
- },
52
- }
53
- ```