AI 생성과 변경 제안
모델 응답을 검증 가능한 문서 변경으로 바꾸고, 검토·취소·충돌·undo까지 연결합니다.
reopt design업데이트
1. 제안 생성부터 적용까지
사용자 요청 → 문서·선택 범위 스냅샷 → 호스트 모델 호출 → json-render patch 파싱 → 변경 규칙 검증 → 변경 전후 미리보기 → 사용자 적용 순서로 진행합니다. 모델 응답을 받았다는 이유만으로 현재 문서를 저장하지 않습니다.
onAIEdit은 다음 문서 또는 SceneTransaction을 반환합니다. 편집기는 후보를 별도로 보여 주고, 적용할 때 시작 revision이 여전히 유효한지 확인합니다. 검토 중 다른 편집이 발생하면 오래된 후보를 적용할 수 없습니다.
2. 편집기에 AI 콜백 연결
AbortSignal은 fetch와 모델 요청까지 전달합니다. endpoint는 패키지에서 제공하지 않으며 앱에서 구현합니다. 실패 시 콜백에서 오류를 던지면 편집기가 오류 상태를 표시합니다. 인증·요금·모델 키는 서버에서 관리하세요.
"use client";
import { DeckEditor, type DeckAIRequest } from "@reopt-ai/opt-deck";
import { parseDeckDocument } from "@reopt-ai/opt-deck/server";
async function requestAI(request: DeckAIRequest) {
const { signal, ...payload } = request;
// /api/presentation-ai is an endpoint implemented by your host application.
const response = await fetch("/api/presentation-ai", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal,
});
if (!response.ok) throw new Error("Unable to create an AI proposal");
return parseDeckDocument(await response.json());
}
export function AIEditor() {
return <DeckEditor onAIEdit={requestAI} locale="ko" />;
}3. 모델 출력 검증
createDeckPrompts는 system 프롬프트(json-render 형식의 덱 카탈로그)와 현재 덱 Spec을 담은 user 프롬프트를 반환합니다. callModel은 사용하는 모델 SDK에 맞춰 호스트가 구현하는 함수입니다. parseDeckReply는 응답을 말과 RFC 6902 JSONL patch로 나누고, applyDeckPatches는 모드·선택 범위·잠금·revision을 검증해 되돌릴 수 있는 변경 하나로 적용합니다.
HTTP 요청 전체의 인증·권한·모드·선택 ID·크기 제한은 별도로 검증해야 합니다. 이 예제의 TypeScript 타입은 신뢰할 수 없는 HTTP 본문의 런타임 검증을 대신하지 않습니다.
import {
parseDeckDocument, createDeckPrompts, parseDeckReply, applyDeckPatches,
type DeckAIMode,
} from "@reopt-ai/opt-deck/server";
type Model = (input: {
system: string; prompt: string; signal: AbortSignal;
}) => Promise<string>;
// Call after host authentication, authorization and request validation.
export async function createProposal(input: {
document: unknown; selection: string[]; slideId: string;
mode: DeckAIMode; prompt: string;
}, signal: AbortSignal, callModel: Model) {
const document = parseDeckDocument(input.document);
const view = {
mode: input.mode,
slideId: input.slideId,
selection: input.mode === "generate" ? [] : input.selection,
};
// The deck catalog in json-render's prompt format, and the current spec.
const { system, user } = createDeckPrompts(document, {
...view, prompt: input.prompt,
});
const output = await callModel({ system, prompt: user, signal });
signal.throwIfAborted();
// Words, then RFC 6902 JSONL patches in a ```spec fence.
const { patches } = parseDeckReply(output);
return applyDeckPatches(document, patches, {
...view, baseRevision: document.revision,
});
}4. 모드와 허용 범위
- generate
- 선택 없이 덱 전체를 새 Spec(Deck → Slide, 항목은 props.items)으로 작성합니다. 기존 문서 위에 쓰면 그 문서의 브랜드와 크기를 유지합니다.
- rewrite
- 말만 바꿉니다. Slide의 title·subtitle·body, 항목(items)의 title·body·value, 노트, Text의 text만 허용합니다.
- layout
- 배치만 바꿉니다. Slide의 layout·tone·variant·composition, 객체의 위치·크기·회전, 슬라이드 순서, Deck의 design·brand·aspect를 허용합니다.
- edit
- 선택 범위 안에서 요소를 추가·교체·삭제하는 patch를 적용합니다. 선택이 있으면 해당 요소와 하위 요소 밖의 변경은 거절됩니다.
- Slide / Item
- 엔진이 배치하는 슬라이드입니다. props와 props.items로 바꾸며, 바뀐 슬라이드만 다시 배치합니다.
- FreeformSlide / objects
- 직접 만든 슬라이드입니다. Text·Shape·Image·Group·Chart·Table을 좌표로 바꾸고, animations로 객체의 등장 효과를 순서대로 정합니다. 잠긴 객체와 열려 있지 않은 슬라이드의 구조 변경은 거절됩니다.
| 항목 | 동작과 사용 기준 |
|---|---|
| generate | 선택 없이 덱 전체를 새 Spec(Deck → Slide, 항목은 props.items)으로 작성합니다. 기존 문서 위에 쓰면 그 문서의 브랜드와 크기를 유지합니다. |
| rewrite | 말만 바꿉니다. Slide의 title·subtitle·body, 항목(items)의 title·body·value, 노트, Text의 text만 허용합니다. |
| layout | 배치만 바꿉니다. Slide의 layout·tone·variant·composition, 객체의 위치·크기·회전, 슬라이드 순서, Deck의 design·brand·aspect를 허용합니다. |
| edit | 선택 범위 안에서 요소를 추가·교체·삭제하는 patch를 적용합니다. 선택이 있으면 해당 요소와 하위 요소 밖의 변경은 거절됩니다. |
| Slide / Item | 엔진이 배치하는 슬라이드입니다. props와 props.items로 바꾸며, 바뀐 슬라이드만 다시 배치합니다. |
| FreeformSlide / objects | 직접 만든 슬라이드입니다. Text·Shape·Image·Group·Chart·Table을 좌표로 바꾸고, animations로 객체의 등장 효과를 순서대로 정합니다. 잠긴 객체와 열려 있지 않은 슬라이드의 구조 변경은 거절됩니다. |
5. 취소·충돌·실패 처리
문서가 바뀌면 기존 요청을 취소하고 늦게 도착한 결과를 버리세요. 기본 편집기는 취소 신호와 후보 revision을 확인하지만, 별도 호스트 UI에서도 계정·프로젝트·문서 식별자를 기준으로 요청을 격리해야 합니다.
현재 Spec이 120,000자를 넘으면 슬라이드를 선택하도록 오류를 냅니다. 2,000,000자를 넘는 응답은 거절합니다. 서버는 모델 비용과 응답 크기에 맞는 더 좁은 제한을 둘 수 있습니다. 모의 응답과 실제 모델 검증은 구분하세요.
6. 디자인 품질 검토
스키마 검증 통과는 내용의 사실성이나 디자인 품질의 보증이 아닙니다. 숫자·고객명·출처, 긴 문구의 넘침, 글꼴·브랜드 일관성, 의도하지 않은 요소 삭제를 확인한 뒤 적용합니다.
편집기는 런타임이 준비된 경우 후보 문서에 텍스트 맞춤 보정을 수행합니다. 실제 문구와 글꼴로 결과를 확인하고, 최종 출력 파일도 별도로 검수하세요.