#가이드 #NSFW 코어 파일 문서 설정 문서 운영 설치 문서
T2Editor 9.1.0의 NSFW 필터는 브라우저 모드를 기준으로 설계되어 있으며, 내부 엔진은 NSFWJS + TensorFlow.js 조합을 사용합니다. 모델은 기본적으로 MobileNetV2Mid를 사용하고, 런타임 자산은 CDN이 아니라 vendor/ 아래의 자체 호스팅 경로에서 읽도록 구성할 수 있습니다.
이 문서는 T2Editor 9.1.0에서 NSFWJS 관련 구조가 어떻게 바뀌었는지, 그리고 어떤 파일이 어떤 책임을 가지는지 한 번에 이해하기 위한 안내서입니다.
기존 구조에서는 브라우저 NSFW 코드가 자체 추론 로직과 워커 처리 중심으로 설명될 수 있었지만, 9.1.0에서는 다음 원칙으로 재정리되었습니다.
NSFWJSMobileNetV2Midwebgpu -> webgl -> wasm -> cpu 순서 폴백이 구조를 아주 간단히 보면 아래와 같습니다.
| 단계 | 설명 |
|---|---|
| 1 | 사용자가 이미지 업로드 모달에서 파일을 고릅니다. |
| 2 | image.js가 브라우저 NSFW API를 불러옵니다. |
| 3 | nsfw_api_browser.js가 NSFWJS 모델을 로드합니다. |
| 4 | 업로드 전 각 이미지가 safe / suspect / unsafe / error 중 하나로 분류됩니다. |
| 5 | 결과가 기존 미리보기 카드와 상태바에 반영됩니다. |
| 6 | 정책에 따라 업로드 허용, 경고 후 허용, 업로드 취소가 결정됩니다. |
즉, NSFWJS는 보이는 UI를 담당하지 않고 분류 엔진만 담당합니다. 사용자가 실제로 보는 경고 배지, 상태바, 경고 모달은 T2Editor의 기존 이미지 플러그인이 담당합니다.
가장 큰 이유는 아래 세 가지입니다.
texteditor.lib.php └─ window.T2EDITOR_NSFW_* 전역 설정 주입 └─ plugin/image/image.js ├─ getNSFWApi() │ └─ import(config/nsfw_api_browser.js) ├─ checkNSFW(file) │ └─ api.classify(file) ├─ resolveNSFWResult(imageData) └─ applyNSFWFilter(imageDataArray) └─ 업로드 허용/경고/차단 결정
| 파일 | 책임 |
|---|---|
editor.lib.php | NSFW 관련 설정 상수를 JS 전역 값으로 주입합니다. |
config/nsfw_api_browser.js | NSFWJS 모델 로딩, 백엔드 선택, 이미지 분류를 담당합니다. |
plugin/image/image.js | 업로드 모달, 상태 배지, 경고 모달, 업로드 정책 적용을 담당합니다. |
plugin/image/image.css | 상태 배지, 상태바, 경고 표시의 시각 스타일을 담당합니다. |
9.1.0의 브라우저 NSFW 결과는 단순히 safe / nsfw 두 단계가 아니라 아래처럼 다룹니다.
| 라벨 | 의미 | 기본 처리 |
|---|---|---|
safe | 업로드 가능으로 판단 | 그대로 허용 |
suspect | 애매하거나 주의가 필요한 상태 | 설정에 따라 경고 후 허용 또는 차단 |
unsafe | 고위험 이미지로 판단 | 설정에 따라 차단 또는 경고 후 허용 |
error | 모델 로딩 또는 추론 실패 | 오류 표시 후 정책에 따라 계속 진행 |
이 라벨 체계 때문에 문서와 코드에서 의심 이미지와 명확한 위험 이미지를 구분해서 다뤄야 합니다.
기본 우선순위는 다음과 같습니다.
textwebgpu -> webgl -> wasm -> cpu
webgpu: 가장 먼저 시도하는 가속 백엔드webgl: 대부분의 브라우저에서 현실적인 폴백wasm: GPU가 어렵거나 제한될 때 사용 가능한 안전한 폴백cpu: 마지막 안전망이 순서는 editor.lib.php에서 전역 설정으로 넘길 수 있고, nsfw_api_browser.js가 실제 선택을 수행합니다.
운영에서는 아래 같은 구조를 권장합니다.
text/plugin/editor/t2editor/vendor/ tfjs/ tfjs-backend-webgl/ tfjs-backend-webgpu/ tfjs-backend-wasm/ nsfwjs/ nsfwjs/models/mobilenet_v2_mid/
이렇게 하면 외부 CDN 장애나 차단의 영향을 줄이고, 배포 경로를 서비스 내부에서 통제할 수 있습니다.
9.1.0에서 NSFWJS 관련 핵심 변화는 아래와 같습니다.
MobileNetV2Mid 모델 도입suspect 상태를 별도 정책 대상으로 추가처음 보는 사람은 guide-nsfwjs-overview → config-nsfwjs-runtime-settings → ops-nsfwjs-selfhost-webgpu-ubuntu 순서로 읽는 편이 좋습니다. 코드를 직접 수정할 사람은 core-nsfw_api_browser-js를 이어서 읽는 것이 안전합니다.
아닙니다. 이 구조에서는 NSFWJS가 분류 엔진만 담당하고, 배지·모달·상태바는 기존 T2Editor 이미지 플러그인이 담당합니다.
완전히 삭제된 것은 아닐 수 있지만, 9.1.0의 권장 경로는 브라우저 모드입니다. 문서와 운영 기본값도 브라우저 모드를 기준으로 작성하는 것이 맞습니다.
T2Editor 9.1.0의 NSFW 필터는 브라우저 모드를 기준으로 설계되어 있으며, 내부 엔진은 NSFWJS + TensorFlow.js 조합을 사용합니다. 모델은 기본적으로 MobileNetV2Mid를 사용하고, 런타임 자산은 CDN이 아니라 vendor/ 아래의 자체 호스팅 경로에서 읽도록 구성할 수 있습니다.
이 문서는 T2Editor 9.1.0에서 NSFWJS 관련 구조가 어떻게 바뀌었는지, 그리고 어떤 파일이 어떤 책임을 가지는지 한 번에 이해하기 위한 안내서입니다.
기존 구조에서는 브라우저 NSFW 코드가 자체 추론 로직과 워커 처리 중심으로 설명될 수 있었지만, 9.1.0에서는 다음 원칙으로 재정리되었습니다.
NSFWJSMobileNetV2Midwebgpu -> webgl -> wasm -> cpu 순서 폴백이 구조를 아주 간단히 보면 아래와 같습니다.
| 단계 | 설명 |
|---|---|
| 1 | 사용자가 이미지 업로드 모달에서 파일을 고릅니다. |
| 2 | image.js가 브라우저 NSFW API를 불러옵니다. |
| 3 | nsfw_api_browser.js가 NSFWJS 모델을 로드합니다. |
| 4 | 업로드 전 각 이미지가 safe / suspect / unsafe / error 중 하나로 분류됩니다. |
| 5 | 결과가 기존 미리보기 카드와 상태바에 반영됩니다. |
| 6 | 정책에 따라 업로드 허용, 경고 후 허용, 업로드 취소가 결정됩니다. |
즉, NSFWJS는 보이는 UI를 담당하지 않고 분류 엔진만 담당합니다. 사용자가 실제로 보는 경고 배지, 상태바, 경고 모달은 T2Editor의 기존 이미지 플러그인이 담당합니다.
가장 큰 이유는 아래 세 가지입니다.
texteditor.lib.php └─ window.T2EDITOR_NSFW_* 전역 설정 주입 └─ plugin/image/image.js ├─ getNSFWApi() │ └─ import(config/nsfw_api_browser.js) ├─ checkNSFW(file) │ └─ api.classify(file) ├─ resolveNSFWResult(imageData) └─ applyNSFWFilter(imageDataArray) └─ 업로드 허용/경고/차단 결정
| 파일 | 책임 |
|---|---|
editor.lib.php | NSFW 관련 설정 상수를 JS 전역 값으로 주입합니다. |
config/nsfw_api_browser.js | NSFWJS 모델 로딩, 백엔드 선택, 이미지 분류를 담당합니다. |
plugin/image/image.js | 업로드 모달, 상태 배지, 경고 모달, 업로드 정책 적용을 담당합니다. |
plugin/image/image.css | 상태 배지, 상태바, 경고 표시의 시각 스타일을 담당합니다. |
9.1.0의 브라우저 NSFW 결과는 단순히 safe / nsfw 두 단계가 아니라 아래처럼 다룹니다.
| 라벨 | 의미 | 기본 처리 |
|---|---|---|
safe | 업로드 가능으로 판단 | 그대로 허용 |
suspect | 애매하거나 주의가 필요한 상태 | 설정에 따라 경고 후 허용 또는 차단 |
unsafe | 고위험 이미지로 판단 | 설정에 따라 차단 또는 경고 후 허용 |
error | 모델 로딩 또는 추론 실패 | 오류 표시 후 정책에 따라 계속 진행 |
이 라벨 체계 때문에 문서와 코드에서 의심 이미지와 명확한 위험 이미지를 구분해서 다뤄야 합니다.
기본 우선순위는 다음과 같습니다.
textwebgpu -> webgl -> wasm -> cpu
webgpu: 가장 먼저 시도하는 가속 백엔드webgl: 대부분의 브라우저에서 현실적인 폴백wasm: GPU가 어렵거나 제한될 때 사용 가능한 안전한 폴백cpu: 마지막 안전망이 순서는 editor.lib.php에서 전역 설정으로 넘길 수 있고, nsfw_api_browser.js가 실제 선택을 수행합니다.
운영에서는 아래 같은 구조를 권장합니다.
text/plugin/editor/t2editor/vendor/ tfjs/ tfjs-backend-webgl/ tfjs-backend-webgpu/ tfjs-backend-wasm/ nsfwjs/ nsfwjs/models/mobilenet_v2_mid/
이렇게 하면 외부 CDN 장애나 차단의 영향을 줄이고, 배포 경로를 서비스 내부에서 통제할 수 있습니다.
9.1.0에서 NSFWJS 관련 핵심 변화는 아래와 같습니다.
MobileNetV2Mid 모델 도입suspect 상태를 별도 정책 대상으로 추가아닙니다. 이 구조에서는 NSFWJS가 분류 엔진만 담당하고, 배지·모달·상태바는 기존 T2Editor 이미지 플러그인이 담당합니다.
완전히 삭제된 것은 아닐 수 있지만, 9.1.0의 권장 경로는 브라우저 모드입니다. 문서와 운영 기본값도 브라우저 모드를 기준으로 작성하는 것이 맞습니다.
| 이전 | 새 버전 | ||
|---|---|---|---|
| 1 | --- | 1 | --- |
| 2 | title: 가이드: NSFWJS 기반 이미지 필터 개요 | 2 | title: 가이드: NSFWJS 기반 이미지 필터 개요 |
| 3 | document_id: guide-nsfwjs-overview | 3 | document_id: guide-nsfwjs-overview |
| 4 | slug: guide-nsfwjs-overview | 4 | slug: guide-nsfwjs-overview |
| 5 | target_editor_version: 9.1.0 | 5 | target_editor_version: 9.1.0 |
| 6 | document_type: guide | 6 | document_type: guide |
| 7 | doc_type: guide | 7 | doc_type: guide |
| 8 | target_readers: [초보자, 웹마스터, 개발자, AI agent] | 8 | target_readers: [초보자, 웹마스터, 개발자, AI agent] |
| 9 | importance: High | 9 | importance: High |
| 10 | dependency: High | 10 | dependency: High |
| 11 | core_type: Guide | 11 | core_type: Guide |
| 12 | stability: [Stable Anchor, Version-Bound] | 12 | stability: [Stable Anchor, Version-Bound] |
| 13 | stable_anchor: [브라우저 우선 구조, 이미지 플러그인 연동, 결과 라벨 체계] | 13 | stable_anchor: [브라우저 우선 구조, 이미지 플러그인 연동, 결과 라벨 체계] |
| 14 | version_bound: [window 전역 설정 키, 백엔드 우선순위 기본값, self-hosted vendor 경로] | 14 | version_bound: [window 전역 설정 키, 백엔드 우선순위 기본값, self-hosted vendor 경로] |
| 15 | related_docs: | 15 | related_docs: |
| 16 | - core-nsfw_api_browser-js | 16 | - core-nsfw_api_browser-js |
| 17 | - config-nsfwjs-runtime-settings | 17 | - config-nsfwjs-runtime-settings |
| 18 | - ops-nsfwjs-selfhost-webgpu-ubuntu | 18 | - ops-nsfwjs-selfhost-webgpu-ubuntu |
| 19 | - migration-legacy-nsfw-to-nsfwjs | 19 | - migration-legacy-nsfw-to-nsfwjs |
| 20 | related_files: | 20 | related_files: |
| 21 | - 9.1.0/t2editor/config/nsfw_api_browser.js | 21 | - 9.1.0/t2editor/config/nsfw_api_browser.js |
| 22 | - 9.1.0/t2editor/plugin/image/image.js | 22 | - 9.1.0/t2editor/plugin/image/image.js |
| 23 | - 9.1.0/t2editor/editor.lib.php | 23 | - 9.1.0/t2editor/editor.lib.php |
| 24 | related_functions: | 24 | related_functions: |
| 25 | - load | 25 | - load |
| 26 | - classify | 26 | - classify |
| 27 | - checkNSFW | 27 | - checkNSFW |
| 28 | - applyNSFWFilter | 28 | - applyNSFWFilter |
| 29 | related_classes_modules: | 29 | related_classes_modules: |
| 30 | - NSFWFilterAPI | 30 | - NSFWFilterAPI |
| 31 | - ImagePlugin | 31 | - ImagePlugin |
| 32 | related_features: | 32 | related_features: |
| 33 | - 브라우저 NSFW 검사 | 33 | - 브라우저 NSFW 검사 |
| 34 | - self-hosted 모델 로딩 | 34 | - self-hosted 모델 로딩 |
| 35 | - WebGPU 우선 백엔드 선택 | 35 | - WebGPU 우선 백엔드 선택 |
| 36 | - 이미지 업로드 경고 처리 | 36 | - 이미지 업로드 경고 처리 |
| 37 | related_ui: | 37 | related_ui: |
| 38 | - 이미지 업로드 모달 | 38 | - 이미지 업로드 모달 |
| 39 | - 미리보기 카드 상태 배지 | 39 | - 미리보기 카드 상태 배지 |
| 40 | - NSFW 상태바 | 40 | - NSFW 상태바 |
| 41 | change_risk: 판정 기준과 로딩 경로를 동시에 변경하면 업로드 UX, 성능, 운영 배포 경로가 함께 영향을 받습니다. | 41 | change_risk: 판정 기준과 로딩 경로를 동시에 변경하면 업로드 UX, 성능, 운영 배포 경로가 함께 영향을 받습니다. |
| 42 | reading_order: 18 | 42 | reading_order: 18 |
| 43 | summary: T2Editor 9.1.0에서 NSFWJS 기반 브라우저 이미지 필터가 어떤 구조로 동작하는지 설명합니다. | 43 | summary: T2Editor 9.1.0에서 NSFWJS 기반 브라우저 이미지 필터가 어떤 구조로 동작하는지 설명합니다. |
| 44 | description: 자체 추론 로직에서 NSFWJS MobileNetV2Mid 기반 구조로 전환된 배경과 파일 간 호출 흐름을 정리한 문서입니다. | 44 | description: 자체 추론 로직에서 NSFWJS MobileNetV2Mid 기반 구조로 전환된 배경과 파일 간 호출 흐름을 정리한 문서입니다. |
| 45 | tags: [NSFWJS, browser-nsfw, self-hosted, webgpu, T2Editor, guide] | 45 | tags: [NSFWJS, browser-nsfw, self-hosted, webgpu, T2Editor, guide] |
| 46 | version_tag: 9.1.0 | 46 | version_tag: 9.1.0 |
| 47 | maintenance_difficulty: Medium | 47 | maintenance_difficulty: Medium |
| 48 | test_requirement: High | 48 | test_requirement: High |
| 49 | ai_agent_risk: Medium | 49 | ai_agent_risk: Medium |
| 50 | source_basis: [현재 코드 분석 기반] | 50 | source_basis: [현재 코드 분석 기반] |
| 51 | beginner_section_included: true | 51 | beginner_section_included: true |
| 52 | webmaster_section_included: true | 52 | webmaster_section_included: true |
| 53 | developer_section_included: true | 53 | developer_section_included: true |
| 54 | --- | 54 | --- |
| 55 | 55 | ||
| 56 | [목차] | 56 | [목차] |
| 57 | 57 | ||
| 58 | [[분류:가이드]] | 58 | [[분류:가이드]] |
| 59 | [[분류:NSFW]] | 59 | [[분류:NSFW]] |
| 60 | [[core-nsfw_api_browser-js|코어 파일 문서]] | ||
| 61 | [[config-nsfwjs-runtime-settings|설정 문서]] | ||
| 62 | [[ops-nsfwjs-selfhost-webgpu-ubuntu|운영 설치 문서]] | ||
| 63 | 60 | ||
| 64 | [note(요약)] | 61 | [note(요약)] |
| 65 | T2Editor 9.1.0의 NSFW 필터는 **브라우저 모드**를 기준으로 설계되어 있으며, 내부 엔진은 **NSFWJS + TensorFlow.js** 조합을 사용합니다. | 62 | T2Editor 9.1.0의 NSFW 필터는 **브라우저 모드**를 기준으로 설계되어 있으며, 내부 엔진은 **NSFWJS + TensorFlow.js** 조합을 사용합니다. |
| 66 | 모델은 기본적으로 `MobileNetV2Mid`를 사용하고, 런타임 자산은 CDN이 아니라 `vendor/` 아래의 **자체 호스팅 경로**에서 읽도록 구성할 수 있습니다. | 63 | 모델은 기본적으로 `MobileNetV2Mid`를 사용하고, 런타임 자산은 CDN이 아니라 `vendor/` 아래의 **자체 호스팅 경로**에서 읽도록 구성할 수 있습니다. |
| 67 | [/note] | 64 | [/note] |
| 68 | 65 | ||
| 69 | # 파일 개요 | 66 | # 파일 개요 |
| 70 | 67 | ||
| 71 | 이 문서는 T2Editor 9.1.0에서 NSFWJS 관련 구조가 어떻게 바뀌었는지, 그리고 어떤 파일이 어떤 책임을 가지는지 한 번에 이해하기 위한 안내서입니다. | 68 | 이 문서는 T2Editor 9.1.0에서 NSFWJS 관련 구조가 어떻게 바뀌었는지, 그리고 어떤 파일이 어떤 책임을 가지는지 한 번에 이해하기 위한 안내서입니다. |
| 72 | 69 | ||
| 73 | 기존 구조에서는 브라우저 NSFW 코드가 자체 추론 로직과 워커 처리 중심으로 설명될 수 있었지만, 9.1.0에서는 다음 원칙으로 재정리되었습니다. | 70 | 기존 구조에서는 브라우저 NSFW 코드가 자체 추론 로직과 워커 처리 중심으로 설명될 수 있었지만, 9.1.0에서는 다음 원칙으로 재정리되었습니다. |
| 74 | 71 | ||
| 75 | - **엔진 교체**: 자체 브라우저 추론 로직 → `NSFWJS` | 72 | - **엔진 교체**: 자체 브라우저 추론 로직 → `NSFWJS` |
| 76 | - **기본 모델 교체**: 커스텀 분류 흐름 → `MobileNetV2Mid` | 73 | - **기본 모델 교체**: 커스텀 분류 흐름 → `MobileNetV2Mid` |
| 77 | - **UI 유지**: NSFWJS 자체 UI를 쓰지 않고 기존 이미지 업로드 UI에 결과만 연결 | 74 | - **UI 유지**: NSFWJS 자체 UI를 쓰지 않고 기존 이미지 업로드 UI에 결과만 연결 |
| 78 | - **운영 방식 변경**: CDN 의존 대신 self-hosted vendor 구조 지원 | 75 | - **운영 방식 변경**: CDN 의존 대신 self-hosted vendor 구조 지원 |
| 79 | - **성능 전략 변경**: `webgpu -> webgl -> wasm -> cpu` 순서 폴백 | 76 | - **성능 전략 변경**: `webgpu -> webgl -> wasm -> cpu` 순서 폴백 |
| 80 | 77 | ||
| 81 | ## 초보자와 웹마스터를 위한 이해 | 78 | ## 초보자와 웹마스터를 위한 이해 |
| 82 | 79 | ||
| 83 | 이 구조를 아주 간단히 보면 아래와 같습니다. | 80 | 이 구조를 아주 간단히 보면 아래와 같습니다. |
| 84 | 81 | ||
| 85 | ||= 단계 ||= 설명 || | 82 | ||= 단계 ||= 설명 || |
| 86 | || 1 || 사용자가 이미지 업로드 모달에서 파일을 고릅니다. || | 83 | || 1 || 사용자가 이미지 업로드 모달에서 파일을 고릅니다. || |
| 87 | || 2 || `image.js`가 브라우저 NSFW API를 불러옵니다. || | 84 | || 2 || `image.js`가 브라우저 NSFW API를 불러옵니다. || |
| 88 | || 3 || `nsfw_api_browser.js`가 NSFWJS 모델을 로드합니다. || | 85 | || 3 || `nsfw_api_browser.js`가 NSFWJS 모델을 로드합니다. || |
| 89 | || 4 || 업로드 전 각 이미지가 `safe / suspect / unsafe / error` 중 하나로 분류됩니다. || | 86 | || 4 || 업로드 전 각 이미지가 `safe / suspect / unsafe / error` 중 하나로 분류됩니다. || |
| 90 | || 5 || 결과가 기존 미리보기 카드와 상태바에 반영됩니다. || | 87 | || 5 || 결과가 기존 미리보기 카드와 상태바에 반영됩니다. || |
| 91 | || 6 || 정책에 따라 업로드 허용, 경고 후 허용, 업로드 취소가 결정됩니다. || | 88 | || 6 || 정책에 따라 업로드 허용, 경고 후 허용, 업로드 취소가 결정됩니다. || |
| 92 | 89 | ||
| 93 | 즉, **NSFWJS는 보이는 UI를 담당하지 않고 분류 엔진만 담당**합니다. | 90 | 즉, **NSFWJS는 보이는 UI를 담당하지 않고 분류 엔진만 담당**합니다. |
| 94 | 사용자가 실제로 보는 경고 배지, 상태바, 경고 모달은 T2Editor의 기존 이미지 플러그인이 담당합니다. | 91 | 사용자가 실제로 보는 경고 배지, 상태바, 경고 모달은 T2Editor의 기존 이미지 플러그인이 담당합니다. |
| 95 | 92 | ||
| 96 | ### 왜 이렇게 바뀌었나요? | 93 | ### 왜 이렇게 바뀌었나요? |
| 97 | 94 | ||
| 98 | 가장 큰 이유는 아래 세 가지입니다. | 95 | 가장 큰 이유는 아래 세 가지입니다. |
| 99 | 96 | ||
| 100 | - 브라우저 추론 엔진을 유지보수하기 쉽게 만들기 위해 | 97 | - 브라우저 추론 엔진을 유지보수하기 쉽게 만들기 위해 |
| 101 | - 기존 UI를 버리지 않고 필터 성능과 구조를 개선하기 위해 | 98 | - 기존 UI를 버리지 않고 필터 성능과 구조를 개선하기 위해 |
| 102 | - 서버 부하를 늘리지 않으면서 클라이언트 하드웨어를 활용하기 위해 | 99 | - 서버 부하를 늘리지 않으면서 클라이언트 하드웨어를 활용하기 위해 |
| 103 | 100 | ||
| 104 | ## 전문 개발자를 위한 분석 | 101 | ## 전문 개발자를 위한 분석 |
| 105 | 102 | ||
| 106 | ## 전체 호출 흐름 | 103 | ## 전체 호출 흐름 |
| 107 | 104 | ||
| 108 | ```text | 105 | ```text |
| 109 | editor.lib.php | 106 | editor.lib.php |
| 110 | └─ window.T2EDITOR_NSFW_* 전역 설정 주입 | 107 | └─ window.T2EDITOR_NSFW_* 전역 설정 주입 |
| 111 | └─ plugin/image/image.js | 108 | └─ plugin/image/image.js |
| 112 | ├─ getNSFWApi() | 109 | ├─ getNSFWApi() |
| 113 | │ └─ import(config/nsfw_api_browser.js) | 110 | │ └─ import(config/nsfw_api_browser.js) |
| 114 | ├─ checkNSFW(file) | 111 | ├─ checkNSFW(file) |
| 115 | │ └─ api.classify(file) | 112 | │ └─ api.classify(file) |
| 116 | ├─ resolveNSFWResult(imageData) | 113 | ├─ resolveNSFWResult(imageData) |
| 117 | └─ applyNSFWFilter(imageDataArray) | 114 | └─ applyNSFWFilter(imageDataArray) |
| 118 | └─ 업로드 허용/경고/차단 결정 | 115 | └─ 업로드 허용/경고/차단 결정 |
| 119 | ``` | 116 | ``` |
| 120 | 117 | ||
| 121 | ### 핵심 파일별 책임 | 118 | ### 핵심 파일별 책임 |
| 122 | 119 | ||
| 123 | ||= 파일 ||= 책임 || | 120 | ||= 파일 ||= 책임 || |
| 124 | || `editor.lib.php` || NSFW 관련 설정 상수를 JS 전역 값으로 주입합니다. || | 121 | || `editor.lib.php` || NSFW 관련 설정 상수를 JS 전역 값으로 주입합니다. || |
| 125 | || `config/nsfw_api_browser.js` || NSFWJS 모델 로딩, 백엔드 선택, 이미지 분류를 담당합니다. || | 122 | || `config/nsfw_api_browser.js` || NSFWJS 모델 로딩, 백엔드 선택, 이미지 분류를 담당합니다. || |
| 126 | || `plugin/image/image.js` || 업로드 모달, 상태 배지, 경고 모달, 업로드 정책 적용을 담당합니다. || | 123 | || `plugin/image/image.js` || 업로드 모달, 상태 배지, 경고 모달, 업로드 정책 적용을 담당합니다. || |
| 127 | || `plugin/image/image.css` || 상태 배지, 상태바, 경고 표시의 시각 스타일을 담당합니다. || | 124 | || `plugin/image/image.css` || 상태 배지, 상태바, 경고 표시의 시각 스타일을 담당합니다. || |
| 128 | 125 | ||
| 129 | ## 결과 라벨 체계 | 126 | ## 결과 라벨 체계 |
| 130 | 127 | ||
| 131 | 9.1.0의 브라우저 NSFW 결과는 단순히 `safe / nsfw` 두 단계가 아니라 아래처럼 다룹니다. | 128 | 9.1.0의 브라우저 NSFW 결과는 단순히 `safe / nsfw` 두 단계가 아니라 아래처럼 다룹니다. |
| 132 | 129 | ||
| 133 | ||= 라벨 ||= 의미 ||= 기본 처리 || | 130 | ||= 라벨 ||= 의미 ||= 기본 처리 || |
| 134 | || `safe` || 업로드 가능으로 판단 || 그대로 허용 || | 131 | || `safe` || 업로드 가능으로 판단 || 그대로 허용 || |
| 135 | || `suspect` || 애매하거나 주의가 필요한 상태 || 설정에 따라 경고 후 허용 또는 차단 || | 132 | || `suspect` || 애매하거나 주의가 필요한 상태 || 설정에 따라 경고 후 허용 또는 차단 || |
| 136 | || `unsafe` || 고위험 이미지로 판단 || 설정에 따라 차단 또는 경고 후 허용 || | 133 | || `unsafe` || 고위험 이미지로 판단 || 설정에 따라 차단 또는 경고 후 허용 || |
| 137 | || `error` || 모델 로딩 또는 추론 실패 || 오류 표시 후 정책에 따라 계속 진행 || | 134 | || `error` || 모델 로딩 또는 추론 실패 || 오류 표시 후 정책에 따라 계속 진행 || |
| 138 | 135 | ||
| 139 | 이 라벨 체계 때문에 문서와 코드에서 **의심 이미지**와 **명확한 위험 이미지**를 구분해서 다뤄야 합니다. | 136 | 이 라벨 체계 때문에 문서와 코드에서 **의심 이미지**와 **명확한 위험 이미지**를 구분해서 다뤄야 합니다. |
| 140 | 137 | ||
| 141 | ## 성능 구조 | 138 | ## 성능 구조 |
| 142 | 139 | ||
| 143 | ### 백엔드 우선순위 | 140 | ### 백엔드 우선순위 |
| 144 | 141 | ||
| 145 | 기본 우선순위는 다음과 같습니다. | 142 | 기본 우선순위는 다음과 같습니다. |
| 146 | 143 | ||
| 147 | ```text | 144 | ```text |
| 148 | webgpu -> webgl -> wasm -> cpu | 145 | webgpu -> webgl -> wasm -> cpu |
| 149 | ``` | 146 | ``` |
| 150 | 147 | ||
| 151 | - `webgpu`: 가장 먼저 시도하는 가속 백엔드 | 148 | - `webgpu`: 가장 먼저 시도하는 가속 백엔드 |
| 152 | - `webgl`: 대부분의 브라우저에서 현실적인 폴백 | 149 | - `webgl`: 대부분의 브라우저에서 현실적인 폴백 |
| 153 | - `wasm`: GPU가 어렵거나 제한될 때 사용 가능한 안전한 폴백 | 150 | - `wasm`: GPU가 어렵거나 제한될 때 사용 가능한 안전한 폴백 |
| 154 | - `cpu`: 마지막 안전망 | 151 | - `cpu`: 마지막 안전망 |
| 155 | 152 | ||
| 156 | 이 순서는 `editor.lib.php`에서 전역 설정으로 넘길 수 있고, `nsfw_api_browser.js`가 실제 선택을 수행합니다. | 153 | 이 순서는 `editor.lib.php`에서 전역 설정으로 넘길 수 있고, `nsfw_api_browser.js`가 실제 선택을 수행합니다. |
| 157 | 154 | ||
| 158 | ### self-hosted 구조 | 155 | ### self-hosted 구조 |
| 159 | 156 | ||
| 160 | 운영에서는 아래 같은 구조를 권장합니다. | 157 | 운영에서는 아래 같은 구조를 권장합니다. |
| 161 | 158 | ||
| 162 | ```text | 159 | ```text |
| 163 | /plugin/editor/t2editor/vendor/ | 160 | /plugin/editor/t2editor/vendor/ |
| 164 | tfjs/ | 161 | tfjs/ |
| 165 | tfjs-backend-webgl/ | 162 | tfjs-backend-webgl/ |
| 166 | tfjs-backend-webgpu/ | 163 | tfjs-backend-webgpu/ |
| 167 | tfjs-backend-wasm/ | 164 | tfjs-backend-wasm/ |
| 168 | nsfwjs/ | 165 | nsfwjs/ |
| 169 | nsfwjs/models/mobilenet_v2_mid/ | 166 | nsfwjs/models/mobilenet_v2_mid/ |
| 170 | ``` | 167 | ``` |
| 171 | 168 | ||
| 172 | 이렇게 하면 외부 CDN 장애나 차단의 영향을 줄이고, 배포 경로를 서비스 내부에서 통제할 수 있습니다. | 169 | 이렇게 하면 외부 CDN 장애나 차단의 영향을 줄이고, 배포 경로를 서비스 내부에서 통제할 수 있습니다. |
| 173 | 170 | ||
| 174 | ## 수정 요약 | 171 | ## 수정 요약 |
| 175 | 172 | ||
| 176 | 9.1.0에서 NSFWJS 관련 핵심 변화는 아래와 같습니다. | 173 | 9.1.0에서 NSFWJS 관련 핵심 변화는 아래와 같습니다. |
| 177 | 174 | ||
| 178 | - 기존 브라우저 추론 코드 대신 NSFWJS 사용 | 175 | - 기존 브라우저 추론 코드 대신 NSFWJS 사용 |
| 179 | - `MobileNetV2Mid` 모델 도입 | 176 | - `MobileNetV2Mid` 모델 도입 |
| 180 | - WebGPU 우선 백엔드 선택 지원 | 177 | - WebGPU 우선 백엔드 선택 지원 |
| 181 | - self-hosted vendor 자산 로딩 지원 | 178 | - self-hosted vendor 자산 로딩 지원 |
| 182 | - 기존 이미지 UI에 맞춘 결과 연동 | 179 | - 기존 이미지 UI에 맞춘 결과 연동 |
| 183 | - `suspect` 상태를 별도 정책 대상으로 추가 | 180 | - `suspect` 상태를 별도 정책 대상으로 추가 |
| 184 | - 업로드 직전 중복 재검사 비용 감소 | 181 | - 업로드 직전 중복 재검사 비용 감소 |
| 185 | 182 | ||
| 186 | [tip(읽는 순서)] | ||
| 187 | 처음 보는 사람은 [[guide-nsfwjs-overview]] → [[config-nsfwjs-runtime-settings]] → [[ops-nsfwjs-selfhost-webgpu-ubuntu]] 순서로 읽는 편이 좋습니다. | ||
| 188 | 코드를 직접 수정할 사람은 [[core-nsfw_api_browser-js]]를 이어서 읽는 것이 안전합니다. | ||
| 189 | [/tip] | ||
| 190 | |||
| 191 | ## 자주 생기는 오해 | 183 | ## 자주 생기는 오해 |
| 192 | 184 | ||
| 193 | [folding(NSFWJS를 쓰면 UI도 자동으로 바뀌나요?)] | 185 | [folding(NSFWJS를 쓰면 UI도 자동으로 바뀌나요?)] |
| 194 | 아닙니다. | 186 | 아닙니다. |
| 195 | 이 구조에서는 NSFWJS가 분류 엔진만 담당하고, 배지·모달·상태바는 기존 T2Editor 이미지 플러그인이 담당합니다. | 187 | 이 구조에서는 NSFWJS가 분류 엔진만 담당하고, 배지·모달·상태바는 기존 T2Editor 이미지 플러그인이 담당합니다. |
| 196 | [/folding] | 188 | [/folding] |
| 197 | 189 | ||
| 198 | [folding(server 모드는 완전히 사라졌나요?)] | 190 | [folding(server 모드는 완전히 사라졌나요?)] |
| 199 | 완전히 삭제된 것은 아닐 수 있지만, 9.1.0의 권장 경로는 브라우저 모드입니다. | 191 | 완전히 삭제된 것은 아닐 수 있지만, 9.1.0의 권장 경로는 브라우저 모드입니다. |
| 200 | 문서와 운영 기본값도 브라우저 모드를 기준으로 작성하는 것이 맞습니다. | 192 | 문서와 운영 기본값도 브라우저 모드를 기준으로 작성하는 것이 맞습니다. |
| 201 | [/folding] | 193 | [/folding] |
| 202 | |||
| 203 | ## 관련 문서 | ||
| 204 | |||
| 205 | - [[core-nsfw_api_browser-js|코어 파일: nsfw_api_browser.js]] | ||
| 206 | - [[config-nsfwjs-runtime-settings|설정: NSFWJS 런타임과 모델 경로]] | ||
| 207 | - [[ops-nsfwjs-selfhost-webgpu-ubuntu|운영: Ubuntu self-hosted + WebGPU 설치]] | ||
| 208 | - [[migration-legacy-nsfw-to-nsfwjs|마이그레이션: 레거시 NSFW 구조에서 NSFWJS로]] | ||
| 209 | |||