Thanks for the dev and walkthrough it’s really great.
I have made a few change:
- Use of a file instead of a input text because the maximum length of 255 was too limiting.
- Adding category to each item and coloring the text of the item depending on the category (the category assignement by Chatgpt is far from perfect need proper prompt engineering.
- Making each item clickable in order to check it off when you completed the purchase of the item.
Here are the different code:
Node Red
[{"id":"a05564b7cf7ef451","type":"inject","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"0 7-21 * * *","once":false,"onceDelay":"10","topic":"","payload":"","payloadType":"date","x":630,"y":1860,"wires":[["804b50e3d1730656"]]},{"id":"369bb2070d279d0f","type":"alexa-remote-event","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","account":"7e07d994aaa8568c","event":"ws-device-activity","x":250,"y":1900,"wires":[["8f6552836a7b1a0d","f9ad5951b230d8b9"]]},{"id":"8f6552836a7b1a0d","type":"switch","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"Success?","property":"payload.data.utteranceType","propertyType":"msg","rules":[{"t":"eq","v":"GENERAL","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":440,"y":1900,"wires":[["4e529c4e3e2ec9d6"]]},{"id":"4e529c4e3e2ec9d6","type":"switch","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"Shopping list?","property":"payload.description.summary","propertyType":"msg","rules":[{"t":"cont","v":"achats","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":620,"y":1900,"wires":[["804b50e3d1730656"]]},{"id":"804b50e3d1730656","type":"alexa-remote-list","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","account":"7e07d994aaa8568c","config":{"option":"getListItems","value":{"list":{"type":"str","value":"YW16bjEuYWNjb3VudC5BR0g0MkY1MkgzQVhWVVBGR0ZTQk8zSEFRQjJRLVNIT1BQSU5HX0lURU0="}}},"x":820,"y":1900,"wires":[["97a28f2f7a335291","b3326780c90e8168"]]},{"id":"97a28f2f7a335291","type":"debug","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"debug 5","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":820,"y":1860,"wires":[]},{"id":"9ab9efc95be86e20","type":"ha-button","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"Update Shopping List","version":0,"debugenabled":false,"outputs":1,"entityConfig":"493ff69ce7a88be3","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"x":460,"y":1940,"wires":[["c5d2b0b8e68369ac"]]},{"id":"b3326780c90e8168","type":"function","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"function 1","func":"// Extract the array from the input payload\nlet items = msg.payload;\n\n// Map through the items to process the value based on the \"completed\" field\nlet values = items.map(item => {\n // Check if the item is completed, and prepend \"!\" if true\n return item.completed ? '!' + item.value : item.value;\n});\n\n// Concatenate the values into a single string\nlet concatenatedValues = values.join(',');\n\n// Set the concatenated string as the new payload\nmsg.payload = {\n model: 'gpt-4o-mini',\n messages: [\n {\n content: 'Voici une liste d articles d une liste de courses. Les 10 catégories suivantes sont définies pour minimiser le chevauchement : 1) Fruits et légumes frais (tous les fruits et légumes frais). 2) Viandes, poissons et fruits de mer (toutes les viandes, poissons, fruits de mer). 3) Produits laitiers et œufs (lait, yaourt, fromage, beurre, œufs). 4) Boulangerie et pâtisserie (pain, viennoiseries, gâteaux, pâtisseries). 5) Épicerie salée (pâtes, riz, conserves salées, sauces, épices, huiles, condiments). 6) Épicerie sucrée (biscuits, confitures, chocolat, sucre, miel, céréales sucrées, desserts). 7) Boissons (eau, jus, soda, café, thé, alcool). 8) Produits d hygiène et de beauté(shampoing, savon, dentifrice, maquillage, produits de soin). 9) Produits d entretien et de nettoyage (lessive, produit vaisselle, nettoyants, désinfectants, éponges). 10) Articles pour la maison et divers (ustensiles de cuisine, piles, papeterie, sacs poubelle, ampoules). Pour chaque article de la liste, réalisez les étapes suivantes : assignez-le à une catégorie parmi celles fournies précédemment puis ajoutez le numéro de cette catégorie avant le nom de l article, séparé par un tiret \"-\". Renvoie moi la liste avec tous les articles (avec son numéro de catégorie) séparé par des virgules comme dans la liste que vous avez reçue, sans espaces supplémentaires. Voici des règles supplémentaires à appliquer : - Si un article commence par un \"!\", gardez ce caractère, c est un caractère spécial utilisé pour autre chose. - Ne modifiez pas les noms des articles de la liste ou les numéros des catégories fournies. - Ne rajoutez aucun texte dans votre réponse avant la liste réordonnée. - Suivez ces consignes à la lettre.Voici la liste: ' + concatenatedValues,\n role: 'user'\n }\n ]\n};\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1000,"y":1900,"wires":[["9884e8e8a18fa8b0","a695509aa4d396a3"]]},{"id":"9884e8e8a18fa8b0","type":"debug","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"debug 7","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1000,"y":1860,"wires":[]},{"id":"a695509aa4d396a3","type":"OpenAI API","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","property":"payload","propertyType":"msg","service":"b9c49ceb7f25e4b8","method":"createChatCompletion","x":1200,"y":1900,"wires":[["3f5b56ab7fc208dc","5fe44d7ad9efb6ca"]]},{"id":"3f5b56ab7fc208dc","type":"debug","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"debug 8","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1200,"y":1860,"wires":[]},{"id":"f9ad5951b230d8b9","type":"debug","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"debug 9","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":240,"y":1860,"wires":[]},{"id":"c5d2b0b8e68369ac","type":"alexa-remote-init","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","account":"7e07d994aaa8568c","option":"initialise","x":640,"y":1940,"wires":[["804b50e3d1730656"]]},{"id":"c36f3801e55b7ecc","type":"file","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"Ecrire fichier liste","filename":"/homeassistant/www/shopping_list.txt","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"utf8","x":1690,"y":1900,"wires":[["1bed472b9b1d91b0"]]},{"id":"1bed472b9b1d91b0","type":"debug","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"debug 12","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1920,"y":1900,"wires":[]},{"id":"5fe44d7ad9efb6ca","type":"change","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.choices[0].message.content","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1430,"y":1900,"wires":[["c36f3801e55b7ecc"]]},{"id":"e2ce153ea3ef1e69","type":"junction","z":"90b28db9888b0e0a","g":"8bfb5eaeacf230b5","x":180,"y":1860,"wires":[[]]},{"id":"7e07d994aaa8568c","type":"alexa-remote-account","name":"Amazon David","authMethod":"proxy","proxyOwnIp":"192.168.1.103","proxyPort":"3456","cookieFile":"/config/alexacookie.txt","refreshInterval":"3","alexaServiceHost":"layla.amazon.com","pushDispatchHost":"","amazonPage":"amazon.fr","acceptLanguage":"fr-fr","onKeywordInLanguage":"on","userAgent":"","usePushConnection":"on","autoInit":"on","autoQueryActivityOnTrigger":"on"},{"id":"493ff69ce7a88be3","type":"ha-entity-config","server":"cd0af06f.2d645","deviceConfig":"e89ac03c8f552ff3","name":"Update Shopping List","version":"6","entityType":"button","haConfig":[{"property":"name","value":"Update Shopping List"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":"config"},{"property":"device_class","value":"update"}],"resend":false,"debugEnabled":false},{"id":"b9c49ceb7f25e4b8","type":"Service Host","apiBase":"https://api.openai.com/v1","secureApiKeyHeaderOrQueryName":"Authorization","organizationId":"","name":"Tompouce Open AI API"},{"id":"cd0af06f.2d645","type":"server","name":"Home Assistant","addon":false,"rejectUnauthorizedCerts":false,"ha_boolean":"","connectionDelay":false,"cacheJson":true,"heartbeat":true,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"","statusYear":"numeric","statusMonth":"numeric","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m:s","enableGlobalContextStore":true},{"id":"e89ac03c8f552ff3","type":"ha-device-config","name":"Node Red Buttons","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""}]
Html code in Home assistant tailwindcss template:
entity: ''
content: |-
<div class="flex flex-wrap gap-2 justify-center p-2">
{% set items = states('sensor.liste_de_courses_alexa').split(',') %}
{% set num_items = items | count %}
{% set status_string = states('input_text.clicked_items') %}
{% set status_length = status_string | length %}
<!-- Ajustement de la longueur de status_string -->
{% if status_length < num_items %}
{% set status_string = status_string + ('0' * (num_items - status_length)) %}
{% elif status_length > num_items %}
{% set status_string = status_string[0:num_items] %}
{% endif %}
<!-- Bouton de mise à jour de la liste -->
<div class="bg-accent rounded-lg p-3">
<span style="font-size:14px">
<div onClick="
hass.callService('button', 'press', {entity_id: 'button.update_shopping_list'});
hass.callService('input_text', 'set_value', {entity_id: 'input_text.clicked_items', value: ''});
" class="hover:scale-105 transition-all cursor-pointer">
🛒📋🔃
</div>
</span>
</div>
<!-- Affichage des éléments triés par catégorie -->
{% for cat in range(1, 11) %}
{% for i in range(0, num_items) %}
{% set item = items[i] %}
{% if item.startswith(cat|string + '-') %}
{% set status = status_string[i]|int(0) %}
<!-- Détermination de la couleur en fonction de la catégorie -->
{% set color = "" %}
{% if cat == 1 %}
{% set color = "#FF0000" %} {# Rouge #}
{% elif cat == 2 %}
{% set color = "#FF7F00" %} {# Orange #}
{% elif cat == 3 %}
{% set color = "#FFFF00" %} {# Jaune #}
{% elif cat == 4 %}
{% set color = "#00FF00" %} {# Vert #}
{% elif cat == 5 %}
{% set color = "#0000FF" %} {# Bleu #}
{% elif cat == 6 %}
{% set color = "#4B0082" %} {# Indigo #}
{% elif cat == 7 %}
{% set color = "#8A2BE2" %} {# Violet #}
{% elif cat == 8 %}
{% set color = "#00FFFF" %} {# Cyan #}
{% elif cat == 9 %}
{% set color = "#FF69B4" %} {# Rose #}
{% elif cat == 10 %}
{% set color = "#800000" %} {# Marron #}
{% endif %}
<!-- Détermination de la couleur à afficher et du style -->
{% if status == 1 %}
{% set display_color = 'gray' %}
{% set text_decoration = 'line-through' %}
{% else %}
{% set display_color = color %}
{% set text_decoration = 'none' %}
{% endif %}
<!-- Création de new_status_string pour le clic -->
{% set new_status_string = status_string[:i] + ('0' if status == 1 else '1') + status_string[i+1:] %}
<!-- Suppression du numéro de catégorie et du tiret de l'article -->
{% set item_name = item.split('-', 1)[1] %}
<!-- Affichage de l'élément cliquable sans le préfixe -->
<div class="bg-accent rounded-lg p-3">
<span id="item-{{ i }}" data-initial-color="{{ color }}" style="font-size:14px; color: {{ display_color }}; text-decoration: {{ text_decoration }}; cursor: pointer;"
onClick="hass.callService('input_text', 'set_value', {entity_id: 'input_text.clicked_items', value: '{{ new_status_string }}'})">
{{ item_name }}
</span>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
ignore_line_breaks: true
always_update: false
parse_jinja: true
code_editor: Ace
entities: []
bindings: []
actions: []
debounceChangePeriod: 100
plugins:
daisyui:
enabled: true
url: https://fastly.jsdelivr.net/npm/daisyui@latest/dist/full.css
theme: dark - dark
overrideCardBackground: false
tailwindElements:
enabled: false
type: custom:tailwindcss-template-card