Retour aux projets

1Glink

LYA Translator

Prototyper une conversation vidéo multilingue où transcription et traduction deviennent lisibles presque en temps réel.

Produit
Conversation multilingue
Rôle
Prototype Angular · UX/UI
Enjeu
Simuler un flux temps réel crédible
  • Angular
  • TypeScript
  • Signals
  • SCSS
  • WebRTC

01 · Le prototype

Rendre visible une interaction qui dépend encore de services à connecter

Le besoin consistait à démontrer une conversation vidéo entre deux personnes parlant des langues différentes. Chaque prise de parole devait apparaître progressivement, puis recevoir presque immédiatement une traduction distincte et lisible.

J’ai construit ce travail comme un prototype frontend : le scénario et sa temporalité sont séparés des composants, afin que l’interface puisse être évaluée sans prétendre reproduire le futur moteur de traduction. Le même découpage prépare ensuite le remplacement de la simulation par des événements backend ou WebRTC.

02 · Flux temps réel

Préparer l’interface à recevoir une autre source de données

La simulation et le futur service de traduction doivent pouvoir alimenter le même état de vue. L’adaptateur constitue la frontière entre le transport et les composants.

  1. 01 · Source

    Recevoir les événements

    Un scénario local, un WebSocket ou un SDK média émettent des fragments sans connaître l’interface.

  2. 02 · Adaptateur

    Normaliser le flux

    Chaque source produit le même contrat : locuteur, langue, texte, nature et état de finalisation.

  3. 03 · État réactif

    Assembler les messages

    Les fragments sont regroupés par prise de parole et exposés sous forme de ViewModels immuables.

  4. 04 · Interface

    Afficher et suivre

    Le panneau distingue transcription et traduction, suit le message actif et conserve l’historique lisible.

Résultat Le passage de la maquette au flux réel peut se concentrer sur l’adaptateur, sans réécrire la présentation.

03 · Expérience en direct

Conserver l’échange humain au centre

La traduction est un support de compréhension. Elle doit rester identifiable sans prendre toute la place face aux deux interlocuteurs.

  1. Deux niveaux de lecture

    La transcription et la traduction utilisent des repères distincts, stables et accompagnés de leur langue.

  2. Une progression perceptible

    L’apparition graduelle des caractères matérialise le traitement en cours sans ajouter un indicateur de chargement permanent.

  3. Un direct maîtrisable

    Les contrôles média restent regroupés et les timers sont stoppés dès la fin ou la destruction de la vue.

Orbe LYA et zone de conversation sur une interface sombre.
L’orbe conserve la présence visuelle de l’agent, tandis que les contenus de conversation restent dans une zone dédiée.

04 · Exemple technique

Du scénario simulé au service réel sans changer les composants

Ces extraits sont anonymisés, simplifiés et réécrits pour le portfolio. Ils expliquent la structure du prototype sans reprendre le code, les scénarios ou les contrats internes du client.

Port applicatif

Définir le flux attendu par le frontend

L’interface dépend d’un contrat minimal que peuvent implémenter aussi bien une simulation qu’un service distant.

export interface TranslationEvent {
  readonly utteranceId: string;
  readonly speaker: 'local' | 'remote';
  readonly kind: 'transcript' | 'translation';
  readonly language: string;
  readonly text: string;
  readonly final: boolean;
}

export abstract class TranslationGateway {
  abstract connect(sessionId: string): Observable<TranslationEvent>;
  abstract disconnect(): void;
}

État réactif

Dériver la conversation affichée

Les signaux conservent une source d’état compacte. Les données triées sont calculées sans mutation du tableau original.

const events = signal<readonly TranslationEvent[]>([]);

const conversation = computed(() =>
  groupByUtterance(events()).map((utterance) => ({
    ...utterance,
    transcript: joinFragments(utterance, 'transcript'),
    translation: joinFragments(utterance, 'translation'),
  })),
);

function append(event: TranslationEvent): void {
  events.update((current) => [...current, event]);
}

Cycle de vie

Nettoyer les ressources du direct

Les flux, timers et médias doivent s’arrêter avec le composant afin d’éviter une démo qui continue en arrière-plan.

const destroyRef = inject(DestroyRef);
const gateway = inject(TranslationGateway);

gateway
  .connect(sessionId())
  .pipe(takeUntilDestroyed(destroyRef))
  .subscribe(append);

destroyRef.onDestroy(() => {
  playbackClock.stop();
  gateway.disconnect();
});

05 · Cohérence UI

Une interface technique qui reste calme

La surface sombre concentre le regard sur les participants. Le panneau de conversation utilise la palette claire du produit et réserve la couleur à la nature du contenu et aux états actifs.

Couleurs

  • NuitEspace de conversation vidéo#171a33
  • IndigoTranscription et actions#2457ff
  • VioletTraduction#6861d9
  • BrumePanneau de lecture#f5f7fb
  • AlerteFin d’appel#d74354

Typographie

Inter · Regular / Medium / Semibold

Une conversation, deux langues, un même rythme.

Chaque fragment précise son locuteur, sa langue et sa fonction sans surcharger le direct.