본문으로 건너뛰기

Illustration

AI 시각 자산 (SVG) — prompt builder + SVG 보안 정화 (script/iframe/external image 차단)

상태

항목
Layerdomain
TierL1
Statuswip
Version0.9.0
가격Free (free)
**카�
�고리**Content

개요

개요

Illustration 은 multi-saas-kit 의 Layer 3 Domain Plugin � 니다. 학습 콘� �츠에 임베드할 SVG 일러스트를 LLM 으로 생성하기 위한 표준 prompt builder + 안전성 검증 sanitizer 를 제공합니다.

LLM 호출 부분은 AiRelay plugin 에 위임 — 본 plugin 은 prompt 구성과 결과 검증 의 Pure 부분만 담당.

핵심 컴포넌트 (3 + 2 enums)

Enums (2�

)

EnumCases메서드
IllustrationKindCARTOON / PHOTO / DIAGRAM / ICONvisualHint()
StylePresetFLAT / CARTOON / LINE / HAND_DRAWNstyleHint()

Kind/Style 별 시각 묘사 hint 자동 생성 — prompt 에 자동 삽� .

PromptBuilder (Pure)

academy.how IllustrationGenerator::buildPrompt 추출.

� 력: caption + kind + style + locale 출력: LLM 에 전달할 SVG 생성 prompt 문자열.

Prompt 에 자동 포함:

  • Kind / Style 시각 hint
  • viewBox (config 으로 변경 가능, default 0 0 480 320)
  • Locale → <title> screen-reader 언어 매핑 (en/ja/zh/zh-TW/ko)
  • 보안 제약 (script/event handler/external image 금지)
  • 크기 제약 (60 lines / 8KB)

SvgSanitizer (Pure)

LLM 이 생성한 SVG 의 안전성 + 형식 검증.

자동 처리:

  • Markdown code fence 자동 제거 (```svg ... ```, ```xml ... ```, ``` ... ```)
  • <svg> 시작 + </svg> 끝 검증

보안 차단:

  • 위험 태그: script, foreignObject, iframe, object, embed
  • 이벤트 핸들러: onclick, onload, onmouseover, onerror
  • External image (<image href="https://...">)

크기 제약:

  • max_size_bytes: 8192 (default)
  • max_lines: 60 (default)

결과 shape:

{
ok: bool,
svg: ?string, // ok=true 시에만 sanitized SVG
issues: ['forbidden_tag_script', 'size_exceeds_8192', ...],
size_bytes: int,
line_count: int,
}

Issue code 는 i18n 가능 — 호출자가 사용자에게 구체적 거부 사유 표시.

설정 (config/illustration.php)

return [
'enabled' => env('PLG_ILLUSTRATION_ENABLED', true),
'svg' => [
'max_size_bytes' => 8192,
'max_lines' => 60,
'view_box' => '0 0 480 320',
],
'forbidden' => [
'tags' => ['script', 'foreignObject', 'iframe', 'object', 'embed'],
'event_handlers' => ['onclick', 'onload', 'onmouseover', 'onerror', 'onfocus', 'onblur'],
'block_external_images' => true,
],
'locale_to_title_lang' => [
'en' => 'English', 'ja' => 'Japanese',
'zh' => 'Chinese (Simplified)', 'zh-CN' => 'Chinese (Simplified)', 'zh-TW' => 'Chinese (Traditional)',
'ko' => 'Korean',
],
'default_title_lang' => 'Korean',
];

사용 예시

use App\Plugins\Illustration\Enums\{IllustrationKind, StylePreset};
use App\Plugins\Illustration\Services\{PromptBuilder, SvgSanitizer};
use App\Plugins\AiRelay\Services\LlmRelayClient;

// 1) Prompt 구성
$builder = PromptBuilder::fromConfig(config('illustration'));
$prompt = $builder->build(
caption: '햇살 아래 사과 한 개',
kind: IllustrationKind::CARTOON,
style: StylePreset::FLAT,
locale: app()->getLocale(),
);

// 2) AiRelay 로 LLM 호출
$llm = LlmRelayClient::fromConfig(config('ai-relay'));
$result = $llm->complete([
'model' => 'gpt-4o-mini',
'messages' => [['role' => 'user', 'content' => $prompt]],
]);

if ($result['status'] !== 'success') {
throw new \RuntimeException('LLM call failed');
}

// 3) SVG 검증
$sanitizer = SvgSanitizer::fromConfig(config('illustration'));
$sanitized = $sanitizer->sanitize($result['data']['text']);

if (! $sanitized['ok']) {
Log::warning('illustration_sanitize_failed', ['issues' => $sanitized['issues']]);
return null;
}

// 4) DB 저장 / 콘�
�츠에 임베드
$documentIllustration->svg_content = $sanitized['svg'];
$documentIllustration->save();

출처

academy.how 의 App\Modules\Content\Services\IllustrationGenerator (320줄) 에서 추출.

  • buildPrompt (50줄) → PromptBuilder::build()
  • kind 분기 → IllustrationKind enum + visualHint()
  • stylePreset 분기 → StylePreset enum + styleHint()
  • locale → titleLang 매핑 → config 기반 resolveTitleLang()
  • SVG 보안 검증 (academy 에 분산되어 있던 부분) → SvgSanitizer 표준화

LLM 호출 / DocumentIllustration Eloquent 저장 / AiRun 추적 부분은 프로젝트 � 임으로 분리.

의존성

  • DocumentProcessor — 생성된 SVG 를 Document 본문에 임베드
  • AiRelay (선택) — LLM 호출 표준 어댑터
  • AiTracking (Phase 2) — 생성 이력 / 재시도 / 실패 로그

다음 단계 (Phase 3+)

  • 표준 Illustration Model + Migration (선택 활성)
  • Filament Resource (운영자가 일러스트 검수)
  • Refine prompt builder (사용자 지시 + 첨부 이미지 기반 재생성)
  • 다중 provider 지원 (OpenAI / Claude / Gemini)
  • Caption → SVG 캐싱 (동일 caption 재사용)

라이선스

MIT

의존성

데모


🛒 Plugin Store에서 보기: store.codebase.how/plugins/illustration