ã¯ããã« ããã«ã¡ã¯ãNTTè¥¿æ¥æ¬ã®äžå·ã§ãã æ¬èšäºã§ã¯ãIndexedDBïŒä¿åïŒãš Transformers.jsïŒèšç®ïŒãçµã¿åããããã©ãŠã¶å
ã§ã¡ã¢ã®æå³æ€çŽ¢ãŸã§ã®Local-First AIå
¥éãããããµã³ãã«ãçšããŠç޹ä»ããŸãã æ¬èšäºã¯2026幎6ææç¹ã®æ
å ±ã«åºã¥ããŸãã çæAIã身è¿ã«ãªã£ãäžæ¹ã§ããAPIã«ãã¹ãŠä»»ããã°ããã®ã§ã¯ïŒããšæããæ¹ãå€ããšæããŸãã ç§ãæåã¯ããæã£ãŠããŸããããã ãè°äºã¡ã¢ãã¯ã©ãŠãã«è²Œããã³ã«ããã®æ¬æãéã£ãŠããã®ããªããšè¿·ãå Žé¢ãããããã®ãã³ã«å€æããã®ã¯è² æ
ã«æããã®ã§ããã©ãŠã¶å
ã§å®çµããæ€çŽ¢ã詊ããŠã¿ããšããããããªãã«äœ¿ãæãããããã«æããããããµã³ãã«ã亀ããŠã玹ä»ããŸãã 察象èªè
LocalStorageãIndexedDBã®åºæ¬çãªäœ¿ãæ¹ã¯çè§£ããŠããæ¹ AIãã¢ããªã±ãŒã·ã§ã³ã«çµã¿èŸŒã¿ãããããµãŒããŒè²»çšããã©ã€ãã·ãŒé¢ã«èª²é¡ãæããŠããæ¹ Local-First AI ã®æçšæ§ãæœè±¡çã§ãèªç€Ÿãããã¯ãã®ã©ãã§å¹ããã€ã¡ãŒãžãã¥ããæ¹ ãAIã«ã³ãŒããæžããããæ®µéããããAIããã©ãŠã¶ç°å¢ãžæé©åãããæ®µéãžã¹ãããã¢ãããããæ¹ ç®æ¬¡ ã¯ãã㫠察象èªè
ç®æ¬¡ 1. èæ¯ã»ç®çïŒãªãä»ãLocal-First AIããªã®ãïŒ 1.1 Local-First AI ãšã¯äœã 1.2 ã€ã¡ãŒãžãããã Before / AfterïŒç€Ÿå
ã¡ã¢æ€çŽ¢ã®äŸïŒ BeforeïŒã¯ã©ãŠãAPIäžå¿ïŒ AfterïŒLocal-First å¯ãïŒ 1.3 æ¬èšäºã®ç¥èãæŽ»ãããŠãŒã¹ã±ãŒã¹ 1.4 çŸå®çãªæ§æïŒããŒã«ã«ãšã¯ã©ãŠãã®åœ¹å²åæ
1.5 ãã¯ãã«æ€çŽ¢ãçšããã¢ããªã±ãŒã·ã§ã³ãçŽé¢ãããã3ã€ã®èª²é¡ 1.6 Local-First AIãåããªãã±ãŒã¹ 2. æè¡çã¢ãããŒãïŒIndexedDBïŒé·æèšæ¶ïŒÃ Transformers.jsïŒæšè«ïŒÃ WorkerïŒæ»ãããïŒ 2.1 ãã©ãŠã¶ããAIã®è³ãã«ããïŒTransformers.jsãšæšè«ããã¯ãšã³ãïŒWASM/WebGPUïŒ 2.2 IndexedDBããAIã®é·æèšæ¶ããšããŠäœ¿ã 3. èšèšäžã®åæ 3.1 ãã®èšäºã§ãå®ãããš/å®ããªãããšã 3.2 åã蟌ã¿åãé
ãã»åããªããšãã®å¯ŸåŠ 4. ãå®è£
ããã©ãŠã¶ã ãã§åããããŒã«ã«AIã¡ã¢æ€çŽ¢ããµã³ãã« 4.1 äœãäœããïŒå®æã€ã¡ãŒãžïŒ 4.2 ãã¡ã€ã«æ§æ 4.3 è©Šãæ¹ 4.3.1 ãã¢ããŒã¿ãšæ€çŽ¢ã¯ãšãªäŸ 4.3.2 æ€çŽ¢çµæã®ã¹ã³ã¢ãšã³ãµã€ã³é¡äŒŒåºŠ å€å®ã®æµãïŒæ€çŽ¢1åãããïŒ ã³ãµã€ã³é¡äŒŒåºŠïŒæå³ã®è¿ãïŒãšã¯ ã¹ã³ã¢ã®èŠæ¹ 4.4 index.htmlïŒUIã»Workerèµ·åïŒ 4.5 embedding.worker.jsïŒCDN + IndexedDB + æ€çŽ¢ïŒ 4.6 åããªãæã®ãã§ãã¯ãã€ã³ã 4.7 ã€ãŸãããã€ã³ã 5. ãŸãšãïŒAIã«ã³ãŒããä»»ããèšèšãæ¡ãããšãå€§äº å·çè
åèè³æã»åºå
ž åæš 1. èæ¯ã»ç®çïŒãªãä»ãLocal-First AIããªã®ãïŒ 1.1 Local-First AI ãšã¯äœã Local-First AI ã¯ãããã¹ãŠã®AIããã©ãŠã¶ã ãã§å®çµããããããšãšå矩ã§ã¯ãããŸãããã¯ã©ãŠãã®ãµãŒããŒãªã©ã«é Œãã®ã§ã¯ãªããèªèº«ã®ããœã³ã³ãã¹ããŒããã©ã³ãªã©æå
ã®ç«¯æ«ïŒããŒã«ã«ç°å¢ïŒäžã§AIã®åŠçãåŠç¿ãå®çµãããèãæ¹ã®äºãæããŸããæ¬èšäºã§æ±ãã®ã¯ããããªèšèšã§ãã ããŒã¿ïŒã¡ã¢ã»ãã°ã»äžæžãïŒã¯ãã©ãŠã¶å
ïŒIndexedDBïŒã«çœ®ã ååŸïŒåã蟌ã¿ã»é¡äŒŒæ€çŽ¢ã»åé¡ãªã©ïŒã¯ç«¯æ«åŽã§åã æç« çæïŒé·æã®èŠçŽã»é«åºŠãªåçïŒã¯å¿
èŠãªãšãã ãã¯ã©ãŠãAPIãžå¯ãã ã€ãŸããã€ããªãããªæ§æã§ãããéåžžã®LLMã®å§åçãªè³¢ããããããéããããªãããŒã¿ãéããªãïŒåŸ
ã¡ãæžããïŒAPI代ãæããããšãã£ãèŠä»¶ã«ãããããèãæ¹ã«ãªããŸãã 1.2 ã€ã¡ãŒãžãããã Before / AfterïŒç€Ÿå
ã¡ã¢æ€çŽ¢ã®äŸïŒ 瀟å
WebããŒã«ãæ³å®ãããäœéšã®éãã§ãã BeforeïŒã¯ã©ãŠãAPIäžå¿ïŒ è°äºã¡ã¢100ä»¶ã®äžããæ€çŽ¢ããã å
¥åã®ãã³ã«èªåã®ããã¯ãšã³ãAPIçµç±ã§ãEmbeddingã¢ãã«ïŒããã¹ããç»åãªã©ã®éæ§é åããŒã¿ãæ°å€ã®é
åïŒãã¯ãã«ïŒã«å€æããæè¡ã®ããšïŒãžæ¬æãéä¿¡ããåã蟌ã¿å æžå¿µ: æ
å ±æã¡åºãããªã·ãŒããã°ä¿åãAPI課éãåç·ã匱ããšåŸ
ã¡ãçºçããŠããŸã AfterïŒLocal-First å¯ãïŒ ã¡ã¢æ¬æã¯ IndexedDB ã«ä¿åïŒãã©ãŠã¶å
ïŒ ãå
é±ã®é害察å¿ããªã©ã®ã¯ãšãªã¯ç«¯æ«å
ã§åã蟌ã¿å â é¡äŒŒã¡ã¢ãäžäœè¡šç€º æ¬æãå€éšãžéããªãèšèšã«ããããïŒååã®ã¢ãã«ååŸéä¿¡ã¯å¥éçºçïŒ ã¢ãã«ååŸåŸã®æ€çŽ¢ã¯ãåã蟌ã¿èšç®ã端æ«åŽã§å®è¡ãããµãŒããŒãžæ¬æãéããã«å¿çã§ãã ãã®èšäºã®ãµã³ãã«ã¯ After ã®ãã¡ãæå³ãè¿ãã¡ã¢ãæ¢ããéšåã ãã§ããèŠçŽããã£ããçæãŸã§ã¯æ±ããªãã®ã§çæããŠãã ããã 1.3 æ¬èšäºã®ç¥èãæŽ»ãããŠãŒã¹ã±ãŒã¹ 次ã®ãããªãŠãŒã¹ã±ãŒã¹ã§ã¯æ¬èšäºã®èãæ¹ãæŽ»èºã§ããããªãšæããŸãã ãèªèº«ã®ãããã¯ããšç
§ããåãããŠæ€èšããŠã¿ãŠãã ããã ã·ãŒã³ å°ãããš Local-First ã§ãããããã㚠瀟å
ã»å人ã®ã¡ã¢ã»è°äºé²ã®æ€çŽ¢ ã¯ã©ãŠãLLMã«è²Œããšæ
å ±ç®¡çãäžå® æ¬æãéããæå³æ€çŽ¢ïŒæ¬èšäºã®ãã¢ïŒ åç·ãäžå®å®ãªçŸå Žã»åºèã»ã€ãã³ã åç·ãäžå®å®ã§APIåŸ
ã¡ãèŽåœç ã¢ãã«ååŸåŸã¯ãªãã©ã€ã³å¯ãã§æ€çŽ¢ã»åé¡ å
¥åäžã®è£å©UI ãµãŒããŒåŸåŸ©ã§å
¥åã®åå¿ãéããªã Worker + ããŒã«ã«æšè«ã§äœæéåºŠãæ¹å äŒç»ã»æ€èšŒãã§ãŒãº ãµãŒããŒæ§ç¯åã«äœéšã詊ããã ããŒã«ã«ãã¡ã€ã«ã§ä»®èª¬æ€èšŒ 1.4 çŸå®çãªæ§æïŒããŒã«ã«ãšã¯ã©ãŠãã®åœ¹å²åæ
å
šéšããŒã«ã«ã«å¯ããå¿
èŠã¯ãããŸããã圹å²ãåãããšèšèšããããã§ãã ãã©ãŠã¶: ä¿åã»æ€çŽ¢ã»åé¡ãªã©ãèªåã®ããŒã¿ã«ã ãå¹ãåŠçã ã¯ã©ãŠã: å質æåªå
ã®çæãå
šç€Ÿãã¬ããžæšªæãªã©ãããŒã¿ãéã£ãŠãããåŠçã 1.5 ãã¯ãã«æ€çŽ¢ãçšããã¢ããªã±ãŒã·ã§ã³ãçŽé¢ãããã3ã€ã®èª²é¡ ãããããŠãŒã¹ã±ãŒã¹ãå¹ãèæ¯ãšããŠã次ã®3ã€ãããåºãŠããŸãã APIã³ã¹ã: ãã¹ãŠã®ãªã¯ãšã¹ãããµãŒããŒãžéããšããŠãŒã¶ãŒå¢ã»å©çšåæ°ã«äŒŽãã³ã¹ããèšãã¿ãããã ãã©ã€ãã·ãŒ: è°äºã¡ã¢ã»é¡§å®¢å¯Ÿå¿ã¡ã¢ãªã©ãå€éšãµãŒããŒãžéããããªãããŒã¿ãããã å¿çæ§ïŒã¬ã€ãã³ã·ãŒïŒ: ãããã¯ãŒã¯çµç±ã®æšè«ã¯ãéåžžãåŸ
æ©æéãçºçããã IndexedDBïŒä¿åïŒãš Transformers.js ãªã©ã䜿ã£ã端æ«å
æšè«ïŒèšç®ïŒãçµã¿åããããšãããããåæã«ç·©åããããå Žé¢ããããŸãïŒç«¯æ«æ§èœã»ãã©ãŠã¶å¯Ÿå¿ãªã©ã®å¶çŽã¯ãããŸãïŒã 1.6 Local-First AIãåããªãã±ãŒã¹ äžèœã§ã¯ãªãã®ã§ãåããªãã±ãŒã¹ãæžããŠãããŸãã é«å質ãªé·æçæãäž»ç®ç å
šç«¯æ«ã§åãå質ãå³å¯ã«ä¿èšŒããã 瀟å
ææžãæ°çŸäžä»¶åäœã§æšªææ€çŽ¢ãããïŒå°çšãã¯ãã«DBãå¿
èŠïŒ ã¢ãã«é
åžã»æŽæ°ã峿 Œã«çµ±å¶ãããç°å¢ ããããèŠä»¶ãäž»ãªãããµãŒããŒåŽã®RAGïŒæ€çŽ¢æ¡åŒµçæïŒãã¯ã©ãŠãAPIã䞻圹ã«ããããŒã«ã«ã¯è£å©ãšããæ§æãçŸå®çã§ãã ä»åã®ãã¢ããã£ãŠããã®ã¯ãããã ãã§ãã èªåã®ã¡ã¢ã ãããããŒã¯ãŒãäžèŽã§ã¯ãªããæå³ãè¿ãé ãã§æ¢ãããã¡ã¢æ¬æãèªåAPIãžéããã«æžãã RAGïŒæ€çŽ¢æ¡åŒµçæïŒã§ãããšãæ¬ãã¢ã¯ RïŒRetrievalïŒæ€çŽ¢ïŒã ãã§ããLLM ãžã®æž¡ãæ¹ãåççæïŒGïŒã¯æ±ããŸããã 2. æè¡çã¢ãããŒãïŒIndexedDBïŒé·æèšæ¶ïŒÃ Transformers.jsïŒæšè«ïŒÃ WorkerïŒæ»ãããïŒ å
ã»ã©ã®å³ã§ç€ºããããã©ãŠã¶å
ãããå
·äœçãªæè¡èŠçŽ ã«åè§£ããŸãã 2.1 ãã©ãŠã¶ããAIã®è³ãã«ããïŒTransformers.jsãšæšè«ããã¯ãšã³ãïŒWASM/WebGPUïŒ çŸä»£ã®ãã©ãŠã¶ã¯WebAssemblyãWebGPU APIãéããŠãé«éãªæŒç®ã掻çšã§ããç°å¢ãå¢ããŠããŸãããããã«JavaScriptåãæšè«ã©ã€ãã©ãªïŒäŸïŒTransformers.jsïŒãçµã¿åããããšãPythonç°å¢ãèªåãµãŒããŒã«äŸåããããã©ãŠã¶äžã§æšè«ãå®è¡ã§ããæ§æãåãããããªããŸãã ãµã³ãã«ã¯ãTransformers.js ã CDNïŒjsDelivrïŒããèªã¿èŸŒãã ãã§åãããŸãããã«ãããŒã«ã¯äœ¿ããŸããã Transformers.js ã¯ç°å¢ã«å¿ã㊠WebAssemblyïŒWASMïŒã WebGPU ãªã©ãžãã©ãŒã«ããã¯ããŸããæ¬èšäºã®ãµã³ãã«ã³ãŒãã¯ãããã©ã«ãã® WASM ããã¯ãšã³ãã§æšè«ããŸãã 2.2 IndexedDBããAIã®é·æèšæ¶ããšããŠäœ¿ã RAGïŒæ€çŽ¢æ¡åŒµçæïŒã¯ãå¿
èŠãªç¥èãæ€çŽ¢ããŠããçæã«æž¡ããèãæ¹ã§ããããã§ã¯ããã©ãŠã¶å
ã«ä¿åããã¡ã¢çŸ€ãåã蟌ã¿ïŒãã¯ãã«ïŒåããŠIndexedDBã«ä¿åããã¯ãšãªã«è¿ããã®ãåãåºãããšããã§ããã ã軜ããªæ§æã«ããŠããŸãã ãŸãããã©ãŠã¶ã§AIåŠçãåããéã®ããã«ããã¯ã«ãªããããã®ããã¡ã€ã³ã¹ã¬ããã®å æã§ããUIæç»ã»å
¥åã»ã¹ã¯ããŒã«ãè©°ãŸããšããŠãŒã¶ãŒäœéšã«æªåœ±é¿ãåºãŸããã¡ã€ã³ã¹ã¬ãããš Worker ã§åœ¹å²ãåããŸãã ã¡ã€ã³ã¹ã¬ãã: UIã®æç»ããŠãŒã¶ãŒå
¥åãçµæè¡šç€º Web Worker: ã¢ãã«ããŒããåã蟌ã¿èšç®ãé¡äŒŒåºŠèšç®ãIndexedDBãžã®æžã蟌㿠3. èšèšäžã®åæ 3.1 ãã®èšäºã§ãå®ãããš/å®ããªãããšã ãããŒã«ã«ã«ä¿åããïŒå®å
šãã§ã¯ãããŸãããããã¯èª€è§£ãèµ·ããããã®ã§ãåæãèšããŸãã å®ããããããšïŒèšèšã§ã³ã³ãããŒã«ããããïŒ ãŠãŒã¶ãŒãå
¥åããã¡ã¢æ¬æããèªåAPIãžéããªãèšèšã«ã§ãã APIã³ã¹ããæããããïŒç«¯æ«å
æšè«ã«å¯ããã»ã©ïŒ å®ããªãããšïŒå¥å¯Ÿçãå¿
èŠïŒ 端æ«ã®ãã«ãŠã§ã¢ææãæªæ§ãã©ãŠã¶æ¡åŒµã端æ«çé£ãªã©ã¯ããŒã«ã«ä¿åã ãã§ã¯é²ããªã XSSïŒã¯ãã¹ãµã€ãã¹ã¯ãªããã£ã³ã°ïŒã§åäžãªãªãžã³äžã®ããŒã¿ãèªãŸãããªã¹ã¯ã¯èŽåœçïŒCSPïŒContent Security Policyã»ãµãã¿ã€ãºãªã©ãåæïŒ ååã ãå€éšéä¿¡ãçºçãã Transformers.js ã¯ã¢ãã«éã¿ã CDN / Hugging Face ããååŸããŸãïŒã¡ã¢æ¬æãã®ãã®ãéãããã§ã¯ãªãããéä¿¡èªäœã¯çºçããŸãïŒ ç€Ÿå
ãããã·ããã¡ã€ã¢ãŠã©ãŒã«ã§å€éš CDN ãå¶éãããŠããç°å¢ã§ã¯ãååã®ã¢ãã«ååŸã倱æããããšããããŸãïŒå¥éãããã¯ãŒã¯èšå®ã®ç¢ºèªãå¿
èŠïŒ 3.2 åã蟌ã¿åãé
ãã»åããªããšãã®å¯ŸåŠ ç«¯æ«ããã©ãŠã¶ã«ãã£ãŠãåã蟌ã¿ã®éãã¯ããªãå€ãããŸããæ¬èšäºã®ãµã³ãã«ã¯ãTransformers.js ã®æ¢å®ã©ãã WASMïŒCPUäžã§åãæ¹åŒïŒã§åãåæã§ããWebGPU ã䜿ããç°å¢ã§ã¯éããªãããšããããŸãããå¿
é ã§ã¯ãããŸããã å°ã£ããšãã¯ããã®é ã§è©Šããšããã§ãã ãŸãåãã â WASM ã§ç»é²ã»æ€çŽ¢ãŸã§éãïŒä»åã®ãã¢ã¯ãããŸã§ïŒ äœåãããã°éããã â 端æ«ã察å¿ããŠããã° WebGPU ã䜿ãïŒTransformers.js ãèªåã§éžã¶ïŒ ããã§ãå³ãã â æå³æ€çŽ¢ããããã®ã§ã¯ãªããè² è·ãäžããïŒããŒã¯ãŒãæ€çŽ¢ã«åãæ¿ãããç»é²ä»¶æ°ã topK ãæžãã ãªã©ïŒ 4. ãå®è£
ããã©ãŠã¶ã ãã§åããããŒã«ã«AIã¡ã¢æ€çŽ¢ããµã³ãã« 4.1 äœãäœããïŒå®æã€ã¡ãŒãžïŒ 1ç« ã® After ããHTML ãšJavaScriptã®2ãã¡ã€ã«ã§åããæ®µéã§ããã¡ã¢ç»é² â åã蟌ã¿ä¿å â ã¯ãšãªã§æå³æ€çŽ¢ããšããæµãã ãã«çµã£ãŠããŸãããã£ããåçã瀟å€API飿ºã¯ç¯å²å€ã§ãã 4.2 ãã¡ã€ã«æ§æ 次ã®2ãã¡ã€ã«ãåããã©ã«ãã«çœ®ããŸãã index.html ⊠UIïŒã¡ã€ã³ã¹ã¬ããïŒ embedding.worker.js ⊠åã蟌ã¿åã»IndexedDBã»æ€çŽ¢ïŒWorkerïŒ 4.3 è©Šãæ¹ ãã®ç« ã® index.html ãš embedding.worker.js ã®ã³ãŒãããããããååãã¡ã€ã«ãšããŠåããã©ã«ãã«ä¿åãã Visual Studio Code ã® Live Server ãªã©ã§ããã®ãã©ã«ãã http://localhost:... çµç±ã§éãïŒ file:// ã§çŽæ¥éããš Worker ãåããªãããšãå€ãã§ãïŒ Google Chrome ãŸã㯠Microsoft Edge ã§ index.html ã衚瀺ãã ããã¢ããŒã¿ãäžæ¬ç»é²ãã§ãµã³ãã«ãå
¥ããïŒååã¯ã¢ãã«ååŸã§æ°åç§ãããããšããããŸãïŒããç»é²ããã1ä»¶ãã€è¶³ããŠè©ŠããŠãããŸããŸãã äžã®æ€èšŒè¡šãšçµæãæ¯ã¹ãããšãã ããä»¶æ°ã6ä»¶ã§ãªããã°ããã¹ãŠåé€ãâããã¢ããŒã¿ãäžæ¬ç»é²ãã§æãã æ€èšŒè¡šã®ã¯ãšãªã§æ€çŽ¢ããŠã¿ãïŒã¡ã¢ã6ä»¶æªæºã§ãæ€çŽ¢ã¯åããŸãã衚瀺件æ°ã¯ãç»é²ä»¶æ°ãš5ä»¶ã®å°ãªãæ¹ãŸã§ïŒ åäœç¢ºèªã®ç®å®: æ€èšŒè¡šã䜿ãå Žåãåã¯ãšãªã§ãæåŸ
ãããäžäœãã¢ããŒã¿ãã1äœãç°å¢ã«ãã£ãŠã¯2äœä»¥å
ãªãæå³ã©ããã§ããå©çšã¢ãã«ã¯ Xenova/all-MiniLM-L6-v2 ã§ãè±èªåããäž»ã§ããæ¥æ¬èªã®ãã¢ã§ãåããŸãããé äœã¯ç«¯æ«ãã¯ãšãªã§ååŸããããšããããŸããçµæã®æ°å€ïŒäŸ: 0.165 ïŒã®èªã¿æ¹ã¯ãç¶ããæ€çŽ¢çµæã®ã¹ã³ã¢ãšã³ãµã€ã³é¡äŒŒåºŠããèŠãŠãã ãããTransformers.js 㯠@xenova/transformers@2.17.2 ïŒCDNïŒã§åºå®ããŠããŸãã 4.3.1 ãã¢ããŒã¿ãšæ€çŽ¢ã¯ãšãªäŸ ããã¢ããŒã¿ãäžæ¬ç»é²ããããš6ä»¶å
¥ããŸãã6ä»¶ããæ±ããªãããã§ã¯ãªããäžã®æ€èšŒè¡šããã®6ä»¶ãæ³å®ããŠããã ãã§ãã äžæ¬ç»é²ããããã¢ããŒã¿ [é害察å¿] 2026-03-15 èªèšŒåºç€ã¿ã€ã ã¢ãŠãã®ä»¶ãåå ã¯DBã®ã³ãã¯ã·ã§ã³ããŒã«æ¯æžãåçºé²æ¢çãšããŠãªãã©ã€äžéã3åã«å€æŽããã¢ã©ãŒãéŸå€ã調æŽããã [æé ] 瀟å€ããã®VPNæ¥ç¶ã«ã€ããŠã瀟å€ãããã¯ãŒã¯ããã¯ããŒã¿ã«çµç±ã§ã®ã¿ã¢ã¯ã»ã¹å¯èœããã¹ã¯ãŒãã¯ITãµããŒãã«ãã±ãããçºè¡ããŠååŸããããšã [顧客A瀟] å¥çŽäžã®ç¹èšäºé
ïŒãã°ã«å人æ
å ±ïŒæ°åã»ã¡ã¢ãïŒãäžåæ®ããªãããšãåãåãã察å¿ã¯å°ä»»ã®ãµããŒãçªå£ãçµç±ããããšã [è°äºé²] 4/1 éçºå®äŸã次æãªãªãŒã¹ã®ç®çã¯RAGæ©èœã®åŒ·åãã€ã³ãã©è²»çšãæãããããäžéšã®æ€çŽ¢åŠçãããã³ããšã³ãïŒãã©ãŠã¶åŽïŒã«ãªãããŒãããæ¹éã§åæã [æè¡ã¡ã¢] åãèŸŒã¿æšè«ã¯ Transformers.jsïŒWASMïŒãæ¢å®ã端æ«ã察å¿ããŠããã° WebGPU ããã¯ãšã³ãã§ GPU æšè«ã«åãæ¿ãå¯èœã [ãªã³ããŒãã£ã³ã°] æ°å
¥ç€Ÿå¡åãPCã»ããã¢ããæé ãåæãã¹ã¯ãŒãã¯å
¥ç€Ÿåæ¥ã«é
åžãããè³æãåç
§ããŸãã¯ã»ãã¥ãªãã£ç ä¿®åç»ã®èŠèŽãå®äºãããããšã æ€çŽ¢ã¯ãšãªãšæåŸ
ãããäžäœãã¢ããŒã¿ æ€çŽ¢ã¯ãšãª æåŸ
ãããäžäœãã¢ããŒã¿ å
é±ã®èªèšŒãšã©ãŒã®åçºé²æ¢ ã¡ã¢1 瀟å€ãã瀟å
ã·ã¹ãã ã«å
¥ã ã¡ã¢2 å人æ
å ±ã®åãæ±ãã«ãŒã« ã¡ã¢3 ã³ã¹ãåæžã®èšèš ã¡ã¢4 GPU æšè« ã¡ã¢5 æ°äººã®åæèšå® ã¡ã¢6 ç»å£ 該åœã¡ã¢ãªãïŒèªå¥äžèŽãªãã»çžå¯Ÿé äœã®ã¿ïŒ 4.3.2 æ€çŽ¢çµæã®ã¹ã³ã¢ãšã³ãµã€ã³é¡äŒŒåºŠ æ€çŽ¢çµæã¯ãã ãããæ¬¡ã®åœ¢ã§åºãŸãã 0.165 (æå³ 0.165) [èªå¥äžèŽ +0.12] - [id=5] [æè¡ã¡ã¢] åãèŸŒã¿æšè«ã¯ Transformers.jsïŒWASMïŒãæ¢å®ã⊠0.411 (æå³ 0.411) [èªå¥äžèŽãªã] - [id=14] [æé ] 瀟å€ããã®VPNæ¥ç¶ã«ã€ããŠã⊠å
é ã® 0.165 ã¯æçµã¹ã³ã¢ã§ãæ¬åŒ§å
ã® æå³ 0.165 ã¯ã³ãµã€ã³é¡äŒŒåºŠïŒæå³ã®è¿ãïŒã ããæãåºããå€ã§ãã [èªå¥äžèŽ +0.12] ã¯ã¯ãšãªæååãæ¬æã«å«ãŸãããšãã®å ç¹ã [èªå¥äžèŽãªã] ã¯å ç¹ãä»ããŠããªãããšã瀺ããŸãããµã³ãã«ã§ã¯ searchScore ã§ã¹ã³ã¢ãäœããéé ã«äžŠã¹ãŠããŸãã å€å®ã®æµãïŒæ€çŽ¢1åãããïŒ ãæ€çŽ¢ããã¿ã³ãæŒããŠããçµæã䞊ã¶ãŸã§ã®æµãã§ãïŒWeb Worker å
ã§å®çµããã¡ã¢æ¬æã¯å€éš API ãžéããŸããïŒã topKïŒãããã±ã€ïŒã¯ãã¹ã³ã¢é ã®äžäœKä»¶ã ãè¿ãããšããæå³ã§ããK ã¯è¿ãä»¶æ°ã§ã倿°åãšã㊠topK ãšæžãããšãå€ãã§ããæ¬ãµã³ãã«ã§ã¯ worker.postMessage({ type: 'search', payload: { query, topK: 5 } }) ã®ãšãã 5ä»¶ã§ãã ã¡ã¢1ä»¶ãããã®ã¹ã³ã¢èšç®ïŒ searchScore ïŒã¯ãæå³ã®è¿ãïŒãã¯ãã«ïŒãšèªå¥äžèŽïŒæååïŒãçµã¿åãããŠããŸãã ç»é²æã¯éæ¹åã§ããã¡ã¢æ¬æãåã蟌ã¿åã㊠text ãš vector ã IndexedDB ã«ä¿åããŸãïŒæ€çŽ¢ã®ãã³ã«åèšç®ããŸããïŒã ã³ãµã€ã³é¡äŒŒåºŠïŒæå³ã®è¿ãïŒãšã¯ Transformers.js ã®ãããªåã蟌ã¿ã¢ãã«ã¯ãã¡ã¢æ¬æãæ€çŽ¢èªããã¯ãã«ïŒæ°å€ã®äžŠã³ïŒã«å€æããŸãã䌌ãæå³ã®æã¯ã䌌ããã¯ãã«ã«ãªããŸããæå³ã§æ¢ããšãã¯ããã¯ãã«å士ã®è¿ãã§äžŠã¹ãã®ãäžè¬çã§ãã ãã®è¿ããæž¬ãææšãã³ãµã€ã³é¡äŒŒåºŠã§ããç»é¢ã® (æå³ 0.xxx) ãããã§ããããã 0ã1 ã®ç¯å²ã§ãïŒ1ã«è¿ãã»ã©æå³ãè¿ãïŒãæ€çŽ¢ã®æ¹æ³èªäœã¯ä»ã«ããããèªãæ¬æã«å«ãŸãããã ããèŠãããŒã¯ãŒãæ€çŽ¢ïŒGoogleæ€çŽ¢ã«è¿ãïŒããã䜿ãããŸããæ¬ãã¢ã¯æå³æ€çŽ¢ãäž»ã«ããèªå¥äžèŽã¯ [èªå¥äžèŽ] ã®å°å¹
ãªå ç¹ãšããŠè¶³ããŠããŸãããã®ãããé害ããã¿ã€ã ã¢ãŠãããšãã£ãèªãæ¬æã«ç¡ããŠããå
容ãè¿ããã°äžäœã«æ¥ãŸãã æçµã¹ã³ã¢ã¯ãã³ãµã€ã³é¡äŒŒåºŠã«ãæ€çŽ¢èªãæ¬æã«ãã®ãŸãŸå«ãŸãããšãã®å°å¹
ãªå ç¹ïŒ [èªå¥äžèŽ] ïŒãè¶³ãããã®ã§ãã ã¹ã³ã¢ã®èŠæ¹ ã¹ã³ã¢ãèªããšãã¯ã次ã®3ã€ãèŠãã°ååã§ãã é äœïŒ0.05 ã§ã 0.4 ã§ããæ°å€ãã䞊ã³ãèªç¶ããèŠã [èªå¥äžèŽ] ïŒä»ããŠããã°ãæ€çŽ¢èªãæ¬æã«å«ãŸããŠãããç¡ããã°ã³ãµã€ã³é¡äŒŒåºŠã ãã§äžŠãã§ãã ä»¶æ°ïŒæå€§5ä»¶ãŸã§åºãããç»é²ã3ä»¶ãªã3ä»¶ãŸã§ãè¿ãé ã«äžŠãã§ããã ãã®ããšããã æ€èšŒè¡šã©ãã6ä»¶å
¥ããç¶æ
ã§ ç»å£ ãæ€çŽ¢ãããšã 0.411 ãªã©ã®æ°å€ãåºãŠãèŠã€ãã£ãã®ããªïŒããšè¿·ããŸãããã©ã®ã¡ã¢ã«ããã®èªã¯ãªãããã¹ãŠ [èªå¥äžèŽãªã] ã§ãããæ°åãä»ããŠããŠããç»é²ãããŠããã¡ã¢ã®ãã¡çžå¯Ÿçã«è¿ãã£ãã ãããšããæå³ã§ããç»é¢äžã®æ³šææãš (æå³ 0.xxx) ãããããŠèŠãŠãã ããã 4.4 index.html ïŒUIã»Workerèµ·åïŒ ã¡ã€ã³ã¹ã¬ãã㯠UI ãš Worker ãžã®ã¡ãã»ãŒãžéåä¿¡ã ããæ
åœããŸãã <!doctype html> < html lang = "ja" > < head > < meta charset = "UTF-8" /> < meta name = "viewport" content = "width=device-width, initial-scale=1.0" /> < title > Local-First AI Memo Search </ title > < style > body { font-family : system-ui , sans-serif ; max-width : 720px ; margin : 2rem auto ; padding : 0 1rem ; line-height : 1.6 ; } textarea , input { width : 100% ; box-sizing : border-box ; } button { margin-top : 0.5rem ; } #status { min-height : 1.5rem ; color : #333 ; margin-top : 1rem ; } ol , ul { padding-left : 1.25rem ; } #memos li { margin-bottom : 0.5rem ; font-size : 0.95rem ; } #memos .meta { color : #666 ; font-size : 0.85rem ; } .note { font-size : 0.9rem ; color : #555 ; background : #f6f6f6 ; padding : 0.75rem 1rem ; border-radius : 6px ; } </ style > </ head > < body > < h1 > Local-First AI Memo Search </ h1 > < section > < h2 > ã¡ã¢ç»é² </ h2 > < textarea id = "memo" rows = "4" placeholder = "ã¡ã¢ãå
¥å" ></ textarea > < button id = "add" type = "button" > ç»é² </ button > < button id = "loadDemo" type = "button" style = "margin-left: 1rem;" > ãã¢ããŒã¿ãäžæ¬ç»é² </ button > < button id = "clearAll" type = "button" style = "margin-left: 1rem;" > ãã¹ãŠåé€ </ button > </ section > < section > < h2 id = "memosHeading" > ç»é²æžã¿ã¡ã¢ïŒèªã¿èŸŒã¿äžâŠïŒ </ h2 > < ul id = "memos" ></ ul > </ section > < section > < h2 > æ€çŽ¢ </ h2 > < input id = "q" type = "search" placeholder = "äŸ: WebGPU æšè« / 瀟å€ãã瀟å
ã·ã¹ãã / ç»å£ïŒç¡é¢ä¿ã¯ãšãªã®äŸïŒ" /> < button id = "go" type = "button" > æ€çŽ¢ </ button > < p class = "note" style = "margin-top: 0.5rem;" > çµæã¯ < code > æçµã¹ã³ã¢ (æå³ã¹ã³ã¢) [èªå¥äžèŽ] </ code > ã®é ã§ããèªå¥äžèŽãç¡ããšãã¯ã ç»é²ã¡ã¢ã®äžã§ãã¯ãã«ãçžå¯Ÿçã«è¿ãé ã«äžŠãã§ããã ãã§ãå¿
ãããé¢é£ã¡ã¢ãããããã§ã¯ãããŸããã </ p > < ol id = "results" ></ ol > </ section > < div id = "status" aria-live = "polite" ></ div > < script type = "module" > const memoEl = document . getElementById ( 'memo' ) ; const addBtn = document . getElementById ( 'add' ) ; const loadDemoBtn = document . getElementById ( 'loadDemo' ) ; const clearAllBtn = document . getElementById ( 'clearAll' ) ; const memosHeading = document . getElementById ( 'memosHeading' ) ; const memosEl = document . getElementById ( 'memos' ) ; const qEl = document . getElementById ( 'q' ) ; const goBtn = document . getElementById ( 'go' ) ; const resultsEl = document . getElementById ( 'results' ) ; const statusEl = document . getElementById ( 'status' ) ; const worker = new Worker ( './embedding.worker.js' , { type : 'module' }) ; function refreshMemos () { worker . postMessage ({ type : 'listMemos' }) ; } function renderMemos ( memos ) { memosHeading . textContent = `ç»é²æžã¿ã¡ã¢ïŒ ${ memos . length } ä»¶ïŒ` ; memosEl . innerHTML = '' ; if ( memos . length === 0 ) { const li = document . createElement ( 'li' ) ; li . textContent = 'ãŸã ã¡ã¢ã¯ç»é²ãããŠããŸãããããã¢ããŒã¿ãäžæ¬ç»é²ãã§è©ŠããŸãã' ; memosEl . appendChild ( li ) ; return; } for ( const m of memos ) { const li = document . createElement ( 'li' ) ; const meta = document . createElement ( 'div' ) ; meta . className = 'meta' ; meta . textContent = `id= ${ m . id } ` ; li . appendChild ( meta ) ; li . appendChild ( document . createTextNode ( m . text )) ; memosEl . appendChild ( li ) ; } } worker . onmessage = ( ev ) => { const { type , payload } = ev . data ; if ( type === 'listMemosResult' ) { renderMemos ( payload . memos ) ; return; } if ( type === 'addMemoResult' ) { statusEl . textContent = `ç»é²ããŸããïŒid= ${ payload . id } ïŒ` ; refreshMemos () ; return; } if ( type === 'loadDemoResult' ) { statusEl . textContent = `ãã¢ããŒã¿ïŒ ${ payload . count } ä»¶ïŒãäžæ¬ç»é²ããŸããïŒæ¢åããŒã¿ã¯çœ®ãæãæžã¿ïŒã` ; refreshMemos () ; return; } if ( type === 'clearAllResult' ) { statusEl . textContent = 'ãã¹ãŠã®ã¡ã¢ãåé€ããŸããã' ; refreshMemos () ; return; } if ( type === 'searchResult' ) { resultsEl . innerHTML = '' ; if ( payload . items . length === 0 ) { const li = document . createElement ( 'li' ) ; li . textContent = '該åœããã¡ã¢ããããŸãã' ; resultsEl . appendChild ( li ) ; statusEl . textContent = '' ; } else { const anyKeyword = payload . items . some (( it ) => it . keywordMatch ) ; for ( const it of payload . items ) { const li = document . createElement ( 'li' ) ; const kwTag = it . keywordMatch ? ` [èªå¥äžèŽ + ${( it . keywordBoost ?? 0 . 12 ) . toFixed ( 2 )} ]` : ' [èªå¥äžèŽãªã]' ; li . textContent = ` ${ it . score . toFixed ( 3 )} (æå³ ${ it . semantic . toFixed ( 3 )} ) ${ kwTag } - [id= ${ it . id } ] ${ it . text } ` ; resultsEl . appendChild ( li ) ; } if ( ! anyKeyword ) { statusEl . textContent = 'ããããèªå¥äžèŽãªãã§ãã衚瀺㯠topK=5 ä»¶ã®ãçžå¯Ÿé äœãã§ãããã¯ãšãªã«è¿ãã¡ã¢ãç¡ãå Žåã§ãã¹ã³ã¢ä»ãã§äžŠã³ãŸããæ¬çªã§ã¯ã¹ã³ã¢éŸå€ãã¡ã¿ããŒã¿çµã蟌ã¿ãæ€èšããŠãã ããã' ; } else { statusEl . textContent = '' ; } } return; } if ( type === 'error' ) { statusEl . textContent = `ãšã©ãŒ: ${ payload . message } ` ; } } ; addBtn . addEventListener ( 'click' , () => { const text = memoEl . value . trim () ; if ( ! text ) return; statusEl . textContent = 'ç»é²äž...ïŒååã¯ã¢ãã«ååŸã®ããæ°åç§ãããå ŽåããããŸãïŒ' ; worker . postMessage ({ type : 'addMemo' , payload : { text } }) ; memoEl . value = '' ; }) ; loadDemoBtn . addEventListener ( 'click' , () => { statusEl . textContent = 'ãã¢ããŒã¿ãç»é²äž...ïŒååã¯ã¢ãã«ååŸã®ããæ°åç§ãããå ŽåããããŸãïŒ' ; worker . postMessage ({ type : 'loadDemoData' }) ; }) ; clearAllBtn . addEventListener ( 'click' , () => { if ( ! confirm ( 'ç»é²æžã¿ã¡ã¢ããã¹ãŠåé€ããŸããããããã§ããïŒ' )) return; worker . postMessage ({ type : 'clearAllMemos' }) ; }) ; goBtn . addEventListener ( 'click' , () => { const query = qEl . value . trim () ; if ( ! query ) return; resultsEl . innerHTML = '' ; statusEl . textContent = 'æ€çŽ¢äž...' ; worker . postMessage ({ type : 'search' , payload : { query , topK : 5 } }) ; }) ; refreshMemos () ; </ script > </ body > </ html > 4.5 embedding.worker.js ïŒCDN + IndexedDB + æ€çŽ¢ïŒ Worker åŽã§ Transformers.jsïŒCDNïŒãèªã¿èŸŒã¿ãIndexedDBïŒçAPIïŒãžä¿åã»æ€çŽ¢ããŸãã import { pipeline } from 'https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2' ; const DB_NAME = 'AI_Memory' ; const DB_VERSION = 1 ; const STORE_NAME = 'memos' ; const MODEL_ID = 'Xenova/all-MiniLM-L6-v2' ; let embedder ; // --- IndexedDBïŒçAPIïŒ --- function openDb () { return new Promise (( resolve , reject ) => { const req = indexedDB . open ( DB_NAME , DB_VERSION ) ; req . onupgradeneeded = ( event ) => { const db = event . target . result ; if ( ! db . objectStoreNames . contains ( STORE_NAME )) { const store = db . createObjectStore ( STORE_NAME , { keyPath : 'id' , autoIncrement : true , }) ; store . createIndex ( 'timestamp' , 'timestamp' ) ; } } ; req . onsuccess = () => resolve ( req . result ) ; req . onerror = () => reject ( req . error ) ; }) ; } function dbAdd ( record ) { return openDb () . then ( ( db ) => new Promise (( resolve , reject ) => { const tx = db . transaction ( STORE_NAME , 'readwrite' ) ; const req = tx . objectStore ( STORE_NAME ) . add ( record ) ; req . onsuccess = () => resolve ( req . result ) ; req . onerror = () => reject ( req . error ) ; tx . oncomplete = () => db . close () ; }) , ) ; } function dbGetAll () { return openDb () . then ( ( db ) => new Promise (( resolve , reject ) => { const tx = db . transaction ( STORE_NAME , 'readonly' ) ; const req = tx . objectStore ( STORE_NAME ) . getAll () ; req . onsuccess = () => resolve ( req . result ) ; req . onerror = () => reject ( req . error ) ; tx . oncomplete = () => db . close () ; }) , ) ; } function dbClearAll () { return openDb () . then ( ( db ) => new Promise (( resolve , reject ) => { const tx = db . transaction ( STORE_NAME , 'readwrite' ) ; const req = tx . objectStore ( STORE_NAME ) . clear () ; req . onsuccess = () => resolve () ; req . onerror = () => reject ( req . error ) ; tx . oncomplete = () => db . close () ; }) , ) ; } async function listMemosForUi () { const all = await dbGetAll () ; return all . map (( m ) => ({ id : m . id , text : m . text , timestamp : m . timestamp })) . sort (( a , b ) => b . timestamp - a . timestamp ) ; } // --- ãã¯ãã«ãŠãŒãã£ãªã㣠--- function float32ToBuffer ( f32 ) { return f32 . buffer . slice ( f32 . byteOffset , f32 . byteOffset + f32 . byteLength ) ; } function bufferToFloat32 ( buf ) { return new Float32Array ( buf ) ; } function cosineSimilarity ( a , b ) { if ( a . length ! == b . length ) throw new Error ( 'ãã¯ãã«é·ãäžèŽããŸãã' ) ; let dot = 0 , na = 0 , nb = 0 ; for ( let i = 0 ; i < a . length ; i ++ ) { dot += a [ i ] * b [ i ] ; na += a [ i ] * a [ i ] ; nb += b [ i ] * b [ i ] ; } const denom = Math . sqrt ( na ) * Math . sqrt ( nb ) ; return denom === 0 ? 0 : dot / denom ; } /** çãã¯ãšãªåã: æ¬æã«ã¯ãšãªèªãå«ãŸãããšãã ãå°å¹
ããŒã¹ãïŒãã€ããªããæ€çŽ¢ã®ç°¡æçïŒ */ function searchScore ( query , qvec , memo ) { const semantic = cosineSimilarity ( qvec , bufferToFloat32 ( memo . vector )) ; const q = query . trim () . toLowerCase () ; if ( q . length < 2 ) { return { score : semantic , semantic , keywordMatch : false , keywordBoost : 0 } ; } const text = memo . text . toLowerCase () ; const keywordMatch = text . includes ( q ) ; const keywordBoost = keywordMatch ? 0 . 12 : 0 ; return { score : semantic + keywordBoost , semantic , keywordMatch , keywordBoost , } ; } // --- åã蟌ã¿ïŒTransformers.js / ããã©ã«ã㯠WASM ããã¯ãšã³ãïŒ --- async function getEmbedder () { if ( embedder ) return embedder ; embedder = await pipeline ( 'feature-extraction' , MODEL_ID ) ; return embedder ; } async function embedText ( text ) { const e = await getEmbedder () ; const out = await e ( text , { pooling : 'mean' , normalize : true }) ; const data = out ?. data ?? out ; if ( data instanceof Float32Array ) return data ; if ( Array . isArray ( data )) return new Float32Array ( data . flat ()) ; throw new Error ( 'åã蟌ã¿ãã¯ãã«ã®åœ¢åŒãæ³å®å€ã§ã' ) ; } // --- ã¡ãã»ãŒãžåŠç --- self .onmessage = async ( ev ) => { try { const { type , payload } = ev . data ; if ( type === 'listMemos' ) { const memos = await listMemosForUi () ; self . postMessage ({ type : 'listMemosResult' , payload : { memos } }) ; return; } if ( type === 'clearAllMemos' ) { await dbClearAll () ; self . postMessage ({ type : 'clearAllResult' , payload : {} }) ; return; } if ( type === 'loadDemoData' ) { await dbClearAll () ; const demoMemos = [ "[é害察å¿] 2026-03-15 èªèšŒåºç€ã¿ã€ã ã¢ãŠãã®ä»¶ãåå ã¯DBã®ã³ãã¯ã·ã§ã³ããŒã«æ¯æžãåçºé²æ¢çãšããŠãªãã©ã€äžéã3åã«å€æŽããã¢ã©ãŒãéŸå€ã調æŽããã" , "[æé ] 瀟å€ããã®VPNæ¥ç¶ã«ã€ããŠã瀟å€ãããã¯ãŒã¯ããã¯ããŒã¿ã«çµç±ã§ã®ã¿ã¢ã¯ã»ã¹å¯èœããã¹ã¯ãŒãã¯ITãµããŒãã«ãã±ãããçºè¡ããŠååŸããããšã" , "[顧客A瀟] å¥çŽäžã®ç¹èšäºé
ïŒãã°ã«å人æ
å ±ïŒæ°åã»ã¡ã¢ãïŒãäžåæ®ããªãããšãåãåãã察å¿ã¯å°ä»»ã®ãµããŒãçªå£ãçµç±ããããšã" , "[è°äºé²] 4/1 éçºå®äŸã次æãªãªãŒã¹ã®ç®çã¯RAGæ©èœã®åŒ·åãã€ã³ãã©è²»çšãæãããããäžéšã®æ€çŽ¢åŠçãããã³ããšã³ãïŒãã©ãŠã¶åŽïŒã«ãªãããŒãããæ¹éã§åæã" , "[æè¡ã¡ã¢] åãèŸŒã¿æšè«ã¯ Transformers.jsïŒWASMïŒãæ¢å®ã端æ«ã察å¿ããŠããã° WebGPU ããã¯ãšã³ãã§ GPU æšè«ã«åãæ¿ãå¯èœã" , "[ãªã³ããŒãã£ã³ã°] æ°å
¥ç€Ÿå¡åãPCã»ããã¢ããæé ãåæãã¹ã¯ãŒãã¯å
¥ç€Ÿåæ¥ã«é
åžãããè³æãåç
§ããŸãã¯ã»ãã¥ãªãã£ç ä¿®åç»ã®èŠèŽãå®äºãããããšã" ] ; for ( const text of demoMemos ) { const vec = await embedText ( text ) ; await dbAdd ({ text , vector : float32ToBuffer ( vec ) , timestamp : Date . now () , model : MODEL_ID , }) ; } self . postMessage ({ type : 'loadDemoResult' , payload : { count : demoMemos . length } }) ; return; } if ( type === 'addMemo' ) { const { text } = payload ; const vec = await embedText ( text ) ; const id = await dbAdd ({ text , vector : float32ToBuffer ( vec ) , timestamp : Date . now () , model : MODEL_ID , }) ; self . postMessage ({ type : 'addMemoResult' , payload : { id } }) ; return; } if ( type === 'search' ) { const { query , topK = 5 } = payload ; const qvec = await embedText ( query ) ; const all = await dbGetAll () ; const items = all . map (( m ) => { const { score , semantic , keywordMatch , keywordBoost } = searchScore ( query , qvec , m , ) ; return { id : m . id , text : m . text , score , semantic , keywordMatch , keywordBoost , } ; }) . sort (( a , b ) => b . score - a . score ) . slice ( 0 , topK ) ; self . postMessage ({ type : 'searchResult' , payload : { items } }) ; return; } self . postMessage ({ type : 'error' , payload : { message : `äžæãªæäœã§ã: ${ type } ` } }) ; } catch ( e ) { self . postMessage ({ type : 'error' , payload : { message : String ( e ?. message ?? e ) } }) ; } } ; 4.6 åããªãæã®ãã§ãã¯ãã€ã³ã ãæ€çŽ¢çµæããããããããã€ãåããããã«èŠãããšãã¯ãããããã®ã¯æ¬¡ã®ã©ããã§ãã WorkerãåããŠããªãïŒ type: 'module' ãå¿ããŠããã file:// ã§éããŠããïŒ out.data ã®åœ¢ãæ³å®ãšéãïŒ embedText ã®åå²ã§åžåïŒ ãã¯ãã«ã®æ£èŠåãå¹ããŠããªãïŒ normalize: true ã確èªïŒ ä¿åãã vector ã®åŸ©å
ãå£ããŠããïŒ ArrayBuffer ã®æ±ããã¹ïŒ 4.7 ã€ãŸãããã€ã³ã IndexedDBã®æ°žç¶æ§: ãã©ãŠã¶èšå®ãã¹ãã¬ãŒãžå§è¿«ç¶æ³ã«ãã£ãŠã¯ãããŒã¿ãåé€ãããå¯èœæ§ããããŸãã ååã®ã¢ãã«ããŒã: ååã¯ã¢ãã«ååŸã§æéãããããŸããããŒãã£ã³ã°è¡šç€ºãåºããŠãããšå®å¿ã§ãã 端æ«å·®: æšè«é床ïŒWASM/WebGPUã®åŠçèœåïŒã¯ç«¯æ«äŸåã§ãããã©ãŒã«ããã¯ãä»¶æ°äžéïŒäŸ: æå€§100ä»¶ïŒãæ€èšããŠãã ããã ä»¶æ°ãå¢ãããšéããªã: æ¬ãµã³ãã«ã¯ IndexedDB ããå
šä»¶ååŸãã1ä»¶ãã€ã¹ã³ã¢èšç®ããŸãïŒ6ä»¶ã®ãã¢ã§ã¯åé¡ã«ãªãã«ããïŒãæ°çŸä»¶ä»¥äžã§ã¯çŽ¢åŒä»ããã¯ãã«DBãå¿
èŠã«ãªããŸãã 5. ãŸãšãïŒAIã«ã³ãŒããä»»ããèšèšãæ¡ãããšãå€§äº ãAIã«IndexedDBã®ã³ãŒããæžããŠããšèšãã°ãäžç¬ã§åããã®ãæã«å
¥ãæä»£ã§ãããã ãä»åã®ãã¢ã§ããèªå¥äžèŽãªãã§ãç¹å®ã®ä»¶æ°è¡šç€ºããããšãã£ãæåããååã ãã¢ãã«ååŸãèµ°ãç¹ã¯ãã³ãŒããæžãã ãã§ã¯èŠèœãšãããããšæããŸãããèšèšåŽïŒå¶çŽããã©ãŒã«ããã¯ãUXïŒãæ¡ã䟡å€ã¯ãããã倧ãããªã£ãŠãããšæããŸãã LocalStorage ã¯äžæçãªèšå®ãIndexedDB ã¯ã¡ã¢ãšãã¯ãã«ã®çœ®ãå ŽãTransformers.js ãš Web Worker ã¯æšè«ã®å®è¡å ŽæããšåããŠèãããšããã§ãã HTML 2ãã¡ã€ã«ãšãã©ãŠã¶ã ãã§ãä¿åã»åã蟌ã¿ã»é¡äŒŒæ€çŽ¢ã®æµãã¯è©ŠããŸããåãããããšãããã¡ã®ãããã¯ãã§ãå€éšã«éããããªãããŒã¿ã¯äœãïŒããããŒã ã§1ã€æ±ºããŠã¿ãŠãã ãããããŒã«ã«ã«å¯ããç¯å²ã®å€æããã ãã¶ã¯ã£ããããŠããŸãã ãã²ãããã詊ããŠã¿ãŠãã ãããã å·çè
äžå· æåïŒNTTè¥¿æ¥æ¬ ããžã¿ã«é©æ°æ¬éš ããžã¿ã«æ¹é©æšé²éšæå±ïŒ NTTè¥¿æ¥æ¬ã®Webã¢ããªã±ãŒã·ã§ã³ã®éçºã»éå¶ã«åŸäºã 奜ããªæè¡ã¹ã¿ãã¯ïŒTypeScript, Vue.js, GraphQL, Laravel åèè³æã»åºå
ž æ¬èšäºãå·çããã«ãããã以äžã®ãµã€ããåèã«ããŸããã MDN Web Docs: IndexedDBïŒ https://developer.mozilla.org/docs/Web/API/IndexedDB_API ïŒ MDN Web Docs: WebGPUïŒ https://developer.mozilla.org/docs/Web/API/WebGPU_API ïŒ MDN Web Docs: Web WorkersïŒ https://developer.mozilla.org/docs/Web/API/Web_Workers_API ïŒ Transformers.jsïŒ https://github.com/huggingface/transformers.js ïŒ jsDelivr CDNïŒ https://www.jsdelivr.com/ ïŒ åæš ãGoogle Chromeãã¯ãGoogle LLCã®åæšãŸãã¯ç»é²åæšã§ãã ãMicrosoft Edgeãã¯ãMicrosoft Corporationã®åæšãŸãã¯ç»é²åæšã§ãã ãVisual Studio Codeãã¯ãMicrosoft Corporationã®åæšãŸãã¯ç»é²åæšã§ãã ãFirefoxãã¯ãMozilla Foundationã®åæšãŸãã¯ç»é²åæšã§ãã ãNode.jsãã¯ãOpenJS Foundationã®åæšãŸãã¯ç»é²åæšã§ãã ãHugging Faceãã¯ãHugging Face, Inc.ã®åæšãŸãã¯ç»é²åæšã§ãã Transformers.js ã¯ãHugging Face, Inc.ãæäŸããã©ã€ãã©ãªã§ãã èšèŒã®äŒç€Ÿåã»è£œååã¯ãããããå瀟ã®åæšãŸãã¯ç»é²åæšã§ãã