tfrere HF Staff commited on
Commit
4cafdc3
·
1 Parent(s): a3df9d9

update Image, fix css

Browse files
app/scripts/TRACKIO-SPACES-MAPPING.md ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Mapping des projets Trackio vers leurs Spaces
2
+
3
+ Ce fichier liste tous les projets Trackio et leurs Space IDs correspondants pour éviter le flooding quand plusieurs embeds sont affichés.
4
+
5
+ ## Projets et leurs Spaces
6
+
7
+ | Projet | Space ID | URL |
8
+ |--------|----------|-----|
9
+ | attention-loss-comparison | tfrere/loss-attention-loss-comparison | https://huggingface.co/spaces/tfrere/loss-attention-loss-comparison |
10
+ | batch-size-loss-comparison | tfrere/loss-batch-size-loss-comparison | https://huggingface.co/spaces/tfrere/loss-batch-size-loss-comparison |
11
+ | doc-masking-loss-comparison | tfrere/loss-doc-masking-loss-comparison | https://huggingface.co/spaces/tfrere/loss-doc-masking-loss-comparison |
12
+ | lr-loss-comparison | tfrere/loss-lr-loss-comparison | https://huggingface.co/spaces/tfrere/loss-lr-loss-comparison |
13
+ | nope-loss-comparison | tfrere/loss-nope-loss-comparison | https://huggingface.co/spaces/tfrere/loss-nope-loss-comparison |
14
+ | spike-loss-comparison | tfrere/loss-spike-loss-comparison | https://huggingface.co/spaces/tfrere/loss-spike-loss-comparison |
15
+ | tied-embeddings-loss-comparison | tfrere/loss-tied-embeddings-loss-comparison | https://huggingface.co/spaces/tfrere/loss-tied-embeddings-loss-comparison |
16
+ | tp-debug-fix-loss-comparison | tfrere/loss-tp-debug-fix-loss-comparison | https://huggingface.co/spaces/tfrere/loss-tp-debug-fix-loss-comparison |
17
+ | wsd-loss-comparison | tfrere/loss-wsd-loss-comparison | https://huggingface.co/spaces/tfrere/loss-wsd-loss-comparison |
18
+
19
+ ## Utilisation dans l'article
20
+
21
+ Pour chaque projet, utilise son Space ID spécifique dans l'iframe :
22
+
23
+ ```html
24
+ <!-- Attention Loss -->
25
+ <iframe
26
+ src="https://tfrere-loss-attention-loss-comparison.hf.space?project=attention-loss-comparison&metrics=loss&sidebar=hidden&navbar=hidden&xmin=0&xmax=40&smoothing=0"
27
+ style="width:100%; height:350px; border:0;">
28
+ </iframe>
29
+
30
+ <!-- Batch Size Loss -->
31
+ <iframe
32
+ src="https://tfrere-loss-batch-size-loss-comparison.hf.space?project=batch-size-loss-comparison&metrics=loss&sidebar=hidden&navbar=hidden&xmin=0&xmax=40&smoothing=0"
33
+ style="width:100%; height:350px; border:0;">
34
+ </iframe>
35
+ ```
36
+
37
+ ## Avantages
38
+
39
+ ✅ **Pas de flooding** : Chaque embed utilise son propre Space
40
+ ✅ **Meilleure performance** : Les requêtes sont distribuées
41
+ ✅ **Isolation** : Chaque projet est indépendant
42
+ ✅ **Scalabilité** : Facile d'ajouter de nouveaux projets
43
+
44
+ ## Notes
45
+
46
+ - Les Spaces seront créés automatiquement lors du premier `trackio.init()`
47
+ - Chaque Space a son propre dataset Hugging Face
48
+ - Les Spaces sont publics par défaut (configurable dans le script)
app/scripts/log-all-loss-files-separate-spaces.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script pour créer un Space Trackio par projet de loss
4
+ Utilise l'API Hugging Face Hub pour créer des Spaces séparés
5
+ """
6
+
7
+ import trackio
8
+ import pandas as pd
9
+ import sys
10
+ from pathlib import Path
11
+ from huggingface_hub import HfApi, SpaceCard
12
+
13
+ def get_project_space_id(project_name):
14
+ """Génère un space_id unique pour chaque projet"""
15
+ username = "tfrere" # Ton username Hugging Face
16
+ space_name = f"loss-{project_name.replace('-', '-').lower()}"
17
+ return f"{username}/{space_name}"
18
+
19
+ def create_space_if_needed(space_id):
20
+ """Crée un Space s'il n'existe pas déjà"""
21
+ api = HfApi()
22
+
23
+ try:
24
+ # Vérifier si le Space existe
25
+ api.space_info(space_id)
26
+ print(f" ✅ Space existant: {space_id}")
27
+ return space_id
28
+ except Exception:
29
+ # Créer le nouveau Space
30
+ try:
31
+ print(f" 🆕 Création du Space: {space_id}")
32
+ # Le Space sera créé automatiquement par Trackio lors du premier init
33
+ return space_id
34
+ except Exception as e:
35
+ print(f" ⚠️ Erreur lors de la création du Space: {e}")
36
+ return space_id
37
+
38
+ def log_loss_file_to_trackio(data_file, project_name=None):
39
+ """Log un fichier de loss vers Trackio avec son propre Space"""
40
+ print(f"\n🚀 Traitement de: {data_file.name}")
41
+
42
+ if not data_file.exists():
43
+ print(f"❌ Fichier non trouvé: {data_file}")
44
+ return False
45
+
46
+ try:
47
+ # Charger les données
48
+ df = pd.read_csv(data_file)
49
+ print(f"📁 Données chargées: {len(df)} lignes")
50
+
51
+ # Obtenir les runs uniques
52
+ if 'run_name' not in df.columns:
53
+ print(f"❌ Pas de colonne 'run_name' dans {data_file.name}")
54
+ return False
55
+
56
+ runs = df['run_name'].unique()
57
+ print(f"🔍 Runs à créer ({len(runs)}):")
58
+ for run in runs:
59
+ count = len(df[df['run_name'] == run])
60
+ print(f' - "{run}": {count} points')
61
+
62
+ # Déterminer le nom du projet et son Space
63
+ if project_name is None:
64
+ # Extraire le nom du fichier et créer un nom de projet
65
+ base_name = data_file.stem.replace('_loss', '').replace('_', '-')
66
+ project_name = f"{base_name}-comparison"
67
+
68
+ space_id = get_project_space_id(project_name)
69
+ print(f"🎯 Projet Trackio: {project_name}")
70
+ print(f"🌐 Space ID: {space_id}")
71
+
72
+ # Créer le Space si nécessaire
73
+ create_space_if_needed(space_id)
74
+
75
+ # Logger chaque run dans le MÊME projet
76
+ for i, run_name in enumerate(runs):
77
+ print(f"\n🌐 Création du run: \"{run_name}\"")
78
+
79
+ # Initialiser Trackio avec le même projet mais son propre Space
80
+ trackio.init(
81
+ project=project_name,
82
+ space_id=space_id, # Space unique pour ce projet
83
+ name=run_name,
84
+ resume="allow"
85
+ )
86
+
87
+ # Filtrer les données pour ce run
88
+ run_data = df[df['run_name'] == run_name]
89
+ print(f"📊 Logging de {len(run_data)} points...")
90
+
91
+ # Logger les données de ce run
92
+ for j, (_, row) in enumerate(run_data.iterrows()):
93
+ log_data = {
94
+ "loss": float(row['loss'])
95
+ }
96
+
97
+ # Utiliser tokens comme axe X principal si disponible
98
+ if 'tokens' in row:
99
+ log_data["tokens"] = float(row['tokens'])
100
+ else:
101
+ # Sinon utiliser un compteur de step
102
+ log_data["step"] = j
103
+
104
+ trackio.log(log_data)
105
+
106
+ if j % 100 == 0 and j > 0:
107
+ print(f" ✅ Étape {j}/{len(run_data)}")
108
+
109
+ # Finaliser ce run
110
+ trackio.finish()
111
+ print(f"✅ Run \"{run_name}\" terminé!")
112
+
113
+ print(f"\n🎉 Projet {project_name} créé avec {len(runs)} runs dans Space {space_id}!")
114
+ return True, space_id
115
+
116
+ except Exception as e:
117
+ print(f"❌ Erreur lors du logging de {data_file.name}: {e}")
118
+ import traceback
119
+ traceback.print_exc()
120
+ return False, None
121
+
122
+ def main():
123
+ print("🎯 Logger tous les fichiers de loss vers Trackio")
124
+ print("=" * 60)
125
+ print("🔄 Un Space Trackio par projet de loss")
126
+ print("=" * 60)
127
+
128
+ # Liste des fichiers à traiter
129
+ data_dir = Path("src/content/assets/data")
130
+
131
+ # Mapping fichier -> nom de projet
132
+ file_mappings = {
133
+ "attention_loss.csv": "attention-loss-comparison",
134
+ "batch-size_loss.csv": "batch-size-loss-comparison",
135
+ "doc-masking_loss.csv": "doc-masking-loss-comparison",
136
+ "lr_loss.csv": "lr-loss-comparison",
137
+ "nope_loss.csv": "nope-loss-comparison",
138
+ "spike_loss.csv": "spike-loss-comparison",
139
+ "tied-embeddings_loss.csv": "tied-embeddings-loss-comparison",
140
+ "tp_debug_fix_loss.csv": "tp-debug-fix-loss-comparison",
141
+ "wsd_loss.csv": "wsd-loss-comparison",
142
+ }
143
+
144
+ # Traiter chaque fichier et stocker les space_ids
145
+ results = {}
146
+ space_ids = {}
147
+
148
+ for filename, project_name in file_mappings.items():
149
+ data_file = data_dir / filename
150
+ if data_file.exists():
151
+ success, space_id = log_loss_file_to_trackio(data_file, project_name)
152
+ results[filename] = success
153
+ if success:
154
+ space_ids[project_name] = space_id
155
+ else:
156
+ print(f"\n⚠️ Fichier non trouvé: {filename}")
157
+ results[filename] = False
158
+
159
+ # Résumé avec les URLs des Spaces
160
+ print("\n" + "=" * 60)
161
+ print("📊 RÉSUMÉ")
162
+ print("=" * 60)
163
+
164
+ success_count = sum(1 for v in results.values() if v)
165
+ total_count = len(results)
166
+
167
+ print("\n✅ Projets créés avec leurs Spaces:")
168
+ for filename, success in results.items():
169
+ if success:
170
+ project_name = file_mappings[filename]
171
+ space_id = space_ids.get(project_name, "N/A")
172
+ status = "✅"
173
+ print(f"{status} {filename:30s} → {space_id}")
174
+
175
+ print(f"\n🎉 {success_count}/{total_count} fichiers loggés avec succès!")
176
+ print(f"\n🌐 URLs des Spaces:")
177
+ for project_name, space_id in space_ids.items():
178
+ print(f" - {project_name}: https://huggingface.co/spaces/{space_id}")
179
+
180
+ return 0 if success_count == total_count else 1
181
+
182
+ if __name__ == "__main__":
183
+ exit(main())
app/scripts/log-all-loss-files.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script générique pour logger n'importe quel fichier de loss vers Trackio
4
+ Un projet Trackio par fichier de loss
5
+ """
6
+
7
+ import trackio
8
+ import pandas as pd
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ def get_project_name_from_file(filename):
13
+ """Convertit un nom de fichier en nom de projet Trackio"""
14
+ # Enlever l'extension et les tirets, remplacer par des tirets simples
15
+ project = filename.replace('_loss.csv', '').replace('_', '-').replace('.csv', '')
16
+ return f"{project}-comparison"
17
+
18
+ def log_loss_file_to_trackio(data_file, project_name=None):
19
+ """Log un fichier de loss vers Trackio"""
20
+ print(f"\n🚀 Traitement de: {data_file.name}")
21
+
22
+ if not data_file.exists():
23
+ print(f"❌ Fichier non trouvé: {data_file}")
24
+ return False
25
+
26
+ try:
27
+ # Charger les données
28
+ df = pd.read_csv(data_file)
29
+ print(f"📁 Données chargées: {len(df)} lignes")
30
+
31
+ # Obtenir les runs uniques
32
+ if 'run_name' not in df.columns:
33
+ print(f"❌ Pas de colonne 'run_name' dans {data_file.name}")
34
+ return False
35
+
36
+ runs = df['run_name'].unique()
37
+ print(f"🔍 Runs à créer ({len(runs)}):")
38
+ for run in runs:
39
+ count = len(df[df['run_name'] == run])
40
+ print(f' - "{run}": {count} points')
41
+
42
+ # Déterminer le nom du projet
43
+ if project_name is None:
44
+ project_name = get_project_name_from_file(data_file.name)
45
+ print(f"🎯 Projet Trackio: {project_name}")
46
+
47
+ # Logger chaque run dans le MÊME projet
48
+ for i, run_name in enumerate(runs):
49
+ print(f"\n🌐 Création du run: \"{run_name}\"")
50
+
51
+ # Initialiser Trackio avec le même projet
52
+ trackio.init(
53
+ project=project_name,
54
+ space_id="tfrere/loss-experiment",
55
+ name=run_name,
56
+ resume="allow" # Permettre de reprendre ou créer un nouveau run
57
+ )
58
+
59
+ # Filtrer les données pour ce run
60
+ run_data = df[df['run_name'] == run_name]
61
+ print(f"📊 Logging de {len(run_data)} points...")
62
+
63
+ # Logger les données de ce run
64
+ for j, (_, row) in enumerate(run_data.iterrows()):
65
+ log_data = {
66
+ "loss": float(row['loss'])
67
+ }
68
+
69
+ # Utiliser tokens comme axe X principal si disponible
70
+ if 'tokens' in row:
71
+ log_data["tokens"] = float(row['tokens'])
72
+ else:
73
+ # Sinon utiliser un compteur de step
74
+ log_data["step"] = j
75
+
76
+ trackio.log(log_data)
77
+
78
+ if j % 100 == 0 and j > 0:
79
+ print(f" ✅ Étape {j}/{len(run_data)}")
80
+
81
+ # Finaliser ce run
82
+ trackio.finish()
83
+ print(f"✅ Run \"{run_name}\" terminé!")
84
+
85
+ print(f"\n🎉 Projet {project_name} créé avec {len(runs)} runs!")
86
+ return True
87
+
88
+ except Exception as e:
89
+ print(f"❌ Erreur lors du logging de {data_file.name}: {e}")
90
+ import traceback
91
+ traceback.print_exc()
92
+ return False
93
+
94
+ def main():
95
+ print("🎯 Logger tous les fichiers de loss vers Trackio")
96
+ print("=" * 60)
97
+ print("🔄 Un projet Trackio par fichier de loss")
98
+ print("=" * 60)
99
+
100
+ # Liste des fichiers à traiter
101
+ data_dir = Path("src/content/assets/data")
102
+
103
+ # Mapping fichier -> nom de projet (optionnel, sinon généré automatiquement)
104
+ file_mappings = {
105
+ "attention_loss.csv": "attention-loss-comparison",
106
+ "batch-size_loss.csv": "batch-size-loss-comparison",
107
+ "doc-masking_loss.csv": "doc-masking-loss-comparison",
108
+ "lr_loss.csv": "lr-loss-comparison",
109
+ "nope_loss.csv": "nope-loss-comparison",
110
+ "spike_loss.csv": "spike-loss-comparison",
111
+ "tied-embeddings_loss.csv": "tied-embeddings-loss-comparison",
112
+ "tp_debug_fix_loss.csv": "tp-debug-fix-loss-comparison",
113
+ "wsd_loss.csv": "wsd-loss-comparison",
114
+ }
115
+
116
+ # Traiter chaque fichier
117
+ results = {}
118
+ for filename, project_name in file_mappings.items():
119
+ data_file = data_dir / filename
120
+ if data_file.exists():
121
+ results[filename] = log_loss_file_to_trackio(data_file, project_name)
122
+ else:
123
+ print(f"\n⚠️ Fichier non trouvé: {filename}")
124
+ results[filename] = False
125
+
126
+ # Résumé
127
+ print("\n" + "=" * 60)
128
+ print("📊 RÉSUMÉ")
129
+ print("=" * 60)
130
+
131
+ success_count = sum(1 for v in results.values() if v)
132
+ total_count = len(results)
133
+
134
+ for filename, success in results.items():
135
+ status = "✅" if success else "❌"
136
+ print(f"{status} {filename}")
137
+
138
+ print(f"\n🎉 {success_count}/{total_count} fichiers loggés avec succès!")
139
+ print(f"📊 Consultez votre dashboard: https://huggingface.co/spaces/tfrere/loss-experiment")
140
+
141
+ return 0 if success_count == total_count else 1
142
+
143
+ if __name__ == "__main__":
144
+ exit(main())
app/src/components/Image.astro CHANGED
@@ -76,6 +76,21 @@ const getOriginalSrc = (imageSrc: any): string => {
76
  };
77
 
78
  const originalSrc = getOriginalSrc(src);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  const hasCaptionSlot = Astro.slots.has("caption");
80
  const hasCaption =
81
  hasCaptionSlot || (typeof caption === "string" && caption.length > 0);
@@ -115,6 +130,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
115
  >
116
  <AstroImage
117
  src={src}
 
 
118
  {...imgProps}
119
  data-zoomable={dataZoomable}
120
  data-downloadable={dataDownloadable}
@@ -125,6 +142,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
125
  ) : (
126
  <AstroImage
127
  src={src}
 
 
128
  {...imgProps}
129
  data-zoomable={dataZoomable}
130
  data-downloadable={dataDownloadable}
@@ -152,10 +171,22 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
152
  target={resolvedTarget}
153
  rel={resolvedRel}
154
  >
155
- <AstroImage src={src} {...imgProps} data-zoomable={dataZoomable} />
 
 
 
 
 
 
156
  </a>
157
  ) : (
158
- <AstroImage src={src} {...imgProps} data-zoomable={dataZoomable} />
 
 
 
 
 
 
159
  )}
160
  <figcaption>
161
  {hasCaptionSlot ? (
@@ -176,6 +207,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
176
  >
177
  <AstroImage
178
  src={src}
 
 
179
  {...imgProps}
180
  data-zoomable={dataZoomable}
181
  data-downloadable={dataDownloadable}
@@ -186,6 +219,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
186
  ) : (
187
  <AstroImage
188
  src={src}
 
 
189
  {...imgProps}
190
  data-zoomable={dataZoomable}
191
  data-downloadable={dataDownloadable}
@@ -213,6 +248,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
213
  >
214
  <AstroImage
215
  src={src}
 
 
216
  {...imgProps}
217
  data-zoomable={dataZoomable}
218
  class={fullWidth ? "full" : ""}
@@ -221,6 +258,8 @@ const resolvedDownloadSrc = downloadSrc || originalSrc;
221
  ) : (
222
  <AstroImage
223
  src={src}
 
 
224
  {...imgProps}
225
  data-zoomable={dataZoomable}
226
  class={fullWidth ? "full" : ""}
 
76
  };
77
 
78
  const originalSrc = getOriginalSrc(src);
79
+
80
+ // Apply safe defaults without requiring callers to specify them
81
+ const MAX_DISPLAY_WIDTH = 1800;
82
+ const resolvedFormat = (imgProps as any).format || "webp";
83
+
84
+ // If no explicit width is provided and we have metadata, cap to MAX_DISPLAY_WIDTH
85
+ let resolvedWidth = (imgProps as any).width;
86
+ if (
87
+ !resolvedWidth &&
88
+ src &&
89
+ typeof src === "object" &&
90
+ typeof src.width === "number"
91
+ ) {
92
+ resolvedWidth = Math.min(src.width, MAX_DISPLAY_WIDTH);
93
+ }
94
  const hasCaptionSlot = Astro.slots.has("caption");
95
  const hasCaption =
96
  hasCaptionSlot || (typeof caption === "string" && caption.length > 0);
 
130
  >
131
  <AstroImage
132
  src={src}
133
+ format={resolvedFormat}
134
+ width={resolvedWidth}
135
  {...imgProps}
136
  data-zoomable={dataZoomable}
137
  data-downloadable={dataDownloadable}
 
142
  ) : (
143
  <AstroImage
144
  src={src}
145
+ format={resolvedFormat}
146
+ width={resolvedWidth}
147
  {...imgProps}
148
  data-zoomable={dataZoomable}
149
  data-downloadable={dataDownloadable}
 
171
  target={resolvedTarget}
172
  rel={resolvedRel}
173
  >
174
+ <AstroImage
175
+ src={src}
176
+ format={resolvedFormat}
177
+ width={resolvedWidth}
178
+ {...imgProps}
179
+ data-zoomable={dataZoomable}
180
+ />
181
  </a>
182
  ) : (
183
+ <AstroImage
184
+ src={src}
185
+ format={resolvedFormat}
186
+ width={resolvedWidth}
187
+ {...imgProps}
188
+ data-zoomable={dataZoomable}
189
+ />
190
  )}
191
  <figcaption>
192
  {hasCaptionSlot ? (
 
207
  >
208
  <AstroImage
209
  src={src}
210
+ format={resolvedFormat}
211
+ width={resolvedWidth}
212
  {...imgProps}
213
  data-zoomable={dataZoomable}
214
  data-downloadable={dataDownloadable}
 
219
  ) : (
220
  <AstroImage
221
  src={src}
222
+ format={resolvedFormat}
223
+ width={resolvedWidth}
224
  {...imgProps}
225
  data-zoomable={dataZoomable}
226
  data-downloadable={dataDownloadable}
 
248
  >
249
  <AstroImage
250
  src={src}
251
+ format={resolvedFormat}
252
+ width={resolvedWidth}
253
  {...imgProps}
254
  data-zoomable={dataZoomable}
255
  class={fullWidth ? "full" : ""}
 
258
  ) : (
259
  <AstroImage
260
  src={src}
261
+ format={resolvedFormat}
262
+ width={resolvedWidth}
263
  {...imgProps}
264
  data-zoomable={dataZoomable}
265
  class={fullWidth ? "full" : ""}
app/src/components/Note.astro CHANGED
@@ -54,9 +54,9 @@ const hasHeader =
54
  .note {
55
  background: var(--surface-bg);
56
  border-left: 2px solid var(--border-color);
57
- border-radius-top-right: 4px;
58
- border-radius-bottom-right: 4px;
59
- padding: 10px 14px;
60
  margin: var(--block-spacing-y) 0;
61
  }
62
  .note__layout {
 
54
  .note {
55
  background: var(--surface-bg);
56
  border-left: 2px solid var(--border-color);
57
+ border-top-right-radius: 8px;
58
+ border-bottom-right-radius: 8px;
59
+ padding: 20px 18px;
60
  margin: var(--block-spacing-y) 0;
61
  }
62
  .note__layout {
app/src/content/embeds/train-model-decision-flowchart.html CHANGED
@@ -19,29 +19,52 @@
19
  }
20
 
21
  .train-model-decision-flowchart .node-rect {
22
- stroke-width: 2px;
23
- rx: 12px;
24
- ry: 12px;
25
  }
26
 
27
  .train-model-decision-flowchart .node-text {
28
  font-size: 18px;
29
- font-weight: 500;
30
  text-anchor: middle;
31
  pointer-events: none;
32
  fill: var(--text-color, #333);
33
  }
34
 
35
  .train-model-decision-flowchart .node-question {
36
- fill: color-mix(in srgb, var(--primary-color) 30%, var(--page-bg));
 
37
  }
38
 
39
  .train-model-decision-flowchart .node-success {
40
- fill: color-mix(in srgb, var(--success-color) 30%, var(--page-bg));
 
41
  }
42
 
43
  .train-model-decision-flowchart .node-category {
44
- fill: color-mix(in srgb, var(--danger-color) 25%, var(--page-bg));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
 
47
  .train-model-decision-flowchart .link-path {
@@ -185,8 +208,8 @@
185
  const nodeExtent = {
186
  minX: d3.min(nodes, d => d.x) - 140,
187
  maxX: d3.max(nodes, d => d.x) + 140,
188
- minY: d3.min(nodes, d => d.y) - 20,
189
- maxY: d3.max(nodes, d => d.y) + 20
190
  };
191
 
192
  const contentWidth = nodeExtent.maxX - nodeExtent.minX;
@@ -423,15 +446,8 @@
423
  case 'category': return 'currentColor';
424
  default: return colors.decision;
425
  }
426
- })
427
- .each(function (d) {
428
- // Set stroke based on type, using CSS variables
429
- const strokeColor = d.type === 'decision'
430
- ? 'var(--border-color, #ddd)'
431
- : 'var(--border-color, #ccc)';
432
- d3.select(this).attr('stroke', strokeColor);
433
- })
434
- .attr('stroke-width', 2);
435
 
436
  nodeMerge.select('.node-text')
437
  .attr('x', d => d.x)
 
19
  }
20
 
21
  .train-model-decision-flowchart .node-rect {
22
+ stroke-width: 2.5px;
23
+ rx: 14px;
24
+ ry: 14px;
25
  }
26
 
27
  .train-model-decision-flowchart .node-text {
28
  font-size: 18px;
29
+ font-weight: 600;
30
  text-anchor: middle;
31
  pointer-events: none;
32
  fill: var(--text-color, #333);
33
  }
34
 
35
  .train-model-decision-flowchart .node-question {
36
+ fill: oklch(from var(--primary-color) calc(l + 0.4) c h / 0.26);
37
+ stroke: oklch(from var(--primary-color) calc(l + 0.15) c h / 0.5) !important;
38
  }
39
 
40
  .train-model-decision-flowchart .node-success {
41
+ fill: oklch(from var(--success-color) calc(l + 0.4) c h / 0.26);
42
+ stroke: oklch(from var(--success-color) calc(l + 0.15) c h / 0.5) !important;
43
  }
44
 
45
  .train-model-decision-flowchart .node-category {
46
+ fill: oklch(from var(--danger-color) calc(l + 0.4) c h / 0.26);
47
+ stroke: oklch(from var(--danger-color) calc(l + 0.15) c h / 0.5) !important;
48
+ }
49
+
50
+ .train-model-decision-flowchart .node-decision {
51
+ stroke: var(--border-color, #ddd) !important;
52
+ }
53
+
54
+ /* Dark mode adjustments */
55
+ [data-theme="dark"] .train-model-decision-flowchart .node-question {
56
+ fill: oklch(from var(--primary-color) calc(l + 0.3) c h / 0.2);
57
+ stroke: oklch(from var(--primary-color) calc(l + 0.1) c h / 0.6) !important;
58
+ }
59
+
60
+ [data-theme="dark"] .train-model-decision-flowchart .node-success {
61
+ fill: oklch(from var(--success-color) calc(l + 0.3) c h / 0.2);
62
+ stroke: oklch(from var(--success-color) calc(l + 0.1) c h / 0.6) !important;
63
+ }
64
+
65
+ [data-theme="dark"] .train-model-decision-flowchart .node-category {
66
+ fill: oklch(from var(--danger-color) calc(l + 0.3) c h / 0.2);
67
+ stroke: oklch(from var(--danger-color) calc(l + 0.1) c h / 0.6) !important;
68
  }
69
 
70
  .train-model-decision-flowchart .link-path {
 
208
  const nodeExtent = {
209
  minX: d3.min(nodes, d => d.x) - 140,
210
  maxX: d3.max(nodes, d => d.x) + 140,
211
+ minY: d3.min(nodes, d => d.y),
212
+ maxY: d3.max(nodes, d => d.y)
213
  };
214
 
215
  const contentWidth = nodeExtent.maxX - nodeExtent.minX;
 
446
  case 'category': return 'currentColor';
447
  default: return colors.decision;
448
  }
449
+ });
450
+ // Stroke is handled by CSS classes
 
 
 
 
 
 
 
451
 
452
  nodeMerge.select('.node-text')
453
  .attr('x', d => d.x)