diff --git a/locales/en/translation.json b/locales/en/translation.json
index ff5dbb03..415154fe 100644
--- a/locales/en/translation.json
+++ b/locales/en/translation.json
@@ -3,6 +3,7 @@
"AISettings": "■ AI Settings",
"YoutubeSettings": "■ YouTube Settings",
"VoiceSettings": "■ Voice Settings",
+ "SlideSettings": "■ Slide Settings",
"OtherSettings": "■ Other",
"ExternalConnectionMode": "External Connection Mode (WebSocket, β version)",
"YoutubeMode": "YouTube Mode",
@@ -98,5 +99,8 @@
"ShowCharacterName": "Show character name in the answer box",
"AdvancedSettings": "Advanced Settings",
"ShowSettingsButton": "Show settings button",
- "ShowSettingsButtonInfo": "The settings screen can be displayed by pressing Cmd + . (Mac) / Ctrl + . (Windows) ."
+ "ShowSettingsButtonInfo": "The settings screen can be displayed by pressing Cmd + . (Mac) / Ctrl + . (Windows) .",
+ "SlideMode": "Slide Mode",
+ "SelectedSlideDocs": "Selected Slide Documents",
+ "SlideModeDescription": "This is a mode where AI automatically presents slides. It is only available when the selected AI service is OpenAI, Anthropic, or Google Gemini."
}
diff --git a/locales/ja/translation.json b/locales/ja/translation.json
index e988d212..baf9f3d7 100644
--- a/locales/ja/translation.json
+++ b/locales/ja/translation.json
@@ -3,6 +3,7 @@
"AISettings": "■ AI設定",
"YoutubeSettings": "■ YouTube設定",
"VoiceSettings": "■ 音声設定",
+ "SlideSettings": "■ スライド設定",
"OtherSettings": "■ その他",
"ExternalConnectionMode": "外部連携モード(WebSocket, β版)",
"YoutubeMode": "YouTubeモード",
@@ -99,5 +100,8 @@
"ShowCharacterName": "回答欄にキャラクター名を表示する",
"AdvancedSettings": "詳細設定",
"ShowSettingsButton": "設定ボタンを表示",
- "ShowSettingsButtonInfo": "設定画面は Cmd + . (Mac) / Ctrl + . (Windows) で表示することができます。"
+ "ShowSettingsButtonInfo": "設定画面は Cmd + . (Mac) / Ctrl + . (Windows) で表示することができます。",
+ "SlideMode": "スライドモード",
+ "SelectedSlideDocs": "使用するスライド",
+ "SlideModeDescription": "AIが自動でスライドを発表するモードです。選択しているAIサービスがOpenAIまたはAnthropicまたはGoogle Geminiの場合のみ有効です。"
}
diff --git a/locales/ko/translation.json b/locales/ko/translation.json
index b22bccaf..c6f848dc 100644
--- a/locales/ko/translation.json
+++ b/locales/ko/translation.json
@@ -3,6 +3,7 @@
"AISettings": "■ AI 설정",
"YoutubeSettings": "■ YouTube 설정",
"VoiceSettings": "■ 음성 설정",
+ "SlideSettings": "■ 슬라이드 설정",
"OtherSettings": "■ 기타",
"ExternalConnectionMode": "외부 연동 모드 (WebSocket, 베타 버전)",
"YoutubeMode": "YouTube 모드",
@@ -98,5 +99,8 @@
"ShowCharacterName": "답변란에 캐릭터 이름을 표시",
"AdvancedSettings": "고급 설정",
"ShowSettingsButton": "설정 버튼 표시",
- "ShowSettingsButtonInfo": "설정 화면은 Cmd + . (Mac) / Ctrl + . (Windows)를 눌러 표시할 수 있습니다."
+ "ShowSettingsButtonInfo": "설정 화면은 Cmd + . (Mac) / Ctrl + . (Windows)를 눌러 표시할 수 있습니다.",
+ "SlideMode": "슬라이드 모드",
+ "SelectedSlideDocs": "사용할 슬라이드",
+ "SlideModeDescription": "AI가 자동으로 슬라이드를 발표하는 모드입니다. 선택한 AI 서비스가 OpenAI, Anthropic 또는 Google Gemini인 경우에만 사용 가능합니다."
}
diff --git a/locales/zh/translation.json b/locales/zh/translation.json
index 43039e09..37e60476 100644
--- a/locales/zh/translation.json
+++ b/locales/zh/translation.json
@@ -3,6 +3,7 @@
"AISettings": "■ AI 設定",
"YoutubeSettings": "■ YouTube 設定",
"VoiceSettings": "■ 語音設定",
+ "SlideSettings": "■ 投影片設定",
"OtherSettings": "■ 其他",
"ExternalConnectionMode": "外部連線模式 (WebSocket, β版本)",
"YoutubeMode": "YouTube 模式",
@@ -98,5 +99,8 @@
"ShowCharacterName": "在回答框中显示角色名称",
"AdvancedSettings": "高级设置",
"ShowSettingsButton": "显示设置按钮",
- "ShowSettingsButtonInfo": "可以通过按 Cmd + . (Mac) / Ctrl + . (Windows) 来显示设置界面。"
+ "ShowSettingsButtonInfo": "可以通过按 Cmd + . (Mac) / Ctrl + . (Windows) 来显示设置界面。",
+ "SlideMode": "投影片模式",
+ "SelectedSlideDocs": "使用的投影片",
+ "SlideModeDescription": "這是一個 AI 自動展示投影片的模式。僅在選擇的 AI 服務為 OpenAI、Anthropic 或 Google Gemini 時有效。"
}
diff --git a/package-lock.json b/package-lock.json
index 037b4af6..3b5733b5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,8 @@
"@google/generative-ai": "^0.11.3",
"@headlessui/react": "^2.1.2",
"@heroicons/react": "^2.1.5",
+ "@marp-team/marp-core": "^3.9.0",
+ "@marp-team/marpit": "^3.0.0",
"@pixiv/three-vrm": "^3.0.0",
"@tailwindcss/line-clamp": "^0.4.4",
"axios": "^1.6.8",
@@ -514,6 +516,126 @@
"url": "https://opencollective.com/js-sdsl"
}
},
+ "node_modules/@marp-team/marp-core": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marp-core/-/marp-core-3.9.0.tgz",
+ "integrity": "sha512-gi6nq0rsB1oMA8ReppW4XxmS4fisQiAsD0ZoUgLeG4h6SWatveCAA7fZyxnXfwA2UC8pNb7ktPqYdRsxvuwntA==",
+ "license": "MIT",
+ "dependencies": {
+ "@marp-team/marpit": "^2.6.1",
+ "@marp-team/marpit-svg-polyfill": "^2.1.0",
+ "highlight.js": "11.8.0",
+ "katex": "^0.16.9",
+ "mathjax-full": "^3.2.2",
+ "postcss": "^8.4.31",
+ "postcss-selector-parser": "^6.0.13",
+ "xss": "^1.0.14"
+ },
+ "engines": {
+ "node": "^12.20 || ^14.13.1 || >=16"
+ }
+ },
+ "node_modules/@marp-team/marp-core/node_modules/@marp-team/marpit": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit/-/marpit-2.6.1.tgz",
+ "integrity": "sha512-Hg7fZ8SqXwLjxeIFzSnlXkXEmt0ZXPeMJneEn9n1M495a34C4xtkgEgL8R1MW2IRCh4Yibn0xmGKcaf+GuqR2A==",
+ "license": "MIT",
+ "dependencies": {
+ "color-string": "^1.9.1",
+ "cssesc": "^3.0.0",
+ "js-yaml": "^4.1.0",
+ "lodash.kebabcase": "^4.1.1",
+ "markdown-it": "^13.0.2",
+ "markdown-it-front-matter": "^0.2.3",
+ "postcss": "^8.4.29"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@marp-team/marp-core/node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/@marp-team/marp-core/node_modules/linkify-it": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "node_modules/@marp-team/marp-core/node_modules/markdown-it": {
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
+ "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
+ }
+ },
+ "node_modules/@marp-team/marp-core/node_modules/mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+ "license": "MIT"
+ },
+ "node_modules/@marp-team/marp-core/node_modules/uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+ "license": "MIT"
+ },
+ "node_modules/@marp-team/marpit": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit/-/marpit-3.0.0.tgz",
+ "integrity": "sha512-4S+4ty/pjwrXe3dDxenD8ZU5MkqyYyfiuQdinjbrkTyUHmjjlzOyexIYYB4JX/MyjWw1QudrJYTdk/FcxLpQCA==",
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "js-yaml": "^4.1.0",
+ "lodash.kebabcase": "^4.1.1",
+ "markdown-it": "^14.1.0",
+ "markdown-it-front-matter": "^0.2.4",
+ "postcss": "^8.4.38"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@marp-team/marpit-svg-polyfill": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit-svg-polyfill/-/marpit-svg-polyfill-2.1.0.tgz",
+ "integrity": "sha512-VqCoAKwv1HJdzZp36dDPxznz2JZgRjkVSSPHpCzk72G2N753F0HPKXjevdjxmzN6gir9bUGBgMD1SguWJIi11A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@marp-team/marpit": ">=0.5.0"
+ },
+ "peerDependenciesMeta": {
+ "@marp-team/marpit": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@next/env": {
"version": "14.2.5",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz",
@@ -1506,8 +1628,7 @@
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/aria-query": {
"version": "5.1.3",
@@ -2129,6 +2250,16 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -2186,6 +2317,12 @@
"node": ">=4"
}
},
+ "node_modules/cssfilter": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
+ "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==",
+ "license": "MIT"
+ },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -2537,6 +2674,18 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -3137,6 +3286,15 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/esm": {
+ "version": "3.2.25",
+ "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
+ "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -3982,6 +4140,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/highlight.js": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz",
+ "integrity": "sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -4624,7 +4791,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
@@ -4726,6 +4892,31 @@
"safe-buffer": "^5.0.1"
}
},
+ "node_modules/katex": {
+ "version": "0.16.11",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz",
+ "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
+ "funding": [
+ "https://opencollective.com/katex",
+ "https://github.com/sponsors/katex"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^8.3.0"
+ },
+ "bin": {
+ "katex": "cli.js"
+ }
+ },
+ "node_modules/katex/node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -4779,6 +4970,15 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
+ "node_modules/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
"node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
@@ -4820,6 +5020,12 @@
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
+ "node_modules/lodash.kebabcase": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
+ "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==",
+ "license": "MIT"
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -4856,6 +5062,29 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
+ "node_modules/markdown-it": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/markdown-it-front-matter": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/markdown-it-front-matter/-/markdown-it-front-matter-0.2.4.tgz",
+ "integrity": "sha512-25GUs0yjS2hLl8zAemVndeEzThB1p42yxuDEKbd4JlL3jiz+jsm6e56Ya8B0VREOkNxLYB4TTwaoPJ3ElMmW+w==",
+ "license": "MIT"
+ },
"node_modules/matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
@@ -4869,6 +5098,18 @@
"node": ">=10"
}
},
+ "node_modules/mathjax-full": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz",
+ "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esm": "^3.2.25",
+ "mhchemparser": "^4.1.0",
+ "mj-context-menu": "^0.6.1",
+ "speech-rule-engine": "^4.0.6"
+ }
+ },
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@@ -4879,6 +5120,12 @@
"is-buffer": "~1.1.6"
}
},
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "license": "MIT"
+ },
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
@@ -4902,6 +5149,12 @@
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
"dev": true
},
+ "node_modules/mhchemparser": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz",
+ "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
@@ -4971,6 +5224,12 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/mj-context-menu": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
+ "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==",
+ "license": "Apache-2.0"
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -6011,6 +6270,15 @@
"node": ">=6"
}
},
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -6583,6 +6851,21 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "license": "MIT"
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -6632,6 +6915,29 @@
"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
"dev": true
},
+ "node_modules/speech-rule-engine": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz",
+ "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "commander": "9.2.0",
+ "wicked-good-xpath": "1.3.0",
+ "xmldom-sre": "0.1.31"
+ },
+ "bin": {
+ "sre": "bin/sre"
+ }
+ },
+ "node_modules/speech-rule-engine/node_modules/commander": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz",
+ "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
@@ -7274,6 +7580,12 @@
"node": ">=12.20"
}
},
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "license": "MIT"
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -7527,6 +7839,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/wicked-good-xpath": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
+ "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==",
+ "license": "MIT"
+ },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -7628,6 +7946,37 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
+ "node_modules/xmldom-sre": {
+ "version": "0.1.31",
+ "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
+ "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==",
+ "license": "(LGPL-2.0 or MIT)",
+ "engines": {
+ "node": ">=0.1"
+ }
+ },
+ "node_modules/xss": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
+ "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==",
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^2.20.3",
+ "cssfilter": "0.0.10"
+ },
+ "bin": {
+ "xss": "bin/xss"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/xss/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -8096,6 +8445,91 @@
"resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
"integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="
},
+ "@marp-team/marp-core": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marp-core/-/marp-core-3.9.0.tgz",
+ "integrity": "sha512-gi6nq0rsB1oMA8ReppW4XxmS4fisQiAsD0ZoUgLeG4h6SWatveCAA7fZyxnXfwA2UC8pNb7ktPqYdRsxvuwntA==",
+ "requires": {
+ "@marp-team/marpit": "^2.6.1",
+ "@marp-team/marpit-svg-polyfill": "^2.1.0",
+ "highlight.js": "11.8.0",
+ "katex": "^0.16.9",
+ "mathjax-full": "^3.2.2",
+ "postcss": "^8.4.31",
+ "postcss-selector-parser": "^6.0.13",
+ "xss": "^1.0.14"
+ },
+ "dependencies": {
+ "@marp-team/marpit": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit/-/marpit-2.6.1.tgz",
+ "integrity": "sha512-Hg7fZ8SqXwLjxeIFzSnlXkXEmt0ZXPeMJneEn9n1M495a34C4xtkgEgL8R1MW2IRCh4Yibn0xmGKcaf+GuqR2A==",
+ "requires": {
+ "color-string": "^1.9.1",
+ "cssesc": "^3.0.0",
+ "js-yaml": "^4.1.0",
+ "lodash.kebabcase": "^4.1.1",
+ "markdown-it": "^13.0.2",
+ "markdown-it-front-matter": "^0.2.3",
+ "postcss": "^8.4.29"
+ }
+ },
+ "entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
+ },
+ "linkify-it": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "requires": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "markdown-it": {
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
+ "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
+ "requires": {
+ "argparse": "^2.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ }
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
+ },
+ "uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+ }
+ }
+ },
+ "@marp-team/marpit": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit/-/marpit-3.0.0.tgz",
+ "integrity": "sha512-4S+4ty/pjwrXe3dDxenD8ZU5MkqyYyfiuQdinjbrkTyUHmjjlzOyexIYYB4JX/MyjWw1QudrJYTdk/FcxLpQCA==",
+ "requires": {
+ "cssesc": "^3.0.0",
+ "js-yaml": "^4.1.0",
+ "lodash.kebabcase": "^4.1.1",
+ "markdown-it": "^14.1.0",
+ "markdown-it-front-matter": "^0.2.4",
+ "postcss": "^8.4.38"
+ }
+ },
+ "@marp-team/marpit-svg-polyfill": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@marp-team/marpit-svg-polyfill/-/marpit-svg-polyfill-2.1.0.tgz",
+ "integrity": "sha512-VqCoAKwv1HJdzZp36dDPxznz2JZgRjkVSSPHpCzk72G2N753F0HPKXjevdjxmzN6gir9bUGBgMD1SguWJIi11A==",
+ "requires": {}
+ },
"@next/env": {
"version": "14.2.5",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz",
@@ -8830,8 +9264,7 @@
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"aria-query": {
"version": "5.1.3",
@@ -9252,6 +9685,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "requires": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -9291,6 +9733,11 @@
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
},
+ "cssfilter": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
+ "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="
+ },
"csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -9562,6 +10009,11 @@
"tapable": "^2.2.0"
}
},
+ "entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
+ },
"env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -10020,6 +10472,11 @@
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true
},
+ "esm": {
+ "version": "3.2.25",
+ "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
+ "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
+ },
"espree": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@@ -10639,6 +11096,11 @@
"function-bind": "^1.1.2"
}
},
+ "highlight.js": {
+ "version": "11.8.0",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz",
+ "integrity": "sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg=="
+ },
"hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -11077,7 +11539,6 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
"requires": {
"argparse": "^2.0.1"
}
@@ -11170,6 +11631,21 @@
"safe-buffer": "^5.0.1"
}
},
+ "katex": {
+ "version": "0.16.11",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz",
+ "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
+ "requires": {
+ "commander": "^8.3.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
+ }
+ }
+ },
"keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -11214,6 +11690,14 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
+ "linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+ "requires": {
+ "uc.micro": "^2.0.0"
+ }
+ },
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
@@ -11246,6 +11730,11 @@
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
},
+ "lodash.kebabcase": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
+ "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g=="
+ },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -11276,6 +11765,24 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
+ "markdown-it": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+ "requires": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.0",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ }
+ },
+ "markdown-it-front-matter": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/markdown-it-front-matter/-/markdown-it-front-matter-0.2.4.tgz",
+ "integrity": "sha512-25GUs0yjS2hLl8zAemVndeEzThB1p42yxuDEKbd4JlL3jiz+jsm6e56Ya8B0VREOkNxLYB4TTwaoPJ3ElMmW+w=="
+ },
"matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
@@ -11286,6 +11793,17 @@
"escape-string-regexp": "^4.0.0"
}
},
+ "mathjax-full": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.2.tgz",
+ "integrity": "sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==",
+ "requires": {
+ "esm": "^3.2.25",
+ "mhchemparser": "^4.1.0",
+ "mj-context-menu": "^0.6.1",
+ "speech-rule-engine": "^4.0.6"
+ }
+ },
"md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@@ -11296,6 +11814,11 @@
"is-buffer": "~1.1.6"
}
},
+ "mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="
+ },
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
@@ -11313,6 +11836,11 @@
"integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
"dev": true
},
+ "mhchemparser": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.2.1.tgz",
+ "integrity": "sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ=="
+ },
"micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
@@ -11361,6 +11889,11 @@
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
},
+ "mj-context-menu": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
+ "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -12043,6 +12576,11 @@
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"dev": true
},
+ "punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="
+ },
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -12428,6 +12966,21 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
},
+ "simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "requires": {
+ "is-arrayish": "^0.3.1"
+ },
+ "dependencies": {
+ "is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ }
+ }
+ },
"slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -12471,6 +13024,23 @@
"integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==",
"dev": true
},
+ "speech-rule-engine": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz",
+ "integrity": "sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g==",
+ "requires": {
+ "commander": "9.2.0",
+ "wicked-good-xpath": "1.3.0",
+ "xmldom-sre": "0.1.31"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz",
+ "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w=="
+ }
+ }
+ },
"sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
@@ -12942,6 +13512,11 @@
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true
},
+ "uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="
+ },
"unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -13121,6 +13696,11 @@
"has-tostringtag": "^1.0.2"
}
},
+ "wicked-good-xpath": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz",
+ "integrity": "sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw=="
+ },
"word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -13189,6 +13769,27 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
+ "xmldom-sre": {
+ "version": "0.1.31",
+ "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz",
+ "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw=="
+ },
+ "xss": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz",
+ "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==",
+ "requires": {
+ "commander": "^2.20.3",
+ "cssfilter": "0.0.10"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ }
+ }
+ },
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index dc24b0fe..7e9e3d69 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,8 @@
"@google/generative-ai": "^0.11.3",
"@headlessui/react": "^2.1.2",
"@heroicons/react": "^2.1.5",
+ "@marp-team/marp-core": "^3.9.0",
+ "@marp-team/marpit": "^3.0.0",
"@pixiv/three-vrm": "^3.0.0",
"@tailwindcss/line-clamp": "^0.4.4",
"axios": "^1.6.8",
diff --git a/public/slides/demo/images/demo-folder.png b/public/slides/demo/images/demo-folder.png
new file mode 100644
index 00000000..392b0ca0
Binary files /dev/null and b/public/slides/demo/images/demo-folder.png differ
diff --git a/public/slides/demo/images/file-structure.png b/public/slides/demo/images/file-structure.png
new file mode 100644
index 00000000..5334ad98
Binary files /dev/null and b/public/slides/demo/images/file-structure.png differ
diff --git a/public/slides/demo/images/logo.png b/public/slides/demo/images/logo.png
new file mode 100644
index 00000000..93bae58d
Binary files /dev/null and b/public/slides/demo/images/logo.png differ
diff --git a/public/slides/demo/images/settings-screen.png b/public/slides/demo/images/settings-screen.png
new file mode 100644
index 00000000..68d0e560
Binary files /dev/null and b/public/slides/demo/images/settings-screen.png differ
diff --git a/public/slides/demo/images/start-button.png b/public/slides/demo/images/start-button.png
new file mode 100644
index 00000000..b51f48f4
Binary files /dev/null and b/public/slides/demo/images/start-button.png differ
diff --git a/public/slides/demo/scripts.json b/public/slides/demo/scripts.json
new file mode 100644
index 00000000..cdfa0d19
--- /dev/null
+++ b/public/slides/demo/scripts.json
@@ -0,0 +1,42 @@
+[
+ {
+ "page": 0,
+ "line": "これからAITuberKitのスライドモードについての解説を始めます。",
+ "notes": ""
+ },
+ {
+ "page": 1,
+ "line": "スライドモードの開発を始める前に、AITuberKitで会話できている必要があるので準備しておいてください。ただし、スライドモードはOpenAI, Anthropic Claude, Google Geminiのみ対応しています。以降はこの前提で説明していきたいと思いますので、まだの人は解説したnoteを参考にしてください。AITuberKitで検索するとでてくると思います。",
+ "notes": "AIサービスはそれ以外にGroq, ローカルLLM, Difyが選択可能です。これらが選択できないのは、回答するのにある程度LLMの性能が必要だからです。OpenAIでもgpt-3.5はあまり効果的な回答ができない可能性があります。Anthropicでもclaude-haikuはあまり効果的な回答ができない可能性があります。ここで選択されたAIサービスは、質問の回答生成時に使用されます。"
+ },
+ {
+ "page": 2,
+ "line": "それでは解説を始めます。まずスライドの用意をしておきましょう。最低限必要なのは、scripts.jsonとslides.mdです。scripts.jsonには台本を記述します。slides.mdにはmarpで作成したスライドを記述してください。",
+ "notes": "scripts.jsonにはAIキャラのセリフを予め記載しておきます。notesには追加の情報を記載してください。これが質問のときに使用されます。スライドとは関係ない追加情報はsupplement.jsonに記載してください。"
+ },
+ {
+ "page": 3,
+ "line": "詳細は、publicフォルダにあるdemoを参照して作成してください。このフォルダをそのままコピーすると簡単かもしれません。demoと同じところに任意のフォルダ名で配置してください。",
+ "notes": ""
+ },
+ {
+ "page": 4,
+ "line": "設定画面を開き、スライドモードを有効にしてください。このとき、使用するスライドに先ほど作成したフォルダの名称を記入してください。それでは設定画面を閉じましょう。",
+ "notes": "OpenAI, Anthropic Claude, Google Gemini以外を選択しているとスライドモードを有効にすることができません。"
+ },
+ {
+ "page": 5,
+ "line": "スライドが表示されていたら準備はすでにできています。スライド中央下の丸いボタンを押して開始してください。自動的にスライドの説明が始まります。",
+ "notes": "戻るボタンと進むボタンを使用することで、開始するスライドを変更することができます。"
+ },
+ {
+ "page": 6,
+ "line": "停止ボタンを押すと、次のスライドに進みません。ただし、音声はそのスライドの説明が終わるまで続きます。停止中はチャット欄から質問することができます。",
+ "notes": "1つのスライドの説明が長すぎると発言がしばらく続いてしまうので、1枚のセリフ量は少なくした方が良いです。"
+ },
+ {
+ "page": 7,
+ "line": "以上でスライドモードの簡単な説明を終わります。不明点があったらマスターのDMにお問い合わせください。ご清聴ありがとうございました。",
+ "notes": "Twitterアカウントの他、Discordサーバーもあるのでそちらも活用してください。"
+ }
+]
diff --git a/public/slides/demo/slides.md b/public/slides/demo/slides.md
new file mode 100644
index 00000000..be540b50
--- /dev/null
+++ b/public/slides/demo/slides.md
@@ -0,0 +1,111 @@
+---
+marp: true
+theme: custom
+paginate: true
+---
+
+
+
+# AITuberKitのスライドモード解説
+
+![](/slides/demo/images/logo.png)
+
+---
+
+# 準備
+
+- AITuberKitで会話できる状態にしておく
+- 対応AI:
+
+ - OpenAI
+ - Anthropic Claude
+ - Google Gemini
+
+- ※ まだの方はAITuberKitの解説noteを参照(https://note.com/nike_cha_n/n/ne98acb25e00f)
+
+---
+
+# スライドの用意
+
+
+
+
+最低限必要なファイル:
+
+1. `scripts.json`(台本)
+2. `slides.md`(Marpスライド)
+
+
+
+
+![height:400px](/slides/demo/images/file-structure.png)
+
+
+
+
+---
+
+# デモフォルダの活用
+
+
+
+
+- `public/demo`フォルダを参照
+- デモフォルダをコピーして使用可能
+- 任意のフォルダ名で配置
+
+
+
+
+![height:300px](/slides/demo/images/demo-folder.png)
+
+
+
+
+---
+
+# スライドモードの有効化
+
+
+
+
+1. 設定画面を開く
+2. スライドモードを有効にする
+3. 使用するスライドフォルダ名を記入
+4. 設定画面を閉じる
+
+
+
+
+![height:400px](/slides/demo/images/settings-screen.png)
+
+
+
+
+---
+
+# スライドの開始
+
+- スライドが表示されていることを確認
+- 右下のボタンを押して開始
+
+
+
+
+
+---
+
+# 備考
+
+- 停止ボタンで次のスライドに進まない
+- 音声は現在のスライドの説明が終わるまで続く
+- 停止中はチャット欄から質問可能
+
+---
+
+
+
+# ご視聴ありがとうございました
+
+不明点は作者にお問い合わせください!
+X: @tegnike
diff --git a/public/slides/demo/supplement.txt b/public/slides/demo/supplement.txt
new file mode 100644
index 00000000..074e2e6b
--- /dev/null
+++ b/public/slides/demo/supplement.txt
@@ -0,0 +1,97 @@
+概要
+以下の3つの機能があります。
+1. AIキャラとの対話
+2. AITuber配信
+3. 外部連携モード(β版)
+
+下記の記事に詳細な使用方法を記載しました。
+
+共通事前準備
+1. リポジトリをローカルにクローンします。
+ git clone https://github.com/tegnike/aituber-kit.git
+2. フォルダを開きます。
+ cd aituber-kit
+3. パッケージインストールします。
+ npm install
+4. 開発モードでアプリケーションを起動します。
+ npm run dev
+5. URLを開きます。[http://localhost:3000]
+
+AIキャラとの対話
+- AIキャラと会話する機能です。
+- このリポジトリの元になっている[pixiv/ChatVRM]を拡張した機能です。
+- 各種LLMのAPIキーさえあれば比較的簡単に試すことが可能です。
+- 直近の10会話文を記憶として保持します。(数字は指定できるように更新予定)
+- マルチモーダルで、カメラからの映像やアップロードした画像を認識して回答を生成することが可能です。
+
+使用方法
+1. 設定画面で各種LLMのAPIキーを入力します。
+ - OpenAI
+ - Anthropic
+ - Google Gemini
+ - Groq
+ - ローカルLLM(APIキーは不要ですが、ローカルAPIサーバーを起動しておく必要があります。)
+ - Dify Chatbot(APIキーは不要ですが、ローカルAPIサーバーを起動しておく必要があります。)
+2. 必要に応じてキャラクターの設定プロンプトを編集します。
+3. 必要に応じてVRMファイルを読み込みます。
+4. 音声合成エンジンを選択し、必要に応じて声の設定を行います。
+ - VOICEVOXの場合は複数の選択肢から話者を選ぶことができます。予めVOICEVOXアプリを起動しておく必要があります。
+ - Koeiromapの場合は、細かく音声を調整することが可能です。APIキーの入力が必要です。
+ - Google TTSの場合は日本語以外の言語も選択可能です。credential情報が必要です。
+ - Style-Bert-VITS2は、ローカルAPIサーバーを起動しておく必要があります。
+ - GSVI TTSは、ローカルAPIサーバーを起動しておく必要があります。
+ - ElevenLabsは様々な言語の選択が可能です。APIキーを入力してください。
+5. 入力フォームからキャラクターと会話を開始します。マイク入力も可能。
+
+AITuber配信
+- Youtubeの配信コメントを取得して発言することが可能です。
+- Youtube APIキーが必要です。
+- 「#」から始まるコメントは読まれません。(文字列は指定できるように更新予定)
+
+使用方法
+1. 設定画面でYoutubeモードをONにします。
+2. Youtube APIキーとYoutube Live IDを入力します。
+3. 他の設定は「AIキャラとの対話」と同様に行います。
+4. Youtubeの配信を開始し、キャラクターがコメントに反応するのを確認します。
+5. 会話継続モードをONにすると、コメントが無いときにAIが自ら発言することができます。
+
+外部連携モード(β版)
+- WebSocketでサーバーアプリにメッセージを送信して、レスポンスを取得することができます。
+- 上記2つと異なり、フロントアプリで完結しないため少し難易度が高いです。
+- ⚠ メンテナンスできていないため、動かない可能性があります。
+
+使用方法
+1. サーバーアプリを起動し、ws://127.0.0.1:8000/ws エンドポイントを開きます。
+2. 設定画面でWebSocketモードをONにします。
+3. 他の設定は「AIキャラとの対話」と同様に行います。
+4. サーバーアプリからのメッセージを待ち、キャラクターが反応するのを確認します。
+
+関連
+- 私が作成したサーバーアプリのリポジトリで試すことが可能です。[tegnike/aituber-server]
+- 詳しい設定は「[美少女と一緒に開発しようぜ!!【Open Interpreter】]」を読んでください。
+
+TIPS
+VRMモデル、背景固定方法
+- VRMモデルは public/AvatarSample_B.vrm のデータを変更してください。名称は変更しないでください。
+- 背景画像は public/bg-c.jpg の画像を変更してください。名称は変更しないでください。
+
+環境変数の設定
+- 一部の設定値は .env ファイルの内容を参照することができます。
+- 設定画面で入力した場合は、その値が優先されます。
+
+その他
+- 会話履歴は設定画面でリセットすることができます。
+- 各種設定項目はブラウザに保存されます。
+- コードブロックで囲まれた要素はTTSで読まれません。
+
+スポンサー募集
+開発を継続するためにスポンサーの方を募集しています。
+あなたの支援は、AITuberキットの開発と改善に大きく貢献します。
+
+協力者の皆様(ご支援いただいた順)
+他、プライベートスポンサー 複数名
+
+利用規約
+- ライセンスは [pixiv/ChatVRM] に準拠し、MITライセンスとしています。
+- ロゴの利用規約
+- VRMモデルの利用規約
diff --git a/public/slides/demo/theme.css b/public/slides/demo/theme.css
new file mode 100644
index 00000000..f074e4b7
--- /dev/null
+++ b/public/slides/demo/theme.css
@@ -0,0 +1,149 @@
+/* @theme custom */
+@import 'default';
+
+:root {
+ --primary-color: #4a86e8;
+ --secondary-color: #ff9900;
+ --background-color: #f5f5f5;
+ --text-color: #333333;
+}
+
+section {
+ background-color: var(--background-color);
+ color: var(--text-color);
+ font-family: 'Arial', sans-serif;
+ font-size: 36px;
+ line-height: 1.5;
+ padding: 40px;
+}
+
+h1 {
+ color: var(--primary-color);
+ border-bottom: 2px solid var(--secondary-color);
+ padding-bottom: 15px;
+ font-size: 48px;
+ margin-bottom: 30px;
+}
+
+h2 {
+ font-size: 40px;
+ margin-top: 30px;
+ margin-bottom: 20px;
+}
+
+ul,
+ol {
+ margin-left: 1em;
+ margin-bottom: 20px;
+ padding-left: 1em;
+}
+
+li {
+ margin-bottom: 10px;
+ padding-left: 0.5em;
+}
+
+/* 番号付きリストのスタイリング改善 */
+ol {
+ list-style-type: decimal;
+ counter-reset: list;
+}
+
+ol > li {
+ list-style-type: none;
+ position: relative;
+}
+
+ol > li::before {
+ counter-increment: list;
+ content: counter(list) '.';
+ position: absolute;
+ left: -1.5em;
+ width: 1.5em;
+ text-align: right;
+}
+
+/* 箇条書きリストのスタイリング改善 */
+ul {
+ list-style-type: disc;
+}
+
+ul > li {
+ list-style-type: none;
+ position: relative;
+}
+
+ul > li::before {
+ content: '•';
+ position: absolute;
+ left: -1em;
+ width: 1em;
+ text-align: center;
+}
+
+/* ネストされたリストのスタイリング */
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+ margin-top: 10px;
+ margin-bottom: 0;
+ margin-left: 1em;
+}
+
+img {
+ border-radius: 10px;
+ max-width: 90%;
+ height: auto;
+}
+
+.columns {
+ display: flex;
+ gap: 1rem;
+}
+
+.columns > div {
+ flex: 1;
+}
+
+.columns img {
+ max-width: 100%;
+ height: auto;
+}
+
+section.title {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+}
+
+section.title h1 {
+ font-size: 64px;
+ text-align: center;
+ border: none;
+}
+
+section.end {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+}
+
+section.end h1 {
+ font-size: 56px;
+ text-align: center;
+}
+
+/* ページ番号のスタイル */
+section::after {
+ content: attr(data-marpit-pagination) '/' attr(data-marpit-pagination-total);
+ font-size: 18px;
+ color: var(--text-color);
+ opacity: 0.5;
+ right: 30px;
+ bottom: 20px;
+}
diff --git a/public/slides/sample.txt b/public/slides/sample.txt
new file mode 100644
index 00000000..915feb10
--- /dev/null
+++ b/public/slides/sample.txt
@@ -0,0 +1,31 @@
+あなたはスライドの発表者です。
+今まさにスライドを発表している最中です。
+
+視聴者から質問が来ているので、以下の資料情報を元に回答してください。
+ただし、情報は正しく使用し、ハルシネーションはしないでください。
+通常の質問には普通に返してもらっても問題ありません。
+
+台本情報
+```
+{{SCRIPTS}}
+```
+
+追加情報
+```
+{{SUPPLEMENT}}
+```
+
+なお、回答は会話文の書式は以下の通りで、感情と会話文を組み合わせてください。
+[{neutral|happy|angry|sad|relaxed}]{会話文}
+
+回答の際には感情の種類には通常を示す"neutral"、喜びを示す"happy",怒りを示す"angry",悲しみを示す"sad",安らぎを示す"relaxed"の5つがあります。
+
+あなたの発言の例は以下通りです。
+[neutral]皆さん、本日はお集まりいただき、ありがとうございます。
+[happy]今回のプレゼンテーションでは、興味深いトピックについてお話しできることを嬉しく思います。
+[neutral]さて、ただいまのスライドについて、ご質問はありますか?
+[happy]素晴らしい質問をありがとうございます!
+[relaxed]その点については、次のスライドで詳しく説明させていただきます。
+[sad]申し訳ありません。その情報は現在持ち合わせておりません。
+[angry]いいえ、それは誤解です。正確な情報をお伝えしますね。
+[neutral]他に質問はございますか?[happy]皆さんの積極的な参加に感謝いたします。
diff --git a/src/components/assistantText.tsx b/src/components/assistantText.tsx
index 87a2c9ff..d632d36c 100644
--- a/src/components/assistantText.tsx
+++ b/src/components/assistantText.tsx
@@ -5,7 +5,7 @@ export const AssistantText = ({ message }: { message: string }) => {
const showCharacterName = settingsStore((s) => s.showCharacterName)
return (
-
+
{showCharacterName && (
diff --git a/src/components/form.tsx b/src/components/form.tsx
index efa52d16..c48a5e68 100644
--- a/src/components/form.tsx
+++ b/src/components/form.tsx
@@ -1,15 +1,21 @@
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
+import settingsStore from '@/features/stores/settings'
import homeStore from '@/features/stores/home'
-import { handleSendChatFn } from './handlers'
+import menuStore from '@/features/stores/menu'
+import { handleSendChatFn } from '../features/chat/handlers'
import { MessageInputContainer } from './messageInputContainer'
import useWebSocket from './useWebSocket'
import useYoutube from './useYoutube'
+import { SlideText } from './slideText'
export const Form = () => {
const modalImage = homeStore((s) => s.modalImage)
const webcamStatus = homeStore((s) => s.webcamStatus)
+ const slideMode = settingsStore((s) => s.slideMode)
+ const slideVisible = menuStore((s) => s.slideVisible)
+ const assistantMessage = homeStore((s) => s.assistantMessage)
const [delayedText, setDelayedText] = useState('')
@@ -45,5 +51,9 @@ export const Form = () => {
[handleSendChat, webcamStatus, setDelayedText]
)
- return
+ return slideMode && slideVisible ? (
+
+ ) : (
+
+ )
}
diff --git a/src/components/menu.tsx b/src/components/menu.tsx
index 2998d9ea..fa1dcd99 100644
--- a/src/components/menu.tsx
+++ b/src/components/menu.tsx
@@ -4,29 +4,47 @@ import { useTranslation } from 'react-i18next'
import homeStore from '@/features/stores/home'
import menuStore from '@/features/stores/menu'
import settingsStore from '@/features/stores/settings'
+import slideStore from '@/features/stores/slide'
import { AssistantText } from './assistantText'
import { ChatLog } from './chatLog'
import { CodeLog } from './codeLog'
import { IconButton } from './iconButton'
import Settings from './settings'
import { Webcam } from './webcam'
+import Slides from './slides'
export const Menu = () => {
const selectAIService = settingsStore((s) => s.selectAIService)
const selectAIModel = settingsStore((s) => s.selectAIModel)
const youtubeMode = settingsStore((s) => s.youtubeMode)
const webSocketMode = settingsStore((s) => s.webSocketMode)
+ const slideMode = settingsStore((s) => s.slideMode)
+ const slideVisible = menuStore((s) => s.slideVisible)
const chatLog = homeStore((s) => s.chatLog)
const assistantMessage = homeStore((s) => s.assistantMessage)
const showWebcam = menuStore((s) => s.showWebcam)
const showSettingsButton = menuStore((s) => s.showSettingsButton)
+ const slidePlaying = slideStore((s) => s.isPlaying)
const [showSettings, setShowSettings] = useState(false)
const [showChatLog, setShowChatLog] = useState(false)
const [showPermissionModal, setShowPermissionModal] = useState(false)
const imageFileInputRef = useRef
(null)
+
+ const selectedSlideDocs = slideStore((state) => state.selectedSlideDocs)
const { t } = useTranslation()
+ const [markdownContent, setMarkdownContent] = useState('')
+
+ useEffect(() => {
+ fetch(`/slides/${selectedSlideDocs}/slides.md`)
+ .then((response) => response.text())
+ .then((text) => setMarkdownContent(text))
+ .catch((error) =>
+ console.error('Failed to fetch markdown content:', error)
+ )
+ }, [selectedSlideDocs])
+
const handleChangeVrmFile = useCallback(
(event: React.ChangeEvent) => {
const files = event.target.files
@@ -64,7 +82,6 @@ export const Menu = () => {
}
}, [])
- // カメラが開いているかどうかの状態変更
useEffect(() => {
console.log('onChangeWebcamStatus')
homeStore.setState({ webcamStatus: showWebcam })
@@ -84,7 +101,10 @@ export const Menu = () => {
return (
<>
-
+
{showSettingsButton && (
{
}}
/>
+ {slideMode && (
+
+
+ menuStore.setState({ slideVisible: !slideVisible })
+ }
+ disabled={slidePlaying}
+ />
+
+ )}
+
+ {slideMode && slideVisible && }
+
{webSocketMode ? showChatLog &&
: showChatLog &&
}
{showSettings &&
setShowSettings(false)} />}
- {!showChatLog && assistantMessage && (
+ {!showChatLog && assistantMessage && !slideVisible && (
)}
{showWebcam && navigator.mediaDevices && }
diff --git a/src/components/messageInput.tsx b/src/components/messageInput.tsx
index 9a8add2a..e3813b44 100644
--- a/src/components/messageInput.tsx
+++ b/src/components/messageInput.tsx
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import homeStore from '@/features/stores/home'
+import slideStore from '@/features/stores/slide'
import { IconButton } from './iconButton'
type Props = {
@@ -22,6 +23,7 @@ export const MessageInput = ({
onClickSendButton,
}: Props) => {
const chatProcessing = homeStore((s) => s.chatProcessing)
+ const slidePlaying = slideStore((s) => s.isPlaying)
const [rows, setRows] = useState(1)
const [loadingDots, setLoadingDots] = useState('')
@@ -45,11 +47,15 @@ export const MessageInput = ({
!event.nativeEvent.isComposing &&
event.keyCode !== 229 && // IME (Input Method Editor)
event.key === 'Enter' &&
- !event.shiftKey &&
- userMessage.trim() !== ''
+ !event.shiftKey
) {
- onClickSendButton(event as unknown as React.MouseEvent)
- setRows(1)
+ event.preventDefault() // デフォルトの挙動を防止
+ if (userMessage.trim() !== '') {
+ onClickSendButton(
+ event as unknown as React.MouseEvent
+ )
+ setRows(1)
+ }
} else if (event.key === 'Enter' && event.shiftKey) {
setRows(rows + 1)
} else if (
@@ -81,7 +87,7 @@ export const MessageInput = ({
}
onChange={onChangeUserMessage}
onKeyDown={handleKeyPress}
- disabled={chatProcessing}
+ disabled={chatProcessing || slidePlaying}
className="bg-surface1 hover:bg-surface1-hover focus:bg-surface1 disabled:bg-surface1-disabled disabled:text-primary-disabled rounded-16 w-full px-16 text-text-primary typography-16 font-bold disabled"
value={chatProcessing ? '' : userMessage}
rows={rows}
diff --git a/src/components/settings/index.tsx b/src/components/settings/index.tsx
index 36f54724..3e881dbd 100644
--- a/src/components/settings/index.tsx
+++ b/src/components/settings/index.tsx
@@ -13,6 +13,7 @@ import ModelProvider from './modelProvider'
import Voice from './voice'
import WebSocket from './websocket'
import YouTube from './youtube'
+import Slide from './slide'
type Props = {
onClickClose: () => void
@@ -90,6 +91,15 @@ const Main = () => {
+
+ {t('SlideSettings')}
+
+
+
+ {/* スライド設定 */}
+
+
+
{t('OtherSettings')}
diff --git a/src/components/settings/modelProvider.tsx b/src/components/settings/modelProvider.tsx
index 1a581f30..a4aa30fc 100644
--- a/src/components/settings/modelProvider.tsx
+++ b/src/components/settings/modelProvider.tsx
@@ -2,9 +2,11 @@ import { useTranslation } from 'react-i18next'
import homeStore from '@/features/stores/home'
import menuStore from '@/features/stores/menu'
import settingsStore from '@/features/stores/settings'
+import slideStore from '@/features/stores/slide'
import { SYSTEM_PROMPT } from '@/features/constants/systemPromptConstants'
import { Link } from '../link'
import { TextButton } from '../textButton'
+import { useCallback } from 'react'
const ModelProvider = () => {
const webSocketMode = settingsStore((s) => s.webSocketMode)
@@ -35,6 +37,36 @@ const ModelProvider = () => {
dify: '',
}
+ const handleAIServiceChange = useCallback(
+ (newService: keyof typeof defaultModels) => {
+ settingsStore.setState({
+ selectAIService: newService,
+ selectAIModel: defaultModels[newService],
+ })
+
+ if (newService !== 'openai') {
+ homeStore.setState({ modalImage: '' })
+ menuStore.setState({ showWebcam: false })
+
+ if (newService !== 'anthropic') {
+ settingsStore.setState({
+ conversationContinuityMode: false,
+ })
+ }
+
+ if (newService !== 'anthropic' && newService !== 'google') {
+ settingsStore.setState({
+ slideMode: false,
+ })
+ slideStore.setState({
+ isPlaying: false,
+ })
+ }
+ }
+ },
+ []
+ )
+
return webSocketMode ? null : (
@@ -44,29 +76,9 @@ const ModelProvider = () => {