- Initialisation de l'infrastructure
L'ajout de capacités conversationnelles pilotées par l'IA exige une base frontend capable de gérer les échanges asynchrones, le traitement des médias et le rendu dynamique. Sous l'écosystème Vite, la configuration TypeScript doit être alignée avec les standards modernes :
npm i axios marked dompurify @types/dompurify
Le fichier tsconfig.json doit activer le mode strict et définir des alias de chemin pour une architecture modulaire :
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strictNullChecks": true,
"allowJs": false,
"baseUrl": "./src",
"paths": {
"@utils/*": ["utilities/*"],
"@api/*": ["services/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.vue"]
}
- Architecture du transport de données
L'interaction avec les endpoints IA repose sur une couche réseau isolée, configurée pour gérer les en-têtes d'authentification et les erreurs système de manière centralisée.
2.1 Fabrique de service réseau
Au lieu d'epxorter une instance statique, nous utilisons une fabrique paramétrable qui injecte automatiquement les intercepteurs :
import axios, { type AxiosInstance, type InternalAxiosRequestConfig } from 'axios'
export function configureNetworkTransport(endpoint: string): AxiosInstance {
const transport = axios.create({
baseURL: endpoint,
timeout: 45000,
headers: { 'Accept': 'application/json' }
})
transport.interceptors.request.use((cfg: InternalAxiosRequestConfig) => {
const authHeader = window.sessionStorage.getItem('session_auth')
if (authHeader) {
cfg.headers['Authorization'] = `Bearer ${authHeader}`
}
return cfg
})
transport.interceptors.response.use(
(res) => res.data,
(err) => {
const statusCode = err.response?.status
if (statusCode === 401) window.location.href = '/auth'
return Promise.reject(new Error(`Transport échec: ${statusCode || err.message}`))
}
)
return transport
}
2.2 Décodage des flux temps réel
Les réponses génératives arrivent en paquets binaires cotninus. Le lecteur doit être drainé itérativement tout en notifiant l'interface utilisateur :
// src/services/streamDecoder.ts
export async function consumeDataStream(
httpStream: Response,
onUpdate: (buffer: string) => void,
onEnd?: () => void,
onFail?: (reason: Error) => void
): Promise<string> {
const payloadReader = httpStream.body?.getReader()
if (!payloadReader) throw new TypeError('Flux réseau invalide')
const utf8Parser = new TextDecoder()
let accumulatedContent = ''
try {
let readCycle = await payloadReader.read()
while (!readCycle.done) {
const decodedChunk = utf8Parser.decode(readCycle.value, { stream: true })
accumulatedContent += decodedChunk
onUpdate(accumulatedContent)
readCycle = await payloadReader.read()
}
onEnd?.()
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
onFail?.(err)
}
} finally {
payloadReader.releaseLock()
}
return accumulatedContent
}
- Interprétation et assainissement du contenu
Les modèles IA émettent majoritairement du balisage Markdown. La conversion en DOM doit impérativement passer par une couche de filtrage pour prévenir les injections de scripts ou de balises non autorisées.
3.1 Pipeline de rendu sécurisé
// src/utilities/contentProcessor.ts
import { marked } from 'marked'
import DOMPurify from 'dompurify'
marked.setOptions({
gfm: true,
breaks: true,
async: false
})
const SANITIZATION_RULES = {
ALLOWED_TAGS: ['p', 'h1', 'h2', 'h3', 'code', 'pre', 'ul', 'ol', 'li', 'strong', 'em', 'br', 'blockquote'],
ALLOWED_ATTR: ['class', 'href', 'target', 'rel']
}
export function processMarkdownInput(rawInput: string): string {
const rawHtml = marked.parse(rawInput) as string
const cleanHtml = DOMPurify.sanitize(rawHtml, SANITIZATION_RULES)
return cleanHtml
.replace(//g, '')
.replace(/<\/code><\/pre>/g, '')
}
Cette fonction peut être directement injectée dans un v-html ou encapsulée dans un composant dédié pour afficher les réponses convesrationnelles tout en maintenant un niveau de sécurité optimal face aux données externes.