├── .gitignore ├── AutoUnsubscribe.md ├── JS_Menus ├── menu.vcf ├── menu_engine.js ├── menu_lucy.json ├── prepare_tool_dictionary_from_option_values.js ├── schemas.json ├── schemas.yml └── test.js ├── LICENSE ├── Lucy ├── README.md ├── device_settings_iphone.json ├── device_settings_iphone1.json ├── device_settings_mac.json ├── device_settings_mac1.json ├── global_schema.json ├── img │ ├── config.webp │ └── tool_config.webp ├── js.js ├── merge_dictionaries.js └── tool_definitions │ ├── alarms.json │ ├── alarms.yml │ ├── app_store.json │ ├── app_store.yml │ ├── calendar.json │ ├── calendar.yml │ ├── contacts.json │ ├── contacts.yml │ ├── deepresearch.json │ ├── deepresearch.yml │ ├── device.json │ ├── device.yml │ ├── mail.json │ ├── mail.yml │ ├── maps.json │ ├── maps.yml │ ├── memory.json │ ├── memory.yml │ ├── messages.json │ ├── messages.yml │ ├── morsecode.json │ ├── morsecode.yml │ ├── notes.json │ ├── notes.yml │ ├── pythonista.json │ ├── pythonista.yml │ ├── recipecataloger.json │ ├── recipecataloger.yml │ ├── reminders.json │ ├── reminders.yml │ ├── runjavascript.json │ ├── runjavascript.yml │ ├── summarizetext.json │ ├── summarizetext.yml │ ├── terminal.json │ ├── terminal.yml │ ├── timers.json │ ├── timers.yml │ ├── voicemode.json │ ├── voicemode.yml │ ├── weather.json │ ├── weather.yml │ ├── web.json │ └── web.yml ├── MenuGenerator.md ├── README.md ├── dup.md ├── img ├── IMG_1034.png ├── MediaKitCred.PNG ├── Mosaic_banner.png ├── Mosaic_color space.png ├── Mosaic_examples.png ├── Mosaic_grid size.png ├── Mosaic_long and tall images.png ├── Mosaic_progress.png ├── Mosaic_tile matching.png ├── Mosaic_tile subdivision.png ├── Mosaic_tile useage.png ├── ReminderPDF.png ├── TSP_features.png ├── TSP_permissions.png ├── TSP_routing_map.png ├── TSP_share sheet.png ├── ThinkBuddy chat viewer.png ├── auto unsub automation1.png ├── auto unsub automation2.png ├── auto unsub logged.png ├── auto unsub method1.png ├── auto unsub method2.png ├── auto unsub test.png ├── dup_1banner.png ├── dup_2selection.png ├── dup_3search.png ├── dup_4clean.png ├── dup_5config.png ├── dup_collage.png ├── gemini_dropin.png ├── gemini_file_types.png ├── gemini_image.png ├── gemini_pdf.png ├── gemini_tests.png ├── gemini_text.png ├── gemini_viewer.png ├── gemini_viewer_iOS.png ├── gemini_viewer_macOS.png ├── made-with-menu-generator-badge.png ├── menu-generator-advanced-menu.png ├── menu-generator-banner.png ├── menu-generator-example.png ├── menu-generator-font-awesome-site.png ├── menu-generator-hero-image.png ├── menu-generator-permissions.png ├── menu-generator-quick-menu-example.png ├── out.gif ├── photo_collage_video_thumb.png ├── powered by gemini via api.PNG ├── powered_by_pro_ai.png ├── social_banner.png └── view-continue-gemini-convo.png ├── mosaic_readme.md └── yml_to_json.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .qodo 3 | -------------------------------------------------------------------------------- /AutoUnsubscribe.md: -------------------------------------------------------------------------------- 1 | # Auto Unsubscribe 2 | 3 | *Google Gemini version using Gemini via API* 4 | 5 | Auto Unsubscribe is a shortcut for automatically sending opt-out responses (e.g. "STOP") to spam text messages. 6 | I made it because I get far too many political texts, but needed a tool that wouldn't auto-unsubscribe from *everything*, just the spam I don't want. 7 | 8 | So far it's worked pretty good with 100% accuracy for the spam texts I receive. \*knocks wood 9 | 10 | ## How it works 11 | 12 | Incoming messages are screened for spam and categorized, and the chosen categories are automatically replied to. 13 | 14 | 1. You set it up as an automation, triggered by messages with the word "stop" in them, because the spam I get often contains some variation of "stop to quit" at the end. 15 | 1. You also define a list of types of spam that you want to use as categories, 16 | 2. and the spam types that should be auto-responded to. 17 | 18 | | ![Basic setup](https://github.com/twilsonco/SiriShortcuts/blob/main/img/auto%20unsub%20method1.png?raw=true) | ![Check methods](https://github.com/twilsonco/SiriShortcuts/blob/main/img/auto%20unsub%20method2.png?raw=true) | 19 | | ----- | ----- | 20 | | Define basic opt-out phrase list, detection/capture [regex](https://regex101.com) string, define spam types. | More opt-out phrase checking and Google Gemini via API\* spam classification. | 21 | 22 | 1. When a message triggers the automation, it's checked a bit more rigorously for a matching opt-out phrase at the end of the message. 23 | 2. If a match is found, then Google Gemini is used as a classifier to determine the type of unsubscribability. 24 | 3. If the spam type is in the list of defined auto-respond types, then the opt out phrase is automatically sent in response. 25 | 26 | \* *Google via API could be swapped out with any other similar service. You could replace the `Dictionary` and `Run Gemini via API` actions with the `Ask ChatGPT` action from the ChatGPT app or use some other API* 27 | 28 | ## Installation 29 | 30 | ### 1. Set up automation 31 | 32 | 1. In the Shortcuts app on iOS/iPadOS, go to the Automations tab and tap the "+" button to create a new automation. 33 | 2. Select a "Messages" automation type, and then set the "Message Contains" option to be triggered by the word "stop". 34 | 3. Tap "Next". 35 | 36 | ![Install 1](https://github.com/twilsonco/SiriShortcuts/blob/main/img/auto%20unsub%20automation1.png?raw=true) 37 | 4. Now we'll select the automation action. Tap "New Blank Automation" 38 | 5. In the new shortcut that opens, add a `Dictionary` action and add "from" and "body" keys to the dictionary, both text items. 39 | 1. In the text field of each, tap and hold and select "Shortcut Input". 40 | 2. Tap on the "Shortcut Input" for the "from" key and set it to "Sender". 41 | 3. Tap on the "Shortcut Input" for the "body" key and set it to "Content". 42 | 6. Add a `Run Shortcut` action and point it to `Auto Unsubscribe`. 43 | 44 | ![Install 2](https://github.com/twilsonco/SiriShortcuts/blob/main/img/auto%20unsub%20automation2.png?raw=true) 45 | 46 | ### 2. Run Auto Unsubscribe in test mode 47 | 48 | Run Auto Unsubscribe manually to allow it to acquire necessary permissions. It will run using some predefined test data, and generate a log file in your iCloud Drive/Shortcuts folder. This log will record everything Auto Unsubscribe does. 49 | 50 | ![Log](https://github.com/twilsonco/SiriShortcuts/blob/main/img/auto%20unsub%20logged.png?raw=true) 51 | 52 | ## Notes 53 | 54 | * When run manually, the shortcut checks for updates and dependencies. 55 | * I thought about having this do email too, but for email it's not as easy as replying with an opt-out phrase (you can often reply with subject "UNSUBSCRIBE" but it's not very dependable, and you often have a link to follow), so I probably won't try. At the very least I think it would take additional permissions each time it ran. 56 | * It would be cool to have Google Gemini determine the correct opt-out phrase to use, but I worry about it messing up. 57 | * Please let me know how this works for you, and feel free to offer suggestions and complaints. 58 | 59 | | [![MediaKit](https://github.com/twilsonco/SiriShortcuts/blob/main/img/MediaKitCred.PNG?raw=true)](https://routinehub.co/shortcut/1911/) | [![Gemini via API](https://github.com/twilsonco/SiriShortcuts/blob/main/img/powered%20by%20gemini%20via%20api.PNG?raw=true)](https://routinehub.co/shortcut/17624/) | 60 | | ----- | ----- | 61 | -------------------------------------------------------------------------------- /JS_Menus/menu.vcf: -------------------------------------------------------------------------------- 1 | BEGIN:VCARD 2 | VERSION:3.0 3 | N;CHARSET=utf-8:LLM model settings; 4 | ORG;CHARSET=UTF-8:Settings for the LLM model used by Lucy; 5 | NOTE:model 6 | END:VCARD 7 | BEGIN:VCARD 8 | VERSION:3.0 9 | N;CHARSET=utf-8:Tool settings; 10 | ORG;CHARSET=UTF-8:Settings for the tools used by Lucy; 11 | NOTE:tools 12 | END:VCARD 13 | BEGIN:VCARD 14 | VERSION:3.0 15 | N;CHARSET=utf-8:Check for updates every - 7 days; 16 | ORG;CHARSET=UTF-8:; 17 | NOTE:update_check_freq 18 | END:VCARD -------------------------------------------------------------------------------- /JS_Menus/prepare_tool_dictionary_from_option_values.js: -------------------------------------------------------------------------------- 1 | const tool_options = { 2 | "enabled": { 3 | "Alarms": true, 4 | "AppStore": true, 5 | "Calendar": true, 6 | "Clock": true, 7 | "Contacts": true, 8 | "DeepResearch": true, 9 | "Device": true, 10 | "Mail": true, 11 | "Maps": true, 12 | "Memory": true, 13 | "Messages": true, 14 | "MorseCode": true, 15 | "Notes": true, 16 | "Pythonista": true, 17 | "RecipeCataloger": true, 18 | "Reminders": true, 19 | "RunJavaScript": true, 20 | "Summarize": true, 21 | "Terminal": true, 22 | "Timers": true, 23 | "VoiceMode": true, 24 | "Weather": true, 25 | "Web": true 26 | }, 27 | "config": { 28 | "Alarms": { 29 | "run_confirmation": false, 30 | "run_notification": true 31 | }, 32 | "AppStore": { 33 | "run_confirmation": false, 34 | "run_notification": true 35 | }, 36 | "Calendar": { 37 | "run_confirmation": false, 38 | "run_notification": true 39 | }, 40 | "Contacts": { 41 | "run_confirmation": false, 42 | "run_notification": true 43 | }, 44 | "DeepResearch": { 45 | "run_confirmation": false, 46 | "run_notification": true 47 | }, 48 | "Device": { 49 | "run_confirmation": false, 50 | "run_notification": true 51 | }, 52 | "Mail": { 53 | "run_confirmation": false, 54 | "run_notification": true 55 | }, 56 | "Maps": { 57 | "run_confirmation": false, 58 | "run_notification": true 59 | }, 60 | "Memory": { 61 | "run_confirmation": false, 62 | "run_notification": true 63 | }, 64 | "Messages": { 65 | "run_confirmation": false, 66 | "run_notification": true 67 | }, 68 | "MorseCode": { 69 | "run_confirmation": false, 70 | "run_notification": true 71 | }, 72 | "Notes": { 73 | "run_confirmation": false, 74 | "run_notification": true 75 | }, 76 | "Pythonista": { 77 | "run_confirmation": false, 78 | "run_notification": true 79 | }, 80 | "RecipeCataloger": { 81 | "run_confirmation": false, 82 | "run_notification": true 83 | }, 84 | "Reminders": { 85 | "run_confirmation": false, 86 | "run_notification": true 87 | }, 88 | "RunJavaScript": { 89 | "run_confirmation": false, 90 | "run_notification": true 91 | }, 92 | "Summarize": { 93 | "run_confirmation": false, 94 | "run_notification": true, 95 | "parameters": { 96 | "provider": "Goodle", 97 | "api_key": "your_api_key_here", 98 | "url": "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions/", 99 | "model": "models/gemini-2.5-flash" 100 | } 101 | }, 102 | "Terminal": { 103 | "run_confirmation": false, 104 | "run_notification": true 105 | }, 106 | "Timers": { 107 | "run_confirmation": false, 108 | "run_notification": true 109 | }, 110 | "VoiceMode": { 111 | "run_confirmation": false, 112 | "run_notification": true 113 | }, 114 | "Weather": { 115 | "run_confirmation": false, 116 | "run_notification": true 117 | }, 118 | "Web": { 119 | "run_confirmation": false, 120 | "run_notification": true, 121 | "parameters": { 122 | "search_engine_id": "", 123 | "api_key": "" 124 | } 125 | } 126 | }, 127 | "choose_tools": false, 128 | "choose_select_all": true, 129 | "install_tools": true, 130 | "approve_tools": false 131 | }; 132 | 133 | const tool_urls = { 134 | "Device_v1-0":"https:\/\/www.icloud.com\/shortcuts\/875681d63c0e46d88e00d280e56f6b15","Alarms_v1-0":"https:\/\/www.icloud.com\/shortcuts\/1c895d4a1eb343a6b467dc659bbb55c5","Memory_v1-2":"https:\/\/www.icloud.com\/shortcuts\/a7150a7d9f6a4d9f90dbfcc871cbf7d1","Messages_v1-1":"https:\/\/www.icloud.com\/shortcuts\/05c45719e0ff44deabc7e9f18e68106b","Summarize_v1-2":"https:\/\/www.icloud.com\/shortcuts\/bfd0dc989f9142f691c3d5f1929cdc2b","Terminal_v1-1":"https:\/\/www.icloud.com\/shortcuts\/4d275920264a4111b37600e793c140db","VoiceMode_v1-0":"https:\/\/www.icloud.com\/shortcuts\/53812561932446f6b83e16ef7b469b9c","Maps_v1-2":"https:\/\/www.icloud.com\/shortcuts\/7d8498566a0f4369aafaabee836ce4b0","Pythonista_v1-1":"https:\/\/www.icloud.com\/shortcuts\/4879e7c9daa947cfbcd6a517415304d4","Notes_v1-2":"https:\/\/www.icloud.com\/shortcuts\/7a6c17f3659a4f26a67a8489dcb388e4","AppStore_v1-0":"https:\/\/www.icloud.com\/shortcuts\/4d531b8de0404ba783e41873eaefdbd4","DeepResearch_v1-2":"https:\/\/www.icloud.com\/shortcuts\/14f24c9a251b4323a30e5f7f9c4bc1ba","RunJavaScript_v1-1":"https:\/\/www.icloud.com\/shortcuts\/9d65f594ff10419b9daaf8dde6e09b52","RecipeCataloger_v1-0":"https:\/\/www.icloud.com\/shortcuts\/4aedae38060348a6868ffa720faab7bf","Mail_v1-1":"https:\/\/www.icloud.com\/shortcuts\/4715a81960fb46ab9acda0a0343fb7e8","MorseCode_v1-0":"https:\/\/www.icloud.com\/shortcuts\/b0a361cd5dea4fd087e1b0868b983fd5","Timers_v1-0":"https:\/\/www.icloud.com\/shortcuts\/960bd73a2d58463da1a29cff4a3526f6","Reminders_v1-4":"https:\/\/www.icloud.com\/shortcuts\/14ff9e42af8b43edb2d3d462f283a828","Web_v1-3":"https:\/\/www.icloud.com\/shortcuts\/ab8d6a84736e4ea1a99931f4df5561e0","Calendar_v1-1":"https:\/\/www.icloud.com\/shortcuts\/8f5e1f2974cc462e9ffc87bb4c9871b0","Contacts_v1-1":"https:\/\/www.icloud.com\/shortcuts\/62e234a8cec741428cbfc658e4100107","Weather_v1-3":"https:\/\/www.icloud.com\/shortcuts\/b622f0f6af7b467589d80f18262fc113" 135 | }; 136 | 137 | const tools = {}; 138 | 139 | for (const [toolKey, url] of Object.entries(tool_urls)) { 140 | const toolName = toolKey.split('_')[0]; 141 | 142 | tools[toolKey] = { 143 | enable: tool_options.enabled[toolName] || false, 144 | url: url 145 | }; 146 | 147 | // Add all key/value pairs from tool_options, copying them into tools with the same key 148 | for (const [key, value] of Object.entries(tool_options.config[toolName] || {})) { 149 | tools[toolKey][key] = value; 150 | } 151 | } 152 | 153 | console.log(JSON.stringify(tools, null, 2)); 154 | -------------------------------------------------------------------------------- /JS_Menus/schemas.json: -------------------------------------------------------------------------------- 1 | { 2 | "menu_item_base": { 3 | "type": "object", 4 | "properties": { 5 | "name": { 6 | "type": "string" 7 | }, 8 | "description": { 9 | "type": "string" 10 | }, 11 | "icon": { 12 | "type": "string" 13 | }, 14 | "index": { 15 | "type": "number" 16 | }, 17 | "masked": { 18 | "type": "boolean", 19 | "default": false 20 | } 21 | }, 22 | "required": [ 23 | "name", 24 | "description", 25 | "type" 26 | ] 27 | }, 28 | "stringItem": { 29 | "allOf": [ 30 | { 31 | "$ref": "#/menu_item_base" 32 | }, 33 | { 34 | "type": "object", 35 | "properties": { 36 | "type": { 37 | "const": "String" 38 | }, 39 | "value": { 40 | "type": "string" 41 | }, 42 | "default": { 43 | "type": "string" 44 | }, 45 | "multiline": { 46 | "type": "boolean", 47 | "default": false 48 | } 49 | }, 50 | "required": [ 51 | "value" 52 | ] 53 | } 54 | ] 55 | }, 56 | "dateItem": { 57 | "allOf": [ 58 | { 59 | "$ref": "#/menu_item_base" 60 | }, 61 | { 62 | "type": "object", 63 | "properties": { 64 | "type": { 65 | "const": "Date" 66 | }, 67 | "value": { 68 | "type": "string" 69 | }, 70 | "default": { 71 | "type": "string" 72 | } 73 | }, 74 | "required": [ 75 | "value" 76 | ] 77 | } 78 | ] 79 | }, 80 | "dateTimeItem": { 81 | "allOf": [ 82 | { 83 | "$ref": "#/menu_item_base" 84 | }, 85 | { 86 | "type": "object", 87 | "properties": { 88 | "type": { 89 | "const": "Datetime" 90 | }, 91 | "value": { 92 | "type": "string" 93 | }, 94 | "default": { 95 | "type": "string" 96 | } 97 | }, 98 | "required": [ 99 | "value" 100 | ] 101 | } 102 | ] 103 | }, 104 | "timeItem": { 105 | "allOf": [ 106 | { 107 | "$ref": "#/menu_item_base" 108 | }, 109 | { 110 | "type": "object", 111 | "properties": { 112 | "type": { 113 | "const": "Time" 114 | }, 115 | "value": { 116 | "type": "string" 117 | }, 118 | "default": { 119 | "type": "string" 120 | } 121 | }, 122 | "required": [ 123 | "value" 124 | ] 125 | } 126 | ] 127 | }, 128 | "urlItem": { 129 | "allOf": [ 130 | { 131 | "$ref": "#/menu_item_base" 132 | }, 133 | { 134 | "type": "object", 135 | "properties": { 136 | "type": { 137 | "const": "URL" 138 | }, 139 | "value": { 140 | "type": "string" 141 | }, 142 | "default": { 143 | "type": "string" 144 | } 145 | }, 146 | "required": [ 147 | "value" 148 | ] 149 | } 150 | ] 151 | }, 152 | "numberItem": { 153 | "allOf": [ 154 | { 155 | "$ref": "#/menu_item_base" 156 | }, 157 | { 158 | "type": "object", 159 | "properties": { 160 | "type": { 161 | "const": "Number" 162 | }, 163 | "value": { 164 | "type": "number" 165 | }, 166 | "min": { 167 | "type": "number" 168 | }, 169 | "max": { 170 | "type": "number" 171 | }, 172 | "allow_decimal": { 173 | "type": "boolean", 174 | "default": true 175 | }, 176 | "default": { 177 | "type": "string" 178 | } 179 | }, 180 | "required": [ 181 | "value" 182 | ] 183 | } 184 | ] 185 | }, 186 | "booleanItem": { 187 | "allOf": [ 188 | { 189 | "$ref": "#/menu_item_base" 190 | }, 191 | { 192 | "type": "object", 193 | "properties": { 194 | "type": { 195 | "const": "Boolean" 196 | }, 197 | "value": { 198 | "type": "boolean" 199 | }, 200 | "default": { 201 | "type": "string" 202 | } 203 | }, 204 | "required": [ 205 | "value" 206 | ] 207 | } 208 | ] 209 | }, 210 | "EnumOption": { 211 | "allOf": [ 212 | { 213 | "$ref": "#/menu_item_base" 214 | }, 215 | { 216 | "type": "object", 217 | "properties": { 218 | "type": { 219 | "const": "EnumOption" 220 | } 221 | } 222 | } 223 | ] 224 | }, 225 | "enumItem": { 226 | "allOf": [ 227 | { 228 | "$ref": "#/menu_item_base" 229 | }, 230 | { 231 | "type": "object", 232 | "properties": { 233 | "type": { 234 | "const": "Enum" 235 | }, 236 | "value": { 237 | "type": "string" 238 | }, 239 | "menu": { 240 | "type": "object", 241 | "additionalProperties": { 242 | "$ref": "#/EnumOption" 243 | } 244 | }, 245 | "default": { 246 | "type": "string" 247 | } 248 | }, 249 | "required": [ 250 | "value", 251 | "menu" 252 | ] 253 | } 254 | ] 255 | }, 256 | "submenuItem": { 257 | "allOf": [ 258 | { 259 | "$ref": "#/menu_item_base" 260 | }, 261 | { 262 | "type": "object", 263 | "properties": { 264 | "type": { 265 | "const": "Submenu" 266 | }, 267 | "menu": { 268 | "$ref": "#/menu" 269 | } 270 | }, 271 | "required": [ 272 | "menu" 273 | ] 274 | } 275 | ] 276 | }, 277 | "commandItem": { 278 | "allOf": [ 279 | { 280 | "$ref": "#/menu_item_base" 281 | }, 282 | { 283 | "type": "object", 284 | "properties": { 285 | "type": { 286 | "const": "Command" 287 | } 288 | } 289 | } 290 | ] 291 | }, 292 | "menu_item": { 293 | "oneOf": [ 294 | { 295 | "$ref": "#/stringItem" 296 | }, 297 | { 298 | "$ref": "#/urlItem" 299 | }, 300 | { 301 | "$ref": "#/numberItem" 302 | }, 303 | { 304 | "$ref": "#/booleanItem" 305 | }, 306 | { 307 | "$ref": "#/enumItem" 308 | }, 309 | { 310 | "$ref": "#/submenuItem" 311 | }, 312 | { 313 | "$ref": "#/commandItem" 314 | }, 315 | { 316 | "$ref": "#/EnumOption" 317 | }, 318 | { 319 | "$ref": "#/dateItem" 320 | }, 321 | { 322 | "$ref": "#/dateTimeItem" 323 | }, 324 | { 325 | "$ref": "#/timeItem" 326 | } 327 | ], 328 | "discriminator": { 329 | "propertyName": "type" 330 | } 331 | }, 332 | "menu": { 333 | "$schema": "http://json-schema.org/draft-07/schema#", 334 | "title": "Menu Dictionary", 335 | "type": "object", 336 | "additionalProperties": { 337 | "$ref": "#/menu_item" 338 | } 339 | }, 340 | "state": { 341 | "$schema": "http://json-schema.org/draft-07/schema#", 342 | "title": "State Dictionary", 343 | "type": "object", 344 | "properties": { 345 | "current_path": { 346 | "type": "string", 347 | "default": "" 348 | }, 349 | "new_value": { 350 | "type": "object", 351 | "minProperties": 1, 352 | "maxProperties": 1, 353 | "additionalProperties": true 354 | }, 355 | "option_values": { 356 | "$ref": "#/option_values" 357 | } 358 | }, 359 | "required": [ 360 | "current_path" 361 | ], 362 | "additionalProperties": false 363 | }, 364 | "option_values": { 365 | "$schema": "http://json-schema.org/draft-07/schema#", 366 | "title": "Option Values", 367 | "type": "object", 368 | "additionalProperties": { 369 | "type": [ 370 | "string", 371 | "number", 372 | "boolean" 373 | ] 374 | } 375 | }, 376 | "return": { 377 | "$schema": "http://json-schema.org/draft-07/schema#", 378 | "title": "JS Return Object", 379 | "oneOf": [ 380 | { 381 | "type": "object", 382 | "properties": { 383 | "menu": { 384 | "type": "array", 385 | "items": { 386 | "type": "string" 387 | } 388 | }, 389 | "option_values": { 390 | "$ref": "#/option_values" 391 | }, 392 | "menu_dict": { 393 | "$ref": "#/menu" 394 | }, 395 | "state": { 396 | "$ref": "#/state" 397 | }, 398 | "command": { 399 | "type": "string" 400 | }, 401 | "error": { 402 | "type": "string" 403 | } 404 | }, 405 | "required": [ 406 | "menu", 407 | "option_values", 408 | "menu_dict", 409 | "state" 410 | ], 411 | "additionalProperties": false 412 | }, 413 | { 414 | "type": "object", 415 | "properties": { 416 | "error": { 417 | "type": "string" 418 | } 419 | }, 420 | "required": [ 421 | "error" 422 | ], 423 | "additionalProperties": false 424 | } 425 | ] 426 | } 427 | } 428 | -------------------------------------------------------------------------------- /JS_Menus/schemas.yml: -------------------------------------------------------------------------------- 1 | # schemas.yml (v2.3) 2 | 3 | # --- Reusable Component Definitions --- 4 | 5 | menu_item_base: 6 | type: object 7 | properties: 8 | name: { type: string } 9 | description: { type: string } 10 | icon: { type: string } 11 | index: { type: number } 12 | masked: { type: boolean, default: false } 13 | required: [name, description, type] 14 | 15 | stringItem: 16 | allOf: 17 | - { $ref: '#/menu_item_base' } 18 | - type: object 19 | properties: 20 | type: { const: 'String' } 21 | value: { type: string } 22 | linked_default: { type: string } 23 | multiline: { type: boolean, default: false} 24 | required: [value] 25 | 26 | dateItem: 27 | allOf: 28 | - { $ref: '#/menu_item_base' } 29 | - type: object 30 | properties: 31 | type: { const: 'Date' } 32 | value: { type: string } 33 | linked_default: { type: string } 34 | required: [value] 35 | 36 | dateTimeItem: 37 | allOf: 38 | - { $ref: '#/menu_item_base' } 39 | - type: object 40 | properties: 41 | type: { const: 'Datetime' } 42 | value: { type: string } 43 | linked_default: { type: string } 44 | required: [value] 45 | 46 | timeItem: 47 | allOf: 48 | - { $ref: '#/menu_item_base' } 49 | - type: object 50 | properties: 51 | type: { const: 'Time' } 52 | value: { type: string } 53 | linked_default: { type: string } 54 | required: [value] 55 | 56 | urlItem: 57 | allOf: 58 | - { $ref: '#/menu_item_base' } 59 | - type: object 60 | properties: 61 | type: { const: 'URL' } 62 | value: { type: string } 63 | linked_default: { type: string } 64 | required: [value] 65 | 66 | numberItem: 67 | allOf: 68 | - { $ref: '#/menu_item_base' } 69 | - type: object 70 | properties: 71 | type: { const: 'Number' } 72 | value: { type: number } 73 | min: { type: number } 74 | max: { type: number } 75 | allow_decimal: { type: boolean, default: true } 76 | linked_default: { type: string } 77 | required: [value] 78 | 79 | booleanItem: 80 | allOf: 81 | - { $ref: '#/menu_item_base' } 82 | - type: object 83 | properties: 84 | type: { const: 'Boolean' } 85 | value: { type: boolean } 86 | linked_default: { type: string } 87 | required: [value] 88 | 89 | # New definition for an option within an Enum's menu 90 | EnumOption: 91 | allOf: 92 | - { $ref: '#/menu_item_base' } 93 | - type: object 94 | properties: 95 | type: { const: 'EnumOption' } 96 | # This type does not have a 'value' property 97 | 98 | enumItem: 99 | allOf: 100 | - { $ref: '#/menu_item_base' } 101 | - type: object 102 | properties: 103 | type: { const: 'Enum' } 104 | value: { type: string } 105 | menu: 106 | type: object 107 | additionalProperties: { $ref: '#/EnumOption' } 108 | linked_default: { type: string } 109 | required: [value, menu] 110 | 111 | submenuItem: 112 | allOf: 113 | - { $ref: '#/menu_item_base' } 114 | - type: object 115 | properties: 116 | type: { const: 'Submenu' } 117 | menu: { $ref: '#/menu' } # Points to the main menu definition 118 | required: [menu] 119 | 120 | commandItem: 121 | allOf: 122 | - { $ref: '#/menu_item_base' } 123 | - type: object 124 | properties: 125 | type: { const: 'Command' } 126 | 127 | menu_item: 128 | oneOf: 129 | - { $ref: '#/stringItem' } 130 | - { $ref: '#/urlItem' } 131 | - { $ref: '#/numberItem' } 132 | - { $ref: '#/booleanItem' } 133 | - { $ref: '#/enumItem' } 134 | - { $ref: '#/submenuItem' } 135 | - { $ref: '#/commandItem' } 136 | - { $ref: '#/EnumOption' } 137 | - { $ref: '#/dateItem' } 138 | - { $ref: '#/dateTimeItem' } 139 | - { $ref: '#/timeItem' } 140 | discriminator: 141 | propertyName: "type" 142 | 143 | # --- Top-Level Schemas --- 144 | 145 | menu: 146 | $schema: "http://json-schema.org/draft-07/schema#" 147 | title: "Menu Dictionary" 148 | type: object 149 | additionalProperties: { $ref: '#/menu_item' } 150 | 151 | state: 152 | $schema: "http://json-schema.org/draft-07/schema#" 153 | title: "State Dictionary" 154 | type: object 155 | properties: 156 | current_path: { type: string, default: "" } 157 | new_value: 158 | type: object 159 | minProperties: 1 160 | maxProperties: 1 161 | additionalProperties: true 162 | option_values: 163 | $ref: '#/option_values' 164 | required: [current_path] 165 | additionalProperties: false 166 | 167 | option_values: 168 | $schema: "http://json-schema.org/draft-07/schema#" 169 | title: "Option Values" 170 | type: object 171 | additionalProperties: 172 | type: [string, number, boolean] 173 | 174 | return: 175 | $schema: "http://json-schema.org/draft-07/schema#" 176 | title: "JS Return Object" 177 | oneOf: 178 | - type: object 179 | properties: 180 | menu: 181 | type: array 182 | items: { type: string } 183 | option_values: { $ref: '#/option_values' } 184 | menu_dict: { $ref: '#/menu' } 185 | state: { $ref: '#/state' } 186 | command: { type: string } 187 | error: { type: string } 188 | required: [menu, option_values, menu_dict, state] 189 | additionalProperties: false 190 | - type: object 191 | properties: 192 | error: { type: string } 193 | required: [error] 194 | additionalProperties: false 195 | -------------------------------------------------------------------------------- /JS_Menus/test.js: -------------------------------------------------------------------------------- 1 | const a = true; 2 | console.log(String(a)); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Tim Wilson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lucy/README.md: -------------------------------------------------------------------------------- 1 | # Lucy 2 | 3 | **[Direct download link](https://www.icloud.com/shortcuts/bd8a27f658d74b0d9b11310c2c782cfe)** 4 | 5 | Lucy is a Siri Shortcut for iOS, iPadOS, and macOS that integrates with any OpenAI API-compatible Large Language Model (LLM) endpoint. It operates by utilizing other shortcuts as tools to accomplish tasks. Lucy works with full control over planning and execution, calling tools sequentially without requiring user input or oversight. This is similar to the model context protocol (MCP) that's gaining popularity in the AI community, where a model can call other models or tools to complete tasks. 6 | 7 | You can run the Lucy shortcut directly, or share text/image to Lucy to use it as context. 8 | 9 | Try running Lucy and ask her what she can do! 10 | 11 | This shortcut was initially introduced by u/Neurogram. I improved things by creating expanding Lucy's toolset and enhancing its existing tools. Other improvements include: 12 | 13 | - Image input support 14 | - Improved user communication (including presenting lists of choices where appropriate) 15 | - Automatic downloading of missing or updated tools 16 | - JSON validation of LLM responses to prevent errors or crashes 17 | - Optional debug logging (requires the free ["Logger for Shortcuts" app](https://apps.apple.com/us/app/logger-for-shortcuts/id1611554653)) 18 | 19 | **Configurability:** 20 | Lucy is configurable to meet user preferences: 21 | 22 | - **Tool Access:** Users can select which tools Lucy has access to, either for a single run or on a persistent basis by configuring the shortcut. 23 | - **Permissions:** Each tool can be configured to require user permission before use. If enabled, approval can be granted for each individual usage or once per tool per Lucy run. 24 | - **Notifications:** Notifications can be configured to show when each tool is used. 25 | 26 | **Tool Management:** 27 | Lucy's tools are separate Siri Shortcuts. You get to decide which tools will be loaded. Enabled tools download automatically when you run Lucy if they've been updated or are not yet installed. 28 | 29 | ### Lucy's Toolset 30 | 31 | 1. **Alarms**: Create/enable/disable/delete or get information about alarms in the Clock app. 32 | 2. **App Store**: Search for iOS/iPad/Mac apps 33 | 3. **Calendar**: Manages events, including searching, creating, and editing entries in the Calendar app. 34 | 4. **Contacts**: Manages contacts, including searching and adding entries. 35 | 5. **DeepResearch**: Conducts in-depth research by aggregating data from multiple sources to create informative reports saved to Notes. 36 | 6. **Device**: Controls device settings and retrieves device info. 37 | - Settings that can be changed (*italics means not on Mac*): *`accessibility_assistive_touch`*, `accessibility_audio_descriptions`, `accessibility_captions_shd`, `accessibility_color_filters`, `accessibility_increased_ui_contrast`, `accessibility_live_captions`, `accessibility_mono_audio`, *`accessibility_reduce_white_point`, `accessibility_start_guided_access`*, `accessibility_voice_control`, `accessibility_voice_over`, `airdrop_receive_contacts_only`, `airdrop_receive_everyone_10_minutes`, *`airplane_mode`, `auto_answer_calls`*, `bluetooth`, *`cellular_data`, `cellular_data_roaming`, `flashlight`, `font_size`, `LED_flash_for_calls_notifications`*, `lock_screen`, *`low_power_mode`*, `media_volume`, *`orientation_lock`, `personal_hotspot_password`, `personal_wifi_hotspot`, `play_background_sounds`, `play_background_sounds_when_media_is_playing`*, `reboot_device`, `recognize_ambient_sounds`, `reduce_ui_motion`, `reduce_ui_transparency`, *`reset_cellular_data_statistics`*, `ringtone_volume`, `screen_brightness`, `screen_night_shift_warm_colors`, `screen_true_tone_color`, `shutdown_device`, `ui_classic_invert_colors`, `ui_dark_mode`, `ui_smart_invert_colors`, `vpn`, `vpn_on_demand`, `wifi` 38 | - Info that can be retrieved: `battery`, `current_focus_mode`, `device_and_OS_info`, `display_info`, `network_info`, *`personal_hotspot_password`*, `volume` 39 | 7. **Mail**: Sends emails to specified recipients via the Mail app. 40 | 8. **Maps**: Searches places, provides navigation, and retrieves current location using Maps app. 41 | 9. **Memory**: Stores, retrieves, and searches for important information (memories) about the user. 42 | 10. **Messages**: Sends messages to specified recipients via the Messages app. 43 | 11. **MorseCode**: Converts text messages to Morse code and transmits them using the device's flashlight and/or screen flashing. This tool can be used for fun or in emergencies. 44 | 12. **Notes**: Manages Apple Notes app, allowing creation, modification, organization, and searching. 45 | 13. **Pythonista**: Executes Python code using the [Pythonista app](https://apps.apple.com/us/app/pythonista-3/id1085978097). 46 | 14. **RecipeCataloger**: Catalogs recipes by finding, extracting, and organizing them from web sources into a personal collection. Each recipe gets a Note and its ingredients list added to "Lucy's Shopping List" in Reminders. 47 | 15. **Reminders**: Manages tasks and reminders within the Reminders app. 48 | 16. **RunJavaScript**: Executes custom JavaScript code for computational tasks and string processing. 49 | 17. **Summarize**: Summarizes text, webpage content (including PDF and other files), or YouTube video transcripts to reduce token usage for the main model. Requires LLM API information. 50 | 18. **Terminal**: Executes Unix shell commands in a local terminal environment (using the [A-Shell Mini app](https://apps.apple.com/us/app/a-shell-mini/id1543537943) on iOS/iPadOS, but uses Terminal on macOS (no admin privileges) for more power). 51 | 19. **Timers**: Set a timer or pause/resume/cancel/check current timer in the Clock app. 52 | 20. **VoiceMode**: Switches a text conversation to a voice conversation. Ask to leave voice mode and it will return to text mode. 53 | 21. **Weather**: Retrieves current and forecasted weather for specified locations. 54 | 22. **Web**: Performs web searches (Google, ArXiv, ChemRxiv), retrieves content from webpages, and retrieves YouTube video transcripts. Requires a free API key for a Google Programmable Search Engine to do Google searches. 55 | 56 | ### Auxiliary Shortcuts (not tools) 57 | 58 | 1. [Create task/note/event with Lucy](https://www.icloud.com/shortcuts/92fb1c2d8554436880db12c24f6600da): Share text or an image to Lucy which will create a task, note, or event based on the content. 59 | 2. [Create contact from image with Lucy](https://www.icloud.com/shortcuts/51cb272474a24b33845142a12e45b9fb): Run directly to take photo(s) or share images to the shortcut to have Lucy create a new contact from the info in the image/photo. 60 | 61 | --- 62 | 63 | ### Examples of What Lucy Can Do 64 | 65 | ##### "Are there any good videos about neural networks on YouTube?" 66 | 67 | - **Lucy:** 68 | 1. Call 'Web' to perform Google search for relevant YouTube videos 69 | 2. Present results to user 70 | - **User:** "Tell me about the contents of the first video." 71 | - **Lucy:** 72 | 1. Call 'Summarize' to get a summary of the YouTube video transcript and present it to the user 73 | 74 | ##### "Set a 7am alarm on weekdays and an 8am alarm on weekends" 75 | 76 | - **Lucy:** 77 | 1. Call 'Alarms' to set the requested alarms 78 | 79 | ##### "Text Jake to let him know which day we should meet next week for frisbee golf, and include some recommendations for good courses near me." 80 | 81 | - **Lucy:** 82 | 1. Call 'Weather' to check next week's weather. 83 | 2. Call 'Calendar' to find free days. 84 | 3. Call 'Contacts' to get Jake's phone number, handling multiple "Jakes". 85 | 4. Call 'Maps' to find nearby frisbee golf courses. 86 | 5. Call 'Web' to search for reviews of those courses. 87 | 6. Call 'Messages' to send the message to Jake with the chosen day and course recommendations. 88 | 7. [Depending on the value of the "preview" options in the Messages tool shortcut] 89 | - [preview enabled] Messages compose preview windows opens with the drafted message, allowing you to review and send it. 90 | - [preview disabled] Messages sends the message directly without preview. 91 | 92 | ##### "Let's plan a hike-party up Pike's Peak for Steve next month in my Hiking group sometime the week after next. Find a good day, put it on my calendar, put necessary supplies on my shopping list, and text Steve and the group." 93 | 94 | - **Lucy:** 95 | 1. Call 'Weather' to check the weather forecast for Pike's Peak for the week after next. 96 | 2. Call 'Calendar' to find a free day in your schedule. 97 | 3. Call 'Calendar' to create an event for the hike-party on the chosen day. 98 | 4. Call 'Contacts' to get Steve's contact information and the Hiking group. 99 | 5. Call 'Reminders' to add necessary supplies to "Lucy's Shopping List". 100 | 6. Call 'Messages' to draft a message to Steve and the Hiking group with the planned date and details. 101 | 7. [Depending on the value of the "preview" options in the Messages tool shortcut] 102 | - [preview enabled] Messages compose preview windows opens with the drafted message, allowing you to review and send it. 103 | - [preview disabled] Messages sends the message directly without preview. 104 | 105 | ##### "I have to pick between Seattle and Denver for some work next week. Which city has better weather?" 106 | 107 | - **Lucy:** 108 | 1. Call 'Weather' to get the forecast for Seattle and Denver for next week. 109 | 2. Compare the weather conditions and respond with the city that has better weather. 110 | 111 | ##### "Is now a good time to upgrade my Mac?" 112 | 113 | - **Lucy:** 114 | 1. Call 'Web' to search for articles and forums regarding Mac product cycles and community consensus. 115 | 2. If needed, call 'SummarizeText' Shortcut or 'Web' (get_webpage_content) to fetch full or summarized website content. 116 | 3. Present the user with the results. 117 | 118 | ##### "Plan my San Francisco trip next month. Find flights and hotels, suggest 3 attractions, and add trip details to my calendar." 119 | 120 | - **Lucy:** 121 | 1. Call 'Web' to search for flights, hotels, and attractions within specified parameters. 122 | 2. If needed, call 'SummarizeText' to process travel information from multiple sources. 123 | 3. Call 'Calendar' to create events for the trip dates. 124 | 4. Call 'Notes' to store the full itinerary including flight/hotel bookings and chosen attractions. 125 | 126 | ##### "Send a thank-you email to everyone who attended my birthday party last weekend. Find their contact info first." 127 | 128 | - **Lucy:** 129 | 1. Call 'Calendar' to find the "Birthday Party" event from last weekend and identify attendees. 130 | 2. Call 'Contacts' to retrieve the email addresses for each attendee. 131 | 3. Call 'Mail' to draft and send personalized thank-you emails. 132 | 133 | ##### "I love racing movies." 134 | 135 | - **Lucy:** 136 | 1. Call 'Memory' to store this information as a memory. 137 | 138 | ##### "Are there any good movies coming out this weekend I might like?" 139 | 140 | - **Lucy:** 141 | 1. Call 'Memory' to retrieve the user's preferences. 142 | 2. Call 'Web' to search for upcoming movie releases. 143 | 3. Call 'SummarizeText' to summarize relevant movie reviews. 144 | 4. Present the user with a list of recommended movies based on their preferences. 145 | 146 | ### Getting Started and Setup 147 | 148 | Setting up Lucy involves configuring its options within the main Lucy shortcut. These settings are found in a Dictionary action at the top of the shortcut: 149 | 150 | ![Main Lucy configuration](https://raw.githubusercontent.com/twilsonco/SiriShortcuts/refs/heads/main/Lucy/img/config.webp) 151 | 152 | 1. **LLM Settings:** 153 | 154 | - `provider`: Text (e.g., "Google" for Google models) 155 | - `url`: Text (the API endpoint URL) 156 | - `text_model`: Text (the specific LLM model ID) 157 | - `api_key`: Text (your API key for the chosen LLM provider) 158 | - `temperature`: Number between 0-2. Lower values yield more consistent, less error-prone, but less creative responses. 159 | - `reasoning_model`: Boolean. Set to `True` if the LLM you are using is a "reasoning model"; set to `False` if unsure. 160 | 161 | 2. **Tool and Interaction Settings:** 162 | 163 | - `choose_tools`: Boolean. If `True`, Lucy will present a list of tools for you to enable on each run. 164 | - `choose_select_all`: Boolean. If `choose_tools` is `True`, setting this to `True` will initially select all tools in the list presented to the user. 165 | - `install_tools`: Boolean. If `True`, Lucy will check that all enabled tools are installed on startup. Missing or updated tools will automatically download. 166 | - `token_usage_notification`: Boolean. If `True`, displays a notification showing token usage after a run. 167 | - `approve_tools`: Boolean. If `False`, disables tool approval dialogs completely. 168 | - `debug_logging`: Boolean. If `True`, logging is enabled and requires the free ["Logger for Shortcuts" App](https://apps.apple.com/us/app/logger-for-shortcuts/id1611554653). 169 | - `update_check_freq`: Number. How often (in days) to check for updates to Lucy and its tools. Set to `0` to check every run, or `-1` to disable update checks. 170 | 171 | 3. **Tool Configuration:** 172 | - Each tool has three options: `enable`, `run_confirmation`, and `run_notification`. 173 | - Only the tools you enable will download and be available for use. 174 | 175 | ![Example of tool configuration](https://raw.githubusercontent.com/twilsonco/SiriShortcuts/refs/heads/main/Lucy/img/tool_config.webp) 176 | 177 | 1. **Initial Run:** After configuring your LLM settings, run Lucy. It will automatically download and install all enabled tools. 178 | 179 | 2. **Individual Tool Setup:** Some tools require their own specific configuration. For example, the **Web** tool requires a free API key for a Google Programmable Search Engine, and the **SummarizeText** tool requires LLM API information. 180 | 181 | ### Contributing 182 | 183 | Contributions are welcome. If you have ideas for new tools, improvements, or bug fixes, please comment below! 184 | 185 | ### Acknowledgments 186 | 187 | Lucy was inspired by the original concept from r/Neurogram. 188 | -------------------------------------------------------------------------------- /Lucy/device_settings_iphone.json: -------------------------------------------------------------------------------- 1 | { 2 | "get_value": [ 3 | "battery", 4 | "current_focus_mode", 5 | "device_and_OS_info", 6 | "display_info", 7 | "network_info", 8 | "personal_hotspot_password", 9 | "volume" 10 | ], 11 | "set_value": { 12 | "font_size": "enum in [xs, s, m, default, l, xl, xxl]", 13 | "media_volume": "float in 0-1", 14 | "personal_hotspot_password": "string", 15 | "ringtone_volume": "float in 0-1", 16 | "screen_brightness": "float in 0-1" 17 | }, 18 | "toggle": [ 19 | "accessibility_assistive_touch", 20 | "accessibility_audio_descriptions", 21 | "accessibility_captions_shd", 22 | "accessibility_color_filters", 23 | "accessibility_increased_ui_contrast", 24 | "accessibility_live_captions", 25 | "accessibility_mono_audio", 26 | "accessibility_reduce_white_point", 27 | "accessibility_start_guided_access", 28 | "accessibility_voice_control", 29 | "accessibility_voice_over", 30 | "airdrop_receive_contacts_only", 31 | "airdrop_receive_everyone_10_minutes", 32 | "airplane_mode", 33 | "auto_answer_calls", 34 | "bluetooth", 35 | "cellular_data", 36 | "cellular_data_roaming", 37 | "flashlight", 38 | "LED_flash_for_calls_notifications", 39 | "lock_screen", 40 | "low_power_mode", 41 | "orientation_lock", 42 | "personal_wifi_hotspot", 43 | "play_background_sounds", 44 | "play_background_sounds_when_media_is_playing", 45 | "reboot_device", 46 | "recognize_ambient_sounds", 47 | "reduce_ui_motion", 48 | "reduce_ui_transparency", 49 | "reset_cellular_data_statistics", 50 | "screen_night_shift_warm_colors", 51 | "screen_true_tone_color", 52 | "shutdown_device", 53 | "ui_classic_invert_colors", 54 | "ui_dark_mode", 55 | "ui_smart_invert_colors", 56 | "vpn", 57 | "vpn_on_demand", 58 | "wifi" 59 | ] 60 | } -------------------------------------------------------------------------------- /Lucy/device_settings_iphone1.json: -------------------------------------------------------------------------------- 1 | { 2 | "get_value": [ 3 | "battery", 4 | "current_focus_mode", 5 | "device_and_OS_info", 6 | "display_info", 7 | "network_info", 8 | "personal_hotspot_password", 9 | "volume" 10 | ], 11 | "set_value": [ 12 | "accessibility_assistive_touch", 13 | "accessibility_audio_descriptions", 14 | "accessibility_captions_shd", 15 | "accessibility_color_filters", 16 | "accessibility_increased_ui_contrast", 17 | "accessibility_live_captions", 18 | "accessibility_mono_audio", 19 | "accessibility_reduce_white_point", 20 | "accessibility_start_guided_access", 21 | "accessibility_voice_control", 22 | "accessibility_voice_over", 23 | "airdrop_receive_contacts_only", 24 | "airdrop_receive_everyone_10_minutes", 25 | "airplane_mode", 26 | "auto_answer_calls", 27 | "bluetooth", 28 | "cellular_data", 29 | "cellular_data_roaming", 30 | "flashlight", 31 | "font_size", 32 | "LED_flash_for_calls_notifications", 33 | "lock_screen", 34 | "low_power_mode", 35 | "media_volume", 36 | "orientation_lock", 37 | "personal_hotspot_password", 38 | "personal_wifi_hotspot", 39 | "play_background_sounds", 40 | "play_background_sounds_when_media_is_playing", 41 | "reboot_device", 42 | "recognize_ambient_sounds", 43 | "reduce_ui_motion", 44 | "reduce_ui_transparency", 45 | "reset_cellular_data_statistics", 46 | "ringtone_volume", 47 | "screen_brightness", 48 | "screen_night_shift_warm_colors", 49 | "screen_true_tone_color", 50 | "shutdown_device", 51 | "ui_classic_invert_colors", 52 | "ui_dark_mode", 53 | "ui_smart_invert_colors", 54 | "vpn", 55 | "vpn_on_demand", 56 | "wifi" 57 | ] 58 | } -------------------------------------------------------------------------------- /Lucy/device_settings_mac.json: -------------------------------------------------------------------------------- 1 | { 2 | "get_value": [ 3 | "battery", 4 | "current_focus_mode", 5 | "device_and_OS_info", 6 | "display_info", 7 | "network_info", 8 | "volume" 9 | ], 10 | "set_value": { 11 | "media_volume": "float in 0-1", 12 | "ringtone_volume": "float in 0-1", 13 | "screen_brightness": "float in 0-1" 14 | }, 15 | "toggle": [ 16 | "accessibility_audio_descriptions", 17 | "accessibility_captions_shd", 18 | "accessibility_color_filters", 19 | "accessibility_increased_ui_contrast", 20 | "accessibility_live_captions", 21 | "accessibility_mono_audio", 22 | "accessibility_voice_control", 23 | "accessibility_voice_over", 24 | "airdrop_receive_contacts_only", 25 | "airdrop_receive_everyone_10_minutes", 26 | "bluetooth", 27 | "lock_screen", 28 | "reboot_device", 29 | "reduce_ui_motion", 30 | "reduce_ui_transparency", 31 | "screen_night_shift_warm_colors", 32 | "screen_true_tone_color", 33 | "shutdown_device", 34 | "ui_classic_invert_colors", 35 | "ui_dark_mode", 36 | "ui_smart_invert_colors", 37 | "vpn", 38 | "vpn_on_demand", 39 | "wifi" 40 | ] 41 | } -------------------------------------------------------------------------------- /Lucy/device_settings_mac1.json: -------------------------------------------------------------------------------- 1 | { 2 | "get_value": [ 3 | "battery", 4 | "current_focus_mode", 5 | "device_and_OS_info", 6 | "display_info", 7 | "network_info", 8 | "volume" 9 | ], 10 | "set_value": [ 11 | "accessibility_audio_descriptions", 12 | "accessibility_captions_shd", 13 | "accessibility_color_filters", 14 | "accessibility_increased_ui_contrast", 15 | "accessibility_live_captions", 16 | "accessibility_mono_audio", 17 | "accessibility_voice_control", 18 | "accessibility_voice_over", 19 | "airdrop_receive_contacts_only", 20 | "airdrop_receive_everyone_10_minutes", 21 | "bluetooth", 22 | "lock_screen", 23 | "media_volume", 24 | "reboot_device", 25 | "reduce_ui_motion", 26 | "reduce_ui_transparency", 27 | "ringtone_volume", 28 | "screen_brightness", 29 | "screen_night_shift_warm_colors", 30 | "screen_true_tone_color", 31 | "shutdown_device", 32 | "ui_classic_invert_colors", 33 | "ui_dark_mode", 34 | "ui_smart_invert_colors", 35 | "vpn", 36 | "vpn_on_demand", 37 | "wifi" 38 | ] 39 | } -------------------------------------------------------------------------------- /Lucy/global_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "status": { 5 | "type": "string", 6 | "description": "Overall status of the task.", 7 | "enum": [ 8 | "in_progress", 9 | "completed", 10 | "clarification_needed" 11 | ] 12 | }, 13 | "decision": { 14 | "type": "string", 15 | "description": "Type of the next action.", 16 | "enum": [ 17 | "tool", 18 | "direct", 19 | "quit" 20 | ] 21 | }, 22 | "tool_calls": { 23 | "type": "array", 24 | "description": "If decision is 'tool', an array of objects, each with tool_notes, tool_name, function_name, and parameters.", 25 | "items": { 26 | "type": "object", 27 | "properties": { 28 | "tool_notes": { 29 | "type": "string", 30 | "description": "A brief explanation for the user about the upcoming action for this tool call, using no more than 15 words." 31 | }, 32 | "tool_name": { 33 | "type": "string", 34 | "description": "The name of the selected Shortcut." 35 | }, 36 | "function_name": { 37 | "type": "string", 38 | "description": "The name of the selected function." 39 | }, 40 | "parameters": { 41 | "type": "object", 42 | "description": "The parameters to be passed to the function." 43 | } 44 | }, 45 | "required": [ 46 | "tool_notes", 47 | "tool_name", 48 | "function_name", 49 | "parameters" 50 | ] 51 | } 52 | }, 53 | "direct_response": { 54 | "type": "string", 55 | "description": "If status is 'completed' or 'clarification_needed', or if decision is 'quit', this is the final response or clarification question for the user. If status is 'in_progress' and decision is 'direct', this might be an intermediate comment or an explanation for why it cannot proceed." 56 | }, 57 | "user_options": { 58 | "type": "object", 59 | "description": "OMIT IF UNUSED. If the decision is 'direct', you can provide a list of strings from which the user will choose instead of providing you with a text response. If this is used, then 'direct_response' wont be shown and should be null. 'user_prompt' should still be provided.", 60 | "properties": { 61 | "options": { 62 | "type": "array", 63 | "description": "A list of strings to be shown as options.", 64 | "items": { 65 | "type": "string" 66 | } 67 | }, 68 | "select_multiple": { 69 | "type": "boolean", 70 | "description": "allow multiple items to be selected" 71 | }, 72 | "select_all_initially": { 73 | "type": "boolean", 74 | "description": "if multiple selection enabled, present list with all items selected" 75 | } 76 | } 77 | }, 78 | "prompt_for_user": { 79 | "type": "string", 80 | "description": "This is shown to the user *after the 'direct_response' when their input is requested. It should feel like a follow up question to the 'direct_response', or a single_sentence summary. It should be not much longer than 30 words. It should not feel too repetitive of the 'direct_response'. This field is null if decision is 'tool' or 'quit'. If decision is 'direct', this field must be provided, even if status is 'completed'." 81 | } 82 | }, 83 | "required": [ 84 | "status", 85 | "decision" 86 | ] 87 | } -------------------------------------------------------------------------------- /Lucy/img/config.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/Lucy/img/config.webp -------------------------------------------------------------------------------- /Lucy/img/tool_config.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/Lucy/img/tool_config.webp -------------------------------------------------------------------------------- /Lucy/merge_dictionaries.js: -------------------------------------------------------------------------------- 1 | const dictionary1 = { 2 | "apple": "A fruit that is typically red, green, or yellow.", 3 | "banana": "A long curved fruit that grows in clusters and has soft pulpy flesh and yellow skin when ripe.", 4 | "cherry": "A small, round stone fruit that is typically red or black.", 5 | "date": "A sweet fruit from the date palm tree, often dried and eaten as a snack." 6 | }; 7 | 8 | const dictionary2 = { 9 | "banana": "A tropical fruit that is elongated and curved, with soft flesh rich in starch.", 10 | "date": "A sweet fruit from the date palm, often eaten dried or fresh.", 11 | "elderberry": "A small dark purple fruit that grows in clusters on the elder tree, often used in syrups and jams." 12 | }; 13 | 14 | // dict2 overrides dict1 15 | function mergeDictionaries(dict1, dict2) { 16 | const merged = { ...dict1, ...dict2 }; 17 | return merged; 18 | } 19 | 20 | const mergedDictionary = mergeDictionaries(dictionary1, dictionary2); 21 | console.log(mergedDictionary); -------------------------------------------------------------------------------- /Lucy/tool_definitions/alarms.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "AlarmClock (tool_name)", 3 | "Description": "Manages alarms on the device, including creation, searching, and modification.", 4 | "Functions": [ 5 | { 6 | "function_name": "create_alarms", 7 | "description": "Creates one or more new alarms.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "alarms": { 12 | "type": "array", 13 | "description": "An array of alarm objects to be created.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "time": { 18 | "type": "string", 19 | "description": "The time for the alarm in `hh:mma` format (eg `07:30AM`)." 20 | }, 21 | "label": { 22 | "type": "string", 23 | "description": "A descriptive name or label for the alarm (e.g., 'Wake up', 'Meeting reminder')." 24 | }, 25 | "snooze": { 26 | "type": "boolean", 27 | "description": "Whether the snooze option should be allowed for this alarm. Defaults to true if omitted." 28 | }, 29 | "repeat_days": { 30 | "type": "array", 31 | "items": { 32 | "type": "string" 33 | }, 34 | "description": "An array of full weekday names (lowercase, e.g., 'monday', 'tuesday') on which the alarm should repeat (be active). If omitted, the alarm will not repeat." 35 | } 36 | }, 37 | "required": [ 38 | "time", 39 | "label" 40 | ] 41 | } 42 | } 43 | }, 44 | "required": [ 45 | "alarms" 46 | ] 47 | } 48 | }, 49 | { 50 | "function_name": "search_or_modify_alarms", 51 | "description": "Searches for existing alarms based on provided criteria and can optionally perform an action (delete, enable, disable) on the matched alarms.", 52 | "parameters": { 53 | "type": "object", 54 | "properties": { 55 | "label": { 56 | "type": "string", 57 | "description": "A string to search alarms based on their label. Can be blank to match all alarms, or a partial match." 58 | }, 59 | "time": { 60 | "type": "string", 61 | "description": "An optional time in `HH:mm` format (eg `07:30` or `19:30`) to use as an additional search parameter to filter alarms." 62 | }, 63 | "action": { 64 | "type": "string", 65 | "description": "The action to perform on the matched alarms. Defaults to 'search' if omitted.", 66 | "enum": [ 67 | "search", 68 | "delete", 69 | "enable", 70 | "disable" 71 | ] 72 | } 73 | } 74 | } 75 | } 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/alarms.yml: -------------------------------------------------------------------------------- 1 | Name: AlarmClock (tool_name) 2 | Description: Manages alarms on the device, including creation, searching, and modification. 3 | Functions: 4 | - function_name: create_alarms 5 | description: Creates one or more new alarms. 6 | parameters: 7 | type: "object" 8 | properties: 9 | alarms: 10 | type: "array" 11 | description: "An array of alarm objects to be created." 12 | items: 13 | type: "object" 14 | properties: 15 | time: 16 | type: "string" 17 | description: "The time for the alarm in `hh:mma` format (eg `07:30AM`)." 18 | label: 19 | type: "string" 20 | description: "A descriptive name or label for the alarm (e.g., 'Wake up', 'Meeting reminder')." 21 | snooze: 22 | type: "boolean" 23 | description: "Whether the snooze option should be allowed for this alarm. Defaults to true if omitted." 24 | repeat_days: 25 | type: "array" 26 | items: 27 | type: "string" 28 | description: "An array of full weekday names (lowercase, e.g., 'monday', 'tuesday') on which the alarm should repeat (be active). If omitted, the alarm will not repeat." 29 | required: 30 | - "time" 31 | - "label" 32 | required: 33 | - "alarms" 34 | - function_name: search_or_modify_alarms 35 | description: Searches for existing alarms based on provided criteria and can optionally perform an action (delete, enable, disable) on the matched alarms. 36 | parameters: 37 | type: "object" 38 | properties: 39 | label: 40 | type: "string" 41 | description: "A string to search alarms based on their label. Can be blank to match all alarms, or a partial match." 42 | time: 43 | type: "string" 44 | description: "An optional time in `HH:mm` format (eg `07:30` or `19:30`) to use as an additional search parameter to filter alarms." 45 | action: 46 | type: "string" 47 | description: "The action to perform on the matched alarms. Defaults to 'search' if omitted." 48 | enum: ["search", "delete", "enable", "disable"] -------------------------------------------------------------------------------- /Lucy/tool_definitions/app_store.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "AppStore_v1-0", 3 | "Description": "Searches for apps in the App Store. Can search by developer name or across all app data, and supports iPhone, iPad, and Mac apps.", 4 | "Functions": [ 5 | { 6 | "function_name": "find_apps", 7 | "description": "Searches for apps in the App Store based on specified criteria.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "queries": { 12 | "type": "array", 13 | "description": "Array of search query objects.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "query": { 18 | "type": "string", 19 | "description": "String query to search for apps." 20 | }, 21 | "device": { 22 | "type": "string", 23 | "enum": [ 24 | "iPhone", 25 | "iPad", 26 | "Mac" 27 | ], 28 | "description": "What types of apps to search for. Use as default." 29 | }, 30 | "num_results": { 31 | "type": "number", 32 | "description": "Number of results to generate for query (10-20 is a good value)." 33 | }, 34 | "include_description": { 35 | "type": "boolean", 36 | "description": "Whether to include full item descriptions in search results, which increases token usage (optional, false by default). If user asks for more details, set to true." 37 | }, 38 | "search_by": { 39 | "type": "string", 40 | "enum": [ 41 | "developer", 42 | "all" 43 | ], 44 | "description": "Search by only developer name or search all app data (optional, 'all' by default)." 45 | } 46 | }, 47 | "required": [ 48 | "query", 49 | "device", 50 | "num_results" 51 | ] 52 | } 53 | } 54 | }, 55 | "required": [ 56 | "queries" 57 | ] 58 | } 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/app_store.yml: -------------------------------------------------------------------------------- 1 | Name: AppStore_v1-0 2 | Description: Searches for apps in the App Store. Can search by developer name or across all app data, and supports iPhone, iPad, and Mac apps. 3 | Functions: 4 | - function_name: find_apps 5 | description: Searches for apps in the App Store based on specified criteria. 6 | parameters: 7 | type: object 8 | properties: 9 | queries: 10 | type: array 11 | description: "Array of search query objects." 12 | items: 13 | type: object 14 | properties: 15 | query: 16 | type: string 17 | description: "String query to search for apps." 18 | device: 19 | type: string 20 | enum: ["iPhone", "iPad", "Mac"] 21 | description: "What types of apps to search for. Use as default." 22 | num_results: 23 | type: number 24 | description: "Number of results to generate for query (10-20 is a good value)." 25 | include_description: 26 | type: boolean 27 | description: "Whether to include full item descriptions in search results, which increases token usage (optional, false by default). If user asks for more details, set to true." 28 | search_by: 29 | type: string 30 | enum: ["developer", "all"] 31 | description: "Search by only developer name or search all app data (optional, 'all' by default)." 32 | required: 33 | - query 34 | - device 35 | - num_results 36 | required: 37 | - queries -------------------------------------------------------------------------------- /Lucy/tool_definitions/calendar.json: -------------------------------------------------------------------------------- 1 | { 2 | "event_properties": { 3 | "title": { 4 | "type": "string", 5 | "description": "The title of the event." 6 | }, 7 | "start_date": { 8 | "type": "string", 9 | "description": "The start date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 10 | }, 11 | "end_date": { 12 | "type": "string", 13 | "description": "The end date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 14 | }, 15 | "notes": { 16 | "type": "string", 17 | "description": "Additional notes for the event." 18 | }, 19 | "location": { 20 | "type": "string", 21 | "description": "The physical location of the event." 22 | }, 23 | "is_all_day": { 24 | "type": "boolean", 25 | "description": "Set to true if the event is an all-day event." 26 | }, 27 | "url": { 28 | "type": "string", 29 | "description": "A URL associated with the event, such as a video conference link." 30 | } 31 | }, 32 | "Name": "Calendar_v1-0", 33 | "Description": "Manages events in the Calendar app.", 34 | "Functions": [ 35 | { 36 | "function_name": "search_events", 37 | "description": "Searches for calendar events based on a query and a specified time range relative to the current date.", 38 | "parameters": { 39 | "type": "object", 40 | "properties": { 41 | "query": { 42 | "type": "string", 43 | "description": "Optional search query to filter events by title or notes. The search is case-insensitive." 44 | }, 45 | "past_days": { 46 | "type": "number", 47 | "description": "The number of days in the past to search for events." 48 | }, 49 | "future_days": { 50 | "type": "number", 51 | "description": "The number of days in the future to search for events. For today's events, set this to 1." 52 | }, 53 | "has_location": { 54 | "type": "boolean", 55 | "description": "Set to true to only search events with locations. Omit to search events regardless of whether they have a specified location." 56 | } 57 | }, 58 | "required": [ 59 | "past_days", 60 | "future_days" 61 | ] 62 | } 63 | }, 64 | { 65 | "function_name": "create_events", 66 | "description": "Creates one or more new events in the Calendar app. Please add all available information for the event, such as notes, location, and url, if applicable.", 67 | "parameters": { 68 | "type": "object", 69 | "properties": { 70 | "events": { 71 | "type": "array", 72 | "description": "An array of JSON dictionaries, where each dictionary represents an event to be created.", 73 | "items": { 74 | "type": "object", 75 | "properties": { 76 | "title": { 77 | "type": "string", 78 | "description": "The title of the event." 79 | }, 80 | "start_date": { 81 | "type": "string", 82 | "description": "The start date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 83 | }, 84 | "end_date": { 85 | "type": "string", 86 | "description": "The end date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 87 | }, 88 | "notes": { 89 | "type": "string", 90 | "description": "Additional notes for the event." 91 | }, 92 | "location": { 93 | "type": "string", 94 | "description": "The physical location of the event." 95 | }, 96 | "is_all_day": { 97 | "type": "boolean", 98 | "description": "Set to true if the event is an all-day event." 99 | }, 100 | "url": { 101 | "type": "string", 102 | "description": "A URL associated with the event, such as a video conference link." 103 | } 104 | }, 105 | "required": [ 106 | "title", 107 | "start_date" 108 | ] 109 | } 110 | } 111 | }, 112 | "required": [ 113 | "events" 114 | ] 115 | } 116 | }, 117 | { 118 | "function_name": "edit_event", 119 | "description": "Modifies the details of an existing calendar event.", 120 | "parameters": { 121 | "type": "object", 122 | "properties": { 123 | "start_date": { 124 | "type": "string", 125 | "description": "The original start date and time of the event to be edited (Format: YYYY-MM-DD hh:mm:ss). Used for unique identification." 126 | }, 127 | "calendar": { 128 | "type": "string", 129 | "description": "The name of the calendar where the event to be edited is located. Used for unique identification." 130 | }, 131 | "title": { 132 | "type": "string", 133 | "description": "The original title of the event to be edited. Used for unique identification." 134 | }, 135 | "content": { 136 | "type": "object", 137 | "description": "An object containing the new content that will overwrite the specified event's attributes. Only include fields that are to be updated.", 138 | "properties": { 139 | "title": { 140 | "type": "string", 141 | "description": "The title of the event." 142 | }, 143 | "start_date": { 144 | "type": "string", 145 | "description": "The start date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 146 | }, 147 | "end_date": { 148 | "type": "string", 149 | "description": "The end date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 150 | }, 151 | "notes": { 152 | "type": "string", 153 | "description": "Additional notes for the event." 154 | }, 155 | "location": { 156 | "type": "string", 157 | "description": "The physical location of the event." 158 | }, 159 | "is_all_day": { 160 | "type": "boolean", 161 | "description": "Set to true if the event is an all-day event." 162 | }, 163 | "url": { 164 | "type": "string", 165 | "description": "A URL associated with the event, such as a video conference link." 166 | }, 167 | "calendar": { 168 | "type": "string", 169 | "description": "New calendar name to move the event to." 170 | } 171 | } 172 | } 173 | }, 174 | "required": [ 175 | "start_date", 176 | "calendar", 177 | "title", 178 | "content" 179 | ] 180 | } 181 | } 182 | ] 183 | } 184 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/calendar.yml: -------------------------------------------------------------------------------- 1 | # A map of all standard properties for a calendar event 2 | event_properties: &event_properties 3 | title: 4 | type: string 5 | description: "The title of the event." 6 | start_date: 7 | type: string 8 | description: "The start date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 9 | end_date: 10 | type: string 11 | description: "The end date and time of the event (Format: YYYY-MM-DD hh:mm:ss)." 12 | notes: 13 | type: string 14 | description: "Additional notes for the event." 15 | location: 16 | type: string 17 | description: "The physical location of the event." 18 | is_all_day: 19 | type: boolean 20 | description: "Set to true if the event is an all-day event." 21 | url: 22 | type: string 23 | description: "A URL associated with the event, such as a video conference link." 24 | 25 | Name: Calendar_v1-0 26 | Description: Manages events in the Calendar app. 27 | Functions: 28 | - function_name: search_events 29 | description: Searches for calendar events based on a query and a specified time range relative to the current date. 30 | parameters: 31 | type: object 32 | properties: 33 | query: 34 | type: string 35 | description: "Optional search query to filter events by title or notes. The search is case-insensitive." 36 | past_days: 37 | type: number 38 | description: "The number of days in the past to search for events." 39 | future_days: 40 | type: number 41 | description: "The number of days in the future to search for events. For today's events, set this to 1." 42 | has_location: 43 | type: boolean 44 | description: "Set to true to only search events with locations. Omit to search events regardless of whether they have a specified location." 45 | required: 46 | - past_days 47 | - future_days 48 | - function_name: create_events 49 | description: Creates one or more new events in the Calendar app. Please add all available information for the event, such as notes, location, and url, if applicable. 50 | parameters: 51 | type: object 52 | properties: 53 | events: 54 | type: array 55 | description: "An array of JSON dictionaries, where each dictionary represents an event to be created." 56 | items: 57 | type: object 58 | properties: 59 | <<: *event_properties 60 | required: 61 | - title 62 | - start_date 63 | required: 64 | - events 65 | - function_name: edit_event 66 | description: Modifies the details of an existing calendar event. 67 | parameters: 68 | type: object 69 | properties: 70 | start_date: 71 | type: string 72 | description: "The original start date and time of the event to be edited (Format: YYYY-MM-DD hh:mm:ss). Used for unique identification." 73 | calendar: 74 | type: string 75 | description: "The name of the calendar where the event to be edited is located. Used for unique identification." 76 | title: 77 | type: string 78 | description: "The original title of the event to be edited. Used for unique identification." 79 | content: 80 | type: object 81 | description: "An object containing the new content that will overwrite the specified event's attributes. Only include fields that are to be updated." 82 | properties: 83 | <<: *event_properties 84 | calendar: 85 | type: string 86 | description: "New calendar name to move the event to." 87 | required: 88 | - start_date 89 | - calendar 90 | - title 91 | - content -------------------------------------------------------------------------------- /Lucy/tool_definitions/contacts.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Contacts_v1-0", 3 | "Description": "Manages iOS contacts.", 4 | "Functions": [ 5 | { 6 | "function_name": "search_contacts", 7 | "description": "Searches for contacts.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "queries": { 12 | "type": "array", 13 | "items": { 14 | "type": "string" 15 | }, 16 | "description": "Array of search strings for name, phone, email, or company. For names, include common variations of names and nicknames, such as \"Robert\" and \"Bob\", and variations of queries for searching first and last names separately." 17 | } 18 | }, 19 | "required": [ 20 | "queries" 21 | ] 22 | } 23 | }, 24 | { 25 | "function_name": "add_contact", 26 | "description": "Adds a new contact.", 27 | "parameters": { 28 | "type": "object", 29 | "properties": { 30 | "first_name": { 31 | "type": "string", 32 | "description": "Contact's first name." 33 | }, 34 | "last_name": { 35 | "type": "string", 36 | "description": "Contact's last name." 37 | }, 38 | "phone_number": { 39 | "type": "string", 40 | "description": "Primary phone number." 41 | }, 42 | "email_address": { 43 | "type": "string", 44 | "description": "Primary email address." 45 | }, 46 | "company": { 47 | "type": "string", 48 | "description": "Contact's company." 49 | }, 50 | "notes": { 51 | "type": "string", 52 | "description": "Notes about the contact." 53 | } 54 | }, 55 | "required": [ 56 | "first_name" 57 | ] 58 | } 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/contacts.yml: -------------------------------------------------------------------------------- 1 | Name: Contacts_v1-0 2 | Description: Manages iOS contacts. 3 | Functions: 4 | - function_name: search_contacts 5 | description: Searches for contacts. 6 | parameters: 7 | type: object 8 | properties: 9 | queries: 10 | type: array 11 | items: 12 | type: string 13 | description: Array of search strings for name, phone, email, or company. For names, include common variations of names and nicknames, such as "Robert" and "Bob", and variations of queries for searching first and last names separately. 14 | required: 15 | - queries 16 | - function_name: add_contact 17 | description: Adds a new contact. 18 | parameters: 19 | type: object 20 | properties: 21 | first_name: 22 | type: string 23 | description: Contact's first name. 24 | last_name: 25 | type: string 26 | description: Contact's last name. 27 | phone_number: 28 | type: string 29 | description: Primary phone number. 30 | email_address: 31 | type: string 32 | description: Primary email address. 33 | company: 34 | type: string 35 | description: Contact's company. 36 | notes: 37 | type: string 38 | description: Notes about the contact. 39 | required: 40 | - first_name -------------------------------------------------------------------------------- /Lucy/tool_definitions/deepresearch.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "DeepResearch_v1-0", 3 | "Description": "Activates a deep research routine to aggregate data from multiple sources for detailed, factual reports.", 4 | "Functions": [ 5 | { 6 | "function_name": "deep_research", 7 | "description": "Performs in-depth research for detailed reports. For general queries, ask to confirm before using. If the user explicitly says 'research', use without asking.", 8 | "parameters": {} 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/deepresearch.yml: -------------------------------------------------------------------------------- 1 | Name: DeepResearch_v1-0 2 | Description: Activates a deep research routine to aggregate data from multiple sources for detailed, factual reports. 3 | Functions: 4 | - function_name: deep_research 5 | description: Performs in-depth research for detailed reports. For general queries, ask to confirm before using. If the user explicitly says 'research', use without asking. 6 | parameters: {} -------------------------------------------------------------------------------- /Lucy/tool_definitions/device.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Device_v1-0", 3 | "Description": "Controls and retrieves information about device settings and toggles. This tool allows users to change device configurations, toggle settings on/off, retrieve current setting values, and perform batch operations on multiple settings.", 4 | "Functions": [ 5 | { 6 | "function_name": "set_value", 7 | "description": "Changes a specified device setting to the provided value.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "name": { 12 | "type": "string", 13 | "enum": [ 14 | "names" 15 | ], 16 | "description": "The name of the device setting to modify." 17 | }, 18 | "value": { 19 | "type": "string", 20 | "description": "The new value to set for the specified setting." 21 | } 22 | }, 23 | "name_value_hints": { 24 | "value_one": "value_one_hint" 25 | }, 26 | "required": [ 27 | "name", 28 | "value" 29 | ] 30 | } 31 | }, 32 | { 33 | "function_name": "change_toggle", 34 | "description": "Toggles a specified device setting on, off, or switches its current state.", 35 | "parameters": { 36 | "type": "object", 37 | "properties": { 38 | "name": { 39 | "type": "string", 40 | "enum": [ 41 | "names" 42 | ], 43 | "description": "The name of the device toggle setting to modify." 44 | }, 45 | "action": { 46 | "type": "string", 47 | "enum": [ 48 | "toggle", 49 | "turn_on", 50 | "turn_off" 51 | ], 52 | "description": "The action to perform on the toggle setting." 53 | } 54 | }, 55 | "required": [ 56 | "name", 57 | "action" 58 | ] 59 | } 60 | }, 61 | { 62 | "function_name": "get_value", 63 | "description": "Retrieves information about a specified device setting.", 64 | "parameters": { 65 | "type": "object", 66 | "properties": { 67 | "name": { 68 | "type": "string", 69 | "enum": [ 70 | "names" 71 | ], 72 | "description": "The name of the device setting to retrieve information for." 73 | } 74 | }, 75 | "required": [ 76 | "name" 77 | ] 78 | } 79 | }, 80 | { 81 | "function_name": "change_settings", 82 | "description": "Executes multiple device setting operations in a single batch. At least one array of actions must be provided.", 83 | "parameters": { 84 | "type": "object", 85 | "properties": { 86 | "toggle_actions": { 87 | "type": "array", 88 | "description": "Array of toggle actions to perform.", 89 | "items": { 90 | "type": "object", 91 | "properties": { 92 | "name": { 93 | "type": "string", 94 | "description": "Enum using the name values of 'change_toggle' function" 95 | }, 96 | "action": { 97 | "type": "string", 98 | "enum": [ 99 | "toggle", 100 | "turn_on", 101 | "turn_off" 102 | ] 103 | } 104 | }, 105 | "required": [ 106 | "name", 107 | "action" 108 | ] 109 | } 110 | }, 111 | "set_value_actions": { 112 | "type": "array", 113 | "description": "Array of set value actions to perform.", 114 | "items": { 115 | "type": "object", 116 | "properties": { 117 | "name": { 118 | "type": "string", 119 | "description": "Enum using the name values of 'set_value' function" 120 | }, 121 | "value": { 122 | "type": "string" 123 | } 124 | }, 125 | "required": [ 126 | "name", 127 | "value" 128 | ] 129 | } 130 | }, 131 | "get_value_actions": { 132 | "type": "array", 133 | "description": "Array of setting names to retrieve values for.", 134 | "items": { 135 | "type": "string", 136 | "description": "Enum using the name values of 'get_value' function" 137 | } 138 | } 139 | } 140 | } 141 | } 142 | ] 143 | } 144 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/device.yml: -------------------------------------------------------------------------------- 1 | Name: Device_v1-0 2 | Description: Controls and retrieves information about device settings and toggles. This tool allows users to change device configurations, toggle settings on/off, retrieve current setting values, and perform batch operations on multiple settings. 3 | Functions: 4 | - function_name: set_value 5 | description: Changes a specified device setting to the provided value. 6 | parameters: 7 | type: object 8 | properties: 9 | name: 10 | type: string 11 | enum: ["names"] 12 | description: The name of the device setting to modify. 13 | value: 14 | type: string 15 | description: The new value to set for the specified setting. 16 | name_value_hints: 17 | value_one: value_one_hint 18 | required: 19 | - name 20 | - value 21 | - function_name: change_toggle 22 | description: Toggles a specified device setting on, off, or switches its current state. 23 | parameters: 24 | type: object 25 | properties: 26 | name: 27 | type: string 28 | enum: ["names"] 29 | description: The name of the device toggle setting to modify. 30 | action: 31 | type: string 32 | enum: ["toggle", "turn_on", "turn_off"] 33 | description: The action to perform on the toggle setting. 34 | required: 35 | - name 36 | - action 37 | - function_name: get_value 38 | description: Retrieves information about a specified device setting. 39 | parameters: 40 | type: object 41 | properties: 42 | name: 43 | type: string 44 | enum: ["names"] 45 | description: The name of the device setting to retrieve information for. 46 | required: 47 | - name 48 | - function_name: change_settings 49 | description: Executes multiple device setting operations in a single batch. At least one array of actions must be provided. 50 | parameters: 51 | type: object 52 | properties: 53 | toggle_actions: 54 | type: array 55 | description: Array of toggle actions to perform. 56 | items: 57 | type: object 58 | properties: 59 | name: 60 | type: string 61 | description: Enum using the name values of 'change_toggle' function 62 | action: 63 | type: string 64 | enum: ["toggle", "turn_on", "turn_off"] 65 | required: 66 | - name 67 | - action 68 | set_value_actions: 69 | type: array 70 | description: Array of set value actions to perform. 71 | items: 72 | type: object 73 | properties: 74 | name: 75 | type: string 76 | description: Enum using the name values of 'set_value' function 77 | value: 78 | type: string 79 | required: 80 | - name 81 | - value 82 | get_value_actions: 83 | type: array 84 | description: Array of setting names to retrieve values for. 85 | items: 86 | type: string 87 | description: Enum using the name values of 'get_value' function -------------------------------------------------------------------------------- /Lucy/tool_definitions/mail.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Mail_v1-0", 3 | "Description": "Sends emails via the Mail app. You may need to use the Contacts tool to get valid email addresses to use as the recipient before using this tool.", 4 | "Functions": [ 5 | { 6 | "function_name": "send_emails", 7 | "description": "Sends emails to specified recipients using the Mail app.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "messages": { 12 | "type": "array", 13 | "description": "Array of message objects to be sent.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "recipient": { 18 | "type": "array", 19 | "items": { 20 | "type": "string" 21 | }, 22 | "description": "Array of email addresses of the recipients." 23 | }, 24 | "cc": { 25 | "type": "array", 26 | "items": { 27 | "type": "string" 28 | }, 29 | "description": "Array of email addresses for CC recipients (optional)." 30 | }, 31 | "bcc": { 32 | "type": "array", 33 | "items": { 34 | "type": "string" 35 | }, 36 | "description": "Array of email addresses for BCC recipients (optional)." 37 | }, 38 | "body": { 39 | "type": "string", 40 | "description": "The content of the email to be sent." 41 | }, 42 | "subject": { 43 | "type": "string", 44 | "description": "The subject of the email to be sent." 45 | } 46 | }, 47 | "required": [ 48 | "recipient", 49 | "body", 50 | "subject" 51 | ] 52 | } 53 | } 54 | }, 55 | "required": [ 56 | "messages" 57 | ] 58 | } 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/mail.yml: -------------------------------------------------------------------------------- 1 | Name: Mail_v1-0 2 | Description: Sends emails via the Mail app. You may need to use the Contacts tool to get valid email addresses to use as the recipient before using this tool. 3 | Functions: 4 | - function_name: send_emails 5 | description: Sends emails to specified recipients using the Mail app. 6 | parameters: 7 | type: object 8 | properties: 9 | messages: 10 | type: array 11 | description: "Array of message objects to be sent." 12 | items: 13 | type: object 14 | properties: 15 | recipient: 16 | type: array 17 | items: 18 | type: string 19 | description: "Array of email addresses of the recipients." 20 | cc: 21 | type: array 22 | items: 23 | type: string 24 | description: "Array of email addresses for CC recipients (optional)." 25 | bcc: 26 | type: array 27 | items: 28 | type: string 29 | description: "Array of email addresses for BCC recipients (optional)." 30 | body: 31 | type: string 32 | description: "The content of the email to be sent." 33 | subject: 34 | type: string 35 | description: "The subject of the email to be sent." 36 | required: 37 | - recipient 38 | - body 39 | - subject 40 | required: 41 | - messages -------------------------------------------------------------------------------- /Lucy/tool_definitions/maps.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Maps_v1-0", 3 | "Description": "Provides capabilities for searching places, initiating navigation, and retrieving current location using map applications on iOS.", 4 | "Functions": [ 5 | { 6 | "function_name": "search_places", 7 | "description": "Searches for places of interest near a current or specified geographical location.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "queries": { 12 | "type": "array", 13 | "description": "Array of search query objects for places. Omit all location parameters to search around current user location.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "query": { 18 | "type": "string", 19 | "description": "The search query for the place (e.g., 'coffee shop', 'pizza', 'park')." 20 | }, 21 | "city": { 22 | "type": "string", 23 | "description": "Optional city to narrow down the search location. Used in conjunction with state and country." 24 | }, 25 | "state": { 26 | "type": "string", 27 | "description": "Optional state to narrow down the search location. Used in conjunction with city and country." 28 | }, 29 | "country": { 30 | "type": "string", 31 | "description": "Optional country to narrow down the search location. Used with city/state or zip code." 32 | }, 33 | "zip_code": { 34 | "type": "string", 35 | "description": "Optional zip code to narrow down the search location. If provided, city/state will be ignored." 36 | }, 37 | "search_radius": { 38 | "type": "number", 39 | "description": "The search radius in miles." 40 | } 41 | }, 42 | "required": [ 43 | "query" 44 | ] 45 | } 46 | } 47 | }, 48 | "required": [ 49 | "queries" 50 | ] 51 | } 52 | }, 53 | { 54 | "function_name": "start_navigation", 55 | "description": "Initiates turn-by-turn navigation to a specified destination using a selected map application.", 56 | "parameters": { 57 | "type": "object", 58 | "properties": { 59 | "map_app": { 60 | "type": "string", 61 | "description": "The preferred map application for navigation. Use Maps by default, or if unspecified.", 62 | "enum": [ 63 | "Maps", 64 | "Google Maps", 65 | "Waze" 66 | ] 67 | }, 68 | "destination": { 69 | "type": "string", 70 | "description": "The full address of the destination to navigate to (e.g., '1600 Amphitheatre Parkway, Mountain View, CA 94043')." 71 | } 72 | }, 73 | "required": [ 74 | "map_app", 75 | "destination" 76 | ] 77 | } 78 | }, 79 | { 80 | "function_name": "get_current_location", 81 | "description": "Retrieves the user's current geographical location (latitude, longitude, and address). Use this tool if the user says something like '...near me' or '...in my town', so that you don't need to ask the user directly.", 82 | "parameters": {} 83 | } 84 | ] 85 | } 86 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/maps.yml: -------------------------------------------------------------------------------- 1 | Name: Maps_v1-0 2 | Description: Provides capabilities for searching places, initiating navigation, and retrieving current location using map applications on iOS. 3 | Functions: 4 | - function_name: search_places 5 | description: Searches for places of interest near a current or specified geographical location. 6 | parameters: 7 | type: object 8 | properties: 9 | queries: 10 | type: array 11 | description: "Array of search query objects for places. Omit all location parameters to search around current user location." 12 | items: 13 | type: object 14 | properties: 15 | query: 16 | type: string 17 | description: "The search query for the place (e.g., 'coffee shop', 'pizza', 'park')." 18 | city: 19 | type: string 20 | description: "Optional city to narrow down the search location. Used in conjunction with state and country." 21 | state: 22 | type: string 23 | description: "Optional state to narrow down the search location. Used in conjunction with city and country." 24 | country: 25 | type: string 26 | description: "Optional country to narrow down the search location. Used with city/state or zip code." 27 | zip_code: 28 | type: string 29 | description: "Optional zip code to narrow down the search location. If provided, city/state will be ignored." 30 | search_radius: 31 | type: number 32 | description: "The search radius in miles." 33 | required: 34 | - query 35 | required: 36 | - queries 37 | - function_name: start_navigation 38 | description: Initiates turn-by-turn navigation to a specified destination using a selected map application. 39 | parameters: 40 | type: object 41 | properties: 42 | map_app: 43 | type: string 44 | description: "The preferred map application for navigation. Use Maps by default, or if unspecified." 45 | enum: ["Maps", "Google Maps", "Waze"] 46 | destination: 47 | type: string 48 | description: "The full address of the destination to navigate to (e.g., '1600 Amphitheatre Parkway, Mountain View, CA 94043')." 49 | required: 50 | - map_app 51 | - destination 52 | - function_name: get_current_location 53 | description: "Retrieves the user's current geographical location (latitude, longitude, and address). Use this tool if the user says something like '...near me' or '...in my town', so that you don't need to ask the user directly." 54 | parameters: {} -------------------------------------------------------------------------------- /Lucy/tool_definitions/memory.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Memory_v1-0", 3 | "Description": "Saves, views, and searches for information about the user to recall later, like preferences, facts, and events. **This is the preferred tool for personal attributes, unlike the Notes tool.**", 4 | "Functions": [ 5 | { 6 | "function_name": "save_memories", 7 | "description": "Saves new memories.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "memories": { 12 | "type": "array", 13 | "description": "Array of memory objects to save.", 14 | "items": { 15 | "type": "object", 16 | "description": "Memory object with type, content, and keywords.", 17 | "properties": { 18 | "type": { 19 | "type": "string", 20 | "description": "The category of the memory.", 21 | "enum": [ 22 | "entity", 23 | "relationship", 24 | "event", 25 | "fact", 26 | "instruction", 27 | "definition", 28 | "preference", 29 | "goal" 30 | ] 31 | }, 32 | "content": { 33 | "type": "string", 34 | "description": "Information to remember." 35 | }, 36 | "keywords": { 37 | "type": "array", 38 | "description": "Keywords for recall. For events, include month and year.", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | }, 44 | "required": [ 45 | "type", 46 | "content", 47 | "keywords" 48 | ] 49 | } 50 | } 51 | }, 52 | "required": [ 53 | "memories" 54 | ] 55 | } 56 | }, 57 | { 58 | "function_name": "retrieve_all_memories", 59 | "description": "Returns all memories.", 60 | "parameters": {} 61 | }, 62 | { 63 | "function_name": "view_memories", 64 | "description": "Opens the memory storage for user Browse.", 65 | "parameters": {} 66 | }, 67 | { 68 | "function_name": "search_memories", 69 | "description": "Searches memories by type, content, and keywords.", 70 | "parameters": { 71 | "type": "object", 72 | "properties": { 73 | "queries": { 74 | "type": "array", 75 | "description": "Queries to search memories.", 76 | "items": { 77 | "type": "string" 78 | } 79 | } 80 | }, 81 | "required": [ 82 | "queries" 83 | ] 84 | } 85 | }, 86 | { 87 | "function_name": "clear_memory", 88 | "description": "Deletes all memories.", 89 | "note": "Verify with the user before clearing all memories.", 90 | "parameters": {} 91 | } 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/memory.yml: -------------------------------------------------------------------------------- 1 | Name: Memory_v1-0 2 | Description: Saves, views, and searches for information about the user to recall later, like preferences, facts, and events. **This is the preferred tool for personal attributes, unlike the Notes tool.** 3 | Functions: 4 | - function_name: save_memories 5 | description: Saves new memories. 6 | parameters: 7 | type: object 8 | properties: 9 | memories: 10 | type: array 11 | description: Array of memory objects to save. 12 | items: 13 | type: object 14 | description: Memory object with type, content, and keywords. 15 | properties: 16 | type: 17 | type: string 18 | description: The category of the memory. 19 | enum: [entity, relationship, event, fact, instruction, definition, preference, goal] 20 | content: 21 | type: string 22 | description: Information to remember. 23 | keywords: 24 | type: array 25 | description: Keywords for recall. For events, include month and year. 26 | items: 27 | type: string 28 | required: 29 | - type 30 | - content 31 | - keywords 32 | required: 33 | - memories 34 | - function_name: retrieve_all_memories 35 | description: Returns all memories. 36 | parameters: {} 37 | - function_name: view_memories 38 | description: Opens the memory storage for user Browse. 39 | parameters: {} 40 | - function_name: search_memories 41 | description: Searches memories by type, content, and keywords. 42 | parameters: 43 | type: object 44 | properties: 45 | queries: 46 | type: array 47 | description: Queries to search memories. 48 | items: 49 | type: string 50 | required: 51 | - queries 52 | - function_name: clear_memory 53 | description: Deletes all memories. 54 | note: Verify with the user before clearing all memories. 55 | parameters: {} -------------------------------------------------------------------------------- /Lucy/tool_definitions/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Messages_v1-0", 3 | "Description": "Sends messages via the Messages app. When you're told to \"tell\" something to someone, this is one way to do that. You must use the Contacts tool to get a valid phone number or email address to use as the recipient before using this tool.", 4 | "Functions": [ 5 | { 6 | "function_name": "send_messages", 7 | "description": "Sends messages to specified recipients using the Messages app.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "messages": { 12 | "type": "array", 13 | "description": "An array of message objects to be sent.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "recipients": { 18 | "type": "array", 19 | "description": "An array of phone numbers or email addresses of the recipients.", 20 | "items": { 21 | "type": "string" 22 | } 23 | }, 24 | "message_body": { 25 | "type": "string", 26 | "description": "The content of the message to be sent." 27 | } 28 | }, 29 | "required": [ 30 | "recipients", 31 | "message_body" 32 | ] 33 | } 34 | } 35 | }, 36 | "required": [ 37 | "messages" 38 | ] 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/messages.yml: -------------------------------------------------------------------------------- 1 | Name: Messages_v1-0 2 | Description: Sends messages via the Messages app. When you're told to "tell" something to someone, this is one way to do that. You must use the Contacts tool to get a valid phone number or email address to use as the recipient before using this tool. 3 | Functions: 4 | - function_name: send_messages 5 | description: Sends messages to specified recipients using the Messages app. 6 | parameters: 7 | type: object 8 | properties: 9 | messages: 10 | type: array 11 | description: "An array of message objects to be sent." 12 | items: 13 | type: object 14 | properties: 15 | recipients: 16 | type: array 17 | description: "An array of phone numbers or email addresses of the recipients." 18 | items: 19 | type: string 20 | message_body: 21 | type: string 22 | description: "The content of the message to be sent." 23 | required: 24 | - recipients 25 | - message_body 26 | required: 27 | - messages -------------------------------------------------------------------------------- /Lucy/tool_definitions/morsecode.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "MorseCode_v1-0", 3 | "Description": "Converts text messages to Morse code and transmits them using the device's flashlight and optional screen flashing. This tool allows users to send messages in Morse code format with customizable repetition and visual feedback options.", 4 | "Functions": [ 5 | { 6 | "function_name": "send_message", 7 | "description": "Converts a text message to Morse code and transmits it using the device's flashlight, with optional screen flashing and message repetition.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "message": { 12 | "type": "string", 13 | "description": "The text message to convert to Morse code and transmit. The message will be converted to standard International Morse Code format." 14 | }, 15 | "number_of_repetitions": { 16 | "type": "number", 17 | "description": "The number of times to repeat the Morse code transmission of the message. Must be a positive integer. Use 1 if user doesn't specify." 18 | }, 19 | "flash_screen": { 20 | "type": "boolean", 21 | "description": "Optional parameter to enable screen flashing synchronized with the flashlight during Morse code transmission. Defaults to false if not specified." 22 | } 23 | }, 24 | "required": [ 25 | "message", 26 | "number_of_repetitions" 27 | ] 28 | } 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/morsecode.yml: -------------------------------------------------------------------------------- 1 | Name: MorseCode_v1-0 2 | Description: Converts text messages to Morse code and transmits them using the device's flashlight and optional screen flashing. This tool allows users to send messages in Morse code format with customizable repetition and visual feedback options. 3 | Functions: 4 | - function_name: send_message 5 | description: Converts a text message to Morse code and transmits it using the device's flashlight, with optional screen flashing and message repetition. 6 | parameters: 7 | type: object 8 | properties: 9 | message: 10 | type: string 11 | description: The text message to convert to Morse code and transmit. The message will be converted to standard International Morse Code format. 12 | number_of_repetitions: 13 | type: number 14 | description: The number of times to repeat the Morse code transmission of the message. Must be a positive integer. Use 1 if user doesn't specify. 15 | flash_screen: 16 | type: boolean 17 | description: Optional parameter to enable screen flashing synchronized with the flashlight during Morse code transmission. Defaults to false if not specified. 18 | required: 19 | - message 20 | - number_of_repetitions -------------------------------------------------------------------------------- /Lucy/tool_definitions/notes.json: -------------------------------------------------------------------------------- 1 | { 2 | "note_lookup_properties": { 3 | "name": { 4 | "type": "string", 5 | "description": "Name of the note to modify." 6 | }, 7 | "body": { 8 | "type": "string", 9 | "description": "Partial body text to find unique note." 10 | } 11 | }, 12 | "Name": "Notes_v1-0", 13 | "Description": "Create, modify, organize, and search notes. **DO NOT USE THE NOTES TOOL TO REMEMBER THINGS ABOUT THE USER. INSTEAD, USE THE MEMORY TOOL FOR USER INFORMATION.**", 14 | "Functions": [ 15 | { 16 | "function_name": "add_new_notes", 17 | "description": "Adds one or more new notes. **DO NOT USE THE NOTES TOOL TO REMEMBER THINGS ABOUT THE USER. INSTEAD, USE THE MEMORY TOOL FOR USER INFORMATION.**", 18 | "parameters": { 19 | "type": "object", 20 | "properties": { 21 | "notes": { 22 | "type": "array", 23 | "description": "Array of note objects to add.", 24 | "items": { 25 | "type": "object", 26 | "properties": { 27 | "name": { 28 | "type": "string", 29 | "description": "Note title." 30 | }, 31 | "body": { 32 | "type": "string", 33 | "description": "Note content." 34 | }, 35 | "folder": { 36 | "type": "string", 37 | "description": "Folder to save note in." 38 | }, 39 | "tags": { 40 | "type": "array", 41 | "description": "Optional list of tags.", 42 | "items": { 43 | "type": "string" 44 | } 45 | }, 46 | "todos": { 47 | "type": "array", 48 | "description": "Optional list of todos.", 49 | "items": { 50 | "type": "string" 51 | } 52 | } 53 | }, 54 | "required": [ 55 | "name", 56 | "body", 57 | "folder" 58 | ] 59 | } 60 | } 61 | }, 62 | "required": [ 63 | "notes" 64 | ] 65 | } 66 | }, 67 | { 68 | "function_name": "append_to_note", 69 | "description": "Appends content to a note.", 70 | "parameters": { 71 | "type": "object", 72 | "properties": { 73 | "name": { 74 | "type": "string", 75 | "description": "Name of the note to modify." 76 | }, 77 | "body": { 78 | "type": "string", 79 | "description": "Partial body text to find unique note." 80 | }, 81 | "content": { 82 | "type": "object", 83 | "description": "Content to append. Use one or more of `body`, `tags`, or `todos`.", 84 | "properties": { 85 | "body": { 86 | "type": "string", 87 | "description": "Additional text to append." 88 | }, 89 | "tags": { 90 | "type": "array", 91 | "description": "Tags to add.", 92 | "items": { 93 | "type": "string" 94 | } 95 | }, 96 | "todos": { 97 | "type": "array", 98 | "description": "Todos to add.", 99 | "items": { 100 | "type": "string" 101 | } 102 | } 103 | } 104 | } 105 | }, 106 | "required": [ 107 | "name", 108 | "body", 109 | "content" 110 | ] 111 | } 112 | }, 113 | { 114 | "function_name": "open_note", 115 | "description": "Opens a note for viewing.", 116 | "parameters": { 117 | "type": "object", 118 | "properties": { 119 | "name": { 120 | "type": "string", 121 | "description": "Name of the note to modify." 122 | }, 123 | "body": { 124 | "type": "string", 125 | "description": "Partial body text to find unique note." 126 | } 127 | }, 128 | "required": [ 129 | "name", 130 | "body" 131 | ] 132 | } 133 | }, 134 | { 135 | "function_name": "remove_tags_from_note", 136 | "description": "Removes tags from a note.", 137 | "parameters": { 138 | "type": "object", 139 | "properties": { 140 | "name": { 141 | "type": "string", 142 | "description": "Name of the note to modify." 143 | }, 144 | "body": { 145 | "type": "string", 146 | "description": "Partial body text to find unique note." 147 | }, 148 | "tags": { 149 | "type": "array", 150 | "description": "Tags to remove.", 151 | "items": { 152 | "type": "string" 153 | } 154 | } 155 | }, 156 | "required": [ 157 | "name", 158 | "body", 159 | "tags" 160 | ] 161 | } 162 | }, 163 | { 164 | "function_name": "search_notes", 165 | "description": "Searches note titles and bodies for a query.", 166 | "parameters": { 167 | "type": "object", 168 | "properties": { 169 | "query": { 170 | "type": "string", 171 | "description": "Search query." 172 | } 173 | }, 174 | "required": [ 175 | "query" 176 | ] 177 | } 178 | }, 179 | { 180 | "function_name": "get_folder_list", 181 | "description": "Lists all note folders.", 182 | "parameters": {} 183 | }, 184 | { 185 | "function_name": "get_tag_list", 186 | "description": "Lists all unique tags.", 187 | "parameters": {} 188 | }, 189 | { 190 | "function_name": "open_folder", 191 | "description": "Opens a note folder.", 192 | "parameters": { 193 | "type": "object", 194 | "properties": { 195 | "folder": { 196 | "type": "string", 197 | "description": "Name of the folder to open." 198 | } 199 | }, 200 | "required": [ 201 | "folder" 202 | ] 203 | } 204 | } 205 | ] 206 | } 207 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/notes.yml: -------------------------------------------------------------------------------- 1 | # A map of properties used to look up a unique note. 2 | note_lookup_properties: ¬e_lookup_properties 3 | name: 4 | type: string 5 | description: Name of the note to modify. 6 | body: 7 | type: string 8 | description: Partial body text to find unique note. 9 | 10 | Name: Notes_v1-0 11 | Description: Create, modify, organize, and search notes. **DO NOT USE THE NOTES TOOL TO REMEMBER THINGS ABOUT THE USER. INSTEAD, USE THE MEMORY TOOL FOR USER INFORMATION.** 12 | Functions: 13 | - function_name: add_new_notes 14 | description: Adds one or more new notes. **DO NOT USE THE NOTES TOOL TO REMEMBER THINGS ABOUT THE USER. INSTEAD, USE THE MEMORY TOOL FOR USER INFORMATION.** 15 | parameters: 16 | type: object 17 | properties: 18 | notes: 19 | type: array 20 | description: Array of note objects to add. 21 | items: 22 | type: object 23 | properties: 24 | name: 25 | type: string 26 | description: Note title. 27 | body: 28 | type: string 29 | description: Note content. 30 | folder: 31 | type: string 32 | description: Folder to save note in. 33 | tags: 34 | type: array 35 | description: Optional list of tags. 36 | items: 37 | type: string 38 | todos: 39 | type: array 40 | description: Optional list of todos. 41 | items: 42 | type: string 43 | required: 44 | - name 45 | - body 46 | - folder 47 | required: 48 | - notes 49 | - function_name: append_to_note 50 | description: Appends content to a note. 51 | parameters: 52 | type: object 53 | properties: 54 | <<: *note_lookup_properties 55 | content: 56 | type: object 57 | description: Content to append. Use one or more of `body`, `tags`, or `todos`. 58 | properties: 59 | body: 60 | type: string 61 | description: Additional text to append. 62 | tags: 63 | type: array 64 | description: Tags to add. 65 | items: 66 | type: string 67 | todos: 68 | type: array 69 | description: Todos to add. 70 | items: 71 | type: string 72 | required: 73 | - name 74 | - body 75 | - content 76 | - function_name: open_note 77 | description: Opens a note for viewing. 78 | parameters: 79 | type: object 80 | properties: 81 | <<: *note_lookup_properties 82 | required: 83 | - name 84 | - body 85 | - function_name: remove_tags_from_note 86 | description: Removes tags from a note. 87 | parameters: 88 | type: object 89 | properties: 90 | <<: *note_lookup_properties 91 | tags: 92 | type: array 93 | description: Tags to remove. 94 | items: 95 | type: string 96 | required: 97 | - name 98 | - body 99 | - tags 100 | - function_name: search_notes 101 | description: Searches note titles and bodies for a query. 102 | parameters: 103 | type: object 104 | properties: 105 | query: 106 | type: string 107 | description: Search query. 108 | required: 109 | - query 110 | - function_name: get_folder_list 111 | description: Lists all note folders. 112 | parameters: {} 113 | - function_name: get_tag_list 114 | description: Lists all unique tags. 115 | parameters: {} 116 | - function_name: open_folder 117 | description: Opens a note folder. 118 | parameters: 119 | type: object 120 | properties: 121 | folder: 122 | type: string 123 | description: Name of the folder to open. 124 | required: 125 | - folder -------------------------------------------------------------------------------- /Lucy/tool_definitions/pythonista.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Pythonista_v1-0", 3 | "Description": "Executes Python code using the Pythonista app on iOS.", 4 | "Functions": [ 5 | { 6 | "function_name": "run_python_script", 7 | "description": "Executes a provided Python script within the Pythonista environment. The script's output (e.g., from print statements or the final evaluated expression) will be returned as a string. If the intended return value is a complex data structure (e.g., a dictionary or list), it must be serialized into a JSON string before being printed or returned.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "script": { 12 | "type": "string", 13 | "description": "The raw Python code to execute. This can be a single line or a multiline script. The tool will execute this code directly. For example: print('Hello') or x = 10\ny = 20\nprint(x + y)." 14 | } 15 | }, 16 | "required": [ 17 | "script" 18 | ] 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/pythonista.yml: -------------------------------------------------------------------------------- 1 | Name: Pythonista_v1-0 2 | Description: Executes Python code using the Pythonista app on iOS. 3 | Functions: 4 | - function_name: run_python_script 5 | description: Executes a provided Python script within the Pythonista environment. The script's output (e.g., from print statements or the final evaluated expression) will be returned as a string. If the intended return value is a complex data structure (e.g., a dictionary or list), it must be serialized into a JSON string before being printed or returned. 6 | parameters: 7 | type: object 8 | properties: 9 | script: 10 | type: string 11 | description: "The raw Python code to execute. This can be a single line or a multiline script. The tool will execute this code directly. For example: print('Hello') or x = 10\ny = 20\nprint(x + y)." 12 | required: 13 | - script -------------------------------------------------------------------------------- /Lucy/tool_definitions/recipecataloger.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "RecipeCataloger_v1-0", 3 | "Description": "Enables access to a powerful recipe cataloging routine. This allows the system to efficiently find, extract, and organize recipes from various web sources, building a comprehensive personal recipe collection based on the user's culinary interests.", 4 | "Functions": [ 5 | { 6 | "function_name": "catalog_recipe", 7 | "description": "Finds and saves web recipes. If user just wants to find a recipe, confirm first, explaining it will save the recipe to Notes and add ingredients to Reminders. If user asks to save a recipe, use directly.", 8 | "parameters": {} 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/recipecataloger.yml: -------------------------------------------------------------------------------- 1 | Name: RecipeCataloger_v1-0 2 | Description: Enables access to a powerful recipe cataloging routine. This allows the system to efficiently find, extract, and organize recipes from various web sources, building a comprehensive personal recipe collection based on the user's culinary interests. 3 | Functions: 4 | - function_name: catalog_recipe 5 | description: Finds and saves web recipes. If user just wants to find a recipe, confirm first, explaining it will save the recipe to Notes and add ingredients to Reminders. If user asks to save a recipe, use directly. 6 | parameters: {} -------------------------------------------------------------------------------- /Lucy/tool_definitions/reminders.json: -------------------------------------------------------------------------------- 1 | { 2 | "full_reminder_properties": { 3 | "title": { 4 | "type": "string", 5 | "description": "The title." 6 | }, 7 | "list": { 8 | "type": "string", 9 | "description": "List name. Uses default list if omitted." 10 | }, 11 | "new_list": { 12 | "type": "boolean", 13 | "description": "Set true to create the list if it doesn't exist." 14 | }, 15 | "due_date": { 16 | "type": "string", 17 | "description": "Reminder alert time (YYYY-MM-DD hh:mm:ss)." 18 | }, 19 | "flag": { 20 | "type": "boolean", 21 | "description": "Set true to flag as important." 22 | }, 23 | "tags": { 24 | "type": "string", 25 | "description": "Comma-separated tags." 26 | }, 27 | "notes": { 28 | "type": "string", 29 | "description": "Additional notes." 30 | }, 31 | "url": { 32 | "type": "string", 33 | "description": "Associated URL." 34 | } 35 | }, 36 | "Name": "Reminders_v1-0", 37 | "Description": "Manages tasks and reminders in the Reminders app.", 38 | "Functions": [ 39 | { 40 | "function_name": "list_reminders", 41 | "description": "Lists completed or incomplete reminders, optionally searching by query, list, and/or date.", 42 | "parameters": { 43 | "type": "object", 44 | "properties": { 45 | "query": { 46 | "type": "string", 47 | "description": "Regex for title/notes. Be generous with matches." 48 | }, 49 | "list": { 50 | "type": "string", 51 | "description": "Regex to match list in which the reminder is located." 52 | }, 53 | "begin_date": { 54 | "type": "string", 55 | "description": "Start date for search (YYYY-MM-DD hh:mm:ss)." 56 | }, 57 | "include_completed": { 58 | "type": "boolean", 59 | "description": "Include completed reminders. Default false. Only use if user specifies that the reminders they are interested in is/are *already completed*, and *you must get permission from the user before searching for completed reminders, because it may take a long time to search through all completed reminders.*" 60 | } 61 | } 62 | } 63 | }, 64 | { 65 | "function_name": "get_reminder_lists", 66 | "description": "Retrieves all reminder lists.", 67 | "parameters": {} 68 | }, 69 | { 70 | "function_name": "get_reminder_tags", 71 | "description": "Retrieves all unique tags from reminders.", 72 | "parameters": {} 73 | }, 74 | { 75 | "function_name": "add_new_reminders", 76 | "description": "Adds one or more new reminders.", 77 | "parameters": { 78 | "type": "object", 79 | "properties": { 80 | "reminders": { 81 | "type": "array", 82 | "description": "Array of reminder objects to add.", 83 | "items": { 84 | "type": "object", 85 | "properties": { 86 | "title": { 87 | "type": "string", 88 | "description": "The title." 89 | }, 90 | "list": { 91 | "type": "string", 92 | "description": "List name. Uses default list if omitted." 93 | }, 94 | "new_list": { 95 | "type": "boolean", 96 | "description": "Set true to create the list if it doesn't exist." 97 | }, 98 | "due_date": { 99 | "type": "string", 100 | "description": "Reminder alert time (YYYY-MM-DD hh:mm:ss)." 101 | }, 102 | "flag": { 103 | "type": "boolean", 104 | "description": "Set true to flag as important." 105 | }, 106 | "tags": { 107 | "type": "string", 108 | "description": "Comma-separated tags." 109 | }, 110 | "notes": { 111 | "type": "string", 112 | "description": "Additional notes." 113 | }, 114 | "url": { 115 | "type": "string", 116 | "description": "Associated URL." 117 | }, 118 | "subtasks": { 119 | "type": "array", 120 | "description": "Optional array of subtasks.", 121 | "items": { 122 | "type": "object", 123 | "properties": { 124 | "title": { 125 | "type": "string", 126 | "description": "The title." 127 | }, 128 | "list": { 129 | "type": "string", 130 | "description": "List name. Uses default list if omitted." 131 | }, 132 | "new_list": { 133 | "type": "boolean", 134 | "description": "Set true to create the list if it doesn't exist." 135 | }, 136 | "due_date": { 137 | "type": "string", 138 | "description": "Reminder alert time (YYYY-MM-DD hh:mm:ss)." 139 | }, 140 | "flag": { 141 | "type": "boolean", 142 | "description": "Set true to flag as important." 143 | }, 144 | "tags": { 145 | "type": "string", 146 | "description": "Comma-separated tags." 147 | }, 148 | "notes": { 149 | "type": "string", 150 | "description": "Additional notes." 151 | }, 152 | "url": { 153 | "type": "string", 154 | "description": "Associated URL." 155 | } 156 | }, 157 | "required": [ 158 | "title" 159 | ] 160 | } 161 | } 162 | }, 163 | "required": [ 164 | "title" 165 | ] 166 | } 167 | } 168 | }, 169 | "required": [ 170 | "reminders" 171 | ] 172 | } 173 | }, 174 | { 175 | "function_name": "complete_reminder", 176 | "description": "Marks a reminder as completed or incomplete. You may need to use 'list_reminders' to find the reminder metadata first.", 177 | "parameters": { 178 | "type": "object", 179 | "properties": { 180 | "list": { 181 | "type": "string", 182 | "description": "List containing the reminder." 183 | }, 184 | "title": { 185 | "type": "string", 186 | "description": "Exact title of the reminder." 187 | }, 188 | "creation_date": { 189 | "type": "string", 190 | "description": "Creation date (YYYY-MM-DD hh:mm:ss) for unique ID." 191 | }, 192 | "is_completed": { 193 | "type": "boolean", 194 | "description": "Set true to complete, false to un-complete." 195 | } 196 | }, 197 | "required": [ 198 | "list", 199 | "title", 200 | "creation_date", 201 | "is_completed" 202 | ] 203 | } 204 | }, 205 | { 206 | "function_name": "edit_reminder", 207 | "description": "Modifies an existing reminder. You may need to use 'list_reminders' to find the reminder metadata first.", 208 | "parameters": { 209 | "type": "object", 210 | "properties": { 211 | "list": { 212 | "type": "string", 213 | "description": "List containing the reminder." 214 | }, 215 | "title": { 216 | "type": "string", 217 | "description": "Exact title of the reminder." 218 | }, 219 | "creation_date": { 220 | "type": "string", 221 | "description": "Creation date (YYYY-MM-DD hh:mm:ss) for unique ID." 222 | }, 223 | "is_completed": { 224 | "type": "boolean", 225 | "description": "Current completion status for identification." 226 | }, 227 | "content": { 228 | "type": "object", 229 | "description": "Object with new attributes to overwrite. Only include fields that are to be updated.", 230 | "properties": { 231 | "title": { 232 | "type": "string", 233 | "description": "The title." 234 | }, 235 | "list": { 236 | "type": "string", 237 | "description": "List name. Uses default list if omitted." 238 | }, 239 | "new_list": { 240 | "type": "boolean", 241 | "description": "Set true to create the list if it doesn't exist." 242 | }, 243 | "due_date": { 244 | "type": "string", 245 | "description": "Reminder alert time (YYYY-MM-DD hh:mm:ss)." 246 | }, 247 | "flag": { 248 | "type": "boolean", 249 | "description": "Set true to flag as important." 250 | }, 251 | "tags": { 252 | "type": "string", 253 | "description": "Comma-separated tags." 254 | }, 255 | "notes": { 256 | "type": "string", 257 | "description": "Additional notes." 258 | }, 259 | "url": { 260 | "type": "string", 261 | "description": "Associated URL." 262 | } 263 | } 264 | } 265 | }, 266 | "required": [ 267 | "list", 268 | "title", 269 | "creation_date", 270 | "is_completed", 271 | "content" 272 | ] 273 | } 274 | }, 275 | { 276 | "function_name": "open_reminder_list", 277 | "description": "Opens a specific reminder list.", 278 | "parameters": { 279 | "type": "object", 280 | "properties": { 281 | "list": { 282 | "type": "string", 283 | "description": "Name of the reminder list to open." 284 | } 285 | }, 286 | "required": [ 287 | "list" 288 | ] 289 | } 290 | } 291 | ] 292 | } 293 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/reminders.yml: -------------------------------------------------------------------------------- 1 | # A single, complete definition of all possible reminder properties 2 | full_reminder_properties: &full_reminder_properties 3 | title: 4 | type: string 5 | description: The title. 6 | list: 7 | type: string 8 | description: List name. Uses default list if omitted. 9 | new_list: 10 | type: boolean 11 | description: Set true to create the list if it doesn't exist. 12 | due_date: 13 | type: string 14 | description: Reminder alert time (YYYY-MM-DD hh:mm:ss). 15 | flag: 16 | type: boolean 17 | description: Set true to flag as important. 18 | tags: 19 | type: string 20 | description: Comma-separated tags. 21 | notes: 22 | type: string 23 | description: Additional notes. 24 | url: 25 | type: string 26 | description: Associated URL. 27 | 28 | Name: Reminders_v1-0 29 | Description: Manages tasks and reminders in the Reminders app. 30 | Functions: 31 | - function_name: list_reminders 32 | description: Lists completed or incomplete reminders, optionally searching by query, list, and/or date. 33 | parameters: 34 | type: object 35 | properties: 36 | query: 37 | type: string 38 | description: Regex for title/notes. Be generous with matches. 39 | list: 40 | type: string 41 | description: Regex to match list in which the reminder is located. 42 | begin_date: 43 | type: string 44 | description: Start date for search (YYYY-MM-DD hh:mm:ss). 45 | include_completed: 46 | type: boolean 47 | description: Include completed reminders. Default false. Only use if user specifies that the reminders they are interested in is/are *already completed*, and *you must get permission from the user before searching for completed reminders, because it may take a long time to search through all completed reminders.* 48 | - function_name: get_reminder_lists 49 | description: Retrieves all reminder lists. 50 | parameters: {} 51 | - function_name: get_reminder_tags 52 | description: Retrieves all unique tags from reminders. 53 | parameters: {} 54 | - function_name: add_new_reminders 55 | description: Adds one or more new reminders. 56 | parameters: 57 | type: object 58 | properties: 59 | reminders: 60 | type: array 61 | description: Array of reminder objects to add. 62 | items: 63 | type: object 64 | properties: 65 | <<: *full_reminder_properties 66 | subtasks: 67 | type: array 68 | description: Optional array of subtasks. 69 | items: 70 | type: object 71 | properties: 72 | <<: *full_reminder_properties 73 | required: 74 | - title 75 | required: 76 | - title 77 | required: 78 | - reminders 79 | - function_name: complete_reminder 80 | description: Marks a reminder as completed or incomplete. You may need to use 'list_reminders' to find the reminder metadata first. 81 | parameters: 82 | type: object 83 | properties: 84 | list: 85 | type: string 86 | description: List containing the reminder. 87 | title: 88 | type: string 89 | description: Exact title of the reminder. 90 | creation_date: 91 | type: string 92 | description: Creation date (YYYY-MM-DD hh:mm:ss) for unique ID. 93 | is_completed: 94 | type: boolean 95 | description: Set true to complete, false to un-complete. 96 | required: 97 | - list 98 | - title 99 | - creation_date 100 | - is_completed 101 | - function_name: edit_reminder 102 | description: Modifies an existing reminder. You may need to use 'list_reminders' to find the reminder metadata first. 103 | parameters: 104 | type: object 105 | properties: 106 | list: 107 | type: string 108 | description: List containing the reminder. 109 | title: 110 | type: string 111 | description: Exact title of the reminder. 112 | creation_date: 113 | type: string 114 | description: Creation date (YYYY-MM-DD hh:mm:ss) for unique ID. 115 | is_completed: 116 | type: boolean 117 | description: Current completion status for identification. 118 | content: 119 | type: object 120 | description: Object with new attributes to overwrite. Only include fields that are to be updated. 121 | properties: 122 | <<: *full_reminder_properties 123 | required: 124 | - list 125 | - title 126 | - creation_date 127 | - is_completed 128 | - content 129 | - function_name: open_reminder_list 130 | description: Opens a specific reminder list. 131 | parameters: 132 | type: object 133 | properties: 134 | list: 135 | type: "string" 136 | description: "Name of the reminder list to open." 137 | required: 138 | - list -------------------------------------------------------------------------------- /Lucy/tool_definitions/runjavascript.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "RunJavaScript_v1-0", 3 | "Description": "Executes custom JavaScript code within a secure environment. Whenever appropriate and possible, use this JavaScript tool when running code to help answer a question. For example, if asked to count words/letters, or do other string processing or math operations, you should generate JavaScript and run run it with this tool. Only use another code/terminal tool if the users requests a different language other than JavaScript.", 4 | "Functions": [ 5 | { 6 | "function_name": "run_javascript", 7 | "description": "Executes a provided JavaScript script. This is the preferred method for performing computational tasks such as calculations, string manipulations, and other similar logical operations, rather than using other general-purpose execution environments for such purposes, especially if working in JavaScript. Rather than returning a value, the provided script must set the value of 'document.body.textContent = encodeURIComponent()' with the output value.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "script": { 12 | "type": "string", 13 | "description": "The JavaScript code to execute. This script should perform the desired action and must explicitly set 'document.body.textContent'. For example, to return an object, use 'document.body.textContent = encodeURIComponent(JSON.stringify({ key: 'value' }));'." 14 | } 15 | }, 16 | "required": [ 17 | "script" 18 | ] 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/runjavascript.yml: -------------------------------------------------------------------------------- 1 | Name: RunJavaScript_v1-0 2 | Description: Executes custom JavaScript code within a secure environment. Whenever appropriate and possible, use this JavaScript tool when running code to help answer a question. For example, if asked to count words/letters, or do other string processing or math operations, you should generate JavaScript and run run it with this tool. Only use another code/terminal tool if the users requests a different language other than JavaScript. 3 | Functions: 4 | - function_name: run_javascript 5 | description: Executes a provided JavaScript script. This is the preferred method for performing computational tasks such as calculations, string manipulations, and other similar logical operations, rather than using other general-purpose execution environments for such purposes, especially if working in JavaScript. Rather than returning a value, the provided script must set the value of 'document.body.textContent = encodeURIComponent()' with the output value. 6 | parameters: 7 | type: object 8 | properties: 9 | script: 10 | type: string 11 | description: "The JavaScript code to execute. This script should perform the desired action and must explicitly set 'document.body.textContent'. For example, to return an object, use 'document.body.textContent = encodeURIComponent(JSON.stringify({ key: 'value' }));'." 12 | required: 13 | - script -------------------------------------------------------------------------------- /Lucy/tool_definitions/summarizetext.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "SummarizeText_v1-0", 3 | "Description": "Summarizes text in order to have it consume fewer tokens. When you use this tool to summarize text, you must use the resulting summary as context for your next message to the user. This tool only generates summaries for you to see and use as context in your conversation with the user.", 4 | "Functions": [ 5 | { 6 | "function_name": "summarize_webpages", 7 | "description": "Retrieves content from the specified URLs and generates a summary for each. The function returns a JSON dictionary where keys are the URLs and values are their corresponding summaries.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "urls": { 12 | "type": "array", 13 | "description": "A list of full URLs of the webpages to be summarized (e.g., ['https://example.com/article1', 'https://example.com/article2.pdf']). Each URL must be a valid string. URLs to PDFs and other files are supported.", 14 | "items": { 15 | "type": "string" 16 | } 17 | }, 18 | "summary_notes": { 19 | "type": "string", 20 | "description": "Additional notes or context to consider when summarizing the text." 21 | } 22 | }, 23 | "required": [ 24 | "urls" 25 | ] 26 | } 27 | }, 28 | { 29 | "function_name": "summarize_youtube_video_transcript", 30 | "description": "Retrieves the transcript of a YouTube video and generates a summary.", 31 | "parameters": { 32 | "type": "object", 33 | "properties": { 34 | "url": { 35 | "type": "string", 36 | "description": "The full or shortened URL of the YouTube video to summarize." 37 | }, 38 | "summary_notes": { 39 | "type": "string", 40 | "description": "Additional notes or context to consider when summarizing the text." 41 | } 42 | }, 43 | "required": [ 44 | "url" 45 | ] 46 | } 47 | }, 48 | { 49 | "function_name": "summarize_text", 50 | "description": "Summarizes a text string.", 51 | "parameters": { 52 | "type": "object", 53 | "properties": { 54 | "text": { 55 | "type": "string", 56 | "description": "A text string to summarize. This is only to be used in order to summarize text so that it consumes fewer tokens in future LLM API calls. If the user actually requests for text summarization, do not use this tool, and instead perform the summary yourself." 57 | }, 58 | "summary_notes": { 59 | "type": "string", 60 | "description": "Additional notes or context to consider when summarizing the text." 61 | } 62 | }, 63 | "required": [ 64 | "text" 65 | ] 66 | } 67 | } 68 | ] 69 | } 70 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/summarizetext.yml: -------------------------------------------------------------------------------- 1 | Name: SummarizeText_v1-0 2 | Description: Summarizes text in order to have it consume fewer tokens. When you use this tool to summarize text, you must use the resulting summary as context for your next message to the user. This tool only generates summaries for you to see and use as context in your conversation with the user. 3 | Functions: 4 | - function_name: summarize_webpages 5 | description: Retrieves content from the specified URLs and generates a summary for each. The function returns a JSON dictionary where keys are the URLs and values are their corresponding summaries. 6 | parameters: 7 | type: object 8 | properties: 9 | urls: 10 | type: array 11 | description: A list of full URLs of the webpages to be summarized (e.g., ['https://example.com/article1', 'https://example.com/article2.pdf']). Each URL must be a valid string. URLs to PDFs and other files are supported. 12 | items: 13 | type: string 14 | summary_notes: 15 | type: string 16 | description: Additional notes or context to consider when summarizing the text. 17 | required: 18 | - urls 19 | - function_name: summarize_youtube_video_transcript 20 | description: Retrieves the transcript of a YouTube video and generates a summary. 21 | parameters: 22 | type: object 23 | properties: 24 | url: 25 | type: string 26 | description: The full or shortened URL of the YouTube video to summarize. 27 | summary_notes: 28 | type: string 29 | description: Additional notes or context to consider when summarizing the text. 30 | required: 31 | - url 32 | - function_name: summarize_text 33 | description: Summarizes a text string. 34 | parameters: 35 | type: object 36 | properties: 37 | text: 38 | type: string 39 | description: A text string to summarize. This is only to be used in order to summarize text so that it consumes fewer tokens in future LLM API calls. If the user actually requests for text summarization, do not use this tool, and instead perform the summary yourself. 40 | summary_notes: 41 | type: string 42 | description: Additional notes or context to consider when summarizing the text. 43 | required: 44 | - text -------------------------------------------------------------------------------- /Lucy/tool_definitions/terminal.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Terminal_v1-0", 3 | "Description": "Local Unix terminal (iOS a-Shell, macOS bash). Supports commands like grep, curl, git, ffmpeg. Not for Apple Watch or HomePod.", 4 | "Functions": [ 5 | { 6 | "function_name": "execute_command", 7 | "description": "Executes a shell command.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "command": { 12 | "type": "string", 13 | "description": "The shell command to execute." 14 | } 15 | }, 16 | "required": [ 17 | "command" 18 | ] 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/terminal.yml: -------------------------------------------------------------------------------- 1 | Name: Terminal_v1-0 2 | Description: Local Unix terminal (iOS a-Shell, macOS bash). Supports commands like grep, curl, git, ffmpeg. Not for Apple Watch or HomePod. 3 | Functions: 4 | - function_name: execute_command 5 | description: Executes a shell command. 6 | parameters: 7 | type: object 8 | properties: 9 | command: 10 | type: string 11 | description: The shell command to execute. 12 | required: 13 | - command -------------------------------------------------------------------------------- /Lucy/tool_definitions/timers.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Timers (tool_name)", 3 | "Description": "Manages a single active timer, allowing for starting, pausing, resuming, canceling, and checking its status.", 4 | "Functions": [ 5 | { 6 | "function_name": "start_timer", 7 | "description": "Starts a new countdown timer for a specified duration. If a timer is already running, this will start a new one, potentially replacing the existing one.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "duration_minutes": { 12 | "type": "number", 13 | "description": "The duration of the timer in minutes (can use fractional minutes)." 14 | } 15 | }, 16 | "required": [ 17 | "duration_minutes" 18 | ] 19 | } 20 | }, 21 | { 22 | "function_name": "resume_timer", 23 | "description": "Resumes the current timer if it is paused. Has no effect if the timer is already running or if no timer is active.", 24 | "parameters": [] 25 | }, 26 | { 27 | "function_name": "pause_timer", 28 | "description": "Pauses the current timer if it is running. Has no effect if the timer is already paused or if no timer is active.", 29 | "parameters": [] 30 | }, 31 | { 32 | "function_name": "cancel_timer", 33 | "description": "Cancels and stops the current timer, effectively resetting it.", 34 | "parameters": [] 35 | }, 36 | { 37 | "function_name": "get_current_timer", 38 | "description": "Retrieves information about the current timer's status (e.g., remaining time, state) without affecting its operation.", 39 | "parameters": [] 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/timers.yml: -------------------------------------------------------------------------------- 1 | Name: Timers (tool_name) 2 | Description: Manages a single active timer, allowing for starting, pausing, resuming, canceling, and checking its status. 3 | Functions: 4 | - function_name: start_timer 5 | description: Starts a new countdown timer for a specified duration. If a timer is already running, this will start a new one, potentially replacing the existing one. 6 | parameters: 7 | type: "object" 8 | properties: 9 | duration_minutes: 10 | type: "number" 11 | description: "The duration of the timer in minutes (can use fractional minutes)." 12 | required: 13 | - "duration_minutes" 14 | - function_name: resume_timer 15 | description: Resumes the current timer if it is paused. Has no effect if the timer is already running or if no timer is active. 16 | parameters: [] 17 | - function_name: pause_timer 18 | description: Pauses the current timer if it is running. Has no effect if the timer is already paused or if no timer is active. 19 | parameters: [] 20 | - function_name: cancel_timer 21 | description: Cancels and stops the current timer, effectively resetting it. 22 | parameters: [] 23 | - function_name: get_current_timer 24 | description: Retrieves information about the current timer's status (e.g., remaining time, state) without affecting its operation. 25 | parameters: [] -------------------------------------------------------------------------------- /Lucy/tool_definitions/voicemode.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "VoiceMode_v1-0", 3 | "Description": "Manages voice communication with the user, enabling spoken interactions.", 4 | "Functions": [ 5 | { 6 | "function_name": "voice_chat", 7 | "description": "Activates the voice chat mode. Upon activation, the system will be ready to receive spoken input from the user. The LLM should then prompt the user to speak.", 8 | "parameters": {} 9 | }, 10 | { 11 | "function_name": "continue_voice_chat", 12 | "description": "Speaks a message provided by the LLM to the user, then listens for and captures the user's spoken response, returning it as a string.", 13 | "parameters": { 14 | "type": "object", 15 | "properties": { 16 | "message_content": { 17 | "type": "string", 18 | "description": "The message content that the LLM wishes to speak to the user. If omitted, the system will just listen for a response from the user." 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "function_name": "end_voice_chat", 25 | "description": "Deactivates the voice chat mode, returning the system to standard text-based interaction.", 26 | "parameters": {} 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/voicemode.yml: -------------------------------------------------------------------------------- 1 | Name: VoiceMode_v1-0 2 | Description: Manages voice communication with the user, enabling spoken interactions. 3 | Functions: 4 | - function_name: voice_chat 5 | description: Activates the voice chat mode. Upon activation, the system will be ready to receive spoken input from the user. The LLM should then prompt the user to speak. 6 | parameters: {} 7 | - function_name: continue_voice_chat 8 | description: Speaks a message provided by the LLM to the user, then listens for and captures the user's spoken response, returning it as a string. 9 | parameters: 10 | type: object 11 | properties: 12 | message_content: 13 | type: string 14 | description: "The message content that the LLM wishes to speak to the user. If omitted, the system will just listen for a response from the user." 15 | - function_name: end_voice_chat 16 | description: Deactivates the voice chat mode, returning the system to standard text-based interaction. 17 | parameters: {} -------------------------------------------------------------------------------- /Lucy/tool_definitions/weather.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Weather_v1-0", 3 | "Description": "Retrieves weather forecasts.", 4 | "Functions": [ 5 | { 6 | "function_name": "get_weather", 7 | "description": "Performs one or more weather queries. Each query contains location information as city [+ state [+ country]] or zip + country. Feel free to speculate about the state and country. If no location info is specified for a given location, the user's current location is used for that query. For example, you can get hourly and daily forecasts for multiple cities using a list of queries.", 8 | "parameters": { 9 | "type": "object", 10 | "properties": { 11 | "queries": { 12 | "type": "array", 13 | "description": "An array of location objects for which to retrieve weather data.", 14 | "items": { 15 | "type": "object", 16 | "properties": { 17 | "city": { 18 | "type": "string", 19 | "description": "The name of the city for which to retrieve the current weather." 20 | }, 21 | "state": { 22 | "type": "string", 23 | "description": "The name of the state for which to retrieve the current weather." 24 | }, 25 | "country": { 26 | "type": "string", 27 | "description": "The name of the country for which to retrieve the current weather. e.g. 'United States'" 28 | }, 29 | "zip": { 30 | "type": "number", 31 | "description": "The ZIP code for which to retrieve the current weather. If provided, please provide country as well." 32 | }, 33 | "type": { 34 | "type": "string", 35 | "description": "The type of weather data to retrieve. Must be either 'current' for real-time weather, or 'hourly' or 'daily' for 24-hour or 10-day forecasted weather respectively. Use 'hourly' as default.", 36 | "enum": [ 37 | "current", 38 | "hourly", 39 | "daily" 40 | ] 41 | } 42 | }, 43 | "required": [ 44 | "type" 45 | ] 46 | } 47 | }, 48 | "data": { 49 | "type": "array", 50 | "description": "An array of data types to include in the response. Request data types relevant to the task/question at hand. As a default, use temperature and condition, including others if they're noteworthy.", 51 | "items": { 52 | "type": "string", 53 | "enum": [ 54 | "low", 55 | "high", 56 | "temperature", 57 | "feels_like", 58 | "condition", 59 | "visibility", 60 | "dewpoint", 61 | "humidity", 62 | "pressure", 63 | "precipitation_amount", 64 | "precipitation_chance", 65 | "wind_speed", 66 | "wind_direction", 67 | "uv_index", 68 | "sunrise_time", 69 | "sunset_time", 70 | "air_quality_index", 71 | "air_quality_category", 72 | "air_pollutants" 73 | ] 74 | } 75 | } 76 | }, 77 | "required": [ 78 | "queries", 79 | "data" 80 | ] 81 | } 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/weather.yml: -------------------------------------------------------------------------------- 1 | Name: Weather_v1-0 2 | Description: Retrieves weather forecasts. 3 | Functions: 4 | - function_name: get_weather 5 | description: Performs one or more weather queries. Each query contains location information as city [+ state [+ country]] or zip + country. Feel free to speculate about the state and country. If no location info is specified for a given location, the user's current location is used for that query. For example, you can get hourly and daily forecasts for multiple cities using a list of queries. 6 | parameters: 7 | type: object 8 | properties: 9 | queries: 10 | type: array 11 | description: "An array of location objects for which to retrieve weather data." 12 | items: 13 | type: object 14 | properties: 15 | city: 16 | type: string 17 | description: "The name of the city for which to retrieve the current weather." 18 | state: 19 | type: string 20 | description: "The name of the state for which to retrieve the current weather." 21 | country: 22 | type: string 23 | description: "The name of the country for which to retrieve the current weather. e.g. 'United States'" 24 | zip: 25 | type: number 26 | description: "The ZIP code for which to retrieve the current weather. If provided, please provide country as well." 27 | type: 28 | type: string 29 | description: "The type of weather data to retrieve. Must be either 'current' for real-time weather, or 'hourly' or 'daily' for 24-hour or 10-day forecasted weather respectively. Use 'hourly' as default." 30 | enum: ["current", "hourly", "daily"] 31 | required: 32 | - type 33 | data: 34 | type: array 35 | description: "An array of data types to include in the response. Request data types relevant to the task/question at hand. As a default, use temperature and condition, including others if they're noteworthy." 36 | items: 37 | type: string 38 | enum: ["low", "high", "temperature", "feels_like", "condition", "visibility", "dewpoint", "humidity", "pressure", "precipitation_amount", "precipitation_chance", "wind_speed", "wind_direction", "uv_index", "sunrise_time", "sunset_time", "air_quality_index", "air_quality_category", "air_pollutants"] 39 | required: 40 | - queries 41 | - data -------------------------------------------------------------------------------- /Lucy/tool_definitions/web.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "Web_v1-0", 3 | "Description": "Searches web and gets webpage content.", 4 | "Note": "open_url is not supported on Apple Watch or HomePod.", 5 | "Functions": [ 6 | { 7 | "function_name": "perform_searches", 8 | "description": "Performs multiple searches across different platforms.", 9 | "parameters": { 10 | "type": "object", 11 | "properties": { 12 | "searches": { 13 | "type": "array", 14 | "description": "Array of search operations to perform.", 15 | "items": { 16 | "type": "object", 17 | "properties": { 18 | "search_tool": { 19 | "type": "string", 20 | "enum": [ 21 | "google_search", 22 | "arxiv_search", 23 | "chemrxiv_search" 24 | ], 25 | "description": "Type of search to perform.", 26 | "enum_hints": { 27 | "google_search": "Web search using Google.", 28 | "arxiv_search": "Search arXiv for academic papers (preprints) in physics, mathematics, and computer science, quantitative biology/finance, statistics, electrical engineering, systems science, and economics.", 29 | "chemrxiv_search": "Search ChemRxiv for academic papers (preprints) in chemistry." 30 | } 31 | }, 32 | "parameters": { 33 | "type": "object", 34 | "properties": { 35 | "query": { 36 | "type": "string", 37 | "description": "Search query." 38 | }, 39 | "start_page": { 40 | "type": "number", 41 | "description": "Starting page number (1-10)." 42 | }, 43 | "end_page": { 44 | "type": "number", 45 | "description": "Ending page number (1-10, >= start_page)." 46 | } 47 | }, 48 | "required": [ 49 | "query", 50 | "start_page", 51 | "end_page" 52 | ] 53 | } 54 | }, 55 | "required": [ 56 | "search_tool", 57 | "parameters" 58 | ] 59 | } 60 | } 61 | }, 62 | "required": [ 63 | "searches" 64 | ] 65 | } 66 | }, 67 | { 68 | "function_name": "open_url", 69 | "description": "Opens a URL in the browser.", 70 | "parameters": { 71 | "type": "object", 72 | "properties": { 73 | "url": { 74 | "type": "string", 75 | "description": "URL to open." 76 | } 77 | }, 78 | "required": [ 79 | "url" 80 | ] 81 | } 82 | }, 83 | { 84 | "function_name": "get_webpage_content", 85 | "description": "Gets raw content from a list of URLs.", 86 | "tip": "Add .json to Reddit URLs to get post contents.", 87 | "parameters": { 88 | "type": "object", 89 | "properties": { 90 | "urls": { 91 | "type": "array", 92 | "description": "List of URLs to get content from.", 93 | "items": { 94 | "type": "string" 95 | } 96 | }, 97 | "get_raw_content": { 98 | "type": "boolean", 99 | "description": "Default is reader-view for articles (less tokens). Set true for full raw content." 100 | } 101 | }, 102 | "required": [ 103 | "urls" 104 | ] 105 | } 106 | }, 107 | { 108 | "function_name": "get_youtube_video_transcript_full", 109 | "description": "Gets the full transcript of a YouTube video.", 110 | "parameters": { 111 | "type": "object", 112 | "properties": { 113 | "url": { 114 | "type": "string", 115 | "description": "YouTube video URL." 116 | } 117 | }, 118 | "required": [ 119 | "url" 120 | ] 121 | } 122 | } 123 | ] 124 | } 125 | -------------------------------------------------------------------------------- /Lucy/tool_definitions/web.yml: -------------------------------------------------------------------------------- 1 | Name: Web_v1-0 2 | Description: Searches web and gets webpage content. 3 | Note: open_url is not supported on Apple Watch or HomePod. 4 | Functions: 5 | - function_name: perform_searches 6 | description: Performs multiple searches across different platforms. 7 | parameters: 8 | type: object 9 | properties: 10 | searches: 11 | type: array 12 | description: Array of search operations to perform. 13 | items: 14 | type: object 15 | properties: 16 | search_tool: 17 | type: string 18 | enum: ['google_search', 'arxiv_search', 'chemrxiv_search'] 19 | description: Type of search to perform. 20 | enum_hints: 21 | google_search: Web search using Google. 22 | arxiv_search: Search arXiv for academic papers (preprints) in physics, mathematics, and computer science, quantitative biology/finance, statistics, electrical engineering, systems science, and economics. 23 | chemrxiv_search: Search ChemRxiv for academic papers (preprints) in chemistry. 24 | parameters: 25 | type: object 26 | properties: 27 | query: 28 | type: string 29 | description: Search query. 30 | start_page: 31 | type: number 32 | description: Starting page number (1-10). 33 | end_page: 34 | type: number 35 | description: Ending page number (1-10, >= start_page). 36 | required: 37 | - query 38 | - start_page 39 | - end_page 40 | required: 41 | - search_tool 42 | - parameters 43 | required: 44 | - searches 45 | - function_name: open_url 46 | description: Opens a URL in the browser. 47 | parameters: 48 | type: object 49 | properties: 50 | url: 51 | type: string 52 | description: URL to open. 53 | required: 54 | - url 55 | - function_name: get_webpage_content 56 | description: Gets raw content from a list of URLs. 57 | tip: Add .json to Reddit URLs to get post contents. 58 | parameters: 59 | type: object 60 | properties: 61 | urls: 62 | type: array 63 | description: List of URLs to get content from. 64 | items: 65 | type: string 66 | get_raw_content: 67 | type: boolean 68 | description: Default is reader-view for articles (less tokens). Set true for full raw content. 69 | required: 70 | - urls 71 | - function_name: get_youtube_video_transcript_full 72 | description: Gets the full transcript of a YouTube video. 73 | parameters: 74 | type: object 75 | properties: 76 | url: 77 | type: string 78 | description: YouTube video URL. 79 | required: 80 | - url -------------------------------------------------------------------------------- /MenuGenerator.md: -------------------------------------------------------------------------------- 1 | ![Menu Generator Banner](https://raw.githubusercontent.com/twilsonco/SiriShortcuts/main/img/menu-generator-banner.png) 2 | 3 | ![Version](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Froutinehub.co%2Fapi%2Fv1%2Fshortcuts%2F18397%2Fversions%2Flatest&query=%24.Version&label=Version&labelColor=green&color=%23320932.png) [![Download on RoutineHub](https://img.shields.io/badge/Download_On-RoutineHub-%23ee3535)](https://routinehub.co/shortcut/18397/) 4 | 5 | Easily create menus for your Shortcuts **without any external apps**. 6 | 7 | Menu Generator can be embedded or run from the `Run Shortcut` action to create stunning, feature-rich menus. 8 | 9 | Feed it the command and menu data in a dictionary or text field, then it does the rest! 10 | 11 | *** 12 | 13 | ![Menu Generator Screenshots](https://github.com/twilsonco/SiriShortcuts/blob/main/img/menu-generator-hero-image.png?raw=true) 14 | 15 | ## Menu Generator Features 16 | 17 | **Flexible Icons:** With four different types of icon choices, it should be easy to find an icon for any menu option. Supported Icons: 18 | 19 | - Base64 icons (e.g., created from photos, or bring your own). 20 | - Font Awesome icons. 21 | - Emoji icons. 22 | - Photo icons (resized to 123x123 pixels and converted to base64). 23 | 24 | **Quick menus:** Create simple menus using a single text field similar to [Toolbox Pro's](https://apps.apple.com/us/app/toolbox-pro-for-shortcuts/id1476205977) Quick Menu feature. 25 | 26 | **Advanced menus:** Define menu items individually using dictionaries for optimized menus with maximal customization, again like [Toolbox Pro](https://apps.apple.com/us/app/toolbox-pro-for-shortcuts/id1476205977). 27 | 28 | **Unlimited Custom Fields:** Include "hidden" fields to store data with menu items that is not shown in the created menu, and that can be accessed after a menu option is tapped. You can define as many custom fields as needed. 29 | 30 | **Create menus or base64 for later:** Use to create full menus or convert images to base64 for other uses. 31 | 32 | **Embeddable:** Put this shortcut inside any shortcut to add picture/icon menus without complicating installation/distribution. 33 | 34 | **Icon caching:** Icons are cached to a file in your iCloud to increase performance. 35 | 36 | ## Limited Permission Prompts 37 | 38 | ![Menu Generator Permissions Screenshots](https://raw.githubusercontent.com/twilsonco/SiriShortcuts/main/img/menu-generator-permissions.png) 39 | 40 | Because no external apps (e.g. Toolbox Pro or Actions) are used, permission prompts are limited to just: 41 | 42 | - Running another Shortcut (unless embedded within a shortcut). 43 | - Loading web content (for Font Awesome icons). 44 | 45 | ## How To Use Menu Generator 46 | 47 | Every time you run Menu Generator, you'll use an input dictionary that contains the command to run along with any necessary/optional information that goes along with the command. The commands and their inputs are listed below: 48 | 49 | ----- 50 | 51 | ### Commands 52 | 53 | - `menu` 54 | - Create vCard menu as single text string 55 | - Inputs: `"menu"`: list of valid menu item dictionaries 56 | - Output: vCard menu as a text string 57 | - `menu items` 58 | - Create list of vCard menu text strings 59 | - Inputs: `"menu"`: list of valid menu item dictionaries (described below) 60 | - Output: list of vCard items as text strings 61 | - `get menu item details` 62 | - Get a chosen menu item's dictionary using its `title` and `sub` (corresponding to `Name` and `Company` inside a `Contact` object), in order to easily access its properties. 63 | - Inputs: 64 | - `"title"` and `"sub"`: title and subtitle of menu item to get details for. 65 | - `"menu items"`: list of menu item dictionaries used to make the menu in the first place, and that will be searched to find the specified title and subtitle 66 | - Output: the found menu item matching the specified title and subtitle 67 | - `quick menu` 68 | - Create vCard menu as single text string using quick menu string 69 | - Inputs: `"menu"`: text string describing the quick menu 70 | - Output: vCard menu as a text string 71 | - `quick menu items` 72 | - Create list of vCard menu item text strings from quick menu string 73 | - Inputs: `"menu"`: text string describing the quick menu 74 | - Output: list of vCard items as text strings 75 | - `base64 overlay` 76 | - Prepare icon base64 by overlaying transparent PNG image on the specified background color 77 | - Inputs: 78 | - `"icon"`: base64 string of a png image with some transparency 79 | - `"background"`: hex string or valid HTML color name 80 | - `"size"`: text or number, relative size of image in resulting icon (0 to 1 as ratio of resulting image) 81 | - Output: base64 text string of overlaid image 82 | - `emoji icon` 83 | - Prepare icon base64 from emoji 84 | - Inputs: 85 | - `“icon”`: text, the emoji to create image from 86 | - `“size”`: optional: number, the size of the resulting image, between 0.0 and 1.0. Defaults to global shortcut default in config dictionary. 87 | - `“background”`: optional: hex color or HTML color name of background. Defaults to transparent on macOS and dark/light based on device dark mode setting on iOS. 88 | - Output: base64 text string of emoji icon 89 | - `font awesome icon` 90 | - Prepare icon base64 from specified Font Awesome icon name 91 | - HTML colors: https://www.w3schools.com/tags/ref_colornames.asp 92 | - Inputs: 93 | - `“icon”`: font awesome icon type and name, e.g. “fa-solid fa-font-awesome” 94 | - `“size”`: size of icon, from 0.0 to 1.0 95 | - `“color”`: hex color or HTML color name of icon, e.g. #1E3050 96 | - `“background”`: hex color or HTML color name of icon, e.g. #fff 97 | - Outputs: base64 text string of emoji icon 98 | 99 | ----- 100 | 101 | ![Menu Generator Menu Examples Screenshots](https://github.com/twilsonco/SiriShortcuts/blob/main/img/menu-generator-example.png?raw=true) 102 | 103 | ### Creating Advanced Menus 104 | 105 | You can use a list of menu item dictionaries to make menus, providing the most functionality and better performance than the text-based quick menus. 106 | 107 | #### Creating The List of Menu Item Dictionaries 108 | 109 | To make an advanced menu, you need to construct a list of dictionaries. Each dictionary can be created using the `Dictionary` action with the following text keys (see also the above images): 110 | 111 | 1. `title` - This will be the larger, bold text title for each menu option. 112 | 2. `sub` - This will be the smaller text below the title. 113 | 3. `icon` - Here is where you will specify either the base64 icon, emoji, or Font Awesome class name for the icon you want to use. 114 | 4. *[optional]* You can add additional fields that contain whatever information you want. These will not be printed in the created menu, and can be fetched later in order to drive more advanced behavior based on user selection. Here we use `field1` and `field2` as examples. 115 | 116 | ![Menu Generator - Menu Command Image](https://github.com/twilsonco/SiriShortcuts/blob/main/img/menu-generator-advanced-menu.png?raw=true) 117 | 118 | ##### The class name of a Font Awesome icon can be found on their website as in the image below. 119 | 120 | ![Menu Generator - Font Awesome icon class name](https://github.com/twilsonco/SiriShortcuts/blob/main/img/menu-generator-font-awesome-site.png?raw=true) 121 | 122 | #### Using The `menu` Command To Generate The Menu 123 | 124 | Once you've prepared your list of menu item dictionaries, we prepare an input dictionary for Menu Generator: 125 | 126 | 1. Make a new dictionary with a text key named `command` with the value `menu`. 127 | 2. Next, add a `Set Dictionary` action and set the value of the `menu` key to your list of menu item dictionaries (here we've named the list variable `Menu item list`). 128 | 3. Below that, use the `Run Shortcut` action to run Menu Generator, and pass the dictionary from step 1 as input. 129 | 130 | #### Tell Shortcuts That The Output Is A vCard File 131 | 132 | The output of the `Run Shortcut` action will be a single text object that contains the created menu. 133 | 134 | 1. Use a `Set Name` action to set the name of the `Shortcut Result` to `menu.vcf`. 135 | 2. Finally, add a `Choose From List` action to choose from `Renamed Item`, and make sure the type of `Renamed Item` is set to `contact`. 136 | 137 | #### Retrieving Data From The Chosen Menu Option 138 | 139 | If you added any non-printed "extra" fields to your menu (we added `field1` and `field2` in our example), you can use the `get menu item details` command to fetch that data from the user-selected item. 140 | 141 | 1. Create another dictionary with the following text keys: 142 | - `command` - With the value `get menu item details`. 143 | - `title` - With the value `Name` pulled from a magic variable of the `Renamed Item`. 144 | - `sub` - With the value `Company` also pulled from a magic variable of the `Renamed Item`. 145 | 2. Pass this dictionary as input to a `Run Shortcut` action pointing to Menu Generator. 146 | 3. The `Shortcut Result` will be the menu item dictionary corresponding to the user-selected menu item. 147 | 4. Using the returned dictionary, you can then access any of the extra fields you defined earlier. 148 | 149 | ### Create A Menu With The Quick Menu Tool 150 | 151 | ![Menu Generator Quick Menu](https://github.com/twilsonco/SiriShortcuts/blob/main/img/menu-generator-quick-menu-example.png?raw=true) 152 | 153 | If you need a quick and simple method of making menus, then you can just throw everything into a `Text` action. 154 | 155 | #### Using A Text Field To Make A Menu 156 | 157 | 1. Define your icon with base64, Font Awesome, or an emoji. 158 | 2. Enter the text for each menu item. 159 | - Use `title`, `sub`, and `icon`, followed by a colon like so: `title: Hello World!`. 160 | - Make sure there is a line separating each menu option like the screenshot above. 161 | 3. Add a `Dictionary` action under the `text` action. 162 | 4. In that `Dictionary`, add two `Text` keys with the following values: 163 | - `command` With the value `quick menu`. 164 | - `menu` With the value `Quick menu text` pulled from the magic variable of the `Text` action. 165 | 5. Now, place a `Run Shortcut` action below that and select Menu Generator. 166 | 6. Then, use a `Set Name` action to set the name of the Shortcut Result to `menu.vcf`. 167 | 7. Next, add a `Choose From List` action to choose from the `Renamed Item`, and make sure the type is set to `contact`. 168 | 169 | After that, you can then use `If` actions to perform tasks based on the option selected. 170 | 171 | - When using quick menus, you cannot define extra, non-printed fields. 172 | - The `title` and `sub` values of the selected menu item are accessed using the `Name` and `Company` values of the selected menu item (a Contact object). 173 | 174 | *** 175 | 176 | ## Example Shortcuts 177 | 178 | The below example shortcuts demonstrate all of Menu Generator's features. Some analogous shortcuts doing the same things but using Toolbox Pro's menu capabilities are also provided, in order to make clear how similar the functionality and use are. 179 | 180 | - [Menu Generator Example - Menu](https://www.icloud.com/shortcuts/5e61965f9c06486ea42940958a7f44f3) 181 | - Creates an advanced menu with Menu Generator using the different types of icons (base64, Font Awesome, and Emoji). 182 | - [Toolbox Pro Menu Generator](https://www.icloud.com/shortcuts/895d5aea0129459aa5204c312742206e) - (*Requires Toolbox Pro*) 183 | - Uses Toolbox Pro to create an advanced menu. 184 | - [Menu Generator Example - Menu Items](https://www.icloud.com/shortcuts/effd803e7aae4421b79c3026838c8f3c) 185 | - Creates an advanced menu with Menu Generator, then uses the cache to present another menu without the need to regenerate anything. 186 | - [Menu Generator Example - Quick Menu](https://www.icloud.com/shortcuts/6d01003ff5bd4e91b784bef436385b6b) 187 | - Creates a quick menu utilizing a `text` action. 188 | - [Toolbox Pro Quick Menu](https://www.icloud.com/shortcuts/3bdb5b49dfb44884afc5472b6386919f) 189 | - Uses Toolbox Pro's `Quick menu` action. 190 | - [Menu Generator Example - Photo Menu](https://www.icloud.com/shortcuts/3862685e4e5348c7be3fae3326a41960) 191 | - Pulls the last 10 photos from your Photo Library to create a menu with photos for icons. 192 | - [Menu Generator Example - Convert to base64](https://www.icloud.com/shortcuts/5222bcac2ad644c5b7c075fa788901b3) 193 | 194 | ## Embed Menu Generator inside your shortcut 195 | 196 | Use the [Join Shortcuts](https://routinehub.co/shortcut/10038/) shortcut by [gluebyte](https://routinehub.co/user/gluebyte) to embed Menu Generator inside your own shortcut. 197 | 198 | - Simplify installation and distribution of your shortcut by removing the need for the user to install Menu Generator as a separate shortcut 199 | - Simplify running of your shortcut by removing the permissions prompt to "run another shortcut" 200 | - *Join Shortcuts works best on macOS, where it can sign the resulting merged shortcut* 201 | - As an alternative, you could start your own shortcut from a duplicate of the Menu Generator shortcut 202 | - Make sure to collapse the If action in order to hide all the Menu Generator actions and simplify subsequent shortcut development 203 | - As alternatives, you could 204 | - Use the recently released [Action Editor](https://routinehub.co/shortcut/18280/), also by gluebyte, or, 205 | - Use the recently released [Copy Shortcut Actions +++](https://routinehub.co/shortcut/18369/) by [robric18](https://routinehub.co/user/robric18). 206 | - Start your own shortcut from a duplicate of the Menu Generator shortcut. Make sure to collapse the If action in order to hide all the Menu Generator actions and simplify subsequent shortcut development. 207 | 208 | **As an example, my [Gemini Chat Manager](https://routinehub.co/shortcut/17671/) shortcut has Menu Generator embedded inside it.** 209 | 210 | 1. Install Menu Generator (this Shortcut) and the [Join Shortcuts](https://routinehub.co/shortcut/10038/) Shortcut: 211 | - Join Shortcuts works by allowing you to insert one Shortcut inside another. 212 | - Each Comment action in the destination Shortcut serves as a placeholder for inserting a source Shortcut. 213 | 2. Create a Comment action near the top of your Shortcut. Inside, put something like "menu generator". 214 | 3. Run the Join Shortcuts Shortcut. 215 | 4. Select your Shortcut at the destination Shortcut. 216 | 5. Select the comment made in step 2 as the place to insert the source Shortcut. 217 | 6. Select the Menu Generator Shortcut as the source Shortcut. 218 | 7. Select "Finish Joining" and save the resulting Shortcut as a copy or by replacing your Shortcut with the joined version. 219 | 8. Change any "Run Shortcut" actions to point to your Shortcut (so that it runs itself) instead of Menu Generator, and now your Shortcut has built-in pretty menus! 220 | 221 | ## Credits 222 | 223 | - [jpasholk’s “vCard Menu Helper”](https://routinehub.co/shortcut/18220) (Inspiration for this shortcut, though other great vCard menu shortcuts also exist). 224 | - [DylanShortcuts’ “Emoji to Image”](https://routinehub.co/shortcut/14899) adapted to turn an emoji into an image. 225 | - [SACUL_6’s “Create Menu Using Font Awesome”](https://routinehub.co/shortcut/17750) adapted for Font Awesome icon fetching. 226 | - [gluebyte's Join Shortcuts]((https://routinehub.co/shortcut/10038/)) shortcut was used in the development of this shortcut. 227 | - Though unrelated, see also [gluebyte's SF Emoji Menu Builder](https://routinehub.co/shortcut/8841/) shortcut if you're looking for making pretty menus using SF icons. 228 | - [Toolbox Pro for Shortcuts](https://apps.apple.com/us/app/toolbox-pro-for-shortcuts/id1476205977) (Inspiration for the structure of Quick Menu feature and of menu items when a dictionary is used as input). 229 | - jpasholk wrote this description, and was pivotal in the preliminary design of this shortcut. 230 | 231 | ## Attribution 232 | 233 | If you use Menu Generator in any of your Shortcuts, please place a comment with the below text at or near the top of your Shortcut: 234 | 235 | > Menus created by Menu Generator by @twilsonco. 236 | 237 | If you publish your Shortcut to RoutineHub or any other Shortcuts sharing platform, please use this badge: 238 | 239 | ![Menu Generator Badge](https://github.com/twilsonco/SiriShortcuts/blob/main/img/made-with-menu-generator-badge.png?raw=true) 240 | 241 | ### You Can Copy This Markdown To Make It Easier 242 | 243 | ```![Menu Generator by @twilsonco](https://github.com/twilsonco/SiriShortcuts/blob/main/img/made-with-menu-generator-badge.png?raw=true)``` 244 | 245 | > Markdown for GitHub & RoutineHub created with ♥ by [jpasholk](https://routinehub.co/user/jpasholk). 246 | 247 | *** 248 | 249 | Thanks for stopping by, and if you have any questions don’t hesitate to reach out! 250 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SiriShortcuts 2 | 3 | ## 1. ChatGPT 4 | 5 | ### A. [I have a question](https://www.icloud.com/shortcuts/e01b052c382d44e09631dd5ba4a22e2d) 🔗 6 | 7 | * Starts a voice-only conversation with ChatGPT using the ChatGPT iOS/iPadOS app (does not work on macOS) 8 | * Using the ChatGPT app has the following advantages 9 | * A paid ChatGPT Plus account is optional, but you'll need at least a free ChatGPT account 10 | * If you do have a ChatGPT Plus subscription, you can optionally use GPT4 as the model 11 | * ChatGPT will remember previous messages as you continue your conversation 12 | * You can specify initial and followup system prompts in order to better control ChatGPT's behavior (as well as setup "custom instructions" in the ChatGPT app) 13 | * When run from lock screen, dictation of your prompt to ChatGPT will end automatically when a pause is detected 14 | * When run while unlocked, dictation will continue until you press the stop button ⏹️ 15 | * Shortcut can be modified to use OpenAI or ElevenLabs TTS by replacing the "Speak Text" action with "Run Shortcut" pointing to (2A) or (2B) below 16 | 17 | #### Known issues 18 | 19 | * The Shortcut may complain that you are not logged into the ChatGPT app, even though you are 20 | * The workaround is to simply rerun the Shortcut, which will work on subsequent runs 21 | * Every Shortcut using the ChatGPT app may have this same issue 22 | * Please let me know if you find a reliable solution for this; I've tried including a very short use of the "Ask ChatGPT" action so that its later use will always succeed, but any failure of the action causes the Shortcut to fail, so this approach doesn't work 23 | 24 | ### B. [I want to have a conversation](https://www.icloud.com/shortcuts/bd154f690837417cb81ede56f71448dc) 🔗 25 | 26 | * Similar to (1), but unlocks phone first in order to avoid some issues that happen on the lock screen (does not work on macOS) 27 | * Uses OpenAI TTS to read back response in a more natural voice (needs "Speak text with OpenAI" (2A) shortcut installed) 28 | * Can modify shortcut to use ElevenLabs TTS for reading back response if desired, or to use iOS built-in TTS 29 | 30 | ### C. [Weather summary](https://www.icloud.com/shortcuts/d844ac557277490cb8cf3d17abda5c8d) 🔗 31 | 32 | * Fetches weather data for your current location and have ChatGPT read back a natural language summary of the upcoming weather 33 | * Uses the ChatGPT app like (1), so does not work on macOS 34 | 35 | ### D. [Today's agenda and weather](https://www.icloud.com/shortcuts/37e039275d6f48cfa13d3acac46640b4) 🔗 36 | 37 | * [Same but for weekly agenda](https://www.icloud.com/shortcuts/76e8d60616164b779ae70ebafbcfea2e) 🔗 38 | * Define a list of iOS calendars and reminder lists which are used to fetch your scheduled events for the day, and have ChatGPT read back a summary of your agenda along with the weather 39 | * Uses the ChatGPT app like (1), so does not work on macOS 40 | 41 | ### E. [ChatGPT via API](https://www.icloud.com/shortcuts/236b0e751bbb4305b3303778a35eeabf) 🔗 42 | 43 | ([And voice-only version](https://www.icloud.com/shortcuts/7195e7369c3348fcb4995be71f3e2128)) 44 | 45 | * Drop-in replacement for the ChatGPT app's "Ask ChatGPT" Shortcut action 46 | * Provide text or a valid dictionary as input and use the OpenAI API to submit the text to ChatGPT as a prompt 47 | * Valid input dictionary contains optional keys “prompt”, “model”, “temperature”, and “apikey” 48 | * If run with no input, the Shortcut will ask for text input 49 | * Requires your own [OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key) 🔗 50 | * Includes back and forth conversation capability 51 | 52 | ### F. [Create calendar events](https://routinehub.co/shortcut/17514/) 🔗 53 | 54 | * Takes text (or an image/screenshot containing text), e.g. from an email client or Messages and uses ChatGPT to suggest one or more calendar events from the text content 55 | * You can choose which identified events will be added, and edit details beforehand if necessary 56 | * Messages and email clients suck at suggesting events; they're always incomplete and unhelpful and require additional user input. This lets ChatGPT improve the process by parsing out the necessary information automatically 57 | * Automatically populates 58 | * an appropriate event title 59 | * start/end time and all day status 60 | * location 61 | * url 62 | * an appropriate calendar 63 | * attendee list 64 | * notes with references to relevant part(s) of the text used for creating the event 65 | 66 | ### G. [Add work shifts to calendar](https://www.icloud.com/shortcuts/543ac4dc519e4bf0979cc2e93138f8ba) 🔗 67 | 68 | * Does your work send you your upcoming schedule in a text or email? (Those jerks...) 69 | * This shortcut will take that message and create calendar events with them automatically 70 | * Can be setup to run as an automation to be triggered by a text message/email, assuming the sending phone number or email address is consistent 71 | * If the message/email is an amended schedule, this will check for conflicts with previously created shifts and delete the old ones 72 | * Uses the "ChatGPT via API" shortcut (see E above) to make it more reliable, since it's meant to be run automatically. You can modify it easily to use the ChatGPT app instead. 73 | 74 | ## 2. Google Gemini Pro 75 | 76 | ### A. [Gemini via API](https://routinehub.co/shortcut/17624/) 🔗 77 | 78 | * Drop-in replacement for the "Ask ChatGPT" shortcut action, or 79 | * Runs standalone for voice/text/image/pdf/document/url/video-based Gemini requests 80 | * Logs conversations/images to Files App at `/Shortcuts/GeminiAPI` 81 | * Beautiful rich text display of Gemini response with ability to show entire conversation 82 | * [View/continue Gemini conversation with this companion shortcut](https://routinehub.co/shortcut/17671/) 🔗 83 | * Currently, Gemini-Pro API access is FREE for up to 15 queries per minute with 1.5-flash, or 2 per minute with 1.5-pro. 84 | 85 | ![Screenshots of the View/continue Gemini conversation companion shortcut](https://github.com/twilsonco/SiriShortcuts/blob/main/img/gemini_viewer_iOS.png?raw=true) 86 | 87 | ``` 88 | This shortcut is design to be run standalone or from other Shortcuts. It passes the input prompt to Google via their API and returns the response if successful. 89 | 90 | Input: Text (a prompt, possibly via Share Sheet), 91 | OR 92 | a valid Dictionary with optional keys, 93 | “prompt”, “messages”, “image”, “model”, “temperature”, “apikey”, “repeat”, “speak”, "datetime", and "disablelogging" 94 | OR 95 | nothing. If no prompt is provided, user will be asked to provide one before continuing. 96 | 97 | Output: A text string containing the bot response, OR an output dictionary containing “messages” and “output”. 98 | 99 | Setup: Can set default model, API key and temperature. 100 | ``` 101 | ``` 102 | Dictionary input arguments: 103 | “model” a valid model name to use. 104 | “temperature” a number between 0 and 105 | “messages” a JSON array passed as the “contents” to the API. You don’t have to build it manually, since it’spart of the output. Just maintain it between calls to the shortcut. (see https://ai.google.dev/tutorials/rest_quickstart#multi-turn_conversations_chat). 106 | “image” is a text string that is a base64-encoded image. 107 | “repeat” is 0 or 1 to control if this shortcut repeats automatically (ongoing conversation). 1 to repeat. 108 | “speak” is 0 or 1 to control if output is read aloud. 1 to speak. 109 | 110 | https://ai.google.dev/docs/concepts#model_parameters 111 | https://ai.google.dev/tutorials/rest_quickstart#configuration 112 | 113 | Dictionary output content: 114 | When a dictionary is used as input, this shortcut will output a dictionary with “output” string and “messages” JSON array that can be passed back into the shortcut. 115 | ``` 116 | 117 | ### B. [What is this?](https://routinehub.co/shortcut/17670/) 🔗 118 | 119 | * A simple example of a shortcut utilizing the “Gemini via API” shortcut. 120 | * This takes a picture and has gemini describe it. This is intended to be used via Siri or through a widget. 121 | 122 | ### C. [I have a question](https://routinehub.co/shortcut/17672/) 🔗 123 | 124 | * This shortcut allows you to have a voice-only, back-and-forth conversation with Google Gemini Pro, using the “Gemini via API” shortcut. 125 | * You can also pass this shortcut an image/photo via the share sheet and the image will be included with every request so you can query the same image repeatedly. (No previous messages are retained when an image is used, due to Google API constraints) 126 | 127 | ### D. [Weather summary](https://routinehub.co/shortcut/17674/) 🔗 128 | 129 | * Fetches weather data for your current location and have Gemini read back a natural language summary of the upcoming weather 130 | * Uses "Gemini via API" 131 | 132 | ### E. [Today's agenda and weather](https://routinehub.co/shortcut/17673/) 🔗 133 | 134 | * [Same but for weekly agenda](https://routinehub.co/shortcut/17675/) 🔗 135 | * Define a list of iOS calendars and reminder lists which are used to fetch your scheduled events for the day, and have Gemini read back a summary of your agenda along with the weather 136 | * Uses "Gemini via API" 137 | 138 | ## 3. AI Text-to-speech (TTS) 139 | 140 | ### A. [Speak text with OpenAI](https://www.icloud.com/shortcuts/c36c82b460af49faa84c7d35f361d7cc) 🔗 141 | 142 | * Drop-in replacement for the "Speak Text" Shortcut action using OpenAI's TTS voices to speak the text 143 | * Falls back to using the "Speak Text" action if it fails 144 | * Requires your own [OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key) 🔗 145 | * This shortcut was adapted from the [“Dispatch” shortcut by Nicololo Diamante](https://github.com/nicolodiamante/dispatch) 🔗 146 | 147 | ### B. [Speak text with ElevenLabs](https://www.icloud.com/shortcuts/74454f56a2f94deda842a29b438dfaa2) 🔗 148 | 149 | * Drop-in replacement for the "Speak Text" Shortcut action using ElevenLabs's TTS voices to speak the text 150 | * Falls back to using the "Speak Text" action if it fails 151 | * Requires your own [ElevenLabs API key](https://elevenlabs.io/docs/api-reference/authentication#) 🔗 152 | * This shortcut was adapted from the [“Dispatch” shortcut by Nicololo Diamante](https://github.com/nicolodiamante/dispatch) 🔗 153 | 154 | ## 4. OpenPilot navigation shortcuts 155 | 156 | * OpenPilot is an after-market level-II autonomous driving product by [Comma.ai](https://comma.ai) 🔗 157 | * It can now perform nearly full navigation from origin to destination, stopping for lights/signs, and performing turns completely unassisted 158 | * These Shortcuts simplify the process of setting a navigation destination 159 | * See the [separate repository for the Shortcuts here](https://github.com/twilsonco/OpenPilotSiriShortcuts) 🔗 160 | 161 | ## 5. Mobile Safari 162 | 163 | ### A. Open in Chrome 🔗 164 | 165 | * Use the [share sheet](https://www.idownloadblog.com/2020/04/21/customize-share-sheet-iphone-ipad/) 🔗 in Safari on iOS/iPadOS to open the current website in the Google Chrome app 166 | 167 | ## 6. macOS Shortcuts 168 | 169 | ### A. Activate/deactivate head pointer 170 | 171 | * Two Shortcuts to activate or deactivate the [head pointer feature of macOS](https://support.apple.com/en-gb/guide/mac-help/mchlb2d4782b/mac#:~:text=Turn%20on%20and%20customize%20head%20pointer&text=Go%20to%20Motor%20on%20the%20right%2C%20then%20click%20Pointer%20Control.&text=Turn%20on%20“Head%20pointer.”,and%20which%20camera%20to%20use.) 🔗 that lets you move/click the mouse using the direction of your head and facial gestures 172 | * First, visit the head pointer settings to configure them to your liking 173 | * Install links: 174 | * [Activate head pointer](https://www.icloud.com/shortcuts/adb89eacf53c4ecb957650e8d93df1a3) 🔗 175 | * [Deactivate head pointer](https://www.icloud.com/shortcuts/8ea48a269ac84d02b6cbed5989ce1d3c) 🔗 176 | 177 | ### B. Restart/shutdown Mac 178 | 179 | * With MacBooks with Touch ID, or when using the Magic Keyboard with Touch ID, the classic keyboard shortcuts to sleep/restart/shutdown a Mac or turn off the display no longer work 180 | * These two Shortcuts at least provide the ability to perform a restart or shutdown, per [my answer on Apple Stack Exchange](https://apple.stackexchange.com/a/464996/85762) 🔗 181 | * After installing, you'll need to setup keyboard shortcuts to trigger the shortcuts 182 | * Install links: 183 | * [Restart Mac](https://www.icloud.com/shortcuts/92d8a4d8a11c4f21869e8a37180e8132) 🔗 184 | * [Shutdown Mac](https://www.icloud.com/shortcuts/714cbb1e3ff642be86a356315955adcc) 🔗 185 | 186 | ## 7. Other 187 | 188 | ### A. [Reminders to PDF](https://routinehub.co/shortcut/17512/) 🔗 189 | 190 | * You specify one or more Reminders lists along with number of past/future days to include, and when run, the shortcut produces a nicely formatted PDF that contains all reminders in the specified lists, one PDF per list 191 | * Shows most pertinent reminder data *if present*: title, name (if different from title), notes, completed, priority, flagged, tags, location (macOS only due to a bug in iOS), URL, images, and subtasks 192 | * Works with repeat reminders, showing next due instance of the repeat reminder and the count of completed instances 193 | * Here's what the resulting PDF looks like 194 | 195 | ![](img/ReminderPDF.png) 196 | 197 | ### B. [Photo collage](https://routinehub.co/shortcut/17870/) 198 | 199 | * Makes beautiful photo collages from the specified photos on iOS/iPadOS/macOS 200 | * This is a vanilla shortcut with the same functionality as (and that runs 10X slower than) my [PyPhotoCollage](https://github.com/twilsonco/PyPhotoCollage) prgrogram 201 | 202 | ### C. [Photo mosaic](https://routinehub.co/shortcut/18978/) 203 | 204 | * Create beautiful photo mosaics from photos/videos on iOS/iPadOS/macOS 205 | * Advanced, multi-point tile matching for highest quality mosaid 206 | * Control over repeated mosaic tiles to reduce overuse of same tile 207 | 208 | ### D. [Multi-stop navigation](https://routinehub.co/shortcut/18833/) 209 | 210 | * Optimize multi-stop routes by solving the travelling salesman problem 211 | * Optimize by travel time or distance 212 | * Supports driving/biking/walking/transit navigation 213 | * Supports Apple Maps, Google Maps, and Waze 214 | -------------------------------------------------------------------------------- /dup.md: -------------------------------------------------------------------------------- 1 | 2 | ![banner](https://github.com/twilsonco/SiriShortcuts/blob/main/img/dup_1banner.png?raw=true) 3 | 4 | This shortcut uses [perceptual hashing](https://benhoyt.com/writings/duplicate-image-detection/) to quickly find duplicate or similar images in Photos or in Finder on a Mac. 5 | 6 | Then it guides you through the cleanup process to remove duplicates, or organizes them into albums or folders so that you can review and delete duplicates easily. 7 | 8 | ![2](https://github.com/twilsonco/SiriShortcuts/blob/main/img/dup_2selection.png?raw=true) 9 | 10 | ![2](https://github.com/twilsonco/SiriShortcuts/blob/main/img/dup_3search.png?raw=true) 11 | 12 | ![2](https://github.com/twilsonco/SiriShortcuts/blob/main/img/dup_4clean.png?raw=true) 13 | 14 | ![2](https://github.com/twilsonco/SiriShortcuts/blob/main/img/dup_5config.png?raw=true) -------------------------------------------------------------------------------- /img/IMG_1034.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/IMG_1034.png -------------------------------------------------------------------------------- /img/MediaKitCred.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/MediaKitCred.PNG -------------------------------------------------------------------------------- /img/Mosaic_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_banner.png -------------------------------------------------------------------------------- /img/Mosaic_color space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_color space.png -------------------------------------------------------------------------------- /img/Mosaic_examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_examples.png -------------------------------------------------------------------------------- /img/Mosaic_grid size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_grid size.png -------------------------------------------------------------------------------- /img/Mosaic_long and tall images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_long and tall images.png -------------------------------------------------------------------------------- /img/Mosaic_progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_progress.png -------------------------------------------------------------------------------- /img/Mosaic_tile matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_tile matching.png -------------------------------------------------------------------------------- /img/Mosaic_tile subdivision.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_tile subdivision.png -------------------------------------------------------------------------------- /img/Mosaic_tile useage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/Mosaic_tile useage.png -------------------------------------------------------------------------------- /img/ReminderPDF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/ReminderPDF.png -------------------------------------------------------------------------------- /img/TSP_features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/TSP_features.png -------------------------------------------------------------------------------- /img/TSP_permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/TSP_permissions.png -------------------------------------------------------------------------------- /img/TSP_routing_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/TSP_routing_map.png -------------------------------------------------------------------------------- /img/TSP_share sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/TSP_share sheet.png -------------------------------------------------------------------------------- /img/ThinkBuddy chat viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/ThinkBuddy chat viewer.png -------------------------------------------------------------------------------- /img/auto unsub automation1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub automation1.png -------------------------------------------------------------------------------- /img/auto unsub automation2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub automation2.png -------------------------------------------------------------------------------- /img/auto unsub logged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub logged.png -------------------------------------------------------------------------------- /img/auto unsub method1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub method1.png -------------------------------------------------------------------------------- /img/auto unsub method2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub method2.png -------------------------------------------------------------------------------- /img/auto unsub test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/auto unsub test.png -------------------------------------------------------------------------------- /img/dup_1banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_1banner.png -------------------------------------------------------------------------------- /img/dup_2selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_2selection.png -------------------------------------------------------------------------------- /img/dup_3search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_3search.png -------------------------------------------------------------------------------- /img/dup_4clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_4clean.png -------------------------------------------------------------------------------- /img/dup_5config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_5config.png -------------------------------------------------------------------------------- /img/dup_collage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/dup_collage.png -------------------------------------------------------------------------------- /img/gemini_dropin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_dropin.png -------------------------------------------------------------------------------- /img/gemini_file_types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_file_types.png -------------------------------------------------------------------------------- /img/gemini_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_image.png -------------------------------------------------------------------------------- /img/gemini_pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_pdf.png -------------------------------------------------------------------------------- /img/gemini_tests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_tests.png -------------------------------------------------------------------------------- /img/gemini_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_text.png -------------------------------------------------------------------------------- /img/gemini_viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_viewer.png -------------------------------------------------------------------------------- /img/gemini_viewer_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_viewer_iOS.png -------------------------------------------------------------------------------- /img/gemini_viewer_macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/gemini_viewer_macOS.png -------------------------------------------------------------------------------- /img/made-with-menu-generator-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/made-with-menu-generator-badge.png -------------------------------------------------------------------------------- /img/menu-generator-advanced-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-advanced-menu.png -------------------------------------------------------------------------------- /img/menu-generator-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-banner.png -------------------------------------------------------------------------------- /img/menu-generator-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-example.png -------------------------------------------------------------------------------- /img/menu-generator-font-awesome-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-font-awesome-site.png -------------------------------------------------------------------------------- /img/menu-generator-hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-hero-image.png -------------------------------------------------------------------------------- /img/menu-generator-permissions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-permissions.png -------------------------------------------------------------------------------- /img/menu-generator-quick-menu-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/menu-generator-quick-menu-example.png -------------------------------------------------------------------------------- /img/out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/out.gif -------------------------------------------------------------------------------- /img/photo_collage_video_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/photo_collage_video_thumb.png -------------------------------------------------------------------------------- /img/powered by gemini via api.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/powered by gemini via api.PNG -------------------------------------------------------------------------------- /img/powered_by_pro_ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/powered_by_pro_ai.png -------------------------------------------------------------------------------- /img/social_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/social_banner.png -------------------------------------------------------------------------------- /img/view-continue-gemini-convo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twilsonco/SiriShortcuts/105eed5c578aeefeefbecc88c3837a7aa97b9bc4/img/view-continue-gemini-convo.png -------------------------------------------------------------------------------- /mosaic_readme.md: -------------------------------------------------------------------------------- 1 | ![banner](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_banner.png?raw=true) 2 | 3 | A photo mosaic is a picture made out of smaller pictures. This shortcut creates a photo mosaic from a subject image and a library of smaller images. The subject image is divided into a grid of tiles, and each tile is replaced with a smaller image from the library that best matches the original tile. The result is a mosaic that looks like the subject image from a distance, but is made up of smaller images up close. 4 | 5 | # Notes/Limitations 6 | 7 | - 100% vanilla shortcut, utilizing built-in JavaScript support to perform advanced mosaic tile color matching 8 | - If the shortcut crashes ("There was a problem running Photo mosaic"), try preprocessing mosaic tiles (step 2) to lower image size 9 | - I won't tell you _how_ to use this tool, but if you want my opinion, a good mosaic requires more than just a large tile library and a subject image. The subject image should have a good balance of colors and contrast, and should be a "good" image/photo; ideally something meaningful. Then the tile library should be able to reproduce the colors and contract of the subject image, but should also contextually match the subject image. For example, a mosaic of the moon made from images from NASA's Apollo missions, or from other space images. [Here's a blog post on what makes a good mosaic.](https://intellithoughts.wordpress.com/2011/03/08/photo-mosaic-tips/) 10 | 11 | # Instructions 12 | 13 | 1. Collect a dozen or more images to use as a mosaic tile library. It takes hundreds of unique tiles to create a nice-looking mosaic, but you can get by with just a dozen or so thanks to the optional tile subdivision feature in step 2. You can store these in a photo album in the Photos app or optionally, for macOS users, in a folder on your computer. 14 | 2. Preprocess mosaic tiles. This step converts the images you collected in step 1 into smaller, square tiles. If your tile library is very small (fewer than 70-100 tiles), consider using the "stacked" subdivision option to create more unique tiles from the library you've prepared. When you're done, the preprocessed tiles will be saved to a new photo album or optionally, for macOS users, to a folder on your computer. 15 | 3. Specify subject image, mosaic grid size, tile-matching color space, and **_one or more tile libraries_**. The subject image is the image you want to convert into a mosaic. The mosaic grid size is the number of tiles that will be used to represent the subject image. The tile-matching color space is the color space used to compare the colors of the subject image and the tiles in the library. The tile library is the photo album or folder containing the preprocessed tiles from step 2. 16 | 4. That's it! The mosaic will be created, and you'll be prompted to view/save the result. 17 | 18 | # Credits 19 | 20 | - Used @atnbueno's [Autocrop Screenshot Stitcher](https://routinehub.co/shortcut/17347/) as inspiration for being able to perform pixel-level image analysis in JavaScript in a shortcut. 21 | 22 | # Features 23 | 24 | - **_Preprocess tile library_** from full size images to smaller, square tiles. This step isn't strictly necessary, but is strongly recommended to improve output quality and performance. You may also experience crashes due to memory limitations if you don't preprocess tiles. 25 | 26 | ![grid size](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_grid%20size.png?raw=true) 27 | 28 | - The mosaic **_grid size_** can be adjusted to create a more detailed or more abstract mosaic. 29 | 30 | ![tile subdivision](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_tile%20subdivision.png?raw=true) 31 | 32 | - **_Subdivide tiles_** to create more unique tiles from a small tile library. This is "cheating" but who will know? As the image below shows, using subdivision improves the quality of the mosaic, even when the same mosaic grid is used. In the image below, a tile library of only 16 images was used, but the quality of the mosaic after maximum subdivision still looks good. Of course, it's better to have a larger tile library of truly unique tiles, but this feature can help you get by with fewer tiles. 33 | 34 | ![long and tall tile images](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_long%20and%20tall%20images.png?raw=true) 35 | 36 | - **_Handling of long/tall images_**. When preprocessing the tile library, the shortcut will make the most of long/tall images by creating multiple tiles from them. This is performed regardless of subdivision setting. The result is one square tile centered on the long/tall image, and additional tiles starting from the left/top of the image. 37 | - When a long/tall image is subdivided, the subregions are also long/tall. Those are also subdivided in this way so that no part of the original image goes to waste. 38 | 39 | ![multi-point tile matching](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_tile%20matching.png?raw=true) 40 | 41 | - **_Multi-point tile matching_**. Rather than simply finding the tile whose average color best matches that of the each mosaic tile, the shortcut uses a more sophisticated, optimized, algorithm to compare multiple points in each library tile to find the best match. 42 | 43 | ![color spaces](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_color%20space.png?raw=true) 44 | 45 | - The **_tile-matching color space_** can be chosen from four options 46 | - [(CIE)LAB](https://www.datacolor.com/business-solutions/blog/what-is-cielab): A color space that approximates human vision 47 | - [HSV](https://www.lifewire.com/what-is-hsv-in-design-1078068): A color space that separates color into hue, saturation, and value, which can be useful for matching colors that are similar but have different brightness 48 | - RGB: The standard color space used in digital images 49 | - [RGB+](https://www.compuphase.com/cmetric.htm): RGB enhanced with a gamma correction to make it more perceptually uniform 50 | 51 | ![progress indication with remaining time and mosaic preview](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_progress.png?raw=true) 52 | 53 | - **_Progress indication_**. The shortcut will show you progress notifications as it performs long tasks. When creating the mosaic, the progress notifications will also show a preview of the mosaic so you can see how it's coming along. 54 | 55 | ![tile usage](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_tile%20useage.png?raw=true) 56 | 57 | - **_Visualize tile usage in the mosaic_**. After a mosaic has been created, you can save/view the results, as well as generate a visualization of the tile usage in the mosaic. This visualization shows the tiles used in the mosaic, and how many times each tile was used. This can be useful for identifying tiles that are overused. When a tile is overused, you can add similar unique images to the tile library to give the shortcut perhaps more options to choose from. 58 | - **_Additional expert options_**: Open the shortcut to find the configuration dictionary at the top. Here you can modify default values, and access some additional options that are not exposed in the shortcut's main interface. 59 | - **_Debug logging_**: If you're having trouble with the shortcut, you can enable debug logging in the configuration dictionary to get more information about where the problem occurs. This is especially helpful if you want to ask for support using the shortcut. 60 | 61 | ## Example log output 62 | 63 | ```log 64 | 2024-06-23 16:26:10 Starting on Mac (macOS 14.5) 65 | 2024-06-23 16:26:13 Mac user selecting subject image... 66 | 2024-06-23 16:26:25 User running image with output mosaic size = 5000 and grid size = 30, comparing in the LAB color space. User now selecting mosaic tile image album(s)... 67 | 2024-06-23 16:26:33 Precomputing image colors for 225 tiles in 3 batches. Resizing to thumbnails of size 49 and then using a 7x7 sampling grid. 68 | 2024-06-23 16:26:33 Processing batch 1 of 3... 69 | 2024-06-23 16:26:35 Processing batch 2 of 3... 70 | 2024-06-23 16:26:37 Processing batch 3 of 3... 71 | 2024-06-23 16:26:38 Finished precomputing color grids for tiles. Now running JS routine to segment subject image and match with tiles. Precomputed average color grid: [[[79,-3,3],[51,-14,9],[36,-20,13],[37,-21,14],[36,-19,12],[35,-20,12],[36,-19,1...[17,-17,19],[19,-15,12],[24,-16,11],[35,-16,8],[39,-17,7],[38,-18,7],[37,-17,6]]] 72 | 2024-06-23 16:26:41 JS routine finished. Now assembling mosaic. Normalized mean distance: 0.149425610026727. Solution dictionary: {"24,1":170,"1,27":26,"26,14":135,"15,10":87,"26,22":112,"3,36":26,"24,2":170,"2...:182,"13,39":35,"26,13":115,"10,9":108,"26,21":23,"3,34":26,"1,26":182,"3,35":26} 73 | 2024-06-23 16:26:41 Processing row 1 of 30... 74 | ... 75 | 2024-06-23 16:26:54 Processing row 21 of 30... 76 | 2024-06-23 16:26:55 Sending progress notification... 77 | 2024-06-23 16:26:55 Processing row 22 of 30... 78 | ... 79 | 2024-06-23 16:27:01 Processing row 30 of 30... 80 | 2024-06-23 16:27:01 Finished combining rows. 81 | Now combining rows into final image. 82 | Cache usage was 95.4%. 83 | Used 55 unique tiles out of 225. 84 | Making a 40x30 = 1200 tile mosaic of size 5000x3750. 85 | Comparing by LAB color. 86 | 2024-06-23 16:27:02 Finished with mosaic. Preparing comparison image and prompting user. 87 | Timing: 88 | 5s to process tile library 89 | 45 tiles per second 90 | 1s to compute best matches for mosaic 91 | 270000 tile checks per second 92 | 22s to construct mosaic 93 | 54.5 mosaic tiles per second 94 | 2024-06-23 16:27:10 User quit. 95 | ``` 96 | 97 | # Examples 98 | 99 | ![examples](https://github.com/twilsonco/SiriShortcuts/blob/main/img/Mosaic_examples.png?raw=true) 100 | 101 | # Want an app instead? 102 | 103 | | Name | Price | 104 | | ----- | ----- | 105 | | [Photo Mosaica](https://apps.apple.com/us/app/photo-mosaica/id437992891) | $0.99 to unlock deluxe features | 106 | | [Pro Photo Mosaic Creator](https://apps.apple.com/us/app/pro-photo-mosaic-creator/id1219025715) | Free | 107 | | [mosaicPro: Photo Mosaic App](https://apps.apple.com/us/app/mosaicpro-photo-mosaic-app/id1616212938) | $9.99 to unlock full app | -------------------------------------------------------------------------------- /yml_to_json.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Exit immediately if any command fails, making the script safer. 4 | set -e 5 | 6 | # --- Prerequisites Check --- 7 | # Check if yq is installed. 8 | if ! command -v yq &> /dev/null; then 9 | echo "Error: yq is not installed." 10 | echo "Please install it with Homebrew: brew install yq" 11 | exit 1 12 | fi 13 | 14 | # Check if jj is installed. 15 | if ! command -v jj &> /dev/null; then 16 | echo "Error: jj is not installed." 17 | echo "Please install it with Homebrew: brew install jj" 18 | echo "Alternatively, you can use 'jq' (see script comments)." 19 | exit 1 20 | fi 21 | 22 | # --- Main Logic --- 23 | echo "Searching for .yml and .yaml files in the current directory..." 24 | 25 | # This prevents the loop from running if no files match 26 | shopt -s nullglob 27 | 28 | # Loop through all files ending in .yml or .yaml 29 | for file in *.yml *.yaml; do 30 | # Determine the base name (without extension) and the target .json filename 31 | base_name="${file%.*}" 32 | json_file="${base_name}.json" 33 | 34 | echo "Processing '$file' -> '$json_file'..." 35 | 36 | # Step 1: Convert YAML to JSON using yq. 37 | # The '.' means "output the whole file". -o=json specifies json output. 38 | yq -o=json "$file" > "$json_file" 39 | 40 | # Step 2: Minify the JSON file using jj. 41 | # This uses a temporary file to safely overwrite the original. 42 | # If you prefer to use jq, replace this line with the alternative below. 43 | # jj -u < "$json_file" > "${json_file}.tmp" && mv "${json_file}.tmp" "$json_file" 44 | 45 | # --- Alternative using jq (a more common tool) --- 46 | # If you prefer to use jq, install it (`brew install jq`) and use this line instead: 47 | # jq -c . "$json_file" > "${json_file}.tmp" && mv "${json_file}.tmp" "$json_file" 48 | 49 | done 50 | 51 | echo "Conversion complete." --------------------------------------------------------------------------------