feat(sujets): POST /sujets/idees — suggestions DeepSeek (G5)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ecb478e10c
commit
bd8ab4b72b
2 changed files with 129 additions and 0 deletions
|
|
@ -2,6 +2,7 @@ import { Hono } from 'hono'
|
|||
import { authMiddleware } from '../middleware/auth.js'
|
||||
import type { AppVariables } from '../middleware/auth.js'
|
||||
import { supabase } from '../lib/supabase.js'
|
||||
import { generateIdees } from '../lib/deepseek.js'
|
||||
|
||||
/**
|
||||
* Routes de la table `sujets` — catalogue des consignes d'examen.
|
||||
|
|
@ -9,8 +10,18 @@ import { supabase } from '../lib/supabase.js'
|
|||
* GET /sujets?mode=EE|EO&tache=1|2|3
|
||||
* Retourne la liste des sujets actifs pour la paire (mode, tache).
|
||||
* Utilisé par l'écran de choix de sujet côté frontend (tâche G4).
|
||||
*
|
||||
* POST /sujets/idees
|
||||
* Génère 5 suggestions d'idées via DeepSeek pour aider l'étudiant
|
||||
* à continuer sa rédaction en cours (tâche G5).
|
||||
*/
|
||||
|
||||
const MIN_WORDS_IDEES = 30
|
||||
|
||||
function countWords(text: string): number {
|
||||
return text.trim().split(/\s+/).filter(Boolean).length
|
||||
}
|
||||
|
||||
const VALID_MODES = ['EE', 'EO'] as const
|
||||
const VALID_TACHES = [1, 2, 3] as const
|
||||
|
||||
|
|
@ -69,4 +80,61 @@ sujets.get('/', authMiddleware, async (c) => {
|
|||
return c.json({ sujets: data ?? [] }, 200)
|
||||
})
|
||||
|
||||
sujets.post('/idees', authMiddleware, async (c) => {
|
||||
let body: unknown
|
||||
try {
|
||||
body = await c.req.json()
|
||||
} catch {
|
||||
return c.json(
|
||||
{
|
||||
error: true,
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'Corps de requête JSON invalide.',
|
||||
},
|
||||
400
|
||||
)
|
||||
}
|
||||
|
||||
const { sujet_consigne, contenu_partiel } = (body ?? {}) as {
|
||||
sujet_consigne?: unknown
|
||||
contenu_partiel?: unknown
|
||||
}
|
||||
|
||||
if (typeof sujet_consigne !== 'string' || sujet_consigne.trim().length === 0) {
|
||||
return c.json(
|
||||
{
|
||||
error: true,
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: 'sujet_consigne requis (string non vide).',
|
||||
},
|
||||
400
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof contenu_partiel !== 'string' || countWords(contenu_partiel) < MIN_WORDS_IDEES) {
|
||||
return c.json(
|
||||
{
|
||||
error: true,
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: `Le contenu doit comporter au moins ${MIN_WORDS_IDEES} mots.`,
|
||||
},
|
||||
400
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const idees = await generateIdees(sujet_consigne, contenu_partiel)
|
||||
return c.json({ idees }, 200)
|
||||
} catch {
|
||||
return c.json(
|
||||
{
|
||||
error: true,
|
||||
code: 'INTERNAL_ERROR',
|
||||
message: 'Une erreur est survenue. Veuillez réessayer dans quelques instants.',
|
||||
},
|
||||
500
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default sujets
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue