mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r6): R6.5 — Assistant mobile (chat sourcé + dictée)
Maquette dédiée validée (docs/02-design/maquettes/maquette-mobile-assistant.html, 3 écrans) — la seule sous-étape de R6 à avoir eu son propre tour de design-first plutôt qu'une exécution directe de la maquette R6 initiale, un chat sourcé étant un patron d'écran neuf. D1 un échange à la fois ; D2 "Voir le document" → métadonnées seules (R6.3), "Ouvrir l'OT" → fiche R4 ; D3 refus chiffré + avertissement permanents, identiques au web ; D4 Assistant rejoint Pilotage pour tout rôle avec WORK_ORDERS.view ; D5 (ajoutée en revue) — la question peut être tapée OU dictée, même pipeline que la dictée déjà livrée en clôture (ADR-004 §5, faster-whisper local, audio jamais persisté), la transcription remplit le champ, jamais d'envoi automatique. api/assistant.ts (useAskAssistant, 503 géré comme le web). Écran Assistant : chat un échange à la fois, citations numérotées, sources avec extrait exact, refus honnête chiffré + Reformuler. Micro dans la barre de saisie : réutilise telle quelle la mécanique de cloture.tsx (useAudioRecorder, setAudioModeAsync, useTranscription, purge quoi qu'il arrive) — pipeline déjà recetté sur iPhone physique (01/08), aucun nouveau bug à découvrir. Fiche document (bibliotheque/[id].tsx, nouveau) — la liste R6.3 y mène aussi désormais. Menu : Assistant route réellement — le Menu R6 n'a plus d'entrée "à venir" dans les 4 groupes (Catégories exceptée, admin, hors périmètre mobile). R6 fonctionnellement complet (Exploitation/Parc/Ressources/Pilotage, Assistant inclus, pour tous les rôles) — reste une recette complète avant de considérer R6 close au sens R0→R5. Typecheck propre, 17 tests Jest, lint 5/5 paquets. Contrat non touché. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
26
apps/mobile/src/api/assistant.ts
Normal file
26
apps/mobile/src/api/assistant.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { AssistantAsk } from '@siop/shared';
|
||||
import { api } from './client';
|
||||
|
||||
/** Hook R6.5 — l'assistant passe par l'API NestJS (le service IA n'est
|
||||
* jamais appelé depuis l'app, ADR-004 §4). Le 503 est un état ATTENDU du
|
||||
* contrat (service éteint ou pas encore déployé) — même message que le web. */
|
||||
|
||||
async function unwrap<T>(res: { data?: T; error?: unknown; response: Response }): Promise<T> {
|
||||
if (res.response.status === 503) {
|
||||
throw new Error('Assistant indisponible pour le moment — réessayez dans un instant.');
|
||||
}
|
||||
if (res.error || res.data === undefined) {
|
||||
const message =
|
||||
(res.error as { message?: string } | undefined)?.message ??
|
||||
`Le serveur a répondu ${res.response.status}`;
|
||||
throw new Error(Array.isArray(message) ? message.join(' — ') : message);
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
export function useAskAssistant() {
|
||||
return useMutation({
|
||||
mutationFn: async (body: AssistantAsk) => unwrap(await api.POST('/assistant/ask', { body })),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user