Last active
May 18, 2025 20:22
-
-
Save abfo/e13af10a597c2fd33737bff68d33c048 to your computer and use it in GitHub Desktop.
Setting Todoist label colors from embeddings using OpenAI - see https://ithoughthecamewithyou.com/post/set-todoist-label-colors-automatically-using-openai-embeddings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from todoist_api_python.api import TodoistAPI | |
from openai import OpenAI | |
import numpy as np | |
# Todoist palette colors from https://developer.todoist.com/api/v1#tag/Colors | |
colors = [ | |
{"id": 30, "name": "berry_red", "hex": "#B8255F"}, | |
{"id": 31, "name": "red", "hex": "#DC4C3E"}, | |
{"id": 32, "name": "orange", "hex": "#C77100"}, | |
{"id": 33, "name": "yellow", "hex": "#B29104"}, | |
{"id": 34, "name": "olive_green", "hex": "#949C31"}, | |
{"id": 35, "name": "lime_green", "hex": "#65A33A"}, | |
{"id": 36, "name": "green", "hex": "#369307"}, | |
{"id": 37, "name": "mint_green", "hex": "#42A393"}, | |
{"id": 38, "name": "teal", "hex": "#148FAD"}, | |
{"id": 39, "name": "sky_blue", "hex": "#319DC0"}, | |
{"id": 40, "name": "light_blue", "hex": "#6988A4"}, | |
{"id": 41, "name": "blue", "hex": "#4180FF"}, | |
{"id": 42, "name": "grape", "hex": "#692EC2"}, | |
{"id": 43, "name": "violet", "hex": "#CA3FEE"}, | |
{"id": 44, "name": "lavender", "hex": "#A4698C"}, | |
{"id": 45, "name": "magenta", "hex": "#E05095"}, | |
{"id": 46, "name": "salmon", "hex": "#C9766F"}, | |
#{"id": 47, "name": "charcoal", "hex": "#808080"}, | |
#{"id": 48, "name": "grey", "hex": "#999999"}, | |
{"id": 49, "name": "taupe", "hex": "#8F7A69"}, | |
] | |
# OpenAI Client | |
oai = OpenAI() | |
# Embedding helper | |
def get_embedding(text): | |
# Replace underscores and hyphens with spaces | |
formatted_text = text.replace('_', ' ').replace('-', ' ') | |
response = oai.embeddings.create( | |
input=formatted_text, | |
model="text-embedding-3-small" | |
) | |
return response.data[0].embedding | |
# Add embeddings to each color in the colors list | |
print("Generating embeddings for colors...") | |
for color in colors: | |
color["embedding"] = get_embedding(color["name"]) | |
# Get API token from environment variable for security | |
# You need to set this environment variable with your Todoist API token | |
api_token = os.environ.get("TODOIST_API_TOKEN") | |
if not api_token: | |
print("Error: TODOIST_API_TOKEN environment variable not set") | |
exit(1) | |
# Initialize the Todoist API client | |
api = TodoistAPI(api_token) | |
try: | |
# Get all labels | |
labels = api.get_labels() | |
for label_iter in labels: | |
for label in label_iter: | |
embedding = get_embedding(label.name) | |
# Fix the calculation of similarities - create a proper comparison array | |
color_embeddings = np.array([color["embedding"] for color in colors]) | |
# Calculate similarities correctly - each embedding is a 1536-dim vector | |
similarities = np.array([np.dot(embedding, color_embedding) / | |
(np.linalg.norm(embedding) * np.linalg.norm(color_embedding)) | |
for color_embedding in color_embeddings]) | |
# Find the color with the highest similarity | |
max_index = np.argmax(similarities) | |
new_color = colors[max_index]["name"] | |
print(f"Setting {label.name} to {new_color}") | |
api.update_label( | |
label_id=label.id, | |
color=new_color | |
) | |
except Exception as error: | |
print(f"Error: {error}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment