fix: slide 3 noire, watermark PPTX, quota génération slides
Some checks failed
CI / Lint, Unit Tests & Build (push) Successful in 5m44s
CI / Deploy production (on server) (push) Failing after 17s

- canvas-board.tsx: préfère data.html (iframe) sur data.spec (ancien renderer)
  → corrige slide 3 noire en mode HTML viewer
- pptx/route.ts: ajoute watermark 'memento-note.com' sur chaque slide
  via buildPptx (PPTX téléchargé depuis le canvas)
- run-for-note/route.ts: checkEntitlementOrThrow avant création agent
- slides.tool.ts: incrementUsageAsync après canvas créé avec succès

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Antigravity
2026-05-29 11:58:31 +00:00
parent 45fd501953
commit 9e23c078e9
4 changed files with 28 additions and 5 deletions

View File

@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server'
import { auth } from '@/auth'
import { prisma } from '@/lib/prisma'
import { checkEntitlementOrThrow, QuotaExceededError, incrementUsageAsync } from '@/lib/entitlements'
type GenerateType = 'slide-generator' | 'excalidraw-generator'
@@ -43,6 +44,16 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: 'Paramètres invalides' }, { status: 400 })
}
// Quota check — slides/excalidraw generation counts as 'reformulate' credit
try {
await checkEntitlementOrThrow(userId, 'reformulate')
} catch (e) {
if (e instanceof QuotaExceededError) {
return NextResponse.json({ error: e.message }, { status: 402 })
}
throw e
}
const note = await prisma.note.findFirst({
where: { id: noteId, userId },
select: { id: true, title: true, notebookId: true },

View File

@@ -43,6 +43,12 @@ async function buildPptx(spec: any): Promise<Buffer> {
for (const slide of (spec.slides ?? [])) {
const s = pptx.addSlide()
// PLG watermark — bottom-right corner of LAYOUT_WIDE (13.33"×7.5")
s.addText('memento-note.com', {
x: 10.0, y: 7.1, w: 3.0, h: 0.25,
fontSize: 7, fontFace: 'Arial', color: 'B8B0A8',
align: 'right', italic: true,
})
switch (slide.type) {
case 'title': {

View File

@@ -218,11 +218,10 @@ function SlidesViewer({ data, name, canvasId }: { data: SlidesPayload; name: str
</button>
</div>
</div>
{/* Slides: React renderer (legacy spec) or iframe (new HTML) */}
{/* Slides: iframe (new HTML format) preferred over legacy React renderer */}
<div className="flex-1 relative overflow-hidden group">
{data.spec ? (
<SlidesRenderer spec={data.spec} />
) : (
{data.html ? (
// New format: standalone animated HTML served via srcDoc
<>
{/* Loading overlay — visible until iframe fires onLoad */}
{!isLoaded && (
@@ -257,7 +256,10 @@ function SlidesViewer({ data, name, canvasId }: { data: SlidesPayload; name: str
<ChevronRight className="w-5 h-5" />
</button>
</>
)}
) : data.spec ? (
// Legacy format: old React renderer (recharts)
<SlidesRenderer spec={data.spec} />
) : null}
</div>
</div>
)

View File

@@ -5,6 +5,7 @@ import { z } from 'zod'
import { toolRegistry } from './registry'
import { prisma } from '@/lib/prisma'
import { buildPresentationHTML } from './slides-html-builder'
import { incrementUsageAsync } from '@/lib/entitlements'
const slideSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('title'), title: z.string(), subtitle: z.string().optional() }),
@@ -80,6 +81,9 @@ RULES:
console.log('[Slides Tool] Canvas created:', canvas.id, '| Slides:', slides.length, '| Size:', Math.round(html.length / 1024), 'KB')
// Decrement reformulate quota (agent-based generation consumes credits)
incrementUsageAsync(ctx.userId, 'reformulate')
if (ctx.actionId) {
await prisma.agentAction.update({
where: { id: ctx.actionId },