Bon alors euh... il faut que je crée une tâche pour, attends... pour
réviser le mockup de la page d'accueil du client, tu sais le projet
euh... comment il s'appelle déjà... ah oui "Transformation Boulangerie Moderne",
c'est ça. Donc il faut que Florian regarde ça, parce que lui il s'occupe
du design système, et euh... on avait dit quoi déjà pour la deadline...
ah oui demain soir, le 17 novembre. Bon alors oui c'est prioritaire,
priorité haute parce que le client attend la présentation vendredi.
Et puis euh... ah oui il faut aussi ajouter le tag "Design" et "Client-Premium"
pour qu'on retrouve facilement dans la base. Voilà je pense que c'est bon.
{
"extractions": [
{"time_sec": 8.5, "field": "title", "value": "Réviser mockup page d'accueil", "confidence": 0.88},
{"time_sec": 12.0, "field": "project_name", "value": "Transformation Boulangerie Moderne", "confidence": 0.95},
{"time_sec": 18.5, "field": "assignee", "value": "Florian", "confidence": 0.92},
{"time_sec": 24.0, "field": "due_date", "value": "demain soir", "needs_correction": true},
{"time_sec": 25.0, "field": "due_date", "value": "2025-11-17", "corrected": true},
{"time_sec": 30.0, "field": "priority", "value": "high", "confidence": 0.90},
{"time_sec": 38.0, "field": "tags", "value": ["Design"], "confidence": 0.95},
{"time_sec": 40.5, "field": "tags", "value": ["Design", "Client-Premium"], "confidence": 0.85}
]
}
{
"task": {
"id": "task_new_001",
"title": "Réviser mockup page d'accueil",
"description": "Révision du mockup pour le projet Transformation Boulangerie Moderne. Présentation client prévue vendredi.",
"project_id": "proj_transformation_boulangerie",
"project_name": "Transformation Boulangerie Moderne",
"status": "todo",
"priority": "high",
"assignee_id": "user_florian_dupont",
"assignee_name": "Florian Dupont",
"due_date": "2025-11-17",
"tags": ["Design", "Client-Premium"],
"created_at": "2025-11-16T14:32:00Z"
}
}
OK alors la prochaine étape pour le Little Helper IA du client, c'est euh...
l'intégration avec Make.com pour automatiser les réponses emails.
Donc ça c'est pour le projet... attends je vérifie... "Automatisation Support ClientCo".
Nicolas et Antoine vont bosser dessus ensemble, parce que Nicolas fait
la partie Make et Antoine gère l'API du Little Helper. Bon alors euh...
pour la date, on a dit mi-décembre, donc disons le 15 décembre, mais euh...
attends non plutôt le 18 parce qu'il y a le sprint review le 16.
Ah et puis c'est bloqué par la tâche "Configuration serveur" qui doit être
terminée avant. Et en priorité... mouais priorité moyenne pour l'instant
parce qu'on a d'autres trucs urgents. Voilà c'est tout je crois.
{
"extractions": [
{"time_sec": 6.0, "field": "title", "value": "Intégration Make.com", "confidence": 0.75},
{"time_sec": 10.5, "field": "title", "value": "Intégration Make.com pour automatisation emails", "confidence": 0.92},
{"time_sec": 15.0, "field": "project_name", "value": "Automatisation Support ClientCo", "confidence": 0.90},
{"time_sec": 19.0, "field": "assignee", "value": "Nicolas", "confidence": 0.88},
{"time_sec": 20.5, "field": "assignee", "value": ["Nicolas", "Antoine"], "multi_assign": true},
{"time_sec": 28.0, "field": "due_date", "value": "2025-12-15", "tentative": true},
{"time_sec": 31.0, "field": "due_date", "value": "2025-12-18", "corrected": true, "reason": "Sprint review le 16"},
{"time_sec": 36.0, "field": "blocked_by", "value": "Configuration serveur", "confidence": 0.85},
{"time_sec": 36.5, "field": "status", "value": "blocked", "auto_inferred": true},
{"time_sec": 41.0, "field": "priority", "value": "medium", "confidence": 0.80}
]
}
{
"task": {
"id": "task_new_002",
"title": "Intégration Make.com pour automatisation emails",
"description": "Intégration Make.com avec API Little Helper IA pour réponses emails automatisées. Nicolas gère Make, Antoine l'API. Bloqué par configuration serveur (sprint review le 16/12).",
"project_id": "proj_automatisation_clientco",
"project_name": "Automatisation Support ClientCo",
"status": "blocked",
"priority": "medium",
"assignee_id": ["user_nicolas_martin", "user_antoine_rousseau"],
"assignee_names": ["Nicolas Martin", "Antoine Rousseau"],
"due_date": "2025-12-18",
"tags": ["No-code", "Automation", "API", "Make.com"],
"blocked_by": {
"task_id": "task_config_serveur_prod",
"task_title": "Configuration serveur production"
},
"created_at": "2025-11-16T14:35:00Z"
}
}
Alors je dois créer une grosse tâche pour la préparation du pitch investisseurs
pour Audiogami. C'est un projet clé donc très haute priorité, urgente même.
Il faut que Timo prépare la démo technique, que moi je finalise les slides
de présentation, et euh... on doit aussi intégrer les retours de l'étude
de marché qu'Antoine a faite. Donc en gros trois sous-tâches: démo tech,
slides exec, et intégration données marché. Pour la date... on pitch le
3 décembre donc il faut que tout soit prêt le 1er décembre au plus tard,
disons même le 30 novembre pour avoir de la marge. Ah et puis il faut
taguer ça "Fundraising", "Stratégie" et "Investor-Ready". Bon et euh...
je mets un commentaire aussi: "Prévoir session de répétition avec Timo
le 29 novembre matin". Voilà c'est complet je pense.
{
"extractions": [
{"time_sec": 5.0, "field": "title", "value": "Préparation pitch investisseurs", "confidence": 0.85},
{"time_sec": 7.5, "field": "project_name", "value": "Audiogami", "confidence": 0.98},
{"time_sec": 11.0, "field": "priority", "value": "urgent", "confidence": 0.95},
{"time_sec": 14.0, "field": "assignee", "value": "Timo", "subtask_detected": true},
{"time_sec": 16.5, "field": "assignee", "value": ["Ulrich", "Timo"], "multi_assign": true},
{"time_sec": 18.0, "field": "subtasks", "value": [{"title": "Démo technique", "assignee": "Timo"}]},
{"time_sec": 20.0, "field": "subtasks", "value": [
{"title": "Démo technique", "assignee": "Timo"},
{"title": "Slides présentation executive", "assignee": "Ulrich"}
]},
{"time_sec": 23.0, "field": "assignee", "value": ["Ulrich", "Timo", "Antoine"]},
{"time_sec": 24.0, "field": "subtasks", "value": [
{"title": "Démo technique Audiogami", "assignee": "Timo"},
{"title": "Slides présentation executive", "assignee": "Ulrich"},
{"title": "Intégration données étude marché", "assignee": "Antoine"}
]},
{"time_sec": 31.0, "field": "due_date", "value": "2025-12-01", "tentative": true},
{"time_sec": 34.0, "field": "due_date", "value": "2025-11-30", "corrected": true, "reason": "Marge sécurité"},
{"time_sec": 38.0, "field": "tags", "value": ["Fundraising"], "confidence": 0.95},
{"time_sec": 39.5, "field": "tags", "value": ["Fundraising", "Stratégie", "Investor-Ready"]},
{"time_sec": 43.0, "field": "comment", "value": "Prévoir session de répétition avec Timo le 29 novembre matin"}
]
}
{
"task": {
"id": "task_new_003",
"title": "Préparation pitch investisseurs Audiogami",
"description": "Préparation complète du pitch investisseurs pour Audiogami. Pitch prévu le 3 décembre. Trois axes: démo technique (Timo), slides exécutives (Ulrich), intégration données marché (Antoine). Session répétition le 29 novembre matin.",
"project_id": "proj_fundraising_audiogami",
"project_name": "Fundraising Audiogami",
"status": "todo",
"priority": "urgent",
"assignee_id": ["user_ulrich_fischer", "user_timo_schuler", "user_antoine_rousseau"],
"assignee_names": ["Ulrich Fischer", "Timo Schuler", "Antoine Rousseau"],
"due_date": "2025-11-30",
"tags": ["Fundraising", "Stratégie", "Investor-Ready"],
"subtasks": [
{
"id": "subtask_001",
"title": "Démo technique Audiogami",
"assignee_id": "user_timo_schuler",
"assignee_name": "Timo Schuler",
"status": "todo"
},
{
"id": "subtask_002",
"title": "Slides présentation executive",
"assignee_id": "user_ulrich_fischer",
"assignee_name": "Ulrich Fischer",
"status": "todo"
},
{
"id": "subtask_003",
"title": "Intégration données étude de marché",
"assignee_id": "user_antoine_rousseau",
"assignee_name": "Antoine Rousseau",
"status": "todo"
}
],
"comments": [
{
"id": "comment_001",
"author_id": "user_ulrich_fischer",
"author_name": "Ulrich Fischer",
"body": "Prévoir session de répétition avec Timo le 29 novembre matin",
"created_at": "2025-11-16T14:38:00Z"
}
],
"created_at": "2025-11-16T14:38:00Z"
}
}
/* === COULEURS PRIMAIRES - Origami Paper === */
:root {
/* Rose signature Audiogami */
--primary-pink: #FF69B4;
--primary-soft: #FFB6D9;
--primary-pale: #FFE4F1;
/* Papier origami */
--secondary-cream: #FFF8F3;
--secondary-gray: #E8E4E1;
--accent-gold: #D4AF37;
/* États système */
--success-green: #4CAF50;
--warning-orange: #FF9800;
--error-red: #F44336;
--info-blue: #2196F3;
/* Texte */
--text-dark: #2C2C2C;
--text-medium: #666666;
--text-light: #999999;
--text-white: #FFFFFF;
/* Overlays */
--shadow-soft: rgba(0, 0, 0, 0.08);
--shadow-medium: rgba(0, 0, 0, 0.15);
--overlay-dark: rgba(44, 44, 44, 0.6);
}
/* Import fonts */
@import url('<https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap>');
/* Hierarchy */
:root {
/* Headers */
--font-heading: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
--weight-heading: 600;
/* Body */
--font-body: 'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
--weight-body: 400;
--weight-medium: 500;
/* Mono (code/data) */
--font-mono: 'JetBrains Mono', 'SF Mono', 'Courier New', monospace;
/* Sizes */
--text-xs: 0.75rem; /* 12px */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
--text-3xl: 1.875rem; /* 30px */
}
/* Typography classes */
h1, .heading-1 {
font-family: var(--font-heading);
font-size: var(--text-3xl);
font-weight: var(--weight-heading);
color: var(--text-dark);
}
h2, .heading-2 {
font-family: var(--font-heading);
font-size: var(--text-2xl);
font-weight: var(--weight-heading);
color: var(--text-dark);
}
body, .body-text {
font-family: var(--font-body);
font-size: var(--text-base);
font-weight: var(--weight-body);
color: var(--text-dark);
line-height: 1.6;
}
/* === ORIGAMI FOLD/UNFOLD ANIMATIONS === */
/* Pliage d'ouverture (reveal) */
@keyframes origami-unfold {
0% {
transform: scaleY(0) rotateX(90deg);
transform-origin: top;
opacity: 0;
}
50% {
transform: scaleY(0.5) rotateX(45deg);
opacity: 0.5;
}
100% {
transform: scaleY(1) rotateX(0deg);
opacity: 1;
}
}
/* Pliage de fermeture (hide) */
@keyframes origami-fold {
0% {
transform: scaleY(1) rotateX(0deg);
opacity: 1;
}
50% {
transform: scaleY(0.5) rotateX(45deg);
opacity: 0.5;
}
100% {
transform: scaleY(0) rotateX(90deg);
transform-origin: top;
opacity: 0;
}
}
/* Pliage latéral (slide reveal) */
@keyframes origami-slide-unfold {
0% {
transform: translateX(-100%) rotateY(-90deg);
opacity: 0;
}
100% {
transform: translateX(0) rotateY(0deg);
opacity: 1;
}
}
/* Effet papier froissé au hover */
.paper-effect {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow:
1px 1px 2px var(--shadow-soft),
2px 2px 4px var(--shadow-soft);
}
.paper-effect:hover {
box-shadow:
2px 2px 4px var(--shadow-soft),
4px 4px 8px rgba(0,0,0,0.06),
inset 1px 1px 2px rgba(255,255,255,0.4);
transform: translateY(-2px) scale(1.01);
}
/* Pulse pour nouveaux champs */
@keyframes field-pulse {
0%, 100% {
background-color: var(--secondary-cream);
border-color: var(--primary-pale);
}
50% {
background-color: var(--primary-pale);
border-color: var(--primary-soft);
}
}
/* Classes utilitaires */
.animate-unfold {
animation: origami-unfold 0.6s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.animate-fold {
animation: origami-fold 0.4s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.animate-pulse {
animation: field-pulse 1.5s ease-in-out 2;
}
/* Buttons */
.btn {
font-family: var(--font-body);
font-weight: var(--weight-medium);
padding: 0.75rem 1.5rem;
border-radius: 8px;
border: none;
cursor: pointer;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-pink), var(--primary-soft));
color: var(--text-white);
box-shadow: 0 2px 8px rgba(255, 105, 180, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 105, 180, 0.4);
}
.btn-secondary {
background: var(--secondary-cream);
color: var(--text-dark);
border: 1px solid var(--secondary-gray);
}
/* Input fields */
.input-field {
font-family: var(--font-body);
font-size: var(--text-base);
padding: 0.75rem 1rem;
border: 2px solid var(--secondary-gray);
border-radius: 8px;
background: white;
transition: all 0.2s ease;
}
.input-field:focus {
outline: none;
border-color: var(--primary-pink);
box-shadow: 0 0 0 3px var(--primary-pale);
}
/* Tags/badges */
.tag {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.75rem;
background: var(--primary-pale);
color: var(--primary-pink);
border-radius: 16px;
font-size: var(--text-sm);
font-weight: var(--weight-medium);
}
/* Cards */
.card {
background: white;
border-radius: 12px;
padding: 1.5rem;
box-shadow:
0 1px 3px var(--shadow-soft),
0 2px 6px var(--shadow-soft);
transition: all 0.3s ease;
}
.card:hover {
box-shadow:
0 4px 8px var(--shadow-soft),
0 6px 12px var(--shadow-medium);
}
<!-- Structure HTML mobile -->
<div class="mobile-container">
<!-- Header sticky -->
<header class="mobile-header">
<button class="btn-back">◀</button>
<h1 class="logo">Audiogami</h1>
<button class="btn-menu">≡</button>
</header>
<!-- Recording status -->
<div class="recording-status">
<div class="status-indicator">
<span class="pulse-dot"></span>
🎤 ENREGISTREMENT
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 60%"></div>
<span class="time">0:32 / 0:45</span>
</div>
</div>
<!-- Transcription panel (collapsible) -->
<div class="transcript-panel">
<div class="transcript-header" onclick="toggleTranscript()">
<h3>Transcription</h3>
<button>▼ AFFICHER MOINS</button>
</div>
<div class="transcript-content" id="transcriptText">
<!-- Texte en typewriter ici -->
<p class="typing-text"></p>
</div>
</div>
<!-- Fields section (scroll vertical) -->
<div class="fields-section">
<!-- Titre -->
<div class="field-group">
<label>📋 Titre de la tâche</label>
<input
type="text"
class="input-field"
id="field-title"
placeholder="Titre détecté apparaîtra ici..."
/>
</div>
<!-- Assigné à -->
<div class="field-group">
<label>👤 Assigné à</label>
<select class="input-field" id="field-assignee">
<option value="">Sélectionner...</option>
<option value="florian">Florian Dupont</option>
<option value="nicolas">Nicolas Martin</option>
<option value="antoine">Antoine Rousseau</option>
<option value="timo">Timo Schuler</option>
<option value="ulrich">Ulrich Fischer</option>
</select>
</div>
<!-- Date limite -->
<div class="field-group">
<label>📅 Date limite</label>
<input
type="date"
class="input-field"
id="field-due-date"
/>
</div>
<!-- Priorité -->
<div class="field-group">
<label>⚡ Priorité</label>
<div class="priority-toggle">
<button class="priority-btn" data-priority="low">
○ Faible
</button>
<button class="priority-btn" data-priority="medium">
○ Moyenne
</button>
<button class="priority-btn active" data-priority="high">
● Haute
</button>
<button class="priority-btn" data-priority="urgent">
○ Urgente
</button>
</div>
</div>
<!-- Tags -->
<div class="field-group">
<label>🏷️ Tags</label>
<div class="tags-container" id="tagsContainer">
<!-- Tags ajoutés dynamiquement -->
</div>
<input
type="text"
class="input-field"
id="field-add-tag"
placeholder="Ajouter un tag..."
/>
</div>
</div>
<!-- Actions sticky bottom -->
<div class="mobile-actions">
<button class="btn btn-secondary btn-pause">
⏸ PAUSE
</button>
<button class="btn btn-primary btn-validate">
✓ VALIDER
</button>
</div>
</div>
/* Mobile styles */
.mobile-container {
min-height: 100vh;
display: flex;
flex-direction: column;
background: var(--secondary-cream);
}
.mobile-header {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
background: white;
border-bottom: 1px solid var(--secondary-gray);
}
.recording-status {
padding: 1rem;
background: linear-gradient(135deg, var(--primary-pale), white);
}
.status-indicator {
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: var(--weight-medium);
color: var(--primary-pink);
margin-bottom: 0.5rem;
}
.pulse-dot {
width: 8px;
height: 8px;
background: var(--primary-pink);
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.5; transform: scale(1.2); }
}
.progress-bar {
position: relative;
height: 6px;
background: var(--secondary-gray);
border-radius: 3px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-pink), var(--primary-soft));
transition: width 0.3s ease;
}
.transcript-panel {
background: white;
margin: 1rem;
border-radius: 12px;
padding: 1rem;
max-height: 200px;
overflow-y: auto;
box-shadow: 0 2px 8px var(--shadow-soft);
}
.typing-text {
font-size: var(--text-sm);
color: var(--text-medium);
line-height: 1.6;
}
.fields-section {
flex: 1;
padding: 1rem;
overflow-y: auto;
}
.field-group {
margin-bottom: 1.5rem;
}
.field-group label {
display: block;
font-size: var(--text-sm);
font-weight: var(--weight-medium);
color: var(--text-dark);
margin-bottom: 0.5rem;
}
.priority-toggle {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.priority-btn {
padding: 0.75rem;
border: 2px solid var(--secondary-gray);
background: white;
border-radius: 8px;
font-size: var(--text-sm);
cursor: pointer;
transition: all 0.2s ease;
}
.priority-btn.active {
border-color: var(--primary-pink);
background: var(--primary-pale);
color: var(--primary-pink);
}
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0.5rem;
}
.mobile-actions {
position: sticky;
bottom: 0;
display: flex;
gap: 0.75rem;
padding: 1rem;
background: white;
border-top: 1px solid var(--secondary-gray);
box-shadow: 0 -2px 8px var(--shadow-soft);
}
.mobile-actions .btn {
flex: 1;
}
<!-- Structure HTML desktop -->
<div class="desktop-container">
<!-- Header global -->
<header class="desktop-header">
<div class="logo-section">
<img src="logo-audiogami.svg" alt="Audiogami" />
<h1>Audiogami</h1>
</div>
<nav class="main-nav">
<a href="#" class="nav-link active">Widget</a>
<a href="#" class="nav-link">Base de données</a>
<a href="#" class="nav-link">Paramètres</a>
</nav>
</header>
<!-- Main grid: 3 colonnes -->
<main class="desktop-main">
<!-- COLONNE 1: Transcription -->
<section class="column column-transcript">
<div class="column-header">
<h2>Transcription</h2>
<div class="recording-indicator">
<span class="pulse-dot"></span>
<span class="time">0:32</span>
</div>
</div>
<div class="progress-bar-desktop">
<div class="progress-fill" style="width: 60%"></div>
</div>
<div class="transcript-text" id="transcriptDesktop">
<!-- Effet typewriter ici -->
<p class="typing-text"></p>
<!-- Mots détectés surlignés -->
<mark class="detected-entity" data-field="title">
réviser le mockup
</mark>
<mark class="detected-entity" data-field="assignee">
Florian
</mark>
<mark class="detected-entity" data-field="date">
demain soir
</mark>
</div>
<div class="transcript-actions">
<button class="btn btn-secondary">
⏸ Pause
</button>
<button class="btn btn-secondary">
⏹ Stop
</button>
</div>
</section>
<!-- COLONNE 2: Extraction & Champs -->
<section class="column column-fields">
<div class="column-header">
<h2>Extraction en cours</h2>
<div class="confidence-badge">
<span class="confidence-icon">✓</span>
92% confiance
</div>
</div>
<div class="extraction-summary">
<div class="summary-item">
<span class="icon">📋</span>
<span class="label">Tâche créée</span>
</div>
</div>
<!-- Formulaire dynamique -->
<form class="extraction-form" id="extractionForm">
<!-- Chaque champ apparaît avec animation origami-unfold -->
<div class="form-field animate-unfold" data-field="title">
<label>Titre</label>
<input
type="text"
class="input-field"
value="Réviser mockup page d'accueil"
/>
<span class="field-status">✓ Détecté</span>
</div>
<div class="form-field animate-unfold" data-field="assignee">
<label>Assigné à</label>
<select class="input-field">
<option value="florian" selected>Florian Dupont</option>
<option value="nicolas">Nicolas Martin</option>
<option value="antoine">Antoine Rousseau</option>
</select>
<span class="field-status">✓ Détecté</span>
</div>
<div class="form-field animate-unfold animate-pulse" data-field="due-date">
<label>Date limite</label>
<input
type="date"
class="input-field"
value="2025-11-17"
/>
<span class="field-status correction">
🔄 Corrigé: "demain soir" → 17/11/2025
</span>
</div>
<div class="form-field animate-unfold" data-field="priority">
<label>Priorité</label>
<div class="priority-grid">
<button type="button" class="priority-option">Faible</button>
<button type="button" class="priority-option">Moyenne</button>
<button type="button" class="priority-option active">Haute</button>
<button type="button" class="priority-option">Urgente</button>
</div>
</div>
<div class="form-field animate-unfold" data-field="tags">
<label>Tags</label>
<div class="tags-input">
<span class="tag">Design ×</span>
<span class="tag">Client-Premium ×</span>
<input type="text" placeholder="Ajouter..." />
</div>
</div>
</form>
<div class="form-actions">
<button class="btn btn-primary btn-validate-desktop">
✓ Valider et enregistrer
</button>
</div>
</section>
<!-- COLONNE 3: Base de données -->
<section class="column column-database">
<div class="column-header">
<h2>Base de données</h2>
<input
type="search"
class="search-input"
placeholder="🔍 Filtrer..."
/>
</div>
<!-- Liste des tâches existantes -->
<div class="tasks-list">
<!-- Nouvelle tâche (preview) -->
<div class="task-card task-new">
<div class="task-checkbox">
<input type="checkbox" id="task-new" />
</div>
<div class="task-content">
<h3 class="task-title">
Réviser mockup page d'accueil
</h3>
<div class="task-meta">
<span class="assignee">@Florian</span>
<span class="due-date">17/11</span>
<span class="priority high">🔥 Haute</span>
</div>
<div class="task-tags">
<span class="tag">Design</span>
<span class="tag">Client-Premium</span>
</div>
</div>
</div>
<!-- Tâches existantes -->
<div class="task-card">
<div class="task-checkbox">
<input type="checkbox" id="task-1" />
</div>
<div class="task-content">
<h3 class="task-title">
Intégration Make.com automatisation emails
</h3>
<div class="task-meta">
<span class="assignee">@Nicolas @Antoine</span>
<span class="due-date">18/12</span>
<span class="priority medium">⚡ Moyenne</span>
<span class="status blocked">🚫 Bloqué</span>
</div>
</div>
</div>
<div class="task-card">
<div class="task-checkbox">
<input type="checkbox" id="task-2" />
</div>
<div class="task-content">
<h3 class="task-title">
Préparation pitch investisseurs Audiogami
</h3>
<div class="task-meta">
<span class="assignee">@Ulrich @Timo</span>
<span class="due-date">30/11</span>
<span class="priority urgent">🔥🔥 Urgente</span>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- Footer: 3 dernières entrées (pleine largeur) -->
<footer class="desktop-footer">
<h3>Dernières entrées</h3>
<div class="recent-tasks-grid">
<div class="recent-task">
<div class="recent-icon">✓</div>
<div class="recent-content">
<h4>Démo client AVA</h4>
<p>@Timo • Terminé • 15/11</p>
</div>
</div>
<div class="recent-task">
<div class="recent-icon">⏳</div>
<div class="recent-content">
<h4>Configuration serveur production</h4>
<p>@Nicolas • En cours • 18/11</p>
</div>
</div>
<div class="recent-task">
<div class="recent-icon">📝</div>
<div class="recent-content">
<h4>Révision UX landing page</h4>
<p>@Antoine • À faire • 20/11</p>
</div>
</div>
</div>
</footer>
</div>
/* Desktop styles */
.desktop-container {
min-height: 100vh;
display: flex;
flex-direction: column;
background: var(--secondary-cream);
}
.desktop-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.5rem 2rem;
background: white;
border-bottom: 2px solid var(--secondary-gray);
}
.logo-section {
display: flex;
align-items: center;
gap: 1rem;
}
.logo-section img {
height: 40px;
}
.main-nav {
display: flex;
gap: 2rem;
}
.nav-link {
color: var(--text-medium);
text-decoration: none;
font-weight: var(--weight-medium);
padding: 0.5rem 1rem;
border-radius: 8px;
transition: all 0.2s ease;
}
.nav-link.active {
background: var(--primary-pale);
color: var(--primary-pink);
}
.desktop-main {
flex: 1;
display: grid;
grid-template-columns: 1fr 1.2fr 1fr;
gap: 1.5rem;
padding: 1.5rem;
overflow: hidden;
}
.column {
background: white;
border-radius: 12px;
padding: 1.5rem;
display: flex;
flex-direction: column;
box-shadow: 0 2px 8px var(--shadow-soft);
overflow-y: auto;
}
.column-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 2px solid var(--secondary-gray);
}
.column-header h2 {
font-size: var(--text-xl);
margin: 0;
}
.recording-indicator {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--primary-pink);
font-weight: var(--weight-medium);
}
.progress-bar-desktop {
height: 4px;
background: var(--secondary-gray);
border-radius: 2px;
overflow: hidden;
margin-bottom: 1.5rem;
}
.transcript-text {
flex: 1;
padding: 1rem;
background: var(--secondary-cream);
border-radius: 8px;
font-size: var(--text-sm);
line-height: 1.8;
overflow-y: auto;
}
.detected-entity {
background: var(--primary-pale);
color: var(--primary-pink);
padding: 0.125rem 0.25rem;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.detected-entity:hover {
background: var(--primary-soft);
}
.transcript-actions {
display: flex;
gap: 0.75rem;
margin-top: 1rem;
}
.extraction-summary {
background: linear-gradient(135deg, var(--primary-pale), white);
padding: 1rem;
border-radius: 8px;
margin-bottom: 1.5rem;
}
.summary-item {
display: flex;
align-items: center;
gap: 0.75rem;
font-weight: var(--weight-medium);
}
.extraction-form {
flex: 1;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.form-field {
opacity: 0;
transform: scaleY(0);
transform-origin: top;
}
.form-field.animate-unfold {
animation: origami-unfold 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.form-field label {
display: block;
font-size: var(--text-sm);
font-weight: var(--weight-medium);
color: var(--text-dark);
margin-bottom: 0.5rem;
}
.field-status {
display: inline-block;
margin-top: 0.25rem;
font-size: var(--text-xs);
color: var(--success-green);
font-weight: var(--weight-medium);
}
.field-status.correction {
color: var(--warning-orange);
}
.priority-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.5rem;
}
.priority-option {
padding: 0.5rem;
border: 2px solid var(--secondary-gray);
background: white;
border-radius: 6px;
font-size: var(--text-sm);
cursor: pointer;
transition: all 0.2s ease;
}
.priority-option.active {
border-color: var(--primary-pink);
background: var(--primary-pale);
color: var(--primary-pink);
font-weight: var(--weight-medium);
}
.tags-input {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.75rem;
border: 2px solid var(--secondary-gray);
border-radius: 8px;
background: white;
}
.tags-input input {
border: none;
outline: none;
flex: 1;
min-width: 100px;
font-size: var(--text-sm);
}
.form-actions {
margin-top: 1rem;
padding-top: 1rem;
border-top: 2px solid var(--secondary-gray);
}
.btn-validate-desktop {
width: 100%;
justify-content: center;
}
.tasks-list {
flex: 1;
display: flex;
flex-direction: column;
gap: 1rem;
}
.task-card {
display: flex;
gap: 1rem;
padding: 1rem;
background: var(--secondary-cream);
border-radius: 8px;
border: 2px solid transparent;
transition: all 0.2s ease;
cursor: pointer;
}
.task-card:hover {
border-color: var(--primary-soft);
background: white;
box-shadow: 0 2px 8px var(--shadow-soft);
}
.task-card.task-new {
background: linear-gradient(135deg, var(--primary-pale), white);
border-color: var(--primary-pink);
animation: origami-unfold 0.6s ease;
}
.task-checkbox input {
width: 20px;
height: 20px;
cursor: pointer;
}
.task-content {
flex: 1;
}
.task-title {
font-size: var(--text-base);
font-weight: var(--weight-medium);
color: var(--text-dark);
margin: 0 0 0.5rem 0;
}
.task-meta {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
font-size: var(--text-xs);
color: var(--text-medium);
margin-bottom: 0.5rem;
}
.task-meta .assignee {
color: var(--info-blue);
font-weight: var(--weight-medium);
}
.task-meta .priority {
font-weight: var(--weight-medium);
}
.task-meta .priority.high {
color: var(--warning-orange);
}
.task-meta .priority.urgent {
color: var(--error-red);
}
.task-meta .status.blocked {
color: var(--error-red);
}
.task-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.desktop-footer {
background: white;
padding: 1.5rem 2rem;
border-top: 2px solid var(--secondary-gray);
}
.desktop-footer h3 {
font-size: var(--text-lg);
margin: 0 0 1rem 0;
}
.recent-tasks-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.recent-task {
display: flex;
gap: 1rem;
padding: 1rem;
background: var(--secondary-cream);
border-radius: 8px;
}
.recent-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--primary-pale);
border-radius: 8px;
font-size: var(--text-lg);
}
.recent-content h4 {
font-size: var(--text-sm);
margin: 0 0 0.25rem 0;
}
.recent-content p {
font-size: var(--text-xs);
color: var(--text-medium);
margin: 0;
}
/* Responsive breakpoint */
@media (max-width: 768px) {
.desktop-container {
display: none;
}
}
@media (min-width: 769px) {
.mobile-container {
display: none;
}
}
// === CONFIGURATION ===
const SCENARIOS = {
A: '/data/scenario-a.json',
B: '/data/scenario-b.json',
C: '/data/scenario-c.json'
};
const PLAYBACK_SPEED = 1.5; // Accéléré pour tests
let currentScenario = null;
let simulationTimer = null;
// === INITIALISATION ===
async function initPrototype() {
// Charger le scénario A par défaut
await loadScenario('A');
// Configurer les event listeners
setupEventListeners();
// Démarrer la simulation automatiquement après 2 sec
setTimeout(() => startSimulation(), 2000);
}
// === CHARGEMENT SCÉNARIO ===
async function loadScenario(scenarioKey) {
const response = await fetch(SCENARIOS[scenarioKey]);
currentScenario = await response.json();
console.log('Scénario chargé:', currentScenario.scenario);
}
// === SIMULATION PRINCIPALE ===
function startSimulation() {
if (!currentScenario) return;
let currentTime = 0;
const chunks = currentScenario.transcript_chunks;
const extractions = currentScenario.extraction_timeline;
// 1. Démarrer l'effet typewriter
animateTranscript(chunks, currentTime);
// 2. Programmer les extractions
extractions.forEach(extraction => {
const delay = (extraction.time_sec * 1000) / PLAYBACK_SPEED;
setTimeout(() => {
updateField(extraction);
}, delay);
});
// 3. Afficher écran validation après 45 sec
const totalDuration = 45000 / PLAYBACK_SPEED;
setTimeout(() => {
showValidationScreen();
}, totalDuration);
// 4. Mettre à jour la barre de progression
updateProgressBar(totalDuration);
}
// === ANIMATION TYPEWRITER ===
function animateTranscript(chunks, startTime = 0) {
const transcriptEl = document.querySelector('.typing-text');
let currentChunkIndex = 0;
let currentCharIndex = 0;
function typeNextChar() {
if (currentChunkIndex >= chunks.length) {
// Transcription terminée
return;
}
const chunk = chunks[currentChunkIndex];
const text = chunk.text;
if (currentCharIndex < text.length) {
// Ajouter le caractère suivant
const char = text[currentCharIndex];
transcriptEl.textContent += char;
currentCharIndex++;
// Délai entre caractères (50ms / speed)
setTimeout(typeNextChar, 50 / PLAYBACK_SPEED);
} else {
// Passer au chunk suivant
transcriptEl.textContent += ' ';
currentChunkIndex++;
currentCharIndex = 0;
// Délai entre chunks (200ms / speed)
setTimeout(typeNextChar, 200 / PLAYBACK_SPEED);
}
}
typeNextChar();
}
// === MISE À JOUR DES CHAMPS ===
function updateField(extraction) {
const field = extraction.field;
const value = extraction.value;
// Sélectionner l'élément DOM
const fieldEl = document.querySelector(`[data-field="${field}"]`);
if (!fieldEl) return;
// Afficher le champ avec animation origami
if (fieldEl.style.display === 'none') {
fieldEl.style.display = 'block';
fieldEl.classList.add('animate-unfold');
}
// Remplir la valeur
const inputEl = fieldEl.querySelector('input, select, textarea');
if (inputEl) {
inputEl.value = Array.isArray(value) ? value[0] : value;
// Si correction, ajouter effet pulse
if (extraction.corrected) {
fieldEl.classList.add('animate-pulse');
showCorrectionBadge(fieldEl, extraction);
}
}
// Cas spéciaux
if (field === 'tags' && Array.isArray(value)) {
updateTags(value);
}
if (field === 'assignee' && Array.isArray(value)) {
handleMultiAssign(value);
}
if (field === 'subtasks') {
createSubtasks(value);
}
}
// === GESTION TAGS ===
function updateTags(tags) {
const container = document.getElementById('tagsContainer');
container.innerHTML = '';
tags.forEach(tag => {
const tagEl = document.createElement('span');
tagEl.className = 'tag';
tagEl.textContent = tag;
// Bouton suppression
const removeBtn = document.createElement('button');
removeBtn.textContent = '×';
removeBtn.onclick = () => tagEl.remove();
tagEl.appendChild(removeBtn);
container.appendChild(tagEl);
// Animation d'apparition
tagEl.style.animation = 'origami-unfold 0.3s ease';
});
}
// === CORRECTION BADGE ===
function showCorrectionBadge(fieldEl, extraction) {
const badge = document.createElement('div');
badge.className = 'correction-badge';
badge.innerHTML = `
<span class="correction-icon">🔄</span>
<span class="correction-text">
Corrigé: "${extraction.raw_value || 'valeur originale'}"
→ ${extraction.value}
</span>
`;
fieldEl.appendChild(badge);
}
// === ÉCRAN DE VALIDATION ===
function showValidationScreen() {
const main = document.querySelector('.desktop-main, .mobile-container');
// Créer overlay de validation
const overlay = document.createElement('div');
overlay.className = 'validation-overlay';
overlay.innerHTML = generateValidationHTML();
// Animation d'apparition
overlay.style.animation = 'origami-unfold 0.6s ease';
main.appendChild(overlay);
// Remplir avec les données finales
populateValidationForm(currentScenario.final_entities);
}
function generateValidationHTML() {
return `
<div class="validation-modal">
<div class="validation-header">
<h2>✓ Validation de la tâche</h2>
<button class="btn-close" onclick="closeValidation()">×</button>
</div>
<div class="validation-content">
<form id="validationForm">
<!-- Champs pré-remplis -->
<!-- Identiques au formulaire principal -->
</form>
</div>
<div class="validation-actions">
<button class="btn btn-secondary" onclick="closeValidation()">
Annuler
</button>
<button class="btn btn-primary" onclick="submitTask()">
✓ Enregistrer dans la base
</button>
</div>
</div>
`;
}
// === SOUMISSION FINALE ===
function submitTask() {
// Récupérer les données du formulaire
const formData = new FormData(document.getElementById('validationForm'));
const taskData = Object.fromEntries(formData);
console.log('Tâche validée:', taskData);
// Animation de succès
showSuccessAnimation();
// Ajouter à la liste des tâches
addToDatabase(taskData);
// Fermer la modal après 1.5 sec
setTimeout(() => {
closeValidation();
resetSimulation();
}, 1500);
}
function showSuccessAnimation() {
const modal = document.querySelector('.validation-modal');
// Overlay de succès
const success = document.createElement('div');
success.className = 'success-overlay';
success.innerHTML = `
<div class="success-icon">✓</div>
<h3>Tâche enregistrée !</h3>
`;
modal.appendChild(success);
}
// === BARRE DE PROGRESSION ===
function updateProgressBar(totalDuration) {
const progressBar = document.querySelector('.progress-fill');
const timeDisplay = document.querySelector('.time');
let elapsed = 0;
const interval = 100; // Update tous les 100ms
const timer = setInterval(() => {
elapsed += interval;
const percentage = (elapsed / totalDuration) * 100;
progressBar.style.width = `${Math.min(percentage, 100)}%`;
const seconds = Math.floor(elapsed / 1000);
const totalSec = Math.floor(totalDuration / 1000);
timeDisplay.textContent = `${seconds}s / ${totalSec}s`;
if (elapsed >= totalDuration) {
clearInterval(timer);
}
}, interval);
}
// === ÉDITION INLINE ===
function enableInlineEdit(fieldEl) {
const input = fieldEl.querySelector('input, select, textarea');
if (!input) return;
// Focus et sélection
input.focus();
if (input.select) input.select();
// Highlight du champ
fieldEl.classList.add('editing');
// Event listener pour sauvegarder
input.addEventListener('blur', () => {
fieldEl.classList.remove('editing');
console.log('Champ mis à jour:', input.name, input.value);
});
}
// === EVENT LISTENERS ===
function setupEventListeners() {
// Boutons de scénario
document.querySelectorAll('.scenario-btn').forEach(btn => {
btn.addEventListener('click', async (e) => {
const scenario = e.target.dataset.scenario;
await loadScenario(scenario);
resetSimulation();
startSimulation();
});
});
// Bouton pause
document.querySelector('.btn-pause')?.addEventListener('click', () => {
pauseSimulation();
});
// Édition des champs
document.querySelectorAll('.form-field').forEach(field => {
field.addEventListener('click', () => {
enableInlineEdit(field);
});
});
}
// === RESET ===
function resetSimulation() {
// Nettoyer la transcription
document.querySelectorAll('.typing-text').forEach(el => {
el.textContent = '';
});
// Réinitialiser les champs
document.querySelectorAll('.form-field').forEach(field => {
field.style.display = 'none';
field.classList.remove('animate-unfold', 'animate-pulse');
});
// Réinitialiser la barre de progression
document.querySelectorAll('.progress-fill').forEach(bar => {
bar.style.width = '0%';
});
}
// === DÉMARRAGE ===
document.addEventListener('DOMContentLoaded', initPrototype);
{
"scenario": "A",
"name": "Simple - Tâche design client",
"description": "Designer créant une tâche de révision mockup",
"transcript_text": "Bon alors euh... il faut que je crée une tâche pour, attends... pour réviser le mockup de la page d'accueil du client, tu sais le projet euh... comment il s'appelle déjà... ah oui \\"Transformation Boulangerie Moderne\\", c'est ça. Donc il faut que Florian regarde ça, parce que lui il s'occupe du design système, et euh... on avait dit quoi déjà pour la deadline... ah oui demain soir, le 17 novembre. Bon alors oui c'est prioritaire, priorité haute parce que le client attend la présentation vendredi. Et puis euh... ah oui il faut aussi ajouter le tag \\"Design\\" et \\"Client-Premium\\" pour qu'on retrouve facilement dans la base. Voilà je pense que c'est bon.",
"transcript_chunks": [
{"time_sec": 0, "text": "Bon alors euh..."},
{"time_sec": 1.5, "text": "il faut que je crée une tâche pour,"},
{"time_sec": 3.0, "text": "attends..."},
{"time_sec": 4.0, "text": "pour réviser le mockup"},
{"time_sec": 6.5, "text": "de la page d'accueil du client,"},
{"time_sec": 9.0, "text": "tu sais le projet euh..."},
{"time_sec": 10.5, "text": "comment il s'appelle déjà..."},
{"time_sec": 12.0, "text": "ah oui \\"Transformation Boulangerie Moderne\\","},
{"time_sec": 15.0, "text": "c'est ça."},
{"time_sec": 16.0, "text": "Donc il faut que Florian regarde ça,"},
{"time_sec": 18.5, "text": "parce que lui il s'occupe du design système,"},
{"time_sec": 21.0, "text": "et euh..."},
{"time_sec": 22.0, "text": "on avait dit quoi déjà pour la deadline..."},
{"time_sec": 24.5, "text": "ah oui demain soir,"},
{"time_sec": 26.0, "text": "le 17 novembre."},
{"time_sec": 28.0, "text": "Bon alors oui c'est prioritaire,"},
{"time_sec": 30.5, "text": "priorité haute"},
{"time_sec": 32.0, "text": "parce que le client attend la présentation vendredi."},
{"time_sec": 35.0, "text": "Et puis euh..."},
{"time_sec": 36.0, "text": "ah oui il faut aussi ajouter le tag \\"Design\\""},
{"time_sec": 39.0, "text": "et \\"Client-Premium\\""},
{"time_sec": 41.0, "text": "pour qu'on retrouve facilement dans la base."},
{"time_sec": 43.5, "text": "Voilà je pense que c'est bon."}
],
"extraction_timeline": [
{
"time_sec": 8.5,
"field": "title",
"value": "Réviser mockup page d'accueil",
"confidence": 0.88,
"source_text": "réviser le mockup de la page d'accueil"
},
{
"time_sec": 12.0,
"field": "project_name",
"value": "Transformation Boulangerie Moderne",
"confidence": 0.95,
"source_text": "Transformation Boulangerie Moderne"
},
{
"time_sec": 18.5,
"field": "assignee",
"value": "Florian",
"confidence": 0.92,
"source_text": "Florian regarde ça"
},
{
"time_sec": 24.0,
"field": "due_date",
"value": "demain soir",
"confidence": 0.70,
"needs_correction": true,
"source_text": "demain soir"
},
{
"time_sec": 25.0,
"field": "due_date",
"value": "2025-11-17",
"confidence": 0.95,
"corrected": true,
"correction_reason": "Interprétation de 'demain soir' basée sur date actuelle + mention explicite '17 novembre'",
"source_text": "le 17 novembre"
},
{
"time_sec": 30.0,
"field": "priority",
"value": "high",
"confidence": 0.90,
"source_text": "priorité haute"
},
{
"time_sec": 38.0,
"field": "tags",
"value": ["Design"],
"confidence": 0.95,
"source_text": "tag Design"
},
{
"time_sec": 40.5,
"field": "tags",
"value": ["Design", "Client-Premium"],
"confidence": 0.85,
"source_text": "et Client-Premium"
}
],
"final_entities": {
"task": {
"id": "task_new_001",
"title": "Réviser mockup page d'accueil",
"description": "Révision du mockup pour le projet Transformation Boulangerie Moderne. Présentation client prévue vendredi.",
"project_id": "proj_transformation_boulangerie",
"project_name": "Transformation Boulangerie Moderne",
"status": "todo",
"priority": "high",
"assignee_id": "user_florian_dupont",
"assignee_name": "Florian Dupont",
"due_date": "2025-11-17",
"tags": ["Design", "Client-Premium"],
"created_at": "2025-11-16T14:32:00Z",
"created_by": "user_current_speaker"
}
},
"existing_tasks": [
{
"id": "task_001",
"title": "Démo client AVA",
"assignee_name": "Timo Schuler",
"status": "done",
"due_date": "2025-11-15",
"priority": "high"
},
{
"id": "task_002",
"title": "Configuration serveur production",
"assignee_name": "Nicolas Martin",
"status": "in_progress",
"due_date": "2025-11-18",
"priority": "medium"
},
{
"id": "task_003",
"title": "Révision UX landing page",
"assignee_name": "Antoine Rousseau",
"status": "todo",
"due_date": "2025-11-20",
"priority": "medium"
}
]
}
### Prototype Audiogami - Feedback utilisateur
**Scénario testé**: [ ] A [ ] B [ ] C [ ] Tous
**Questions (échelle 1-5)**:
1. La transcription en temps réel était-elle claire?
☐ 1 - Pas du tout ☐ 2 ☐ 3 ☐ 4 ☐ 5 - Très clair
2. L'apparition progressive des champs était-elle rassurante?
☐ 1 - Perturbante ☐ 2 ☐ 3 ☐ 4 ☐ 5 - Rassurante
3. Avez-vous compris quand et comment corriger les champs?
☐ 1 - Pas compris ☐ 2 ☐ 3 ☐ 4 ☐ 5 - Évident
4. L'écran de validation finale était-il utile?
☐ 1 - Inutile ☐ 2 ☐ 3 ☐ 4 ☐ 5 - Essentiel
5. Recommanderiez-vous ce système à un collègue?
☐ 1 - Non ☐ 2 ☐ 3 ☐ 4 ☐ 5 - Absolument
**Questions ouvertes**:
6. Qu'avez-vous le plus apprécié?
[ ]
7. Qu'avez-vous trouvé frustrant ou confus?
[ ]
8. Utiliseriez-vous cet outil pour [votre usage] ?
[ ]
**Suggestions d'amélioration**:
[ ]
[ ]