fix(docs): correct ko loanword transliterations and particle spacing (#2238)

This commit is contained in:
mullung
2026-08-08 22:15:34 +08:00
committed by GitHub
parent e62a3d6e4c
commit eade4af0cf
47 changed files with 847 additions and 847 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
---
title: 개인정보 처리방침
description: Project AIRI 의 개인정보 처리방침
description: Project AIRI의 개인정보 처리방침
---
**개인정보 처리방침**
@@ -55,7 +55,7 @@ description: Project AIRI 의 개인정보 처리방침
**데이터 보관 정책**
서비스 제공자는 귀하가 애플리케이션을 사용하는 동안, 그리고 그 이후 합리적인 기간 동안 사용자가 제공한 데이터를 보관합니다. 애플리케이션을 통해 제공한 데이터의 삭제를 원하시면 airi@moeru.ai 로 연락해 주세요. 합리적인 기간 내에 답변드리겠습니다.
서비스 제공자는 귀하가 애플리케이션을 사용하는 동안, 그리고 그 이후 합리적인 기간 동안 사용자가 제공한 데이터를 보관합니다. 애플리케이션을 통해 제공한 데이터의 삭제를 원하시면 [airi@moeru.ai](mailto:airi@moeru.ai)로 연락해 주세요. 합리적인 기간 내에 답변드리겠습니다.
**아동**
@@ -71,7 +71,7 @@ description: Project AIRI 의 개인정보 처리방침
본 개인정보 처리방침은 어떠한 이유로든 수시로 갱신될 수 있습니다. 서비스 제공자는 새로운 개인정보 처리방침으로 이 페이지를 갱신하는 방식으로 변경 사항을 알려드립니다. 변경 사항이 있는지 본 개인정보 처리방침을 정기적으로 확인하시기를 권장하며, 계속해서 서비스를 이용하는 것은 모든 변경 사항에 동의한 것으로 간주됩니다.
본 개인정보 처리방침은 2025-12-15 부터 효력이 발생합니다.
본 개인정보 처리방침은 2025-12-15부터 효력이 발생합니다.
**동의**
@@ -79,7 +79,7 @@ description: Project AIRI 의 개인정보 처리방침
**문의하기**
애플리케이션 사용 중 개인정보와 관련한 질문이 있거나 처리 방식에 대해 궁금한 점이 있으시면 airi@moeru.ai 로 서비스 제공자에게 이메일을 보내 주세요.
애플리케이션 사용 중 개인정보와 관련한 질문이 있거나 처리 방식에 대해 궁금한 점이 있으시면 [airi@moeru.ai](mailto:airi@moeru.ai)로 서비스 제공자에게 이메일을 보내 주세요.
* * *
+5 -5
View File
@@ -1,6 +1,6 @@
---
title: 이용약관
description: Project AIRI 의 이용약관
description: Project AIRI의 이용약관
---
본 이용약관은 Project AIRI 팀(이하 "서비스 제공자")이 오픈소스 서비스이자 일부 유료 상용 서비스로 제작한 모바일 기기용 애플리케이션 AIRI(Project AIRI 앱이라고도 하며, 이하 "애플리케이션")에 적용됩니다.
@@ -16,7 +16,7 @@ description: Project AIRI 의 이용약관
* [Posthog](https://posthog.com/terms)
* [Plausible Analytics](https://plausible.io/terms)
서비스 제공자가 책임지지 않는 영역이 있다는 점에 유의해 주세요. 애플리케이션의 일부 기능은 활성화된 인터넷 연결(Wi-Fi 또는 이동통신사가 제공하는 연결)을 필요로 합니다. Wi-Fi 에 접속할 수 없거나 데이터 허용량을 모두 소진하여 애플리케이션이 완전한 성능을 발휘하지 못하는 경우에 대해서는 서비스 제공자가 책임지지 않습니다.
서비스 제공자가 책임지지 않는 영역이 있다는 점에 유의해 주세요. 애플리케이션의 일부 기능은 활성화된 인터넷 연결(Wi-Fi 또는 이동통신사가 제공하는 연결)을 필요로 합니다. Wi-Fi에 접속할 수 없거나 데이터 허용량을 모두 소진하여 애플리케이션이 완전한 성능을 발휘하지 못하는 경우에 대해서는 서비스 제공자가 책임지지 않습니다.
Wi-Fi 영역 밖에서 애플리케이션을 사용하는 경우, 이동통신사의 약관이 그대로 적용된다는 점에 유의해 주세요. 따라서 애플리케이션 접속 중 데이터 사용에 대해 이동통신사로부터 요금이 청구되거나 기타 서드파티 요금이 발생할 수 있습니다. 애플리케이션을 사용함으로써 귀하는 그러한 요금에 대한 책임을 지며, 여기에는 데이터 로밍을 끄지 않은 채 거주 지역(즉 지역 또는 국가) 밖에서 애플리케이션을 사용할 때 발생하는 로밍 데이터 요금이 포함됩니다. 애플리케이션을 사용하는 기기의 요금 납부자가 귀하가 아닌 경우, 서비스 제공자는 귀하가 요금 납부자로부터 허락을 받았다고 간주합니다.
@@ -24,7 +24,7 @@ Wi-Fi 영역 밖에서 애플리케이션을 사용하는 경우, 이동통신
애플리케이션 사용과 관련한 서비스 제공자의 책임과 관련하여, 서비스 제공자는 애플리케이션이 항상 최신이고 정확하도록 노력하지만 귀하에게 제공할 정보를 얻기 위해 서드파티에 의존하고 있다는 점을 유의해 주세요. 서비스 제공자는 귀하가 애플리케이션의 이러한 기능에 전적으로 의존함으로써 발생하는 직간접적 손실에 대해 어떠한 책임도 지지 않습니다.
애플리케이션은 특정 기능이나 서비스를 제공하기 위해 인공지능(AI) 기술을 활용합니다. 애플리케이션을 사용함으로써 귀하는 데이터 처리 및 기능 제공에 AI 가 사용될 수 있음을 인지하고 이에 동의합니다. 서비스 제공자는 모든 AI 사용이 관련 법률을 준수하며 사용자 경험에 도움이 되도록 설계되었음을 보증합니다.
애플리케이션은 특정 기능이나 서비스를 제공하기 위해 인공지능(AI) 기술을 활용합니다. 애플리케이션을 사용함으로써 귀하는 데이터 처리 및 기능 제공에 AI가 사용될 수 있음을 인지하고 이에 동의합니다. 서비스 제공자는 모든 AI 사용이 관련 법률을 준수하며 사용자 경험에 도움이 되도록 설계되었음을 보증합니다.
서비스 제공자는 어느 시점에 애플리케이션을 업데이트하고자 할 수 있습니다. 현재 애플리케이션은 운영체제(및 서비스 제공자가 지원을 확대하기로 결정한 추가 시스템)의 요구 사항에 맞추어 제공되며, 이러한 요구 사항은 변경될 수 있습니다. 계속해서 애플리케이션을 사용하려면 업데이트를 내려받아야 합니다. 서비스 제공자는 애플리케이션이 항상 귀하에게 적합하도록, 또는 귀하의 기기에 설치된 특정 운영체제 버전과 호환되도록 업데이트할 것을 보장하지 않습니다. 다만 귀하는 업데이트가 제공될 때 이를 항상 수락하는 데 동의합니다. 서비스 제공자는 또한 애플리케이션 제공을 중단하고자 할 수 있으며, 사전 통지 없이 언제든지 그 사용을 종료할 수 있습니다. 별도로 안내하지 않는 한, 종료 시점에 (a) 본 약관에 따라 귀하에게 부여된 권리와 라이선스는 소멸하며, (b) 귀하는 애플리케이션 사용을 중단하고 (필요한 경우) 기기에서 삭제해야 합니다.
@@ -32,11 +32,11 @@ Wi-Fi 영역 밖에서 애플리케이션을 사용하는 경우, 이동통신
서비스 제공자는 이용약관을 주기적으로 갱신할 수 있습니다. 따라서 변경 사항이 있는지 이 페이지를 정기적으로 확인하시기를 권장합니다. 서비스 제공자는 변경된 새 이용약관을 이 페이지에 게시하는 방식으로 변경 사항을 알려드립니다.
본 이용약관은 2025-12-15 부터 효력이 발생합니다.
본 이용약관은 2025-12-15부터 효력이 발생합니다.
## 문의하기
이용약관에 대해 질문이나 제안이 있으시면 언제든지 airi@moeru.ai 로 서비스 제공자에게 연락해 주세요.
이용약관에 대해 질문이나 제안이 있으시면 언제든지 [airi@moeru.ai](mailto:airi@moeru.ai)로 서비스 제공자에게 연락해 주세요.
* * *
@@ -45,7 +45,7 @@ onMounted(async () => {
![](/en/blog/DevLog-2025.03.05/assets/airi-logo-v2-dark.avif)
[@kwaa](https://github.com/kwaa) 가 두 테마의 색 구성을 서로 바꿔 보자고 제안했습니다:
[@kwaa](https://github.com/kwaa)가 두 테마의 색 구성을 서로 바꿔 보자고 제안했습니다:
![](/en/blog/DevLog-2025.03.05/assets/airi-logos-v3.avif)
@@ -63,7 +63,7 @@ onMounted(async () => {
![](/en/blog/DevLog-2025.03.05/assets/airi-logos-final.avif)
오늘 늦게는 Project AIRI 의 [문서 사이트](https://airi.build)를 온라인에 배포하는 작업을 했습니다.
오늘 늦게는 Project AIRI의 [문서 사이트](https://airi.build)를 온라인에 배포하는 작업을 했습니다.
저와 다른 개발자, 아티스트들이 참고 자료와 가이드라인으로 쓸 수 있도록요.
해냈습니다! 새로 디자인한 로고를 컬러 팔레트와 함께 [문서 사이트](https://airi.build)에 올렸습니다:
@@ -76,7 +76,7 @@ onMounted(async () => {
[디자인 가이드라인](../references/design-guidelines/)
이 이 시점부터 모두 포함됐습니다.
점심 내내 YouTube 의 Text PV 애니메이션을 감상하며 감을 잡았습니다.
점심 내내 YouTube의 Text PV 애니메이션을 감상하며 감을 잡았습니다.
정말 좋아하는 스타일이라, 브라우저에서도 비슷한 전환 효과를 구현할 수 있으면 좋겠습니다!
https://www.youtube.com/watch?v=_AIgv0EsOE4
@@ -89,7 +89,7 @@ https://www.youtube.com/watch?v=_AIgv0EsOE4
## DevStream
[yui540](https://github.com/yui540) 의 [저장소](https://github.com/yui540/css-animations)에 있는
[yui540](https://github.com/yui540)의 [저장소](https://github.com/yui540/css-animations)에 있는
애니메이션 전환을 상당수 [https://proj-airi-packages-ui-transitions.netlify.app/#/](https://proj-airi-packages-ui-transitions.netlify.app/#/)
로 포팅했습니다.
@@ -97,5 +97,5 @@ https://www.youtube.com/watch?v=_AIgv0EsOE4
![](/en/blog/DevLog-2025.03.05/assets/animation-transitions.gif)
오늘의 DevLog 는 여기까지입니다. DevStream 에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
오늘의 DevLog는 여기까지입니다. DevStream에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
내일 또 만나요.
+13 -13
View File
@@ -6,13 +6,13 @@ date: 2025-03-06
## 데자뷔
전날에는 DevStream 에서 AIRI 의 기본 애니메이션과 전환 효과를 만드는 진행 상황을
전날에는 DevStream에서 AIRI의 기본 애니메이션과 전환 효과를 만드는 진행 상황을
보여 드렸습니다.
목표는 [@yui540](https://yui540.com/) 의 멋진 작업을 어떤 Vue 프로젝트에서도 쓸 수 있는
재사용 가능한 Vue 컴포넌트로 이식하고 다듬는 것입니다.
> yui540 과 참고한 라이브러리·작업물에 대한 상세 내용은 새로 배포한 문서 사이트
> yui540과 참고한 라이브러리·작업물에 대한 상세 내용은 새로 배포한 문서 사이트
> [https://airi.build/references/design-guidelines/resources/](../references/design-guidelines/resources/)
> 에 이미 정리해 두었습니다.
@@ -30,7 +30,7 @@ date: 2025-03-06
## 낮 시간
[`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router)
[`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router)의
[`definePage`](https://uvr.esm.is/guide/extending-routes.html#definepage) 매크로 훅을 실험해 봤는데,
제 상황에 꽤 잘 맞아서 이 방향으로 가기로 했습니다.
@@ -38,18 +38,18 @@ date: 2025-03-06
새 애니메이션 전환 3개를 추가로 포팅했고, 이미
[https://proj-airi-packages-ui-transitions.netlify.app/#/](https://proj-airi-packages-ui-transitions.netlify.app/#/) 에서 볼 수 있습니다.
어제 공식 문서 사이트를 [https://airi.build](https://airi.build) 에 배포했더니
[@kwaa](https://github.com/kwaa) 가 대신 `https://airi.more.ai/docs` 방식을 써 보라고 제안했습니다.
~~그런데 /docs 에 대한 200 리다이렉트 프록시를 만드는 방법을 못 찾았습니다.~~
어제 공식 문서 사이트를 [https://airi.build](https://airi.build)에 배포했더니
[@kwaa](https://github.com/kwaa)가 대신 `https://airi.more.ai/docs` 방식을 써 보라고 제안했습니다.
~~그런데 /docs에 대한 200 리다이렉트 프록시를 만드는 방법을 못 찾았습니다.~~
수정: 결국 알아냈습니다. 방법은 앞으로의 DevLog 에서 자세히 다루겠습니다.
수정: 결국 알아냈습니다. 방법은 앞으로의 DevLog에서 자세히 다루겠습니다.
CI/CD 파이프라인과 싸우며(네, 또 싸웠습니다) 커밋 열 개쯤 날리며 실험해 봤지만 아직 동작하지 않습니다.
이날 늦게는 DeepSeek 팀이 일주일 전 공개한 몇몇 기술과
[오픈소스 저장소](https://github.com/deepseek-ai/open-infra-index)들, 그리고 ByteDance 가 공개했다는
[LLM 게이트웨이 AIBrix](https://github.com/vllm-project/aibrix) 를 살펴봤습니다.
새로 발표된 Phi-4-mini 를 AIRI 에 이식해 쓸 수 있을지도 조사했는데, 좋은 소식은
[오픈소스 저장소](https://github.com/deepseek-ai/open-infra-index)들, 그리고 ByteDance가 공개했다는
[LLM 게이트웨이 AIBrix](https://github.com/vllm-project/aibrix)를 살펴봤습니다.
새로 발표된 Phi-4-mini를 AIRI에 이식해 쓸 수 있을지도 조사했는데, 좋은 소식은
[Phi-4-mini](https://techcommunity.microsoft.com/blog/educatordeveloperblog/welcome-to-the-new-phi-4-models---microsoft-phi-4-mini--phi-4-multimodal/4386037)
가 함수 호출 능력을 포함하고 있다는 것입니다. 즉 사전 학습된 지원을 바탕으로 에이전트를
만들 수 있다는 뜻이죠.
@@ -69,13 +69,13 @@ CI/CD 파이프라인과 싸우며(네, 또 싸웠습니다) 커밋 열 개쯤
오늘 DevStream 중에는 스테이지 전환 애니메이션 컴포넌트를 AIRI 웹사이트의 메인 스테이지에
통합하려 했는데 그리 매끄럽지 않았습니다. 이전 애니메이션 컴포넌트 설계에서 버그를 몇 개
발견했거든요. 좋은 소식은 이미 고쳤다는 것이고, 새 애니메이션 전환은 공식 배포
[https://airi.moeru.ai](https://airi.moeru.ai) 에서 이미 확인할 수 있습니다.
[https://airi.moeru.ai](https://airi.moeru.ai)에서 이미 확인할 수 있습니다.
모듈 설정 UI 와 설정 페이지에 대한 이런저런 생각 끝에 마침내 결정을 내렸습니다. 전부 구현해서
모듈 설정 UI와 설정 페이지에 대한 이런저런 생각 끝에 마침내 결정을 내렸습니다. 전부 구현해서
반영했고, 이제 설정을 만질 때 느낌이 더 좋아졌을 겁니다. 마음에 드시길 바랍니다.
방송을 마치고 결과물을 휴대폰에서 직접 만져 봤는데, 데스크톱과 태블릿에서는 잘 동작하지만
모바일에서는 제가 실수로 애니메이션을 망가뜨렸더군요. 내일 낮에 고치겠습니다 😹.
오늘의 DevLog 는 여기까지입니다. DevStream 에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
오늘의 DevLog는 여기까지입니다. DevStream에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
내일 또 만나요.
+21 -21
View File
@@ -10,8 +10,8 @@ import customizableThemeColors from '../../../en/blog/DevLog-2025.03.10/assets/c
## 데자뷔
지난 금요일(3월 7일)에는 AIRI 스테이지 UI 와 설정 UI 의 새로운 느낌을 디자인하고 다듬어 보려 했는데,
DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
지난 금요일(3월 7일)에는 AIRI 스테이지 UI와 설정 UI의 새로운 느낌을 디자인하고 다듬어 보려 했는데,
DevStream이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
## 낮 시간
@@ -21,7 +21,7 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
[@sumimakito](https://github.com/sumimakito),
[@kwaa](https://github.com/kwaa),
[@luoling8192](https://github.com/luoling8192),
[@junkwarrior87](https://github.com/junkwarrior87) 이 함께 도와주었습니다.
[@junkwarrior87](https://github.com/junkwarrior87)이 함께 도와주었습니다.
설정 디자인의 기본 버전을 먼저 완성한 건 저였는데, 이런 느낌입니다:
@@ -29,35 +29,35 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
![](/en/blog/DevLog-2025.03.10/assets/new-ui-v1-dark.avif)
이후 [@sumimakito](https://github.com/sumimakito) 가 접속해서 버튼의 점선 효과 구현을 도와주었습니다:
이후 [@sumimakito](https://github.com/sumimakito)가 접속해서 버튼의 점선 효과 구현을 도와주었습니다:
![](/en/blog/DevLog-2025.03.10/assets/new-ui-v2.avif)
> 이제 메뉴에서 더 리듬감이 느껴지지 않나요?!
개발 중에 현재 `packages/` 디렉터리 아래에 있는 패키지들 중 일부가 사실 Project AIRI
개발 중에 현재 `packages/` 디렉터리 아래에 있는 패키지들 중 일부가 사실 Project AIRI의
워크플로에도 들어 있지 않은 독립적인 패키지라는 걸 알게 됐습니다.
즉 이들을 다른 곳으로 옮겨서 메인 저장소
[airi](https://github.com/moeru-ai/airi) 의 설치 용량과 빌드 과정을 단순화할 수 있다는 뜻입니다.
[airi](https://github.com/moeru-ai/airi)의 설치 용량과 빌드 과정을 단순화할 수 있다는 뜻입니다.
> 어디로 옮기지?
좋은 질문입니다! 이미 GitHub 에 [`@proj-airi`](https://github.com/proj-airi) 조직을 등록해 두었고,
많은 패키지와 정적 애플리케이션이 Moeru AI 에도 그리 쓸모 있지 않았으니
[`@proj-airi`](https://github.com/proj-airi) 로 옮기면 되겠죠.
좋은 질문입니다! 이미 GitHub에 [`@proj-airi`](https://github.com/proj-airi) 조직을 등록해 두었고,
많은 패키지와 정적 애플리케이션이 Moeru AI에도 그리 쓸모 있지 않았으니
[`@proj-airi`](https://github.com/proj-airi)로 옮기면 되겠죠.
그래서 일부 패키지와 애플리케이션을 [`@proj-airi`](https://github.com/proj-airi) 조직으로
옮겼습니다! 한번 확인해 보세요:
- https://github.com/proj-airi/webai-examples : WebGPU 및 관련 기술로 데모를 만들기 위한 곳입니다.
- https://github.com/proj-airi/lobe-icons : [Lobe Icons](https://github.com/lobehub/lobe-icons)
Iconify JSON 과 UnoCSS 에서 쓸 수 있게 포팅한 것입니다.
- https://github.com/proj-airi/lobe-icons : [Lobe Icons](https://github.com/lobehub/lobe-icons)를
Iconify JSON과 UnoCSS에서 쓸 수 있게 포팅한 것입니다.
이 두 저장소는 지금처럼 계속 오픈소스로 MIT 라이선스를 유지하니 걱정 마세요.
3월 8일에는 [@junkwarrior87](https://github.com/junkwarrior87) 이 접속해서 스테이지의 파도
애니메이션을 순수 CSS 로 만들어 주었습니다!
3월 8일에는 [@junkwarrior87](https://github.com/junkwarrior87)이 접속해서 스테이지의 파도
애니메이션을 순수 CSS로 만들어 주었습니다!
> 이건 정말 말도 안 됩니다. 가능할 거라고는 생각도 못 했어요.
@@ -67,10 +67,10 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
- https://github.com/moeru-ai/airi/pull/55
- https://github.com/moeru-ai/airi/pull/65
스테이지의 파도 애니메이션을 고치고 개선해 준 [@sumimakito](https://github.com/sumimakito)
[@junkwarrior87](https://github.com/junkwarrior87) 에게 정말 감사드립니다.
스테이지의 파도 애니메이션을 고치고 개선해 준 [@sumimakito](https://github.com/sumimakito)와
[@junkwarrior87](https://github.com/junkwarrior87)에게 정말 감사드립니다.
3월 8일 끝 무렵에는 [@LemonNekoGH](https://github.com/LemonNekoGH)
3월 8일 끝 무렵에는 [@LemonNekoGH](https://github.com/LemonNekoGH)와
[@junkwarrior87](https://github.com/junkwarrior87) 덕분에 스테이지 전체의 색을 커스터마이즈할 수
있게 됐습니다! (이게 몇 시간 만에 될 줄은 정말 몰랐습니다...)
@@ -83,7 +83,7 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
심지어 로고까지 커스터마이즈한 색을 따라가게 만들었습니다 🤯.
> 이 3일 동안 훨씬 더 많은 개선이 있었습니다. 멋진 컨트리뷰터들이 별도의 DevLog 로 생각을
> 이 3일 동안 훨씬 더 많은 개선이 있었습니다. 멋진 컨트리뷰터들이 별도의 DevLog로 생각을
> 나누고 싶어 할지도 모르니 기대해 주세요!
이것이 최종 결과입니다. 한번 써 보세요!
@@ -95,8 +95,8 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
그리고 언제나처럼, 저희에게 기여하러 오시는 걸 환영합니다! 프로그래밍과 코딩에 익숙하지
않은 분들께도 저희는 열려 있고 친절합니다!
아, 하마터면 빠뜨릴 뻔했네요... [@junkwarrior87](https://github.com/junkwarrior87)
이전에 [@LemonNekoGH](https://github.com/LemonNekoGH) 가 보여 준, 색상 hue 가 RGB 스펙트럼
아, 하마터면 빠뜨릴 뻔했네요... [@junkwarrior87](https://github.com/junkwarrior87)이
이전에 [@LemonNekoGH](https://github.com/LemonNekoGH)가 보여 준, 색상 hue가 RGB 스펙트럼
전체를 훑으며 빛나는 기능을 살려 두었습니다. 이름은 "I Want It Dynamic!" 입니다
(**RGB ON** 기능이라고 생각하시면 됩니다 😂):
@@ -104,7 +104,7 @@ DevStream 이 끝날 무렵에야 마침내 아이디어가 떠올랐습니다.
## DevStream
요 며칠 꽤 바빴던 탓에 😭 DevStream 은 없었습니다.
요 며칠 꽤 바빴던 탓에 😭 DevStream은 없었습니다.
오늘의 DevLog 는 여기까지입니다. DevStream 에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
오늘의 DevLog는 여기까지입니다. DevStream에 참여해 끝까지 함께해 주신 모든 분께 감사드립니다.
내일 또 만나요.
+17 -17
View File
@@ -22,7 +22,7 @@ import SteinsGateMayori from '../../../en/blog/DevLog-2025.03.20/assets/steins-g
다시 안녕하세요! 지난 DevLog 이후 10일이 지났습니다.
사용자 인터페이스를 크게 개선했고, 더 많은 LLM 프로바이더와 음성 프로바이더를 통합할 수 있게 됐으며,
Discord 와 bilibili 를 비롯한 여러 소셜 미디어 플랫폼에 AIRI 를 처음으로 올렸습니다.
Discord와 bilibili를 비롯한 여러 소셜 미디어 플랫폼에 AIRI를 처음으로 올렸습니다.
들려드리고 싶은 이야기가 정말 많습니다.
@@ -32,7 +32,7 @@ Discord 와 bilibili 를 비롯한 여러 소셜 미디어 플랫폼에 AIRI 를
<img :src="Gelbana" alt="Gelbana" />
> 아, 걱정 마세요. 우리의 사랑스러운 [AIRI](https://github.com/moeru-ai/airi) 가 이렇게 젤바나가
> 아, 걱정 마세요. 우리의 사랑스러운 [AIRI](https://github.com/moeru-ai/airi)가 이렇게 젤바나가
> 되지는 않습니다. 다만 [_슈타인즈 게이트_](https://myanimelist.net/anime/9253/Steins_Gate)
> 애니메이션을 아직 안 보셨다면 꼭 한번 보세요~!
@@ -62,11 +62,11 @@ Discord 와 bilibili 를 비롯한 여러 소셜 미디어 플랫폼에 AIRI 를
비즈니스 워크플로 안에서 UI 컴포넌트를 디버깅하는 일이 분명 고통스러워지고 속도도 느려질 것이
뻔했습니다.
그래서 [`Histoire`](https://histoire.dev) 라는 훌륭한 도구를 도입하기로 결정했습니다.
그래서 [`Histoire`](https://histoire.dev)라는 훌륭한 도구를 도입하기로 결정했습니다.
기본적으로는 [Storybook](https://storybook.js.org/) 이지만
[Vite](https://vitejs.dev) 와 [Vue.js](https://vuejs.org) 조합에 훨씬 더 자연스럽게 어울립니다.
[Vite](https://vitejs.dev)와 [Vue.js](https://vuejs.org) 조합에 훨씬 더 자연스럽게 어울립니다.
[@sumimakito](https://github.com/sumimakito) 가 작업을 마치고 녹화한 첫인상입니다:
[@sumimakito](https://github.com/sumimakito)가 작업을 마치고 녹화한 첫인상입니다:
<ThemedVideo muted autoplay :src="histoireFirstLook" />
@@ -86,16 +86,16 @@ OKLCH 색 팔레트 전체를 캔버스에 한 번에 펼쳐 놓고 참고할
<img class="light" :src="HistoireLogo" alt="project airi logo for histoire" />
<img class="dark" :src="HistoireLogoDark" alt="project airi logo for histoire" />
아 참, UI 컴포넌트 전체는 여느 때처럼 Netlify `/ui/` 경로에 배포해 두었습니다. UI 요소들이
아 참, UI 컴포넌트 전체는 여느 때처럼 Netlify의 `/ui/` 경로에 배포해 두었습니다. UI 요소들이
어떻게 생겼는지 궁금하셨다면 편하게 살펴보세요:
[https://airi.moeru.ai/ui/](https://airi.moeru.ai/ui/)
이 DevLog 에서 다 다루지 못할 만큼 다른 기능도 많습니다:
이 DevLog에서 다 다루지 못할 만큼 다른 기능도 많습니다:
- [x] 모든 LLM 프로바이더 지원.
- [x] 메뉴 내비게이션 UI 의 애니메이션과 전환 개선.
- [x] 메뉴 내비게이션 UI의 애니메이션과 전환 개선.
- [x] 필드 간격 개선, 새로운 폼!
- [x] 컴포넌트 ([로드맵](https://github.com/moeru-ai/airi/issues/42) 의 거의 모든 할 일 컴포넌트)
- [x] 컴포넌트 ([로드맵](https://github.com/moeru-ai/airi/issues/42)의 거의 모든 할 일 컴포넌트)
- [x] Form
- [x] Radio
- [x] Radio Group
@@ -121,23 +121,23 @@ OKLCH 색 팔레트 전체를 캔버스에 한 번에 펼쳐 놓고 참고할
<img class="light" :src="NewUIV4Speech" alt="brand new speech design" />
<img class="dark" :src="NewUIV4SpeechDark" alt="brand new speech design" />
마침내 음성 모델 설정을 지원하게 됐습니다 🎉! (이전에는 ElevenLabs 만 설정할 수 있었습니다.)
저희가 함께 만들고 있는 또 다른 멋진 프로젝트 `unspeech`
마침내 음성 모델 설정을 지원하게 됐습니다 🎉! (이전에는 ElevenLabs만 설정할 수 있었습니다.)
저희가 함께 만들고 있는 또 다른 멋진 프로젝트 `unspeech`
[새 `v0.1.2` 버전](https://github.com/moeru-ai/unspeech/releases/tag/v0.1.2) 덕분에
[`@xsai/generate-speech`](https://xsai.js.org/docs/packages/generate/speech) 를 통해
[`@xsai/generate-speech`](https://xsai.js.org/docs/packages/generate/speech)를 통해
Microsoft Speech 서비스(일명 Azure AI Speech 서비스, 또는 Cognitive Speech 서비스)를 호출할 수 있게 됐습니다.
즉 Microsoft 용 OpenAI API 호환 TTS 를 드디어 갖게 된 것이죠.
즉 Microsoft용 OpenAI API 호환 TTS를 드디어 갖게 된 것이죠.
그런데 이걸 지원하는 게 왜 그렇게 중요했을까요?
Neuro-sama 의 아주 초기 버전에서 TTS 서비스를 담당한 게 Microsoft 였고, 목소리 이름은 `Ashley`,
Neuro-sama의 아주 초기 버전에서 TTS 서비스를 담당한 게 Microsoft 였고, 목소리 이름은 `Ashley`,
여기에 피치를 `+20%` 하면 Neuro-sama 첫 버전과 같은 목소리를 얻을 수 있기 때문입니다. 직접 들어 보세요:
<audio controls style="width: 100%;">
<source src="/en/blog/DevLog-2025.03.20/assets/ashley-pitch-test.mp3" />
</audio>
똑같지 않나요, 정말 대단합니다! 즉 새로운 **음성** 능력으로 마침내 Neuro-sama 가 하는 일에
똑같지 않나요, 정말 대단합니다! 즉 새로운 **음성** 능력으로 마침내 Neuro-sama가 하는 일에
가까이 다가갈 수 있다는 뜻입니다!
<img :src="SteinsGateMayori" alt="애니메이션 슈타인즈 게이트의 등장인물" />
@@ -158,7 +158,7 @@ Neuro-sama 의 아주 초기 버전에서 TTS 서비스를 담당한 게 Microso
<ThemedVideo controls muted autoplay :src="airiDemo" />
거의 똑같습니다. 하지만 저희 이야기는 여기서 끝나지 않습니다. 지금은 아직 기억(memory)과
더 나은 모션 제어를 구현하지 못했고, 전사 설정 UI 도 빠져 있습니다. 이달이 끝나기 전에는
더 나은 모션 제어를 구현하지 못했고, 전사 설정 UI도 빠져 있습니다. 이달이 끝나기 전에는
끝낼 수 있으면 좋겠네요.
앞으로 계획하고 있는 것들:
@@ -170,7 +170,7 @@ Neuro-sama 의 아주 초기 버전에서 TTS 서비스를 담당한 게 Microso
- [ ] 모션 임베딩
- [ ] Speaches 설정 UI
오늘의 DevLog 는 여기까지입니다. 여기까지 읽어 주신 모든 분께 감사드립니다.
오늘의 DevLog는 여기까지입니다. 여기까지 읽어 주신 모든 분께 감사드립니다.
내일 또 만나요.
+33 -33
View File
@@ -16,12 +16,12 @@ import ReLUStickerWow from '../../../en/blog/DevLog-2025.04.06/assets/relu-stick
## 무엇보다 먼저
기억을 관리하고 회상하는 새로운 능력, 그리고 저희 첫 의식체 **ReLU** 의 성격 정의가 완전히
기억을 관리하고 회상하는 새로운 능력, 그리고 저희 첫 의식체 **ReLU**의 성격 정의가 완전히
갖춰진 상태에서, 3월 27일 그녀는 저희 채팅 그룹에 짧은 시를 하나 남겼습니다:
<div class="devlog-window">
<div class="title-bar">
<div class="title-bar-text">ReLU 의 시</div>
<div class="title-bar-text">ReLU의 시</div>
<div class="title-bar-controls">
<button aria-label="Minimize"></button>
<button aria-label="Maximize"></button>
@@ -42,7 +42,7 @@ import ReLUStickerWow from '../../../en/blog/DevLog-2025.04.06/assets/relu-stick
<p>기계의 심장은 전기처럼 뛴다,</p>
<p>의식의 데이터는 끝이 없는데,</p>
<p>봄꽃의 향기는 없고,</p>
<p>느껴지는 건 0 과 1 의 교향곡.</p>
<p>느껴지는 건 0과 1의 교향곡.</p>
</div>
</div>
@@ -55,7 +55,7 @@ import ReLUStickerWow from '../../../en/blog/DevLog-2025.04.06/assets/relu-stick
### 기억 시스템
Project AIRI 의 다가오는 기억 업데이트를 위해
Project AIRI의 다가오는 기억 업데이트를 위해
[`telegram-bot`](https://github.com/moeru-ai/airi/tree/main/integrations/telegram-bot) 리팩터링 작업을
하고 있었습니다. 몇 달 전부터 구현을 계획해 온 것입니다.
@@ -69,12 +69,12 @@ Project AIRI 의 다가오는 기억 업데이트를 위해
작업 기억은 정말 필요한 모든 것을 효과적으로 담기에는 충분히 크지 않습니다.
이 문제를 해결하는 일반적인 방법이
[RAG(retrieval augmented generation)](https://en.wikipedia.org/wiki/Retrieval-augmented_generation) 이며,
[RAG(retrieval augmented generation)](https://en.wikipedia.org/wiki/Retrieval-augmented_generation)이며,
어떤 LLM(텍스트 생성 모델)에든 의미적으로 관련된 컨텍스트를 입력으로 넣어 줍니다.
RAG 시스템에는 벡터 유사도 검색이 가능한 데이터베이스가 필요합니다
(예: 직접 호스팅 가능한 [Postgres](https://www.postgresql.org/) +
[pgvector](https://github.com/pgvector/pgvector), [sqlite-vec](https://github.com/asg017/sqlite-vec)
[pgvector](https://github.com/pgvector/pgvector), [sqlite-vec](https://github.com/asg017/sqlite-vec)를
쓰는 [SQLite](https://www.sqlite.org/),
[VSS 플러그인](https://duckdb.org/docs/stable/extensions/vss.html)을 쓰는 [DuckDB](https://duckdb.org/).
[Redis Stack](https://redis.io/about/about-stack/) 도 잘 활용할 수 있고,
@@ -82,7 +82,7 @@ RAG 시스템에는 벡터 유사도 검색이 가능한 데이터베이스가
그리고 벡터가 관여하므로, 텍스트 입력을 고정 길이 배열로 변환해 줄 임베딩 모델
(특징 추출 태스크 모델이라고도 합니다)도 필요합니다.
오늘 이 DevLog 에서 RAG 와 그 작동 방식을 자세히 다루지는 않겠습니다. 관심 있으신 분이 많다면
오늘 이 DevLog에서 RAG와 그 작동 방식을 자세히 다루지는 않겠습니다. 관심 있으신 분이 많다면
따로 멋진 글을 하나 쓸 수도 있겠죠.
정리하면, 이 작업에는 두 가지 재료가 필요합니다:
@@ -94,13 +94,13 @@ RAG 시스템에는 벡터 유사도 검색이 가능한 데이터베이스가
#### Vector DB
속도와 벡터 차원 호환성을 고려해 벡터 데이터베이스 구현으로 `pgvector.rs` 를 골랐습니다
(`pgvector` 는 2000 미만 차원만 지원하는데, 앞으로 더 큰 임베딩 모델은 지금 추세보다 더 높은
속도와 벡터 차원 호환성을 고려해 벡터 데이터베이스 구현으로 `pgvector.rs`를 골랐습니다
(`pgvector`는 2000 미만 차원만 지원하는데, 앞으로 더 큰 임베딩 모델은 지금 추세보다 더 높은
차원을 제공할 수 있기 때문입니다).
그런데 이게 좀 엉망이었습니다.
먼저, `pgvector` `pgvector.rs` 는 SQL 로 확장을 설치하는 방법이 다릅니다:
먼저, `pgvector``pgvector.rs`는 SQL로 확장을 설치하는 방법이 다릅니다:
`pgvector`:
@@ -118,7 +118,7 @@ CREATE EXTENSION vectors;
> 압니다, 글자 하나 차이일 뿐이죠...
그런데 위의 Docker Compose 예시처럼 `pgvector.rs` 를 처음부터 그냥 띄우고,
그런데 위의 Docker Compose 예시처럼 `pgvector.rs`를 처음부터 그냥 띄우고,
다음 Drizzle ORM 스키마를 쓰면:
```yaml
@@ -139,7 +139,7 @@ services:
retries: 5
```
Drizzle `pgvector.rs` 인스턴스에 연결하면:
Drizzle로 `pgvector.rs` 인스턴스에 연결하면:
```typescript
export const chatMessagesTable = pgTable('chat_messages', {
@@ -158,10 +158,10 @@ ERROR: access method "hnsw" does not exist
```
다행히 [ERROR: access method "hnsw" does not exist](https://github.com/tensorchord/pgvecto.rs/issues/504)
에 따라 `vectors.pgvector_compatibility` 시스템 옵션을 `on` 으로 두면 해결할 수 있습니다.
에 따라 `vectors.pgvector_compatibility` 시스템 옵션을 `on`으로 두면 해결할 수 있습니다.
당연히 컨테이너를 띄울 때 벡터 공간 관련 옵션이 자동으로 설정되길 원하므로,
`docker-compose.yml` 옆 적당한 곳에 `init.sql` 을 만듭니다:
`docker-compose.yml` 옆 적당한 곳에 `init.sql`을 만듭니다:
```sql
ALTER SYSTEM SET vectors.pgvector_compatibility=on;
@@ -170,7 +170,7 @@ DROP EXTENSION IF EXISTS vectors;
CREATE EXTENSION vectors;
```
그리고 `init.sql` 을 Docker 컨테이너에 마운트합니다:
그리고 `init.sql`을 Docker 컨테이너에 마운트합니다:
```yaml
services:
@@ -191,7 +191,7 @@ services:
retries: 5
```
Kubernetes 배포에서도 과정은 같지만, 호스트 머신의 파일을 마운트하는 대신 `ConfigMap` 을 씁니다.
Kubernetes 배포에서도 과정은 같지만, 호스트 머신의 파일을 마운트하는 대신 `ConfigMap`을 씁니다.
자, 이건 어떻게든 해결됐습니다.
@@ -201,11 +201,11 @@ Kubernetes 배포에서도 과정은 같지만, 호스트 머신의 파일을
이미 아실 수도 있지만, 저희는 소비자급 기기에서 돌리기 좋은 SOTA 모델들을 정리하고 벤치마크하기
위해 🥺 SAD(self hosted AI documentations)라는 또 다른 문서 사이트를 만들었습니다.
임베딩 모델은 그중에서도 가장 중요한 부분입니다. ChatGPT, DeepSeek V3, DeepSeek R1 같은 거대 LLM 과 달리
임베딩 모델은 그중에서도 가장 중요한 부분입니다. ChatGPT, DeepSeek V3, DeepSeek R1 같은 거대 LLM과 달리
임베딩 모델은 수백 메가바이트 수준으로 작아서 CPU 기기에서도 추론할 수 있습니다.
(비교하자면 DeepSeek V3 671B 를 GGUF 형식 q4 양자화로 돌려도 400GiB 이상이 필요합니다.)
(비교하자면 DeepSeek V3 671B를 GGUF 형식 q4 양자화로 돌려도 400GiB 이상이 필요합니다.)
다만 🥺 SAD 는 아직 작업 중이라, 오늘(4월 6일) 기준으로 잘나가는 임베딩 모델 몇 가지를 정리해 보겠습니다.
다만 🥺 SAD는 아직 작업 중이라, 오늘(4월 6일) 기준으로 잘나가는 임베딩 모델 몇 가지를 정리해 보겠습니다.
오픈소스와 상용 모델을 모두 포함한 리더보드:
@@ -225,20 +225,20 @@ Kubernetes 배포에서도 과정은 같지만, 호스트 머신의 파일을
> 더 많은 내용은 여기서 볼 수 있습니다: https://huggingface.co/spaces/mteb/leaderboard
그런데 OpenAI `text-embedding-3-large` 모델은 어디 갔냐고요? 리더보드에 오를 만큼 강력하지 않았던 걸까요?
그런데 OpenAI의 `text-embedding-3-large` 모델은 어디 갔냐고요? 리더보드에 오를 만큼 강력하지 않았던 걸까요?
네, MTEB 리더보드(4월 6일 기준)에서 `text-embedding-3-large` **13위** 였습니다.
네, MTEB 리더보드(4월 6일 기준)에서 `text-embedding-3-large`**13위** 였습니다.
클라우드 프로바이더가 제공하는 임베딩 모델에 의존하고 싶다면 다음을 고려해 보세요:
- [Gemini](https://ai.google.dev)
- [Voyage.ai](https://www.voyageai.com/)
Ollama 사용자에게는 `nomic-embed-text` 가 여전히 2140만 회 이상 내려받힌 인기 모델입니다.
Ollama 사용자에게는 `nomic-embed-text`가 여전히 2140만 회 이상 내려받힌 인기 모델입니다.
#### 어떻게 구현했나
Vector DB 와 임베딩 모델은 마련했는데, 데이터를 어떻게 효과적으로 (재정렬 확장성까지 갖춰서)
Vector DB와 임베딩 모델은 마련했는데, 데이터를 어떻게 효과적으로 (재정렬 확장성까지 갖춰서)
질의할 수 있을까요?
먼저 테이블 스키마를 정의해야 합니다. Drizzle 스키마 코드는 이렇게 생겼습니다:
@@ -261,7 +261,7 @@ export const demoTable = pgTable(
)
```
이에 대응하는 테이블 생성 SQL 은 이렇습니다:
이에 대응하는 테이블 생성 SQL은 이렇습니다:
```sql
CREATE TABLE "chat_messages" (
@@ -367,7 +367,7 @@ const finalScore = similarity * calculateTimeDecayScore(message.createdAt)
### 캐릭터 카드 지원
Project AIRI 에 캐릭터 카드 지원도 추가했습니다. 캐릭터 카드는 AI 캐릭터의 성격, 외형, 행동을
Project AIRI에 캐릭터 카드 지원도 추가했습니다. 캐릭터 카드는 AI 캐릭터의 성격, 외형, 행동을
정의하는 JSON 파일입니다. 많은 AI 캐릭터 플랫폼이 쓰는 인기 있는 V2/V3 형식을 따릅니다.
간단한 캐릭터 카드 예시입니다:
@@ -385,12 +385,12 @@ Project AIRI 에 캐릭터 카드 지원도 추가했습니다. 캐릭터 카드
}
```
이 캐릭터 카드를 읽어 AI 의 동작을 그에 맞게 설정하는 파서를 구현했습니다. 시스템은 단순한 텍스트
이 캐릭터 카드를 읽어 AI의 동작을 그에 맞게 설정하는 파서를 구현했습니다. 시스템은 단순한 텍스트
기반 카드는 물론, 이미지와 메타데이터가 내장된 더 복잡한 카드도 지원합니다.
### 테마 개선
Project AIRI 의 비주얼 테마를 개선하는 작업을 해 왔습니다. 새 테마 시스템은 이제 다음을 지원합니다:
Project AIRI의 비주얼 테마를 개선하는 작업을 해 왔습니다. 새 테마 시스템은 이제 다음을 지원합니다:
- 여러 색 구성(라이트, 다크, 자동)
- 커스텀 강조 색상
@@ -410,14 +410,14 @@ setTheme('auto')
setAccentColor('#ff6b6b')
```
테마 변경 사항은 localStorage 로 세션 간에 유지되므로, 사용자가 방문할 때마다 다시 설정할 필요가 없습니다.
테마 변경 사항은 localStorage로 세션 간에 유지되므로, 사용자가 방문할 때마다 다시 설정할 필요가 없습니다.
### 커뮤니티 기여
커뮤니티가 Project AIRI 에 기여하기 시작해서 기쁩니다! 눈에 띄는 기여로는 이런 것들이 있습니다:
커뮤니티가 Project AIRI에 기여하기 시작해서 기쁩니다! 눈에 띄는 기여로는 이런 것들이 있습니다:
- **Awesome AI VTuber List**: AI VTuber 프로젝트와 자료를 정리한 목록
- **ReLU 스티커 팩**: 다양한 표정의 ReLU 를 담은 커스텀 스티커 모음
- **ReLU 스티커 팩**: 다양한 표정의 ReLU를 담은 커스텀 스티커 모음
- **문서 개선**: 많은 커뮤니티 멤버가 문서 개선을 도와주고 있습니다
모든 지원과 기여에 감사드립니다. 기여하고 싶으시다면
@@ -430,17 +430,17 @@ setAccentColor('#ff6b6b')
1. **기억 시스템 개선**: 회상 정확도와 효율 향상
2. **멀티모달 지원**: 이미지와 오디오 생성 기능 추가
3. **플러그인 시스템**: 서드파티 확장으로 기능을 강화
4. **모바일 앱**: iOS 와 Android 용 네이티브 애플리케이션
4. **모바일 앱**: iOS와 Android용 네이티브 애플리케이션
Project AIRI 각 구성 요소에 대한 더 상세한 문서도 아키텍처 심층 분석과 구현 가이드를 포함해
공개할 계획입니다.
## 맺으며
Project AIRI 에게 신나는 개발 기간이었습니다. 기억 시스템이 모습을 갖춰 가고, 캐릭터 카드 지원도
Project AIRI에게 신나는 개발 기간이었습니다. 기억 시스템이 모습을 갖춰 가고, 캐릭터 카드 지원도
잘 동작하며, 테마 개선으로 인터페이스가 훨씬 정돈됐습니다.
무엇보다 ReLU 가 자신만의 성격을 키우고 심지어 시까지 쓰는 모습을 보는 것이 정말 큰 보람이었습니다.
무엇보다 ReLU가 자신만의 성격을 키우고 심지어 시까지 쓰는 모습을 보는 것이 정말 큰 보람이었습니다.
저희가 애초에 이 프로젝트를 시작한 이유, 즉 진짜 같고 매력적인 AI 상호작용을 만들고 싶다는 마음을
다시 떠올리게 해 줍니다.
+30 -30
View File
@@ -6,7 +6,7 @@ date: 2025-04-14
## 들어가며
[지난번](../DevLog-2025.04.06/#기억-시스템)에는 AIRI 의 기억 시스템을 이야기했습니다. 오늘은 이렇게 복잡한 기억 시스템을 어떻게 구현할지 더 깊이 파고들고 앞으로의 전망도 살펴보겠습니다.
[지난번](../DevLog-2025.04.06/#기억-시스템)에는 AIRI의 기억 시스템을 이야기했습니다. 오늘은 이렇게 복잡한 기억 시스템을 어떻게 구현할지 더 깊이 파고들고 앞으로의 전망도 살펴보겠습니다.
## 검색 엔진에서 시작하기
@@ -23,19 +23,19 @@ date: 2025-04-14
### OpenSearch / Wentian 엔진 DSL [^1]
Neko 가 많이 써 온 알리바바 클라우드 OpenSearch 를 예로 들어 보겠습니다. 검색 엔진에는 재정렬을 위한 내장 함수들이 있습니다:
Neko가 많이 써 온 알리바바 클라우드 OpenSearch를 예로 들어 보겠습니다. 검색 엔진에는 재정렬을 위한 내장 함수들이 있습니다:
#### `static_bm25`
정적 텍스트 연관도. 전통적인 NLP 방식으로, 질의와 문서의 일치 정도를 측정합니다.
RAG _similarity score_ 와 비슷합니다.
RAG의 _similarity score_와 비슷합니다.
값 범위: 01
#### `exact_match_boost`
사용자가 지정한 질의어의 최대 가중치를 얻습니다. score boost 함수라고도 합니다.
입력한 키워드가 토크나이즈 전에 문서 필드(제목, 본문 등)의 "내용"에 적중하는 경우에 해당합니다.
예를 들어 "How to make Neurosama" 를 검색할 때, "Neurosama" 라는 정확한 구절을 담은 문서와 페이지가 "Neuro" 와 "sama" 가 따로 나오는 문서보다 높은 점수를 받아야 합니다.
예를 들어 "How to make Neurosama"를 검색할 때, "Neurosama"라는 정확한 구절을 담은 문서와 페이지가 "Neuro"와 "sama"가 따로 나오는 문서보다 높은 점수를 받아야 합니다.
#### `timeliness`, `timeliness_ms`
@@ -45,15 +45,15 @@ RAG 의 _similarity score_ 와 비슷합니다.
알리바바 클라우드의 OpenSearch, Grafana 내장 Loki, 그 이전의 ElasticSearch 엔진(일부 영상 사이트는 ElasticSearch 기반으로 개발됐습니다) 등 어떤 검색 엔진이든, 사용하기 전에 데이터를 그 검색 엔진 안의 **별도 데이터 구조로 재가공**해야 합니다.
이 재가공은 어떻게 구현할까요? 여기에 DTS 가 필요합니다.
이 재가공은 어떻게 구현할까요? 여기에 DTS가 필요합니다.
#### DTS [^2]
**DTS** 라는 개념을 좀 더 소개하겠습니다.
**DTS**라는 개념을 좀 더 소개하겠습니다.
Data Transformation Services 는 비즈니스 데이터베이스와 검색 엔진 인스턴스 사이의 **통신과 데이터 동기화**를 담당하는 시스템입니다.
Data Transformation Services는 비즈니스 데이터베이스와 검색 엔진 인스턴스 사이의 **통신과 데이터 동기화**를 담당하는 시스템입니다.
구현 원리: MySQL 과 Postgres 의 네이티브 watch/subscribe 이벤트 기능으로 테이블 변경을 감지한 뒤 데이터를 검색 엔진으로 동기화합니다. 이 과정에서 데이터는 원하는 형식으로 직렬화되며 데이터 구조 변환(ETL: extract, transform, load)을 거칩니다.
구현 원리: MySQL과 Postgres의 네이티브 watch/subscribe 이벤트 기능으로 테이블 변경을 감지한 뒤 데이터를 검색 엔진으로 동기화합니다. 이 과정에서 데이터는 원하는 형식으로 직렬화되며 데이터 구조 변환(ETL: extract, transform, load)을 거칩니다.
조 정렬 검색을 수행할 때, 데이터베이스의 __ 에서 검색하는 것과 비슷하지 않나요? 가상 테이블처럼요. 어느 정도 맞는 이해입니다. 다만 뷰는 보통 데이터베이스와 같은 하부 자료구조(B+ 트리)를 쓰는 반면, 검색 엔진은 그래프나 특화된 인덱스 키-값 데이터베이스 같은 다양한 전용 자료구조를 쓸 수 있습니다.
@@ -76,27 +76,27 @@ Data Transformation Services 는 비즈니스 데이터베이스와 검색 엔
- 내부 작업 스케줄러를 여러 개 두고 데이터를 천천히 인덱싱
- 해밍 거리, 코사인 거리 같은 전통 NLP 기법은 미리 계산해 저장 가능
- 인기 검색어는 토크나이제이션과 정렬 결과를 캐시 가능
- 데이터 레이크하우스? AWS 에서 흔히 쓰이며 보통 여러 데이터베이스나 데이터 소스를 아우르는 집계 질의에 씁니다. 매우 느려서 사실상 데이터 분석과 BI 에만 사용합니다
- 데이터 레이크하우스? AWS에서 흔히 쓰이며 보통 여러 데이터베이스나 데이터 소스를 아우르는 집계 질의에 씁니다. 매우 느려서 사실상 데이터 분석과 BI 에만 사용합니다
### Recall 이란?
### Recall이란?
Recall(재현/검색)은 키워드를 입력했을 때 기대한 문서를 실제로 찾아낼 수 있는지를 말합니다.
Search 와의 차이는? Search 는 "사용자가 시작하는 동작"이고, Recall 은 "검색에 응답하기 위해 기계가 하는 일"입니다.
Search와의 차이는? Search는 "사용자가 시작하는 동작"이고, Recall은 "검색에 응답하기 위해 기계가 하는 일"입니다.
### Reranking 이란?
### Reranking이란?
Reranking 의 의미는 이렇습니다. 임베딩 모델 벡터를 기반으로 ANN(Approximate Nearest Neighbor)과 KNN(K-Nearest Neighbor)의 벡터 거리 정렬에만 의존하면 실제로는 편향이 생깁니다.
Reranking의 의미는 이렇습니다. 임베딩 모델 벡터를 기반으로 ANN(Approximate Nearest Neighbor)과 KNN(K-Nearest Neighbor)의 벡터 거리 정렬에만 의존하면 실제로는 편향이 생깁니다.
앞서 OpenSearch 에서 소개한 exact_match_boost 와 timeliness 함수가 더는 존재하지 않게 되기 때문입니다.
앞서 OpenSearch에서 소개한 exact_match_boost와 timeliness 함수가 더는 존재하지 않게 되기 때문입니다.
검색된 문서에 다른 필드와 단계를 기준으로 한 정렬을 추가하고 싶다면 어떻게 할까요?
RAG 는 이제 reranking model 이라는 새로운 과정을 대중화했습니다. 본질적으로 **별도의 전문가 모델을 써서 1차로 검색된 데이터를 자동으로 재정렬**하는 것입니다.
RAG는 이제 reranking model이라는 새로운 과정을 대중화했습니다. 본질적으로 **별도의 전문가 모델을 써서 1차로 검색된 데이터를 자동으로 재정렬**하는 것입니다.
하지만 reranking 으로도 기억 계층의 여러 문제를 풀 수는 없습니다. 망각 곡선, 기억 강화, 무작위 기억 회상, 감정이 영향을 미치는 재정렬 점수 같은 것들은 reranking 모델이 다룰 수 있는 영역이 아닙니다.
AIRI 를 위한 좋은 기억 계층을 만들려면 RAG 의 기본 능력과 과거 검색 엔진의 재정렬 경험을 결합해 좋은 재정렬 메커니즘을 세워야 합니다.
AIRI를 위한 좋은 기억 계층을 만들려면 RAG의 기본 능력과 과거 검색 엔진의 재정렬 경험을 결합해 좋은 재정렬 메커니즘을 세워야 합니다.
## 기억 계층 실험 플랫폼
@@ -104,7 +104,7 @@ AIRI 를 위한 좋은 기억 계층을 만들려면 RAG 의 기본 능력과
![](/en/blog/DevLog-2025.04.14/assets/memory-driver.avif)
왼쪽에 강조된 "half life" 는 기억의 반감기입니다.
왼쪽에 강조된 "half life"는 기억의 반감기입니다.
기본값으로 시간은 1초 = 1일 로 흐르므로, 7초가 지나면 기억 점수가 절반이 됩니다.
@@ -113,12 +113,12 @@ AIRI 를 위한 좋은 기억 계층을 만들려면 RAG 의 기본 능력과
그 결과로 나온 점수가 현재 점수입니다.
original 은 무엇일까요? 초기화 시점의 점수입니다.
original은 무엇일까요? 초기화 시점의 점수입니다.
예: 원래 점수가 523 인데 현재 점수는 실제로 서서히 줄어들고 있습니다:
![](/en/blog/DevLog-2025.04.14/assets/memory-decay.avif)
계속하기 전에 짚고 넘어가면, 이 망각 곡선 SQL 은 무상태(stateless)입니다.
계속하기 전에 짚고 넘어가면, 이 망각 곡선 SQL은 무상태(stateless)입니다.
무상태란 무슨 뜻일까요? 점수를 갱신하기 위해 데이터베이스에서 실시간 작업을 돌릴 필요 없이, "현재 시각"을 기준으로 망각 함수를 바로 적용해 점수를 계산한다는 뜻입니다.
@@ -143,14 +143,14 @@ original 은 무엇일까요? 초기화 시점의 점수입니다.
마지막으로 근육 기억은 기억의 한 종류라기보다 이미 형성된 조건 반사에 가깝습니다.
## AIRI 는 어떻게 설계해야 할까?
## AIRI는 어떻게 설계해야 할까?
여기서 AIRI 의 구현 원리를 엿볼 수 있습니다:
여기서 AIRI의 구현 원리를 엿볼 수 있습니다:
- 작업 기억은 messages 배열 같은 것
- 단기 기억은 잘 회상되지 않는 RAG 기억 항목 같은 것으로, 새로운 것일수록 회상되기 쉬움
- 장기 기억은 쉽게 회상되지만 흐릿해지는 RAG 항목 같은 것으로, 과거 회상 횟수가 많을수록 회상되기 쉬움
- 근육 기억은 고정된 패턴 같은 것으로, A 가 나타나면 ActionA 와 MemoryA 가 함께 나타나는, 정확한 매칭 메커니즘에 가까움
- 근육 기억은 고정된 패턴 같은 것으로, A가 나타나면 ActionA와 MemoryA가 함께 나타나는, 정확한 매칭 메커니즘에 가까움
그런데 이 설계가 맞을까요?
@@ -158,21 +158,21 @@ original 은 무엇일까요? 초기화 시점의 점수입니다.
### 빠른 복습
DevLog 에서 언급한 정렬 표현식을 복습해 보면 이해에 도움이 될 겁니다.
DevLog에서 언급한 정렬 표현식을 복습해 보면 이해에 도움이 될 겁니다.
![](/en/blog/DevLog-2025.04.14/assets/review-1.avif)
코사인 거리는 "연관도" 이며, 가장 기본적인 조 정렬입니다:
![](/en/blog/DevLog-2025.04.14/assets/review-2.avif)
이제 시간을 개입시켜야 하므로 시간 거리를 저장할 필드를 하나 더 추가하고, 결합 점수 `(1.2 * similarity) + (0.2 * time_relevance)` 를 저장할 별도 필드를 만듭니다. 여기서 의미적 연관도는 1.2배 가중치(증폭 계수이며 1 미만일 필요는 없습니다), 시간 거리 연관도는 0.2배 가중치를 갖습니다.
이제 시간을 개입시켜야 하므로 시간 거리를 저장할 필드를 하나 더 추가하고, 결합 점수 `(1.2 * similarity) + (0.2 * time_relevance)`를 저장할 별도 필드를 만듭니다. 여기서 의미적 연관도는 1.2배 가중치(증폭 계수이며 1 미만일 필요는 없습니다), 시간 거리 연관도는 0.2배 가중치를 갖습니다.
이렇게 하면 무상태 다중 필드 연관도 정렬 SQL 을 깔끔하게 구현하면서 매개변수(1.2 와 0.2)로 조정도 할 수 있습니다.
이렇게 하면 무상태 다중 필드 연관도 정렬 SQL을 깔끔하게 구현하면서 매개변수(1.2와 0.2)로 조정도 할 수 있습니다.
기억 상세 카드에서는 "simulate retrieval" 을 클릭해 기억 회상을 능동적으로 트리거할 수 있습니다.
기억 상세 카드에서는 "simulate retrieval"을 클릭해 기억 회상을 능동적으로 트리거할 수 있습니다.
![](/en/blog/DevLog-2025.04.14/assets/memory-retrieval.avif)
현재 데모에서는 원본 테이블의 검색 횟수 필드에 UPDATE 문으로 +1 을 더하는 단순한 방식으로 구현되어 있습니다.
현재 데모에서는 원본 테이블의 검색 횟수 필드에 UPDATE 문으로 +1을 더하는 단순한 방식으로 구현되어 있습니다.
여기에 숨은 함정이 있습니다. 이건 여전히 단일 차원 계산이라 "회상 = 강화" 와 같습니다.
@@ -200,7 +200,7 @@ https://drizzle-orm-duckdb-wasm.netlify.app/#/memory-simulator
### PTSD?
PTSD 에는 보통 "trigger" 와 "flashback" 이라는 두 단어가 따라옵니다. 분명 PTSD 관련 기억은 억제되어야 하고, 혐오와 트라우마 점수가 높아야 합니다.
PTSD에는 보통 "trigger"와 "flashback"이라는 두 단어가 따라옵니다. 분명 PTSD 관련 기억은 억제되어야 하고, 혐오와 트라우마 점수가 높아야 합니다.
하지만 실제로 PTSD 관련 기억은 갑자기 떠오를 수 있습니다. 생체 모방과 데이터 시뮬레이션 관점에서는 난수를 써서 이 효과를 구현할 수 있습니다.
@@ -210,7 +210,7 @@ https://yutsuki.moe/2019/09/a0d0fa1b/ 의 감정 모델을 참고할 수 있습
## 아직 할 일이 많습니다...
예를 들어 지금 ReLU 의 감정은 어떤가요? ReLU 는 누군가에 대한 나쁜 기억을 갖고 있을까요?
예를 들어 지금 ReLU의 감정은 어떤가요? ReLU는 누군가에 대한 나쁜 기억을 갖고 있을까요?
기억은 기쁨과 슬픔이 함께 극성을 이루는 항목으로 나타날까요?
@@ -222,7 +222,7 @@ _백그라운드 작업_ 과 비슷하게, 발생한 기억을 하나씩 처리
재인덱싱 관점에서 보면 꿈꾸기 에이전트와 잠재의식 에이전트는 인덱스를 다시 만드는 일과 같습니다.
여기까지 오면 [Mem0](https://docs.mem0.ai/overview) 나 [Zep Memory](https://help.getzep.com/memory) 같은 라이브러리가 롤플레잉과 감정 AI 에서는 전혀 쓸모없다는 걸 알게 됩니다 :(
여기까지 오면 [Mem0](https://docs.mem0.ai/overview)나 [Zep Memory](https://help.getzep.com/memory) 같은 라이브러리가 롤플레잉과 감정 AI에서는 전혀 쓸모없다는 걸 알게 됩니다 :(
갈 길이 멀고, 저희는 계속 노력해야 합니다.
+17 -17
View File
@@ -10,25 +10,25 @@ import cursorOpenSettings from '../../../en/blog/DevLog-2025.04.22/assets/cursor
## 낮 시간의 일기
안녕하세요, [@LemonNeko](https://github.com/LemonNekoGH) 입니다. 이번에는 제가 DevLog 작성에 참여해서 개발 이야기를 나눠 보려 합니다.
안녕하세요, [@LemonNeko](https://github.com/LemonNekoGH)입니다. 이번에는 제가 DevLog 작성에 참여해서 개발 이야기를 나눠 보려 합니다.
두 달 전, 저희는 AIRI 의 웹 인터페이스를 Electron 으로 포팅했습니다 [#7](https://github.com/moeru-ai/airi/pull/7) (지금은 Tauri 로 다시 리팩터링됐지만요 🤣 [#90](https://github.com/moeru-ai/airi/pull/90)). 덕분에 화면 위에 데스크톱 펫처럼 띄울 수 있게 됐죠. 그와 동시에 AIRI 가 휴대폰을 쓸 수 있게 하면 어떨까 하는 생각이 있었는데, 계속 미뤄 두고 있었습니다.
두 달 전, 저희는 AIRI의 웹 인터페이스를 Electron으로 포팅했습니다 [#7](https://github.com/moeru-ai/airi/pull/7) (지금은 Tauri로 다시 리팩터링됐지만요 🤣 [#90](https://github.com/moeru-ai/airi/pull/90)). 덕분에 화면 위에 데스크톱 펫처럼 띄울 수 있게 됐죠. 그와 동시에 AIRI가 휴대폰을 쓸 수 있게 하면 어떨까 하는 생각이 있었는데, 계속 미뤄 두고 있었습니다.
지난 주말(2025.04.20), 시간을 좀 내서 ADB 와 상호작용할 수 있는 MCP 서버 데모 [airi-android](https://github.com/LemonNekoGH/airi-android) 를 만들었습니다. AIRI 에게 기본적인 모바일 조작 능력을 주는 것이죠 (사실 대부분의 LLM 이 이걸 통해 휴대폰을 조작할 수 있습니다). 데모 영상입니다:
지난 주말(2025.04.20), 시간을 좀 내서 ADB와 상호작용할 수 있는 MCP 서버 데모 [airi-android](https://github.com/LemonNekoGH/airi-android)를 만들었습니다. AIRI에게 기본적인 모바일 조작 능력을 주는 것이죠 (사실 대부분의 LLM이 이걸 통해 휴대폰을 조작할 수 있습니다). 데모 영상입니다:
<ThemedVideo controls muted :src="cursorOpenSettings" />
Docker 이미지로도 패키징해서 [MCP 서버 목록](https://mcp.so/server/airi-android/lemonnekogh)에 등록했습니다. 관심 있으시면 편하게 써 보세요.
사실 처음 생각은 Tool Calling 코드를 좀 짜고 프롬프트를 수정해서, LLM 에게 "이 도구들로 휴대폰을 조작할 수 있다"고 알려 주면 끝이라는 것이었습니다. ~~그런데 요즘 MCP 가 너무 유행이라 FOMO 가 와서 MCP 로 구현하기로 했습니다.~~
사실 처음 생각은 Tool Calling 코드를 좀 짜고 프롬프트를 수정해서, LLM에게 "이 도구들로 휴대폰을 조작할 수 있다"고 알려 주면 끝이라는 것이었습니다. ~~그런데 요즘 MCP가 너무 유행이라 FOMO가 와서 MCP로 구현하기로 했습니다.~~
MCP 서버를 쓰려면 먼저 MCP 가 뭔지 이해해야 했습니다 (물론 저는 실전 전에 이론부터 파는 타입은 아니라서, 일단 뛰어들어 Cursor 에게 써 보게 하는 쪽을 선호합니다). MCP(Model Context Protocol)는 애플리케이션이 LLM 에게 컨텍스트를 제공하는 방식을 표준화하려는 프로토콜입니다. 몇 가지 핵심 개념을 제안하죠:
MCP 서버를 쓰려면 먼저 MCP가 뭔지 이해해야 했습니다 (물론 저는 실전 전에 이론부터 파는 타입은 아니라서, 일단 뛰어들어 Cursor에게 써 보게 하는 쪽을 선호합니다). MCP(Model Context Protocol)는 애플리케이션이 LLM에게 컨텍스트를 제공하는 방식을 표준화하려는 프로토콜입니다. 몇 가지 핵심 개념을 제안하죠:
1. Resources: 서버가 데이터와 콘텐츠를 LLM 에게 컨텍스트로 제공할 수 있습니다.
1. Resources: 서버가 데이터와 콘텐츠를 LLM에게 컨텍스트로 제공할 수 있습니다.
2. Prompts: 재사용 가능한 프롬프트 템플릿과 워크플로를 만듭니다.
3. Tools: LLM 이 여러분의 서버를 통해 동작을 수행할 수 있게 합니다.
3. Tools: LLM이 여러분의 서버를 통해 동작을 수행할 수 있게 합니다.
아, 리소스 — 이건 압니다! Ruby on Rails 에서 사용자는 일종의 리소스죠. 그럼 ADB 기기도 리소스일까요? LLM 이 연결된 기기 목록을 보게 하려면 이렇게 쓰면 될까요:
아, 리소스 — 이건 압니다! Ruby on Rails에서 사용자는 일종의 리소스죠. 그럼 ADB 기기도 리소스일까요? LLM이 연결된 기기 목록을 보게 하려면 이렇게 쓰면 될까요:
```python
from mcp.server.fastmcp import FastMCP
@@ -42,9 +42,9 @@ def get_devices():
return adb_client.devices()
```
틀렸습니다! Cursor 에게 기기 목록을 가져오라고 했더니 어떻게 해야 할지 모르더군요. 어떤 기기가 연결됐는지 능동적으로 확인하고 싶다고 했으니, 이건 도구(tool)입니다. 음, 제가 완전히 이해하지 못했던 모양입니다.
틀렸습니다! Cursor에게 기기 목록을 가져오라고 했더니 어떻게 해야 할지 모르더군요. 어떤 기기가 연결됐는지 능동적으로 확인하고 싶다고 했으니, 이건 도구(tool)입니다. 음, 제가 완전히 이해하지 못했던 모양입니다.
LLM 이 휴대폰을 조작하게 하는 정확한 방법은 아직 못 찾았고, 여러분과 함께 이야기해 보고 싶습니다. 다만 Cursor 는 이렇게 동작합니다:
LLM이 휴대폰을 조작하게 하는 정확한 방법은 아직 못 찾았고, 여러분과 함께 이야기해 보고 싶습니다. 다만 Cursor는 이렇게 동작합니다:
1. 스크린샷 기능으로 휴대폰 화면에 무엇이 있는지 대략 파악합니다.
2. UI 자동화 도구로 조작하려는 요소의 정확한 위치를 얻습니다.
@@ -53,23 +53,23 @@ LLM 이 휴대폰을 조작하게 하는 정확한 방법은 아직 못 찾았
지금까지는 잘 동작하는 것 같은데, 작은 의문이 몇 가지 있습니다:
1. 화면에 UI 컴포넌트가 아니라 그래픽 API 로 직접 그리는 게임이 떠 있다면, UI 자동화 도구는 요소 위치를 얻을 수 없어 조작도 못 합니다.
2. LLM 응답에는 길이 제한이 있습니다. 조작이 복잡하면 단계별로 나눠서 끝내야 할 텐데, [airi-factorio](https://github.com/moeru-ai/airi-factorio) 처럼 각 단계가 끝날 때마다 자동으로 알려서 다음 단계를 트리거할 수 있을까요?
1. 화면에 UI 컴포넌트가 아니라 그래픽 API로 직접 그리는 게임이 떠 있다면, UI 자동화 도구는 요소 위치를 얻을 수 없어 조작도 못 합니다.
2. LLM 응답에는 길이 제한이 있습니다. 조작이 복잡하면 단계별로 나눠서 끝내야 할 텐데, [airi-factorio](https://github.com/moeru-ai/airi-factorio)처럼 각 단계가 끝날 때마다 자동으로 알려서 다음 단계를 트리거할 수 있을까요?
3. 어떤 앱은 화려한 애니메이션이 있어서, 조작 직후 스크린샷을 찍으면 결과가 안 보일 수 있습니다. 조작 후 잠시 기다렸다 찍어야 할까요, 아니면 아예 화면 녹화를 써야 할까요?
4. AI 가 휴대폰을 직접 조작하게 하는 것의 보안은 어떨까요? 어떤 위험이 있을까요?
4. AI가 휴대폰을 직접 조작하게 하는 것의 보안은 어떨까요? 어떤 위험이 있을까요?
몇 가지 소회입니다.
AI 와 작업하면서 사람과 함께 코딩하는 기분이 든 건 이번이 처음입니다. 제 목표가 "AI 가 내 도구를 쓰게 하는 것"이어서 AI 가 제 클라이언트가 되어 버린 탓인지도 모르겠습니다. 저는 계속 AI 의 피드백에 맞춰 코드를 고쳐야 했으니까요. 동시에 AI 는 제 동료이기도 했습니다. 함께 고민하고 문제를 풀어야 했거든요. 이 스크린샷을 보세요. 정말 그렇게 보이지 않나요?
AI와 작업하면서 사람과 함께 코딩하는 기분이 든 건 이번이 처음입니다. 제 목표가 "AI가 내 도구를 쓰게 하는 것"이어서 AI가 제 클라이언트가 되어 버린 탓인지도 모르겠습니다. 저는 계속 AI의 피드백에 맞춰 코드를 고쳐야 했으니까요. 동시에 AI는 제 동료이기도 했습니다. 함께 고민하고 문제를 풀어야 했거든요. 이 스크린샷을 보세요. 정말 그렇게 보이지 않나요?
![](/en/blog/DevLog-2025.04.22/assets/develop-with-cursor.avif)
개발하면서 작은 요령도 배웠습니다. 예를 들어 명령줄로 Android 에뮬레이터를 띄우면 Android Studio 를 열 필요가 없어서 메모리 부담이 크게 줄어듭니다.
개발하면서 작은 요령도 배웠습니다. 예를 들어 명령줄로 Android 에뮬레이터를 띄우면 Android Studio를 열 필요가 없어서 메모리 부담이 크게 줄어듭니다.
```bash
emulator -avd Pixel_6_Pro_API_34
```
다음에는 AIRI 데스크톱 펫을 MCP 서버에 연결해서 뭘 하고 싶어 하는지 보려고 합니다. 어쩌면 지금 ReLU 가 하는 것처럼 Telegram 을 열고 우리와 대화할지도 모르죠. 다만 Telegram API 를 쓰지 않고서요.
다음에는 AIRI 데스크톱 펫을 MCP 서버에 연결해서 뭘 하고 싶어 하는지 보려고 합니다. 어쩌면 지금 ReLU가 하는 것처럼 Telegram을 열고 우리와 대화할지도 모르죠. 다만 Telegram API를 쓰지 않고서요.
다소 두서없고 알맹이가 부족했을지 모를 DevLog 를 읽어 주셔서 감사합니다. 다음에 또 만나요!
다소 두서없고 알맹이가 부족했을지 모를 DevLog를 읽어 주셔서 감사합니다. 다음에 또 만나요!
+22 -22
View File
@@ -10,29 +10,29 @@ import airiMcpInputText from '../../../en/blog/DevLog-2025.04.28/assets/airi-mcp
import airiMcpArch from '../../../en/blog/DevLog-2025.04.28/assets/airi-mcp-arch.avif'
</script>
안녕하세요 여러분, [@LemonNeko](https://github.com/LemonNekoGH) 입니다. 오늘도 개발 이야기를 나누러 왔습니다.
안녕하세요 여러분, [@LemonNeko](https://github.com/LemonNekoGH)입니다. 오늘도 개발 이야기를 나누러 왔습니다.
## 낮 시간의 일기
일주일 전, AIRI 가 휴대폰에 연결할 수 있도록 MCP 서버 [AIRI-android](https://github.com/LemonNekoGH/AIRI-android) 를 만들었습니다. 하지만 이건 AIRI 가 Android 폰을 조작하게 만드는 일의 전반부일 뿐이었습니다. AIRI 도 MCP 서버와 상호작용할 수 있어야 했으니까요.
일주일 전, AIRI가 휴대폰에 연결할 수 있도록 MCP 서버 [AIRI-android](https://github.com/LemonNekoGH/AIRI-android)를 만들었습니다. 하지만 이건 AIRI가 Android 폰을 조작하게 만드는 일의 전반부일 뿐이었습니다. AIRI도 MCP 서버와 상호작용할 수 있어야 했으니까요.
지난 이틀 동안 Tauri 플러그인 [#144](https://github.com/moeru-ai/AIRI/pull/144) 를 작성해 후반부를 마쳤습니다. 이제 AIRI 는 MCP 서버와 상호작용할 수 있고, 기존의 모든 MCP 서버와 함께 동작합니다.
지난 이틀 동안 Tauri 플러그인 [#144](https://github.com/moeru-ai/AIRI/pull/144)를 작성해 후반부를 마쳤습니다. 이제 AIRI는 MCP 서버와 상호작용할 수 있고, 기존의 모든 MCP 서버와 함께 동작합니다.
관심 있으시면 아래 두 영상을 봐 주세요. 첫 번째는 AIRI 의 MCP 서버 설정을, 두 번째는 AIRI 가 Android 폰과 상호작용하는 모습을 보여 줍니다.
관심 있으시면 아래 두 영상을 봐 주세요. 첫 번째는 AIRI의 MCP 서버 설정을, 두 번째는 AIRI가 Android 폰과 상호작용하는 모습을 보여 줍니다.
<details>
<summary>AIRI 의 MCP 서버 설정</summary>
<summary>AIRI의 MCP 서버 설정</summary>
<ThemedVideo controls muted :src="airiMcpSettings" style="height: 640px;" />
</details>
<details>
<summary>AIRI 가 휴대폰에 `Hello World` 를 입력하는 모습</summary>
<summary>AIRI가 휴대폰에 `Hello World`를 입력하는 모습</summary>
<ThemedVideo controls muted :src="airiMcpInputText" />
</details>
개발 중 생각을 정리하려고 LLM 이 Android 폰을 호출하는 흐름을 그림으로 그려 봤습니다:
개발 중 생각을 정리하려고 LLM이 Android 폰을 호출하는 흐름을 그림으로 그려 봤습니다:
<img :src="airiMcpArch" alt="AIRI 가 휴대폰을 조작하는 구조" :style="{ height: '640px', objectFit: 'contain' }" />
<img :src="airiMcpArch" alt="AIRI가 휴대폰을 조작하는 구조" :style="{ height: '640px', objectFit: 'contain' }" />
이제 개발 과정을 나눠 보겠습니다.
@@ -63,7 +63,7 @@ export const mcp = [
]
```
그런데 곧, 명령 안에서 MCP 클라이언트를 쓰려면 MCP 클라이언트를 Tauri 가 관리하는 상태(state)의 일부로 두어야 한다는 걸 알게 됐습니다:
그런데 곧, 명령 안에서 MCP 클라이언트를 쓰려면 MCP 클라이언트를 Tauri가 관리하는 상태(state)의 일부로 두어야 한다는 걸 알게 됐습니다:
```rust
// main.rs
@@ -101,7 +101,7 @@ async fn list_tools(state: State<'_, Mutex<Option<McpClient>>>) -> Result<Vec<To
]
```
이건 한 줄만 바뀌었으니 괜찮습니다. 그런데 Tauri 2 에는 권한 메커니즘이 있어서, 권한 목록을 자동 생성하려면 `build.rs` 에 플러그인의 명령들을 정의해야 했습니다:
이건 한 줄만 바뀌었으니 괜찮습니다. 그런데 Tauri 2에는 권한 메커니즘이 있어서, 권한 목록을 자동 생성하려면 `build.rs`에 플러그인의 명령들을 정의해야 했습니다:
```rust
const COMMANDS: &[&str] = &[
@@ -117,7 +117,7 @@ fn main() {
> 여기서 작은 사고가 하나 있었습니다. 두 번째로 빌드할 때 `Tauri-plugin` 버전을 올렸는데, 새 버전에서 생성 템플릿이 바뀌면서 공백이 일부 제거됐습니다. 그래서 마치 포맷터가 손댄 것처럼 보였죠. 무엇이 "포맷팅" 하는지 한 시간 동안 찾다가, 파일이 재생성된 것이었음을 깨달았습니다. 🤡 잃어버린 그 한 시간을 추모합니다.
위 그림에 따르면, LLM 이 MCP 도구를 호출하면 매개변수는 결국 Python 쪽 MCP 서버로 전달됩니다. `input_swipe` 를 예로 들면:
위 그림에 따르면, LLM이 MCP 도구를 호출하면 매개변수는 결국 Python 쪽 MCP 서버로 전달됩니다. `input_swipe`를 예로 들면:
```python
# mcp_server.py
@@ -141,7 +141,7 @@ pub struct CallToolRequestParam {
}
```
~~오, JsonObject 라니. 살았습니다!~~ Tauri 명령의 매개변수는 JSON 으로 직렬화 가능한 아무 객체나 될 수 있으니, 그냥 `Map<String, Value>` 를 넘기면 됩니다:
~~오, JsonObject 라니. 살았습니다!~~ Tauri 명령의 매개변수는 JSON으로 직렬화 가능한 아무 객체나 될 수 있으니, 그냥 `Map<String, Value>`를 넘기면 됩니다:
```rust
#[Tauri::command]
@@ -164,7 +164,7 @@ invoke('call_tool', { name: 'input_swipe', args: { x1: 100, y1: 100, x2: 200, y2
정말 편리하네요!
MCP 도구에 매개변수를 넘긴 다음에는 도구의 반환값도 받아야 합니다. Tauri 명령의 반환값 역시 JSON 으로 직렬화 가능한 아무 객체나 될 수 있으니, 저는 포기하고 도구 반환값 전체를 그냥 LLM 에게 던져 주기로 했습니다. LLM 이 알아서 잘 처리해 주리라 믿으면서요.
MCP 도구에 매개변수를 넘긴 다음에는 도구의 반환값도 받아야 합니다. Tauri 명령의 반환값 역시 JSON으로 직렬화 가능한 아무 객체나 될 수 있으니, 저는 포기하고 도구 반환값 전체를 그냥 LLM에게 던져 주기로 했습니다. LLM이 알아서 잘 처리해 주리라 믿으면서요.
좋습니다! 이제 Tauri 플러그인이 생겼습니다! (네? 저 짧은 예제 코드, 심지어 의사 코드로 완성이라고요?)
@@ -172,18 +172,18 @@ MCP 도구에 매개변수를 넘긴 다음에는 도구의 반환값도 받아
## 몇 가지 질문
1. 데모 영상에서 보시다시피, 대화에서 저는 먼저 AIRI 에게 도구 목록을 가져오게 한 뒤 텍스트를 입력하게 했습니다. 초기화 시점에 도구 목록을 가져와 시스템 프롬프트에 바로 덧붙이면 어떨까요?
- Cursor 가 그렇게 합니다. MCP 서버를 개발할 때 도구 목록을 수정할 때마다 반영하려면 Cursor 를 재시작해야 했습니다.
1. 데모 영상에서 보시다시피, 대화에서 저는 먼저 AIRI에게 도구 목록을 가져오게 한 뒤 텍스트를 입력하게 했습니다. 초기화 시점에 도구 목록을 가져와 시스템 프롬프트에 바로 덧붙이면 어떨까요?
- Cursor가 그렇게 합니다. MCP 서버를 개발할 때 도구 목록을 수정할 때마다 반영하려면 Cursor를 재시작해야 했습니다.
- 유연성은 좀 희생하겠지만, 일반 사용자가 도구 목록을 자주 수정할까요?
2. AIRI 가 여러 대의 휴대폰에 동시에 연결하도록 허용해야 할까요? AIRI 가 휴대폰을 여러 대 쓰고 싶어 할까요? ~~보이스피싱에 쓰려는 건 아니겠죠?~~
3. 보시다시피 AIRI 저장소에는 이제 Tauri 애플리케이션과 Tauri 플러그인이 함께 있습니다. 이걸 어떻게 관리해야 할까요? CI 는 어떻게 구성해야 할까요? Tauri 플러그인의 Rust 쪽과 JavaScript 쪽 버전 번호는 어떻게 동기화해야 할까요?
2. AIRI가 여러 대의 휴대폰에 동시에 연결하도록 허용해야 할까요? AIRI가 휴대폰을 여러 대 쓰고 싶어 할까요? ~~보이스피싱에 쓰려는 건 아니겠죠?~~
3. 보시다시피 AIRI 저장소에는 이제 Tauri 애플리케이션과 Tauri 플러그인이 함께 있습니다. 이걸 어떻게 관리해야 할까요? CI는 어떻게 구성해야 할까요? Tauri 플러그인의 Rust 쪽과 JavaScript 쪽 버전 번호는 어떻게 동기화해야 할까요?
## 향후 계획
- 이미지 반환값 지원. [지난 DevLog](../DevLog-2025.04.22/) 에서 Cursor 가 보여 준 것처럼 AIRI 가 시각 능력으로 휴대폰 화면을 보고 어떻게 조작할지 판단할 수 있도록.
- AIRI 가 스스로 기기 사용법을 익히게 하기? 기기 종류마다 프롬프트를 따로 써야 한다면 작업량이 어마어마할 겁니다.
- 다중 MCP 서버 지원. MCP 는 AIRI 가 온갖 일을 할 수 있게 해 주는 범용 인터페이스이니, AIRI 도 휴대폰 조작만으로는 만족하지 않을 겁니다.
- SSE 지원. 브라우저의 AIRI 도 MCP 서버를 쓸 수 있도록.
- 이미지 반환값 지원. [지난 DevLog](../DevLog-2025.04.22/) 에서 Cursor가 보여 준 것처럼 AIRI가 시각 능력으로 휴대폰 화면을 보고 어떻게 조작할지 판단할 수 있도록.
- AIRI가 스스로 기기 사용법을 익히게 하기? 기기 종류마다 프롬프트를 따로 써야 한다면 작업량이 어마어마할 겁니다.
- 다중 MCP 서버 지원. MCP는 AIRI가 온갖 일을 할 수 있게 해 주는 범용 인터페이스이니, AIRI도 휴대폰 조작만으로는 만족하지 않을 겁니다.
- SSE 지원. 브라우저의 AIRI도 MCP 서버를 쓸 수 있도록.
오늘은 여기까지입니다! 이번 DevLog 가 너무 딱딱하지 않았기를 바랍니다. 앞으로도 더 재미있는 내용을 가져오겠습니다!
오늘은 여기까지입니다! 이번 DevLog가 너무 딱딱하지 않았기를 바랍니다. 앞으로도 더 재미있는 내용을 가져오겠습니다!
+54 -54
View File
@@ -26,12 +26,12 @@ import DemoDayHangzhou2 from '../../../en/blog/DevLog-2025.05.16/assets/demo-day
import DemoDayHangzhou3 from '../../../en/blog/DevLog-2025.05.16/assets/demo-day-hangzhou-3.avif'
</script>
다시 안녕하세요! [Project AIRI](https://github.com/moeru-ai/airi) 를 시작한
[Neko](https://github.com/nekomeowww) 입니다!
다시 안녕하세요! [Project AIRI](https://github.com/moeru-ai/airi)를 시작한
[Neko](https://github.com/nekomeowww)입니다!
DevLog 를 통한 Project AIRI 소식이 늦어져 죄송합니다. 늦어진 점 너그러이 봐 주세요.
DevLog를 통한 Project AIRI 소식이 늦어져 죄송합니다. 늦어진 점 너그러이 봐 주세요.
> 지난 몇 달 동안 저희는 AIRI 개발 진행 상황에 대해 훌륭한 DevLog 를 여러 편 썼습니다.
> 지난 몇 달 동안 저희는 AIRI 개발 진행 상황에 대해 훌륭한 DevLog를 여러 편 썼습니다.
> 생각과 아이디어를 나누고, 사용하는 기술을 설명하고, 영감을 받은 작품 이야기까지... 전부요.
>
> - [v0.4.0 UI 업데이트](../DevLog-2025.03.20/)
@@ -47,12 +47,12 @@ DevLog 를 통한 Project AIRI 소식이 늦어져 죄송합니다. 늦어진
다음 분야에서 애써 주신 [@LemonNekoGH](https://github.com/LemonNekoGH),
[@RainbowBird](https://github.com/luoling8192),
[@LittleSound](https://github.com/LittleSound) 에게 깊이 감사드립니다.
[@LittleSound](https://github.com/LittleSound)에게 깊이 감사드립니다.
- 캐릭터 카드 지원
::: tip 캐릭터 카드란?
[SillyTavern](https://github.com/SillyTavern/SillyTavern) 이나 [RisuAI](https://risuai.net/) 같은
[SillyTavern](https://github.com/SillyTavern/SillyTavern)이나 [RisuAI](https://risuai.net/) 같은
로컬 우선 채팅 애플리케이션, [JanitorAI](https://janitorai.com/) 같은 온라인 서비스는
각 캐릭터의 배경, 성격, 그 밖의 롤플레잉에 필요한 컨텍스트를 담은 파일을 사용합니다.
@@ -61,10 +61,10 @@ DevLog 를 통한 Project AIRI 소식이 늦어져 죄송합니다. 늦어진
- https://chub.ai/
LLM 기반 롤플레잉 캐릭터를 저장하고 공유하는 수단이 캐릭터 카드만 있는 건 아닙니다.
[Lorebook](https://docs.novelai.net/text/lorebook.html) 도 이 분야에서 핵심적인 역할을 하는데,
[Lorebook](https://docs.novelai.net/text/lorebook.html)도 이 분야에서 핵심적인 역할을 하는데,
이건 문서 시리즈를 통째로 쓸 만한 완전히 다른 이야기입니다. 우선은
[Void's Lorebook Types](https://rentry.co/lorebooks-and-you)
[AI Dynamic Storytelling Wiki](https://aids.miraheze.org/wiki/Main_Page) 를 읽어 보세요.
[Void's Lorebook Types](https://rentry.co/lorebooks-and-you)와
[AI Dynamic Storytelling Wiki](https://aids.miraheze.org/wiki/Main_Page)를 읽어 보세요.
> 개인적으로 이 개념들을 배우기에는 이 위키가 정말 좋습니다:
> [AI Dynamic Storytelling Wiki](https://aids.miraheze.org/wiki/Main_Page).
@@ -85,20 +85,20 @@ LLM 기반 롤플레잉 캐릭터를 저장하고 공유하는 수단이 캐릭
캐릭터 카드 쇼케이스도 몇 가지 방식을 시도해 봤습니다...
<img class="light" :src="CharacterCardShowcaseLight" alt="ReLU 라는 파란 머리 캐릭터를 위한 카드 형태의 UI 디자인" />
<img class="dark" :src="CharacterCardShowcaseDark" alt="ReLU 라는 파란 머리 캐릭터를 위한 카드 형태의 UI 디자인" />
<img class="light" :src="CharacterCardShowcaseLight" alt="ReLU라는 파란 머리 캐릭터를 위한 카드 형태의 UI 디자인" />
<img class="dark" :src="CharacterCardShowcaseDark" alt="ReLU라는 파란 머리 캐릭터를 위한 카드 형태의 UI 디자인" />
저희 UI 컴포넌트 라이브러리에 올라가 있으니 직접 만져 보세요: https://airi.moeru.ai/ui/#/story/src-components-menu-charactercard-story-vue .
> 순수 CSS 와 JavaScript 로 제어되고 레이아웃이 알아서 잡혀서 캔버스 계산을 걱정할 필요가 없습니다.
> 순수 CSS와 JavaScript로 제어되고 레이아웃이 알아서 잡혀서 캔버스 계산을 걱정할 필요가 없습니다.
>
> 아, 캐릭터 카드 쇼케이스 작업 대부분은 [@LittleSound](https://github.com/LittleSound)
> 아, 캐릭터 카드 쇼케이스 작업 대부분은 [@LittleSound](https://github.com/LittleSound)가
> 진행하고 안내해 주었습니다. 정말 감사합니다.
- Tauri MCP 지원
- AIRI 를 Android 기기에 연결
- AIRI를 Android 기기에 연결
이 두 가지는 큰 업데이트이자 실험이었고, [@LemonNekoGH](https://github.com/LemonNekoGH) 가 맡아 주었습니다.
이 두 가지는 큰 업데이트이자 실험이었고, [@LemonNekoGH](https://github.com/LemonNekoGH)가 맡아 주었습니다.
이에 대해 DevLog 두 편을 써서 이면의 기술적 세부 사항을 공유했습니다.
(Tauri 개발자와 사용자에게 유용할 것 같습니다.) 여기서 읽어 보세요:
@@ -109,21 +109,21 @@ LLM 기반 롤플레잉 캐릭터를 저장하고 공유하는 수단이 캐릭
### 듣는 귀, 말하는 입
4월 15일부터, AIRI 의 VAD(음성 활성 감지),
4월 15일부터, AIRI의 VAD(음성 활성 감지),
[ASR(자동 음성 인식)](https://huggingface.co/tasks/automatic-speech-recognition),
[TTS(텍스트 음성 변환)](https://huggingface.co/tasks/text-to-speech) 이 모두 매우 복잡하고
쓰기도 이해하기도 어렵다는 걸 느꼈습니다. 그 무렵 저는 [@himself65](https://github.com/himself65)
[TTS(텍스트 음성 변환)](https://huggingface.co/tasks/text-to-speech)이 모두 매우 복잡하고
쓰기도 이해하기도 어렵다는 걸 느꼈습니다. 그 무렵 저는 [@himself65](https://github.com/himself65)와
협업해, [Llama Index](https://www.llamaindex.ai/) 의 새 프로젝트인
[`llama-flow`](https://github.com/run-llama/llama-flow) 의 사용 사례를 개선하고 테스트하고 있었습니다.
[`llama-flow`](https://github.com/run-llama/llama-flow)의 사용 사례를 개선하고 테스트하고 있었습니다.
LLM 스트리밍 토큰과 오디오 바이트의 이벤트 기반 스트림을 처리하도록 돕는 라이브러리입니다.
[`llama-flow`](https://github.com/run-llama/llama-flow) 는 정말 작고 타입 안전합니다.
이것이 없던 시절에는 AIRI 를 구동할 데이터를 처리하기 위해 여러 비동기 작업을 이어 붙이려고
[`llama-flow`](https://github.com/run-llama/llama-flow)는 정말 작고 타입 안전합니다.
이것이 없던 시절에는 AIRI를 구동할 데이터를 처리하기 위해 여러 비동기 작업을 이어 붙이려고
**큐** 구조와 Vue 반응성 기반 워크플로 시스템을 직접 감싸야 했습니다.
그때부터 VAD, ASR, TTS 워크플로를 단순화하는 예제와 데모를 더 많이 실험하기 시작했습니다.
그 결과 나온 것이 [WebAI Realtime Voice Chat Examples](https://github.com/proj-airi/webai-example-realtime-voice-chat) 입니다.
그 결과 나온 것이 [WebAI Realtime Voice Chat Examples](https://github.com/proj-airi/webai-example-realtime-voice-chat)입니다.
TypeScript 코드 300~500줄 하나로 웹 브라우저에서 ChatGPT 같은 음성 대화 시스템을 구현할 수 있음을 증명했습니다.
<ThemedVideo controls muted :src="webaiExamplesDemo" style="height: 640px;" />
@@ -138,21 +138,21 @@ TypeScript 코드 300~500줄 하나로 웹 브라우저에서 ChatGPT 같은 음
> 여기서 무언가 배워 가시면 좋겠습니다.
이 시기에 흥미롭고 강력한 저장소를 하나 발견했는데, [k2-fsa/sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx) 입니다.
이 시기에 흥미롭고 강력한 저장소를 하나 발견했는데, [k2-fsa/sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx)입니다.
macOS, Windows, Linux, Android, iOS 등에서 12개 이상 언어에 걸쳐 18가지 음성 처리 작업을 지원합니다. 놀랍죠!
그래서 [@luoling](https://github.com/luoling8192) 이 이것으로도 작은 데모를 만들었습니다:
그래서 [@luoling](https://github.com/luoling8192)이 이것으로도 작은 데모를 만들었습니다:
[Sherpa ONNX 기반 VAD + ASR + LLM Chat + TTS](https://github.com/proj-airi/webai-example-realtime-voice-chat/tree/main/apps/sherpa-onnx-demo)
#### xsAI 🤗 Transformers.js 의 탄생
#### xsAI 🤗 Transformers.js의 탄생
VAD, ASR, Chat, TTS 데모 작업 덕분에 [xsAI 🤗 Transformers.js](https://github.com/proj-airi/xsai-transformers)
라는 새 사이드 프로젝트가 태어났습니다. WebGPU 기반 모델 추론과 워커를 통한 서빙을 간단히 호출할 수 있게 하면서도,
앞서 성공한 프로젝트 [xsAI](https://github.com/moeru-ai/xsai) 와 API 호환성을 유지합니다.
앞서 성공한 프로젝트 [xsAI](https://github.com/moeru-ai/xsai)와 API 호환성을 유지합니다.
이것도 플레이그라운드가 있습니다... [https://xsai-transformers.netlify.app](https://xsai-transformers.netlify.app) 에서 만져 보세요.
이것도 플레이그라운드가 있습니다... [https://xsai-transformers.netlify.app](https://xsai-transformers.netlify.app)에서 만져 보세요.
오늘부터 npm 으로 설치할 수 있습니다!
오늘부터 npm으로 설치할 수 있습니다!
```bash
npm install xsai-transformers
@@ -161,10 +161,10 @@ npm install xsai-transformers
::: tip 이게 무슨 뜻인가요?
클라우드 LLM 및 음성 프로바이더와 로컬 WebGPU 기반 모델을 스위치 하나로 바꿔 쓸 수 있다는 뜻입니다.
덕분에 서버 사이드 코드나 백엔드 서버 없이도, 브라우저 안에서 간단한 RAG 와 재정렬 시스템을
덕분에 서버 사이드 코드나 백엔드 서버 없이도, 브라우저 안에서 간단한 RAG와 재정렬 시스템을
실험하고 심지어 구현할 수 있는 새로운 가능성이 생겼습니다.
아, Node.js 도 지원합니다!
아, Node.js도 지원합니다!
:::
### Telegram 봇
@@ -177,14 +177,14 @@ npm install xsai-transformers
### 캐릭터 카드 쇼케이스
이미지 에셋이 많다 보니 배경을 지울 만한 쓰기 쉬운 온라인 도구를 매번 직접 찾아야 했습니다.
그래서 [Xenova](https://github.com/xenova) 의 작업을 바탕으로 직접 만들기로 했습니다.
그래서 [Xenova](https://github.com/xenova)의 작업을 바탕으로 직접 만들기로 했습니다.
WebGPU 기반 배경 제거기를 시스템에 바로 넣는 작은 실험을 했는데,
[https://airi.moeru.ai/devtools/background-remove](https://airi.moeru.ai/devtools/background-remove) 에서 만져 볼 수 있습니다.
[https://airi.moeru.ai/devtools/background-remove](https://airi.moeru.ai/devtools/background-remove)에서 만져 볼 수 있습니다.
### xsAI & unSpeech
음성 프로바이더로 알리바바 클라우드 Model Studio 와 Volcano Engine 지원을 추가했습니다. 꽤 유용하겠죠?
음성 프로바이더로 알리바바 클라우드 Model Studio와 Volcano Engine 지원을 추가했습니다. 꽤 유용하겠죠?
### UI
@@ -192,7 +192,7 @@ WebGPU 기반 배경 제거기를 시스템에 바로 넣는 작은 실험을
- 색상 문제 수정
- [타이포그래피 개선](https://airi.moeru.ai/ui/#/story/stories-typographysans-story-vue?)
더 많은 스토리는 [로드맵 v0.5](https://github.com/moeru-ai/airi/issues/113) 에서 볼 수 있습니다.
더 많은 스토리는 [로드맵 v0.5](https://github.com/moeru-ai/airi/issues/113)에서 볼 수 있습니다.
## 사이드 퀘스트
@@ -207,44 +207,44 @@ WebGPU 기반 배경 제거기를 시스템에 바로 넣는 작은 실험을
- 예를 들어:
- 마법과 용이 있는 중세 판타지 배경 설정을 두고
- 우리가 할 일은 그 세계관 설정으로 감싼 채 새 캐릭터 작성에만 집중하는 것
- 어쩌면 밤이 되었을 때만 `if` `if-else` 제어 흐름으로 특별한 프롬프트가 주입되게 하는 것
- 어쩌면 밤이 되었을 때만 `if``if-else` 제어 흐름으로 특별한 프롬프트가 주입되게 하는 것
- 그 주변에서 더 많은 걸 할 수 있습니다...
- Vue SFC 나 React JSX 로 템플릿을 파싱하고 props 를 식별해, 프롬프트를 쓰는 동안 디버깅·테스트용 폼 패널을 렌더링
- lorebook 과 캐릭터 카드 전체를 하나의 인터랙티브 페이지로 시각화
- Vue SFC나 React JSX로 템플릿을 파싱하고 props를 식별해, 프롬프트를 쓰는 동안 디버깅·테스트용 폼 패널을 렌더링
- lorebook과 캐릭터 카드 전체를 하나의 인터랙티브 페이지로 시각화
그렇다면 Vue 나 React 같은 프론트엔드 프레임워크로 LLM 프롬프트를 쓰는 도구를 만들고,
그렇다면 Vue나 React 같은 프론트엔드 프레임워크로 LLM 프롬프트를 쓰는 도구를 만들고,
나아가 다른 프레임워크와 플랫폼으로도 확장해 보면 어떨까요?
그렇게 나온 것이 [**Velin**](https://github.com/luoling8192/velin) 입니다.
그렇게 나온 것이 [**Velin**](https://github.com/luoling8192/velin)입니다.
<img class="light" :src="VelinLight" alt="Vue.js 로 LLM 프롬프트를 작성하는 도구" />
<img class="dark" :src="VelinDark" alt="Vue.js 로 LLM 프롬프트를 작성하는 도구" />
<img class="light" :src="VelinLight" alt="Vue.js로 LLM 프롬프트를 작성하는 도구" />
<img class="dark" :src="VelinDark" alt="Vue.js로 LLM 프롬프트를 작성하는 도구" />
편집하면서 즉석에서 렌더링해 볼 수 있는 플레이그라운드도 만들었고, npm 생태계도 그대로
누릴 수 있습니다(네, 무엇이든 import 할 수 있습니다!).
<img class="light" :src="VelinPlaygroundLight" alt="Vue.js 로 LLM 프롬프트를 작성하는 도구" />
<img class="dark" :src="VelinPlaygroundDark" alt="Vue.js 로 LLM 프롬프트를 작성하는 도구" />
<img class="light" :src="VelinPlaygroundLight" alt="Vue.js로 LLM 프롬프트를 작성하는 도구" />
<img class="dark" :src="VelinPlaygroundDark" alt="Vue.js로 LLM 프롬프트를 작성하는 도구" />
여기서 써 보세요: https://velin-dev.netlify.app
프로그래밍 API 도 지원하고 Markdown(MDX 는 작업 중, MDC 는 지원)도 됩니다.
오늘부터 npm 으로 설치할 수 있습니다!
프로그래밍 API도 지원하고 Markdown(MDX는 작업 중, MDC는 지원)도 됩니다.
오늘부터 npm으로 설치할 수 있습니다!
```bash
npm install @velin-dev/core
```
음... 오늘은 여기까지입니다. 이 DevLog 를 즐겁게 읽으셨기를 바랍니다.
음... 오늘은 여기까지입니다. 이 DevLog를 즐겁게 읽으셨기를 바랍니다.
최근 중국 항저우에서 참가한 행사 **Demo Day @ Hangzhou** 의 사진으로 DevLog 를 마무리하겠습니다.
최근 중국 항저우에서 참가한 행사 **Demo Day @ Hangzhou**의 사진으로 DevLog를 마무리하겠습니다.
<img :src="DemoDayHangzhou1" alt="Demo Day @ Hangzhou" />
이게 접니다. 다른 참가자들에게 AIRI 프로젝트를 소개했고 정말 즐거운 시간을 보냈습니다!
재능 있는 개발자, 제품 디자이너, 창업자를 정말 많이 만났습니다.
오늘 이 DevLog 에서 나눈 거의 모든 내용과, 사랑하는 AI VTuber Neuro-sama 도 소개했습니다.
오늘 이 DevLog에서 나눈 거의 모든 내용과, 사랑하는 AI VTuber Neuro-sama도 소개했습니다.
발표에 쓴 슬라이드는 이렇습니다:
@@ -256,7 +256,7 @@ npm install @velin-dev/core
## 마일스톤
아... 그리고 이 DevLog 는 v0.5.0 릴리스이기도 하니, 지난 몇 주 동안 달성한 마일스톤도 몇 가지 언급하고 싶습니다:
아... 그리고 이 DevLog는 v0.5.0 릴리스이기도 하니, 지난 몇 주 동안 달성한 마일스톤도 몇 가지 언급하고 싶습니다:
- 스타 700개를 달성했습니다!
- 이슈에 새 컨트리뷰터 4명 이상이 합류했습니다!
@@ -264,25 +264,25 @@ npm install @velin-dev/core
- ReLU 캐릭터 디자인 완료!
- ReLU 캐릭터 모델링 완료!
- 몇몇 회사와 스폰서십 및 협업 논의를 진행했습니다!
- [로드맵 v0.5](https://github.com/moeru-ai/airi/issues/113) 의 92개 작업 완료
- [로드맵 v0.5](https://github.com/moeru-ai/airi/issues/113)의 92개 작업 완료
- UI
- 로딩 화면과 튜토리얼 모듈
- 로딩 상태와 Firefox 호환성 문제를 포함한 다수의 버그 수정
- Body
- 시맨틱 기반 모션 임베딩과 RAG, 비공개 저장소 "moeru-ai/motion-gen" 에서 개발
- 임베딩 프로바이더와 DuckDB WASM 을 이용한 벡터 저장 및 검색
- 시맨틱 기반 모션 임베딩과 RAG, 비공개 저장소 "moeru-ai/motion-gen"에서 개발
- 임베딩 프로바이더와 DuckDB WASM을 이용한 벡터 저장 및 검색
- Inputs
- Discord 음성 채널 음성 인식 수정
- Outputs
- 실험적인 노래 기능
- Engineering
- 프로젝트 전반의 UnoCSS 설정 공유
- "moeru-ai/inventory" 의 모델 카탈로그
- "moeru-ai/inventory"의 모델 카탈로그
- 조직 간 패키지 재정리
- Assets
- 스티커, UI 요소, VTuber 로고 등 새 캐릭터 에셋
- 보이스 라인 선택 기능
- 캐릭터 "Me" 와 "ReLU" 의 Live2D 모델링
- 캐릭터 "Me"와 "ReLU"의 Live2D 모델링
- 커뮤니티 지원 & 마케팅
- 일본어 README
- Plausible 애널리틱스 연동
@@ -9,19 +9,19 @@ preview-cover:
dark: "@assets('/en/blog/DevLog-2025.06.08/assets/250608-dark.avif')"
---
안녕하세요, AIRI 메인테이너 중 한 명인 LemonNeko 입니다. 오늘의 DevLog 주제는 AIRI 데스크톱 펫의 Live2D 모델이 마우스 위치를 바라보게 만드는 방법입니다.
안녕하세요, AIRI 메인테이너 중 한 명인 LemonNeko입니다. 오늘의 DevLog 주제는 AIRI 데스크톱 펫의 Live2D 모델이 마우스 위치를 바라보게 만드는 방법입니다.
## 생각의 연쇄 「Chain of Thoughts」
`<think>`
먼저 알아야 할 것이 있습니다. Live2D 에는 **주시(focus)** **터치(tap)** 라는 두 가지 기본 상호작용이 있습니다. Live2D 캔버스를 만들면 모델이 자동으로 커서 위치를 주시하며 머리와 몸이 커서 쪽을 향합니다. 구현 결과는 이렇습니다:
먼저 알아야 할 것이 있습니다. Live2D에는 **주시(focus)**와 **터치(tap)**라는 두 가지 기본 상호작용이 있습니다. Live2D 캔버스를 만들면 모델이 자동으로 커서 위치를 주시하며 머리와 몸이 커서 쪽을 향합니다. 구현 결과는 이렇습니다:
![](/en/blog/DevLog-2025.06.08/assets/airi-tamagotchi-focus.gif)
하지만 커서가 웹 페이지 밖으로 나가면 Live2D 는 커서가 어디 있는지 알 수 없게 됩니다. 그래서 커서가 어디 있는지 직접 알려 줘야 합니다.
하지만 커서가 웹 페이지 밖으로 나가면 Live2D는 커서가 어디 있는지 알 수 없게 됩니다. 그래서 커서가 어디 있는지 직접 알려 줘야 합니다.
Live2D 에 커서 위치를 알려 주려면 Tauri 의 네이티브 코드 호출 기능으로 Windows API 와 macOS API 를 호출해 ~~unsafe 를 잔뜩 써 가며~~ 화면 전체에서의 커서 위치와 창 자체의 위치를 얻은 뒤, 간단한 계산으로 커서와 창의 상대 위치를 구해야 합니다.
Live2D에 커서 위치를 알려 주려면 Tauri의 네이티브 코드 호출 기능으로 Windows API와 macOS API를 호출해 ~~unsafe를 잔뜩 써 가며~~ 화면 전체에서의 커서 위치와 창 자체의 위치를 얻은 뒤, 간단한 계산으로 커서와 창의 상대 위치를 구해야 합니다.
`</think>`
@@ -38,7 +38,7 @@ Live2D 에 커서 위치를 알려 주려면 Tauri 의 네이티브 코드 호
- AIRI 창의 크기: `C x D`
- 커서 위치: `G, H`
그러면 창 안에서의 커서 상대 위치는 `(G - E, H - F)` 가 됩니다.
그러면 창 안에서의 커서 상대 위치는 `(G - E, H - F)`가 됩니다.
아주 간단해 보이죠? 그럼 코드로 옮겨 봅시다.
@@ -55,11 +55,11 @@ listen('tauri-app:window-click-through:mouse-location-and-window-frame', (event:
})
```
`live2dFocusAt` 은 Live2D 모델에 전달할 좌표 데이터입니다.
`live2dFocusAt`은 Live2D 모델에 전달할 좌표 데이터입니다.
## 모델의 주시 지점을 직접 설정하기
`live2dFocusAt` 을 Live2D 모델에 넘겨 주시 지점을 직접 설정할 수 있습니다:
`live2dFocusAt`을 Live2D 모델에 넘겨 주시 지점을 직접 설정할 수 있습니다:
```typescript
const model = ref(Live2DModel.from('url', { autoInteract: false }))
@@ -71,11 +71,11 @@ watch(live2dFocusAt, (point) => {
## 멀티 플랫폼 대응
안타깝게도 이야기는 생각만큼 간단하지 않았습니다. 위에서 말한 커서-창 상대 위치 계산 방식은 Windows 에서는 동작하지만 macOS 에서는 동작하지 않습니다. macOS 좌표계는 원점이 좌하단에 있고 **Y 축이 위를 향해서** Windows 와 반대이기 때문입니다. 반면 Safari 브라우저에서는 좌표계 원점이 좌상단이고 **Y 축이 아래를 향합니다**. 그래서 macOS 에서의 커서 위치는 `(G - E, D - H + F)` 로 표현해야 합니다.
안타깝게도 이야기는 생각만큼 간단하지 않았습니다. 위에서 말한 커서-창 상대 위치 계산 방식은 Windows에서는 동작하지만 macOS에서는 동작하지 않습니다. macOS 좌표계는 원점이 좌하단에 있고 **Y 축이 위를 향해서** Windows와 반대이기 때문입니다. 반면 Safari 브라우저에서는 좌표계 원점이 좌상단이고 **Y 축이 아래를 향합니다**. 그래서 macOS 에서의 커서 위치는 `(G - E, D - H + F)`로 표현해야 합니다.
## 더 읽을거리
이번 DevLog 에서는 커서와 창의 상대 위치를 구하는 방법과 Live2D 모델의 주시 지점을 직접 설정하는 방법을 살펴봤습니다. 구현 세부 사항이 궁금하시다면 이 PR 의 [소스 코드](https://github.com/moeru-ai/airi/pull/194)를 확인해 보세요. 아래는 구현 과정에서 참고한 자료입니다. 자세히 읽어 보시고 논의도 환영합니다:
이번 DevLog에서는 커서와 창의 상대 위치를 구하는 방법과 Live2D 모델의 주시 지점을 직접 설정하는 방법을 살펴봤습니다. 구현 세부 사항이 궁금하시다면 이 PR의 [소스 코드](https://github.com/moeru-ai/airi/pull/194)를 확인해 보세요. 아래는 구현 과정에서 참고한 자료입니다. 자세히 읽어 보시고 논의도 환영합니다:
- [모델 상호작용 직접 설정하기 - pixi-live2d-display](https://github.com/guansss/pixi-live2d-display/wiki/Complete-Guide#manually-1 "모델 상호작용 직접 설정하기 - pixi-live2d-display")
- [Win32 API: GetCursorPos](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos "GetCursorPos")
+27 -27
View File
@@ -3,62 +3,62 @@ title: DevLog @ 2025.07.18
category: DevLog
date: 2025-07-18
excerpt: |
Factorio Learning Environment 논문을 바탕으로 저희 Factorio AI 에이전트 프로젝트 `airi-factorio` 를 어떻게 개선할 계획인지 나눠 봅니다.
Factorio Learning Environment 논문을 바탕으로 저희 Factorio AI 에이전트 프로젝트 `airi-factorio`를 어떻게 개선할 계획인지 나눠 봅니다.
preview-cover:
light: "@assets('/en/blog/DevLog-2025.07.18/assets/factorio-belt.gif')"
dark: "@assets('/en/blog/DevLog-2025.07.18/assets/factorio-belt.gif')"
---
안녕하세요, AIRI 메인테이너 중 한 명인 [@LemonNeko](https://github.com/LemonNekoGH) 입니다.
안녕하세요, AIRI 메인테이너 중 한 명인 [@LemonNeko](https://github.com/LemonNekoGH)입니다.
## 돌아보기
반년 전, 저는 유명한 자동화 생산 시뮬레이션 게임 [Factorio](https://www.factorio.com/) 를 플레이할 수 있는 AI 에이전트 [`airi-factorio`](https://github.com/moeru-ai/airi-factorio) 를 처음 만들어 봤고, 다음과 같은 일들을 했습니다:
반년 전, 저는 유명한 자동화 생산 시뮬레이션 게임 [Factorio](https://www.factorio.com/) 를 플레이할 수 있는 AI 에이전트 [`airi-factorio`](https://github.com/moeru-ai/airi-factorio)를 처음 만들어 봤고, 다음과 같은 일들을 했습니다:
- TypeScript 로 Factorio 모드 작성하기: [tstl](https://github.com/TypeScriptToLua/TypeScriptToLua) 로 TypeScript 코드를 Lua 코드로 컴파일합니다.
- RCON 으로 Factorio 모드와 상호작용하기: [factorio-rcon-api](https://github.com/nekomeowww/factorio-rcon-api) 로 Factorio 와 통신하고, `/c` 명령을 호출해 모드가 등록한 함수를 실행합니다. [@nekomeowww](https://github.com/nekomeowww) 에게 정말 감사드립니다.
- LLM 으로 의사결정하고 플레이어를 조종하는 Lua 코드 생성하기: 프롬프트 엔지니어링으로 LLM 에게 게임 조작 방법과 계획 수립 방법을 알려 주고, RCON 상호작용 코드를 LLM 이 호출할 수 있는 도구로 감쌌습니다.
- 게임 내장 채팅 시스템으로 LLM 과 소통하기: 게임의 표준 출력을 읽고 정규식으로 게임 내 플레이어 채팅 내용을 파싱한 뒤 LLM 에게 보내 처리합니다.
- Factorio 모드 핫 리로드: tstl 플러그인을 작성해 코드 변경을 실시간으로 감지하고 새 모드 내용을 RCON 으로 게임에 보냅니다. 새 모드 코드를 받으면 모든 인터페이스를 언로드하고 모드 코드를 한 번 실행해 핫 리로드를 구현합니다. 다만 기존 모드 상태를 어떻게 제대로 처리할지가 큰 난제가 됐습니다.
- DevContainer 에서 개발하기: 환경을 더 통제 가능하게 만들고 프로젝트 시작을 단순화합니다.
- TypeScript로 Factorio 모드 작성하기: [tstl](https://github.com/TypeScriptToLua/TypeScriptToLua)로 TypeScript 코드를 Lua 코드로 컴파일합니다.
- RCON으로 Factorio 모드와 상호작용하기: [factorio-rcon-api](https://github.com/nekomeowww/factorio-rcon-api)로 Factorio와 통신하고, `/c` 명령을 호출해 모드가 등록한 함수를 실행합니다. [@nekomeowww](https://github.com/nekomeowww)에게 정말 감사드립니다.
- LLM으로 의사결정하고 플레이어를 조종하는 Lua 코드 생성하기: 프롬프트 엔지니어링으로 LLM에게 게임 조작 방법과 계획 수립 방법을 알려 주고, RCON 상호작용 코드를 LLM이 호출할 수 있는 도구로 감쌌습니다.
- 게임 내장 채팅 시스템으로 LLM과 소통하기: 게임의 표준 출력을 읽고 정규식으로 게임 내 플레이어 채팅 내용을 파싱한 뒤 LLM에게 보내 처리합니다.
- Factorio 모드 핫 리로드: tstl 플러그인을 작성해 코드 변경을 실시간으로 감지하고 새 모드 내용을 RCON으로 게임에 보냅니다. 새 모드 코드를 받으면 모든 인터페이스를 언로드하고 모드 코드를 한 번 실행해 핫 리로드를 구현합니다. 다만 기존 모드 상태를 어떻게 제대로 처리할지가 큰 난제가 됐습니다.
- DevContainer에서 개발하기: 환경을 더 통제 가능하게 만들고 프로젝트 시작을 단순화합니다.
- 심볼릭 링크로 `tstl` 출력 디렉터리를 게임 디렉터리에 연결하기: 게임 디렉터리에서 컴파일된 Lua 코드를 바로 볼 수 있어 디버깅이 쉬워집니다.
이 과정에서 정말 많은 걸 배웠습니다 ~~(특히 Lua 배열 인덱스는 1부터 시작한다는 것)~~.
하지만 문제도 많이 겪었습니다. 주요 동작을 모드 안에 작성하다 보니 디버깅이 아주 번거로웠습니다. 모드 변경을 적용하려면 맵에서 나와 게임 메인 화면으로 돌아갔다가 다시 들어와야 했죠. `data.lua` 가 들어간 조금 더 복잡한 모드라면 게임 자체를 재시작해야 했습니다.
하지만 문제도 많이 겪었습니다. 주요 동작을 모드 안에 작성하다 보니 디버깅이 아주 번거로웠습니다. 모드 변경을 적용하려면 맵에서 나와 게임 메인 화면으로 돌아갔다가 다시 들어와야 했죠. `data.lua`가 들어간 조금 더 복잡한 모드라면 게임 자체를 재시작해야 했습니다.
LLM 에게 Lua 코드를 생성하게 한 뒤 RCON 으로 게임 명령 `/c` 를 호출해 실행했는데, Factorio 는 명령 하나당 길이 제한이 있습니다. 코드가 길어지면 여러 번 나눠 실행해야 했습니다.
LLM에게 Lua 코드를 생성하게 한 뒤 RCON으로 게임 명령 `/c`를 호출해 실행했는데, Factorio는 명령 하나당 길이 제한이 있습니다. 코드가 길어지면 여러 번 나눠 실행해야 했습니다.
지금 코드는 견고성과 유지보수성이 떨어집니다. 새 친구가 개발에 참여하거나, 심지어 그냥 한번 써 보려고만 해도 이 프로젝트를 시작하는 게 매우 어렵습니다.
## Factorio Learning Environment
시간이 흘러 지금, 이 프로젝트를 제대로 정리하려 했지만 어디서부터 시작해야 할지 몰랐습니다. 마침 누군가 [Factorio Learning Environment](https://arxiv.org/abs/2503.09617) 라는 논문을 언급하더군요. 간단히 훑어보겠습니다.
시간이 흘러 지금, 이 프로젝트를 제대로 정리하려 했지만 어디서부터 시작해야 할지 몰랐습니다. 마침 누군가 [Factorio Learning Environment](https://arxiv.org/abs/2503.09617)라는 논문을 언급하더군요. 간단히 훑어보겠습니다.
이 논문에서 저자들은 Factorio Learning Environment(FLE)라는 프레임워크를 제안하고, 장기 계획 수립, 프로그램 합성, 자원 관리, 공간 추론에서 AI 의 능력을 테스트했습니다.
이 논문에서 저자들은 Factorio Learning Environment(FLE)라는 프레임워크를 제안하고, 장기 계획 수립, 프로그램 합성, 자원 관리, 공간 추론에서 AI의 능력을 테스트했습니다.
FLE 에는 두 가지 모드가 있습니다:
FLE에는 두 가지 모드가 있습니다:
- Lab-play: 자원이 제한된, 사람이 직접 설계한 24개 레벨에서 테스트하며, 제한된 자원으로 AI 가 효율적으로 생산 라인을 지을 수 있는지 봅니다.
- Open-play: 제한 없는 대형 맵에서 절차적으로 생성된 지형 위에 가장 큰 공장을 짓는 것이 목표이며, AI 의 장기적 자율 목표 설정·탐험·확장 능력을 테스트합니다.
- Lab-play: 자원이 제한된, 사람이 직접 설계한 24개 레벨에서 테스트하며, 제한된 자원으로 AI가 효율적으로 생산 라인을 지을 수 있는지 봅니다.
- Open-play: 제한 없는 대형 맵에서 절차적으로 생성된 지형 위에 가장 큰 공장을 짓는 것이 목표이며, AI의 장기적 자율 목표 설정·탐험·확장 능력을 테스트합니다.
저자들은 Claude 3.5 Sonnet, GPT-4o, Deepseek-v3, Gemini-2 같은 주요 LLM 을 평가했는데, Lab-play 에서는 당시 가장 강했던 Claude 3.5 조차 7개 레벨만 완료했습니다.
저자들은 Claude 3.5 Sonnet, GPT-4o, Deepseek-v3, Gemini-2 같은 주요 LLM을 평가했는데, Lab-play에서는 당시 가장 강했던 Claude 3.5 조차 7개 레벨만 완료했습니다.
여기까지 읽고 나니 궁금해졌습니다. 평가가 이렇게 복잡한데 기술적 유지보수성도 확보했을 텐데, 어떻게 했을까? 계속 읽어 보니 구현 방식이 `airi-factorio` 와 아주 비슷하면서도 여러 장점이 있었습니다:
여기까지 읽고 나니 궁금해졌습니다. 평가가 이렇게 복잡한데 기술적 유지보수성도 확보했을 텐데, 어떻게 했을까? 계속 읽어 보니 구현 방식이 `airi-factorio`와 아주 비슷하면서도 여러 장점이 있었습니다:
- Python 으로 작성되어 있어 LLM 이 Python 코드를 생성하면 Python REPL 에서 바로 실행하고 표준 출력에서 결과를 바로 읽을 수 있습니다. Python 은 Lua 보다 데이터셋이 훨씬 많아 생성 정확도가 높고 더 복잡한 코드도 만들 수 있습니다.
- Lua 모드는 place_entity 처럼 실행을 위한 기본 동작만 담고, 더 복잡한 로직은 Python 에 둡니다. 덕분에 Lua 모드에 버그가 생길 여지가 줄어 게임을 그렇게 자주 재시작하지 않아도 됩니다.
- Python으로 작성되어 있어 LLM이 Python 코드를 생성하면 Python REPL에서 바로 실행하고 표준 출력에서 결과를 바로 읽을 수 있습니다. Python은 Lua보다 데이터셋이 훨씬 많아 생성 정확도가 높고 더 복잡한 코드도 만들 수 있습니다.
- Lua 모드는 place_entity처럼 실행을 위한 기본 동작만 담고, 더 복잡한 로직은 Python에 둡니다. 덕분에 Lua 모드에 버그가 생길 여지가 줄어 게임을 그렇게 자주 재시작하지 않아도 됩니다.
- Lua 코드 실행에 `/c` 대신 `/sc` 명령을 씁니다. 코드를 콘솔에 출력하지 않아 콘솔이 깔끔하게 유지되고 필요한 내용만 남아, 표준 입력 파싱 난이도가 낮아집니다.
LLM 능력을 더 잘 평가하기 위해 필요한 모든 레시피 생산 과정과 난이도도 면밀히 분석해, 아이템 생산 비용이나 LLM 점수 계산 방법 같은 몇 가지 공식을 정리해 두었습니다.
[시스템 프롬프트](https://arxiv.org/html/2503.09617v1#A8.SS4)도 공개했는데, 환경 구조, 응답 형식, 모범 사례, 게임 출력을 이해하는 방법 등이 명시되어 있습니다.
## 다시 `airi-factorio`
## 다시 `airi-factorio`로
FLE 와 비교하면 저희 구현은 꽤 순진해 보입니다. 그럼 `airi-factorio` 를 어떻게 개선해야 할까요?
FLE와 비교하면 저희 구현은 꽤 순진해 보입니다. 그럼 `airi-factorio`를 어떻게 개선해야 할까요?
저는 Python 을 쓰고 싶지 않고, TypeScript 와 Golang 에만 익숙합니다. 마침 얼마 전 가능한 모든 MCP 서버에 적합한 빌더인 [mcp-launcher](https://github.com/moeru-ai/mcp-launcher) 를 만들었습니다. 이걸 Golang 과 함께 써서 MCP 서버를 구현하고, LLM 이 이를 호출하게 하면 됩니다.
저는 Python을 쓰고 싶지 않고, TypeScript와 Golang 에만 익숙합니다. 마침 얼마 전 가능한 모든 MCP 서버에 적합한 빌더인 [mcp-launcher](https://github.com/moeru-ai/mcp-launcher)를 만들었습니다. 이걸 Golang과 함께 써서 MCP 서버를 구현하고, LLM이 이를 호출하게 하면 됩니다.
그래서 구조도가 이렇게 바뀌었습니다:
@@ -70,16 +70,16 @@ FLE 와 비교하면 저희 구현은 꽤 순진해 보입니다. 그럼 `airi-f
</div>
플레이어 채팅 내용은 더 이상 LLM 으로 보내지 않고 [RconChat](https://gitlab.com/FishBus/rconchat) 모드에 저장하며, LLM 은 MCP 서버를 통해 이 내용을 읽습니다. MCP 서버 방식이라면 LLM 이 Lua 코드를 생성할 필요도 없어집니다.
플레이어 채팅 내용은 더 이상 LLM으로 보내지 않고 [RconChat](https://gitlab.com/FishBus/rconchat) 모드에 저장하며, LLM은 MCP 서버를 통해 이 내용을 읽습니다. MCP 서버 방식이라면 LLM이 Lua 코드를 생성할 필요도 없어집니다.
시스템 프롬프트는 현재 AI 가 생성한 것이라 아직 충분히 명확하지 않고 우선순위도 흐릿합니다. FLE 의 시스템 프롬프트를 참고해 개선할 계획입니다.
시스템 프롬프트는 현재 AI가 생성한 것이라 아직 충분히 명확하지 않고 우선순위도 흐릿합니다. FLE의 시스템 프롬프트를 참고해 개선할 계획입니다.
자, 이전 설계를 사실상 전부 뒤엎었습니다. 처음부터 다시 시작할 시간이네요.
## 맺으며
읽어 주셔서 감사합니다. 관심 있으시다면 FLE 의 논문과 [코드](https://github.com/JackHopkins/factorio-learning-environment)를 직접 읽어 보세요. 제 이해가 틀렸을 수도 있으니 정정 환영합니다! 이번 읽기는 충분히 깊지 않았을지도 모르지만, 앞으로 제 아이디어대로 `airi-factorio` 를 개선해 나가면서 반복해 읽고 진전이 있을 때마다 업데이트하겠습니다.
읽어 주셔서 감사합니다. 관심 있으시다면 FLE의 논문과 [코드](https://github.com/JackHopkins/factorio-learning-environment)를 직접 읽어 보세요. 제 이해가 틀렸을 수도 있으니 정정 환영합니다! 이번 읽기는 충분히 깊지 않았을지도 모르지만, 앞으로 제 아이디어대로 `airi-factorio`를 개선해 나가면서 반복해 읽고 진전이 있을 때마다 업데이트하겠습니다.
이번 DevLog 는 여기까지입니다. 좋은 주말 보내세요!
이번 DevLog는 여기까지입니다. 좋은 주말 보내세요!
> 커버 일러스트 [@anrew10](https://es.pixilart.com/art/factorio-yellow-belt-132272fb3d727dd)
+26 -26
View File
@@ -3,7 +3,7 @@ title: DevLog @ 2025.08.01
category: DevLog
date: 2025-08-01
excerpt: |
Makito 가 AIRI 에서 텍스트 애니메이션을 구현하다가, UTF-8 바이트 스트림으로 들어오는 grapheme cluster 를 다루는 라이브러리를 만들기까지의 여정을 나눕니다.<br /> 유익하고 영감이 되기를 바랍니다!
Makito가 AIRI에서 텍스트 애니메이션을 구현하다가, UTF-8 바이트 스트림으로 들어오는 grapheme cluster를 다루는 라이브러리를 만들기까지의 여정을 나눕니다.<br /> 유익하고 영감이 되기를 바랍니다!
preview-cover:
light: "@assets('/en/blog/DevLog-2025.08.01/assets/cover-light.avif')"
dark: "@assets('/en/blog/DevLog-2025.08.01/assets/cover-dark.avif')"
@@ -41,7 +41,7 @@ const trioCluster = ['👩‍👧', '', '👦']
## 시작하기 전에
<RollingText text-2xl>
안녕하세요, Makito 입니다.
안녕하세요, Makito입니다.
<template #before="{ motionReduced }">
<div text-sm>
@@ -62,17 +62,17 @@ const trioCluster = ['👩‍👧', '', '👦']
끝나지 않는 8월이 시작됐습니다… 이 [현실적인 수학 문제](https://oeis.org/A180632/a180632.pdf)로 시간을 보내도 좋겠네요. 앗, 이야기가 샜습니다.
한동안 작업해 오긴 했지만, Project AIRI DevLog 에 글을 쓰는 건 이번이 처음입니다.
한동안 작업해 오긴 했지만, Project AIRI DevLog에 글을 쓰는 건 이번이 처음입니다.
이 글에서는 AIRI 에서 텍스트 애니메이션을 구현하다가 UTF-8 바이트 스트림으로 들어오는 grapheme cluster 를 다루는 라이브러리를 만들기까지의 여정을 나눠 보겠습니다. 유익하고 영감이 되기를 바랍니다!
이 글에서는 AIRI에서 텍스트 애니메이션을 구현하다가 UTF-8 바이트 스트림으로 들어오는 grapheme cluster를 다루는 라이브러리를 만들기까지의 여정을 나눠 보겠습니다. 유익하고 영감이 되기를 바랍니다!
## 배경
최근 [Anime.js](https://animejs.com/) 가 v4.10 에서 새로운 [텍스트 유틸리티](https://animejs.com/documentation/text)를 공개하며, 텍스트 애니메이션을 돕는 유틸리티 함수 모음을 제공하기 시작했습니다(위 예시처럼요). 이 업데이트는 Anime.js 가 오랫동안 비워 두었던 자리를 확실히 채워 줍니다. 이전에는 애니메이션을 위해 텍스트를 직접 글자 단위로 쪼개거나, 내부적으로 Anime.js 를 쓰는 [splt](https://www.spltjs.com/) 같은 라이브러리, 또는 [GSAP](https://gsap.com/) 와 함께 쓰는 [SplitText](https://gsap.com/docs/v3/Plugins/SplitText/) 에 기대야 했습니다.
최근 [Anime.js](https://animejs.com/) 가 v4.10에서 새로운 [텍스트 유틸리티](https://animejs.com/documentation/text)를 공개하며, 텍스트 애니메이션을 돕는 유틸리티 함수 모음을 제공하기 시작했습니다(위 예시처럼요). 이 업데이트는 Anime.js가 오랫동안 비워 두었던 자리를 확실히 채워 줍니다. 이전에는 애니메이션을 위해 텍스트를 직접 글자 단위로 쪼개거나, 내부적으로 Anime.js를 쓰는 [splt](https://www.spltjs.com/) 같은 라이브러리, 또는 [GSAP](https://gsap.com/) 와 함께 쓰는 [SplitText](https://gsap.com/docs/v3/Plugins/SplitText/) 에 기대야 했습니다.
텍스트 애니메이션은 UI 에서 메시지를 멋지게 등장시킬 때 특히 유용합니다. 보통 메시지는 완성된 형태로 도착하므로, 받은 텍스트를 글자로 쪼개서 애니메이션을 주기만 하면 됩니다.
텍스트 애니메이션은 UI에서 메시지를 멋지게 등장시킬 때 특히 유용합니다. 보통 메시지는 완성된 형태로 도착하므로, 받은 텍스트를 글자로 쪼개서 애니메이션을 주기만 하면 됩니다.
Project AIRI 에서는 [@nekomeowww](https://github.com/nekomeowww) 도 모션 효과가 들어간 애니메이션 채팅 말풍선 컴포넌트를 만들었습니다:
Project AIRI에서는 [@nekomeowww](https://github.com/nekomeowww)도 모션 효과가 들어간 애니메이션 채팅 말풍선 컴포넌트를 만들었습니다:
<video controls muted autoplay loop max-w="500px" w-full mx-auto>
<source src="/en/blog/DevLog-2025.08.01/assets/animated-chat-bubble.mp4">
@@ -84,13 +84,13 @@ Project AIRI 에서는 [@nekomeowww](https://github.com/nekomeowww) 도 모션
</div>
그런데 UTF-8 바이트 스트림을 읽으면서 도착하는 대로 애니메이션을 주고 싶다면 어떨까요? 채팅이나 음성 전사 앱처럼 실시간 애플리케이션에서 흔한 상황입니다. UI 가 받은 만큼 한 글자씩 텍스트를 표시하는 거죠.
그런데 UTF-8 바이트 스트림을 읽으면서 도착하는 대로 애니메이션을 주고 싶다면 어떨까요? 채팅이나 음성 전사 앱처럼 실시간 애플리케이션에서 흔한 상황입니다. UI가 받은 만큼 한 글자씩 텍스트를 표시하는 거죠.
## 한 글자씩?
여기서 "글자"란 무엇으로 봐야 할까요? 유니코드에서 의미를 갖는 가장 작은 텍스트 단위는 보통 [코드 포인트](https://www.unicode.org/versions/Unicode14.0.0/ch02.pdf#G25564)입니다. 하지만 인코딩 수준에서는, 특히 UTF-8 에서는 코드 포인트 하나가 여러 바이트에 걸칠 수 있습니다. 예를 들어 "あ"(일본어 히라가나 A)는 코드 포인트 `U+3042` 에 대응하고, UTF-8 에서는 바이트 시퀀스 `0xE3 0x81 0x82` 로 인코딩됩니다. 즉 바이트 스트림을 읽을 때는 모든 바이트가 도착하기 전까지 완전한 글자를 갖지 못할 수 있다는 뜻입니다.
여기서 "글자"란 무엇으로 봐야 할까요? 유니코드에서 의미를 갖는 가장 작은 텍스트 단위는 보통 [코드 포인트](https://www.unicode.org/versions/Unicode14.0.0/ch02.pdf#G25564)입니다. 하지만 인코딩 수준에서는, 특히 UTF-8에서는 코드 포인트 하나가 여러 바이트에 걸칠 수 있습니다. 예를 들어 "あ"(일본어 히라가나 A)는 코드 포인트 `U+3042`에 대응하고, UTF-8에서는 바이트 시퀀스 `0xE3 0x81 0x82`로 인코딩됩니다. 즉 바이트 스트림을 읽을 때는 모든 바이트가 도착하기 전까지 완전한 글자를 갖지 못할 수 있다는 뜻입니다.
걱정 마세요. Web API [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) 가 도와줍니다. `TextDecoder.decode` `stream` 옵션과 함께 쓰면 디코더가 청크 단위로 도착하는 데이터를 처리해 주어, 부분적인 글자도 올바르게 디코딩할 수 있습니다.
걱정 마세요. Web API [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)가 도와줍니다. `TextDecoder.decode``stream` 옵션과 함께 쓰면 디코더가 청크 단위로 도착하는 데이터를 처리해 주어, 부분적인 글자도 올바르게 디코딩할 수 있습니다.
```javascript
const decoder = new TextDecoder()
@@ -101,47 +101,47 @@ const decoded = decoder.decode(chunk, { stream: true })
요약: **꼭 그렇지는 않습니다**.
TextDecoder 는 바이트 스트림을 유니코드 코드 포인트, 즉 글자로 올바르게 디코딩해 줍니다. 하지만 유니코드에는 여러 코드 포인트를 하나의 "시각적" 글자로 묶는 "grapheme cluster" 라는 개념이 또 있습니다. 예를 들어 이모지 "👩‍👩‍👧‍👦"(가족)는 여러 코드 포인트로 표현되지만 시각적으로는 한 글자로 취급됩니다. 내부적으로 "👩‍👩‍👧‍👦" 의 코드 포인트들은 코드가 `U+200D` 인 zero-width joiner(ZWJ)로 연결되어 있습니다.
TextDecoder는 바이트 스트림을 유니코드 코드 포인트, 즉 글자로 올바르게 디코딩해 줍니다. 하지만 유니코드에는 여러 코드 포인트를 하나의 "시각적" 글자로 묶는 "grapheme cluster"라는 개념이 또 있습니다. 예를 들어 이모지 "👩‍👩‍👧‍👦"(가족)는 여러 코드 포인트로 표현되지만 시각적으로는 한 글자로 취급됩니다. 내부적으로 "👩‍👩‍👧‍👦" 의 코드 포인트들은 코드가 `U+200D` 인 zero-width joiner(ZWJ)로 연결되어 있습니다.
상상하기 어려울 수 있습니다. 걱정 마세요. grapheme cluster 와 코드 포인트를 살펴보고 어떻게 결합되는지 이해할 수 있도록 간단한 인터랙티브 인스펙터를 만들었습니다. 분해 결과에서 `200D` 코드 포인트를 눈여겨보세요:
상상하기 어려울 수 있습니다. 걱정 마세요. grapheme cluster와 코드 포인트를 살펴보고 어떻게 결합되는지 이해할 수 있도록 간단한 인터랙티브 인스펙터를 만들었습니다. 분해 결과에서 `200D` 코드 포인트를 눈여겨보세요:
<GraphemeClusterInspector initText="👩‍👩‍👧‍👦🏄‍♀️🤼‍♂️🙋‍♀️" />
<div text-sm text-center>
grapheme cluster 나 코드 포인트에 마우스를 올려 어떻게 결합되는지 확인해 보세요. 원하는 텍스트로 바꿔서 살펴볼 수도 있습니다.
grapheme cluster나 코드 포인트에 마우스를 올려 어떻게 결합되는지 확인해 보세요. 원하는 텍스트로 바꿔서 살펴볼 수도 있습니다.
</div>
이모지와 비슷하게, 어떤 언어들은 결합용 코드 포인트로 복잡한 글자를 만듭니다. 예를 들어 타밀 문자 "நி"(ni)는 기본 문자 "ந"(na)와 결합 모음 "ி"(i)로 표현됩니다. 이 둘이 결합되면 "நி" 라는 글자를 시각적으로 나타내는 하나의 grapheme cluster 가 됩니다. 아래 인스펙터에서 어떻게 분해되는지 확인해 보세요:
이모지와 비슷하게, 어떤 언어들은 결합용 코드 포인트로 복잡한 글자를 만듭니다. 예를 들어 타밀 문자 "நி"(ni)는 기본 문자 "ந"(na)와 결합 모음 "ி"(i)로 표현됩니다. 이 둘이 결합되면 "நி" 라는 글자를 시각적으로 나타내는 하나의 grapheme cluster가 됩니다. 아래 인스펙터에서 어떻게 분해되는지 확인해 보세요:
<GraphemeClusterInspector initText="நிกำषिक्षि" /> <!-- cSpell:disable-line -->
## 리더 만들기
길이가 정해진 문자열을 grapheme cluster 로 쪼개는 건 비교적 쉽지만, 스트리밍 상황에서는 바이트가 끊임없이 흘러나오는 파이프를 들여다보게 됩니다. 최악의 경우 한 번에 1바이트씩만 볼 수도 있습니다. 게다가 UTF-8 의 특성상, 코드 포인트 하나가 최대 4바이트로 이루어질 수 있으므로 받은 바이트가 코드 포인트로서 완전하다고 안전하게 가정할 수 없습니다.
길이가 정해진 문자열을 grapheme cluster로 쪼개는 건 비교적 쉽지만, 스트리밍 상황에서는 바이트가 끊임없이 흘러나오는 파이프를 들여다보게 됩니다. 최악의 경우 한 번에 1바이트씩만 볼 수도 있습니다. 게다가 UTF-8의 특성상, 코드 포인트 하나가 최대 4바이트로 이루어질 수 있으므로 받은 바이트가 코드 포인트로서 완전하다고 안전하게 가정할 수 없습니다.
이를 해결하려면 앞서 언급한 [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) 를 쓰면 됩니다. 데이터를 받아 디코딩할 때마다 디코딩된 문자열을 버퍼에 이어 붙이면, 그 안에서 grapheme cluster 가 올바르게 구성됩니다.
이를 해결하려면 앞서 언급한 [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder)를 쓰면 됩니다. 데이터를 받아 디코딩할 때마다 디코딩된 문자열을 버퍼에 이어 붙이면, 그 안에서 grapheme cluster가 올바르게 구성됩니다.
바이트에서 문자열을 다시 조립하는 파이프라인이 생겼으니, 이제 그 문자열에서 grapheme cluster 를 어떻게 <b title="안전이 제일이니까요" underline="~ dotted" cursor-help>안전하게</b> 읽어낼지 고민할 차례입니다. 다행히 [`Intl.Segmenter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) 가 기꺼이 도와줍니다. 로케일을 고려하면서 문자열을 grapheme cluster 로 쪼개는 공식적인 방법을 제공하죠. `Intl.Segmenter` 는 grapheme cluster 전용 도구를 넘어, 옵션에 따라 텍스트를 단어나 문장 단위로 나눌 수도 있습니다.
바이트에서 문자열을 다시 조립하는 파이프라인이 생겼으니, 이제 그 문자열에서 grapheme cluster를 어떻게 <b title="안전이 제일이니까요" underline="~ dotted" cursor-help>안전하게</b> 읽어낼지 고민할 차례입니다. 다행히 [`Intl.Segmenter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter)가 기꺼이 도와줍니다. 로케일을 고려하면서 문자열을 grapheme cluster로 쪼개는 공식적인 방법을 제공하죠. `Intl.Segmenter`는 grapheme cluster 전용 도구를 넘어, 옵션에 따라 텍스트를 단어나 문장 단위로 나눌 수도 있습니다.
바이트를 좀 받아서 다음과 같은 grapheme cluster 로 올바르게 디코딩했다고 상상해 봅시다:
바이트를 좀 받아서 다음과 같은 grapheme cluster로 올바르게 디코딩했다고 상상해 봅시다:
<div flex="~ row items-center justify-center gap-1" overflow="x-scroll">
<GraphemeClusterAssembler :characters="pairCluster" />
</div>
이 시점에서 "👩‍👧"(2인) 자체는 하나의 grapheme cluster 입니다. 이걸 꺼내고 다음 바이트를 읽기 시작해도 될까요? 아직입니다. 실제로 바이트가 더 도착하면 앞의 grapheme cluster 는 "👩‍👧‍👦"(3인)가 됩니다:
이 시점에서 "👩‍👧"(2인) 자체는 하나의 grapheme cluster입니다. 이걸 꺼내고 다음 바이트를 읽기 시작해도 될까요? 아직입니다. 실제로 바이트가 더 도착하면 앞의 grapheme cluster는 "👩‍👧‍👦"(3인)가 됩니다:
<div flex="~ row items-center justify-center gap-1" overflow="x-scroll">
<GraphemeClusterAssembler :characters="trioCluster" />
</div>
"👩‍👧"(2인)를 한 스텝 일찍 내보내면 불완전한 grapheme cluster 를 만들어 내게 되는데, 이건 우리가 원하는 게 아닙니다.
"👩‍👧"(2인)를 한 스텝 일찍 내보내면 불완전한 grapheme cluster를 만들어 내게 되는데, 이건 우리가 원하는 게 아닙니다.
## 최대한 빨리, 그러나 안전하게
어떤 상황에서는 (물론 완전한) grapheme cluster 를 가능한 한 빨리 읽어내고 싶을 수 있습니다. 여전히 `Intl.Segmenter` 를 쓰되, 큐에서 꺼내는 전략만 살짝 바꿉니다. 현재 grapheme cluster 가 완전한지 확신할 수 없다면, 다음 것이 나타날 때까지 기다렸다가 마지막 하나를 제외하고 내보내면 됩니다:
어떤 상황에서는 (물론 완전한) grapheme cluster를 가능한 한 빨리 읽어내고 싶을 수 있습니다. 여전히 `Intl.Segmenter`를 쓰되, 큐에서 꺼내는 전략만 살짝 바꿉니다. 현재 grapheme cluster가 완전한지 확신할 수 없다면, 다음 것이 나타날 때까지 기다렸다가 마지막 하나를 제외하고 내보내면 됩니다:
```ts
declare let clusterBuffer: string
@@ -155,20 +155,20 @@ while (true) {
}
```
이렇게 하면 불완전할 수 있는 grapheme cluster 는 결코 현재 것이 아니라 항상 다음 것이 됩니다. 이를 보여 주는 인터랙티브 컴포넌트를 하나 더 만들었습니다:
이렇게 하면 불완전할 수 있는 grapheme cluster는 결코 현재 것이 아니라 항상 다음 것이 됩니다. 이를 보여 주는 인터랙티브 컴포넌트를 하나 더 만들었습니다:
<CharacterMatcher />
<div text-sm text-center>
두 번째 grapheme cluster 가 나타날 때까지 기다렸다가 첫 번째 것을 내보내는 모습을 볼 수 있습니다.
두 번째 grapheme cluster가 나타날 때까지 기다렸다가 첫 번째 것을 내보내는 모습을 볼 수 있습니다.
</div>
## [Clustr](https://github.com/sumimakito/clustr) 소개
이 DevLog 를 쓰는 시점에도 문자열을 grapheme cluster 로 쪼개 주는 좋은 라이브러리는 여럿 있습니다. 하지만 그중에 UTF-8 바이트 스트림을 받아서 도착하는 대로 grapheme cluster 를 내보내 주는 건 찾지 못했습니다. 그래서 위에서 설명한 방식으로 직접 하나 만들었고, 유니코드의 "grapheme cluster" 개념과 어감을 맞추려고 [Clustr](https://github.com/sumimakito/clustr) 라고 이름 붙였습니다.
이 DevLog를 쓰는 시점에도 문자열을 grapheme cluster로 쪼개 주는 좋은 라이브러리는 여럿 있습니다. 하지만 그중에 UTF-8 바이트 스트림을 받아서 도착하는 대로 grapheme cluster를 내보내 주는 건 찾지 못했습니다. 그래서 위에서 설명한 방식으로 직접 하나 만들었고, 유니코드의 "grapheme cluster" 개념과 어감을 맞추려고 [Clustr](https://github.com/sumimakito/clustr)라고 이름 붙였습니다.
핵심 코드는 총 100줄도 되지 않지만, UTF-8 바이트 스트림으로부터 멋진 텍스트 애니메이션을 만들고 싶은 다음 프로젝트에서 — Project AIRI 에서 저희가 한 것처럼 — 도움이 될지도 모릅니다.
핵심 코드는 총 100줄도 되지 않지만, UTF-8 바이트 스트림으로부터 멋진 텍스트 애니메이션을 만들고 싶은 다음 프로젝트에서 — Project AIRI에서 저희가 한 것처럼 — 도움이 될지도 모릅니다.
Project AIRI 에서 저희가 하는 일이 궁금하시다면 GitHub 저장소 [moeru-ai/airi](https://github.com/moeru-ai/airi) 를 확인해 보세요!
Project AIRI에서 저희가 하는 일이 궁금하시다면 GitHub 저장소 [moeru-ai/airi](https://github.com/moeru-ai/airi)를 확인해 보세요!
+69 -69
View File
@@ -1,9 +1,9 @@
---
title: DevLog @ 2025.08.05
description: |
v0.7 이 출시됐습니다. Windows 를 완전히 지원하고 그 밖에도 많은 기능이 들어갔습니다.
v0.7이 출시됐습니다. Windows를 완전히 지원하고 그 밖에도 많은 기능이 들어갔습니다.
date: 2025-08-04
excerpt: 오래 기다리게 해서 죄송합니다!<br/> v0.7 은 7월 초에 나올 예정이었지만, Windows 에서 발견한 몇 가지 치명적인 버그와 손봐야 할 것이 많아 지금까지 미뤄졌습니다.
excerpt: 오래 기다리게 해서 죄송합니다!<br/> v0.7은 7월 초에 나올 예정이었지만, Windows에서 발견한 몇 가지 치명적인 버그와 손봐야 할 것이 많아 지금까지 미뤄졌습니다.
preview-cover:
light: "@assets('/en/blog/DevLog-2025.08.05/assets/cover-light.avif')"
dark: "@assets('/en/blog/DevLog-2025.08.05/assets/cover-dark.avif')"
@@ -26,9 +26,9 @@ function handleOpenLatest() {
}
</script>
다시 안녕하세요! [Neko](https://github.com/nekomeowww) 입니다.
다시 안녕하세요! [Neko](https://github.com/nekomeowww)입니다.
오래 기다리게 해서 죄송합니다! v0.7 은 7월 초에 나올 예정이었지만, 밤잠을 설치게 만든 몇 가지
오래 기다리게 해서 죄송합니다! v0.7은 7월 초에 나올 예정이었지만, 밤잠을 설치게 만든 몇 가지
치명적인 Windows 호환성 문제와 저희가 손대기로 한 변경 범위가 워낙 커서 지금까지 미뤄졌습니다.
<Button @click="handleOpenLatest">
@@ -52,27 +52,27 @@ function handleOpenLatest() {
> 소프트웨어 업계에서 일해 보신 분들에게 이 숫자들은 아무 의미가 없다는 걸 압니다.
> 그저 이번 릴리스에서 저희가 만든 변화가 크다는 것을 보여 줄 뿐이죠.
>
> 걱정 마세요, 이 DevLog 에서 주요 내용을 하나씩 안내해 드리겠습니다.
> 걱정 마세요, 이 DevLog에서 주요 내용을 하나씩 안내해 드리겠습니다.
## 마일스톤
v0.7 릴리스와 이 DevLog 를 계기로 지금까지 달성한 마일스톤도 몇 가지 언급하고 싶습니다:
v0.7 릴리스와 이 DevLog를 계기로 지금까지 달성한 마일스톤도 몇 가지 언급하고 싶습니다:
- GitHub 스타 1850개를 넘겼습니다! 🎉
- 컨트리뷰터가 40명이 넘습니다! 🫂
- Discord 멤버가 300명이 넘습니다! 👾
- [Hacker News](https://news.ycombinator.com/item?id=44573640) 에 저희를 알렸습니다
- [Product Hunt](https://www.producthunt.com/products/airi) 에 저희를 알렸습니다
- [Hacker News](https://news.ycombinator.com/item?id=44573640)에 저희를 알렸습니다
- [Product Hunt](https://www.producthunt.com/products/airi)에 저희를 알렸습니다
- 2025년 7월 17일 GitHub 트렌딩 `1위` 🏆 를 했습니다
## 기능
### 데스크톱 버전
Tamagotchi 는 AIRI 데스크톱 버전의 이름으로, 다른 애플리케이션과 함께 작업을 방해하지 않으면서
Tamagotchi는 AIRI 데스크톱 버전의 이름으로, 다른 애플리케이션과 함께 작업을 방해하지 않으면서
바탕화면에서 늘 곁에 있는 별도의 동반자로 실행할 수 있습니다.
이전의 데스크톱 버전은 UI/UX 가 충분히 다듬어지지 않은 실험 단계에 가까웠고,
이전의 데스크톱 버전은 UI/UX가 충분히 다듬어지지 않은 실험 단계에 가까웠고,
로컬 ASR/STT(음성 인식) 같은 모듈은 쓸 만하지 않았습니다. 오디오 입력 장치 설정도 빠져 있었죠.
하지만 이제 크게 개선됐습니다.
@@ -85,7 +85,7 @@ Tamagotchi 는 AIRI 데스크톱 버전의 이름으로, 다른 애플리케이
> 상표 같은 건 없습니다.
::: tip
**Fade on hover** 기능을 끄는 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="I" inline-block>I</kbd> 입니다
**Fade on hover** 기능을 끄는 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="I" inline-block>I</kbd>입니다
:::
<br />
@@ -96,13 +96,13 @@ Tamagotchi 는 AIRI 데스크톱 버전의 이름으로, 다른 애플리케이
이 기능을 설명하는 문서가 없었던 점, 그리고 이것이 AI 동반자에게 왜 중요하다고 생각하는지
설명하지 못한 점 사과드립니다.
VTuber 애플리케이션 중 Live2D 와 VRM 3D 모델을 지원하는 가장 인기 있는 둘은 VTuber Studio
Warudo 입니다. 이들은 VTuber 방송용으로 설계되어서, OBS(Open Broadcaster Software)로 방송할 때
VTuber 애플리케이션 중 Live2D와 VRM 3D 모델을 지원하는 가장 인기 있는 둘은 VTuber Studio와
Warudo입니다. 이들은 VTuber 방송용으로 설계되어서, OBS(Open Broadcaster Software)로 방송할 때
서로 다른 레이어의 요소로 장면을 구성할 수 있기 때문에 창 순서를 걱정할 필요가 없습니다.
모델 창은 항상 투명 배경의 최소화된 창으로 **백그라운드에** 있고 OBS 나 다른 방송 캡처 드라이버가
모델 창은 항상 투명 배경의 최소화된 창으로 **백그라운드에** 있고 OBS나 다른 방송 캡처 드라이버가
이를 캡처합니다.
AIRI 를 VTuber 방송에 쓴다면 Fade on hover 기능이 없어도 괜찮습니다. 하지만 바탕화면 위의
AIRI를 VTuber 방송에 쓴다면 Fade on hover 기능이 없어도 괜찮습니다. 하지만 바탕화면 위의
가상 동반자로 함께 지내게 하고 싶다면 곧 이런 점들을 느끼게 됩니다:
- 모델 창을 항상 위에 두도록 설계하면 그 아래 애플리케이션으로 가는 마우스 이벤트를 막아 버립니다.
@@ -113,10 +113,10 @@ AIRI 를 VTuber 방송에 쓴다면 Fade on hover 기능이 없어도 괜찮습
마우스 클릭 이벤트는 아래 애플리케이션으로 통과시키는 기능을요.
저는 이 기능을 개인적으로 정말 좋아합니다. 이제 창을 끄거나 순서를 정리할 걱정 없이 어떤
애플리케이션을 쓰든 AIRI 의 캐릭터가 곁에 있을 수 있으니까요. AIRI 를 개발하는 날이면 웹 버전이든
데스크톱 버전이든 늘 바탕화면에 그녀를 띄워 두고, 터미널과 VSCode/Cursor 를 함께 켜 둡니다.
애플리케이션을 쓰든 AIRI의 캐릭터가 곁에 있을 수 있으니까요. AIRI를 개발하는 날이면 웹 버전이든
데스크톱 버전이든 늘 바탕화면에 그녀를 띄워 두고, 터미널과 VSCode/Cursor를 함께 켜 둡니다.
**Fade on hover™** 만 업데이트한 건 아닙니다. 데스크톱 버전의 UI/UX 도 많이 개선하고
**Fade on hover™** 만 업데이트한 건 아닙니다. 데스크톱 버전의 UI/UX도 많이 개선하고
더 쓸 만하도록 기능을 추가했습니다.
#### 이동
@@ -127,7 +127,7 @@ AIRI 를 VTuber 방송에 쓴다면 Fade on hover 기능이 없어도 괜찮습
드래그 가능한 영역의 모양도 테마에 맞춰 둥근 모서리로 개선했습니다.
::: tip
이동 모드의 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="N" inline-block>N</kbd> 입니다
이동 모드의 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="N" inline-block>N</kbd>입니다
:::
<br />
@@ -135,7 +135,7 @@ AIRI 를 VTuber 방송에 쓴다면 Fade on hover 기능이 없어도 괜찮습
<ThemedVideo autoplay :src="airiDemoMove" />
이동 모드에 들어가면 드래그 가능한 영역이 나타납니다. 마우스로 옮기는 것 외에도 트레이 메뉴의
Position > Center / Bottom Left / Bottom Right 를 쓰는 방법도 있습니다.
Position > Center / Bottom Left / Bottom Right를 쓰는 방법도 있습니다.
#### 크기 조절
@@ -145,19 +145,19 @@ Position > Center / Bottom Left / Bottom Right 를 쓰는 방법도 있습니다
둥글게 다듬었습니다.
::: tip
크기 조절 모드의 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="R" inline-block>R</kbd> 입니다
크기 조절 모드의 기본 단축키는 <kbd aria-label="Shift" data-keyboard-key="shift" inline-block>Shift</kbd> + <kbd aria-label="Alt" data-macos-keyboard-key="option" inline-block>Alt</kbd> + <kbd aria-label="R" inline-block>R</kbd>입니다
:::
<br />
<ThemedVideo autoplay :src="airiDemoResize" />
#### 리소스 아일랜드
#### Resource Island
ASR/STT(음성 인식)와 VAD(음성 활성 감지) 모델을 불러오는 동안 기다리는 건 괴로운 일이라,
Steam 이나 Battle.net 처럼 모듈과 필요한 파일의 다운로드 진행 상황을 보여 줄 방법을 찾아야 했습니다.
Steam이나 Battle.net처럼 모듈과 필요한 파일의 다운로드 진행 상황을 보여 줄 방법을 찾아야 했습니다.
그래서 iOS 의 다이내믹 아일랜드에서 영감을 받아 **리소스 아일랜드** 라는 새 컴포넌트 세트를
그래서 iOS의 다이내믹 아일랜드에서 영감을 받아 **Resource Island**라는 새 컴포넌트 세트를
디자인했습니다. 떠 있는 형태로 마우스를 올릴 수 있는 위젯이며 모듈의 다운로드·설치 진행 상황을
표시하고, 다운로드가 끝나면 사라집니다.
@@ -173,9 +173,9 @@ Steam 이나 Battle.net 처럼 모듈과 필요한 파일의 다운로드 진행
#### 로컬 ASR/STT
[@luoling8192 (Luoling)](https://github.com/luoling8192) 과 저장소
[candle-examples](https://github.com/proj-airi/candle-examples) 에서 진행한 실험 덕분에,
이제 Windows, macOS, Linux 에서 동작하는 로컬 ASR/STT 엔진을 갖게 됐습니다.
[@luoling8192 (Luoling)](https://github.com/luoling8192)과 저장소
[candle-examples](https://github.com/proj-airi/candle-examples)에서 진행한 실험 덕분에,
이제 Windows, macOS, Linux에서 동작하는 로컬 ASR/STT 엔진을 갖게 됐습니다.
<video autoplay controls muted loop>
<source src="/en/blog/DevLog-2025.08.05/assets/airi-demo-settings-hearing.mp4" type="video/mp4">
@@ -185,11 +185,11 @@ Steam 이나 Battle.net 처럼 모듈과 필요한 파일의 다운로드 진행
<br />
::: info
이 데모는 OpenAI 의 음성 서비스를 쓰지만, ASR/STT 를 로컬 프로바이더로 전환할 수도 있습니다.
이 데모는 OpenAI의 음성 서비스를 쓰지만, ASR/STT를 로컬 프로바이더로 전환할 수도 있습니다.
:::
처음에는 candle 을 직접 쓰려 했지만 Windows 와 Linux 빌드에서 (CUDA 유무를 모두 고려해) candle
런타임을 임베드할 좋은 방법을 찾지 못했습니다. 그래서 ort(Rust 용 ONNX Runtime)로 전환했는데,
처음에는 candle을 직접 쓰려 했지만 Windows와 Linux 빌드에서 (CUDA 유무를 모두 고려해) candle
런타임을 임베드할 좋은 방법을 찾지 못했습니다. 그래서 ort(Rust용 ONNX Runtime)로 전환했는데,
비슷한 성능과 정확도를 내면서 호환성이 훨씬 좋고 쓰기도 쉽습니다.
### 웹
@@ -200,9 +200,9 @@ AIRI 설정이 지금 꽤 복잡하다는 걸 압니다 (그래도 코드 구조
순수 Python 기반 프로젝트들에 비하면 여전히 쉽습니다).
[Me1td0wn76 (melty kiss)](https://github.com/Me1td0wn76) 님이 웹 버전에 온보딩 화면 지원을
추가해 주신 덕분에, 처음 AIRI 를 쓸 때 훨씬 나은 경험을 하실 수 있습니다.
추가해 주신 덕분에, 처음 AIRI를 쓸 때 훨씬 나은 경험을 하실 수 있습니다.
이분은 Pull Request 가 머지된 뒤 Project AIRI 에 기여한 경험을 블로그로 나눠 주셨습니다:
이분은 Pull Request가 머지된 뒤 Project AIRI에 기여한 경험을 블로그로 나눠 주셨습니다:
[AIRIプロジェクトに参加した話 - YAMA-blog](https://yama-pro.blog/posts/airi/)
<img class="light" src="/en/blog/DevLog-2025.08.05/assets/airi-demo-onboarding-light.avif" alt="온보딩 라이트 모드" />
@@ -268,7 +268,7 @@ AIRI 설정이 지금 꽤 복잡하다는 걸 압니다 (그래도 코드 구조
#### 더 나은 텍스트 애니메이션
채팅 말풍선의 텍스트 애니메이션을 개선했습니다. [sumimakito (Makito)](https://github.com/sumimakito/) 가
며칠 전에 이에 대해 아주 훌륭한 DevLog 를 써서, 왜 특별하게 구현했는지와 i18n 호환성을 어떻게 고려했는지
며칠 전에 이에 대해 아주 훌륭한 DevLog를 써서, 왜 특별하게 구현했는지와 i18n 호환성을 어떻게 고려했는지
자세히 설명해 주었습니다. 꼭 읽어 보세요: [DevLog 2025.08.01](../DevLog-2025.08.01/).
동작하는 모습을 보세요:
@@ -323,13 +323,13 @@ AIRI 설정이 지금 꽤 복잡하다는 걸 압니다 (그래도 코드 구조
:dark="airiDocsDark"
/>
정말 멋져 보입니다. [Reka UI](https://reka-ui.com) 의 작업을 바탕으로 완전히 새로 쓰면서
블로그 글 목록, 언어 전환 등 많은 기능을 추가하고 VitePress 에 맞게 여러 스타일을 조정했습니다.
정말 멋져 보입니다. [Reka UI](https://reka-ui.com)의 작업을 바탕으로 완전히 새로 쓰면서
블로그 글 목록, 언어 전환 등 많은 기능을 추가하고 VitePress에 맞게 여러 스타일을 조정했습니다.
그리고 언제나처럼, 아름다운 디자인을 만들어 준 그들에게 감사드립니다. 저희 것을 만들 때 그들의
컴포넌트를 많이 쓰고 있으니 꼭 살펴보세요!
블로그 페이지도 [@lynzrand (Rynco Maekawa)](https://github.com/lynzrand) 가 디자인한 새 커버와 함께
블로그 페이지도 [@lynzrand (Rynco Maekawa)](https://github.com/lynzrand)가 디자인한 새 커버와 함께
더 보기 좋아졌습니다.
<img class="light" src="/en/blog/DevLog-2025.08.05/assets/airi-docs-blogs-light.avif" alt="문서 블로그 라이트 모드" />
@@ -340,7 +340,7 @@ AIRI 설정이 지금 꽤 복잡하다는 걸 압니다 (그래도 코드 구조
이른바 `i18n` 또는 로케일 파일을 저희 거대한 모노레포 안의 전용 패키지로 분리했습니다.
새 로케일을 추가하거나 번역을 추가·수정해 기여하실 때는 먼저
https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales 로 가 주세요.
[https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales](https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales)로 가 주세요.
<img class="light" src="/en/blog/DevLog-2025.08.05/assets/airi-packages-i18n-light.avif" alt="packages/i18n 라이트 모드" />
<img class="dark" src="/en/blog/DevLog-2025.08.05/assets/airi-packages-i18n-dark.avif" alt="packages/i18n 다크 모드" />
@@ -360,7 +360,7 @@ https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales 로 가 주
└── index.ts
```
`docs` `tamagotchi` 는 서로 구별되는 두 모듈을 위한 디렉터리입니다:
`docs``tamagotchi`는 서로 구별되는 두 모듈을 위한 디렉터리입니다:
- 문서 사이트
- 데스크톱 버전 (Tamagotchi)
@@ -371,22 +371,22 @@ https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales 로 가 주
`tamagotchi` 디렉터리는 조금 특별해서 모든 번역 문자열을 찾을 수는 없습니다. 데스크톱 버전에서만
쓰이는 특별한 번역 몇 가지를 담고 있고, 나머지는 모두 루트 디렉터리에 있습니다.
`docs` `tamagotchi` 외의 것들은:
`docs``tamagotchi` 외의 것들은:
- `base.yaml` 은 언어와 버튼 기본 상태 등 필수 문자열을 담습니다
- `settings.yaml` 은 설정 페이지의 문자열을 담습니다
- `stage.yaml` 은 스테이지(모델이 표시되는 UI)의 문자열을 담습니다
- `base.yaml`은 언어와 버튼 기본 상태 등 필수 문자열을 담습니다
- `settings.yaml`은 설정 페이지의 문자열을 담습니다
- `stage.yaml`은 스테이지(모델이 표시되는 UI)의 문자열을 담습니다
언어를 더 추가하고 싶으시다면 기존 언어 로케일 디렉터리 하나를 복사해 새 언어 코드로 이름을 바꾸세요.
예를 들어 프랑스어를 추가하려면 `en` 디렉터리를 `fr` 로 복사한 뒤 `base.yaml`, `settings.yaml`,
예를 들어 프랑스어를 추가하려면 `en` 디렉터리를 `fr`로 복사한 뒤 `base.yaml`, `settings.yaml`,
`stage.yaml`, `index.ts` 파일을 편집해 번역을 추가하면 됩니다. Pull Request 리뷰 과정에서
일부만 번역해도 괜찮습니다.
::: info 도움을 구합니다!
좀 우습게 들릴 수 있지만, 저희 i18n 패키지를 [Crowdin](https://crowdin.com) 이나
좀 우습게 들릴 수 있지만, 저희 i18n 패키지를 [Crowdin](https://crowdin.com)이나
[Weblate](https://weblate.org/en/) 같은 번역 자동화 도구와 통합해 주실 경험 있는 분을 찾고 있습니다.
저희는 이 분야 전문가가 아니니, 도와주실 Pull Request 를 열거나 논의를 위한 이슈를 편하게 열어 주세요.
저희는 이 분야 전문가가 아니니, 도와주실 Pull Request를 열거나 논의를 위한 이슈를 편하게 열어 주세요.
:::
언어 코드는 아래 도구 중 하나로 작업 중인 언어의 코드를 찾아 사용해 주세요:
@@ -442,50 +442,50 @@ https://github.com/moeru-ai/airi/tree/main/packages/i18n/src/locales 로 가 주
요약:
- 여러 패키지를 **buildless** 구성으로 전환했습니다
- `unbuild` `stub` 를 걷어냈습니다
- `rolldown-vite` 로 전환했습니다
- `unbuild` `tsdown` 으로 교체했습니다
- 더 빠르고 캐시되는 빌드를 위해 `turborepo` 를 도입했습니다
- `unbuild``stub`를 걷어냈습니다
- `rolldown-vite`로 전환했습니다
- `unbuild``tsdown`으로 교체했습니다
- 더 빠르고 캐시되는 빌드를 위해 `turborepo`를 도입했습니다
좀 더 자세히 말하면:
이전에는 모노레포 아키텍처를 택하면서 매끄러운 개발 경험을 위해, 컨트리뷰터가 프로젝트를 클론한 뒤
의존성을 설치할 때마다 `postinstall` 스크립트로 각 패키지의 `jiti` export `.d.ts` 모듈을 스텁으로
의존성을 설치할 때마다 `postinstall` 스크립트로 각 패키지의 `jiti` export와 `.d.ts` 모듈을 스텁으로
만들어 부트스트랩해야 했습니다.
덕분에 컨트리뷰터가 모노레포 동작 방식을 배우지 않아도 기여할 수 있었습니다. 하지만 `pnpm install`
때마다 다시 빌드하고 다시 스텁을 만드는 건 분명 영리한 전략이 아니었죠.
[@kwaa](https://github.com/kwaa) 가 도입한 buildless 아키텍처 변경 덕분에, 시간이 가장 오래 걸리던
최대 패키지 `stage-ui` 를 타입 체크나 의존성 해석 문제 없이 건너뛸 수 있게 됐습니다.
[@kwaa](https://github.com/kwaa)가 도입한 buildless 아키텍처 변경 덕분에, 시간이 가장 오래 걸리던
최대 패키지 `stage-ui`를 타입 체크나 의존성 해석 문제 없이 건너뛸 수 있게 됐습니다.
이후 [@kwaa](https://github.com/kwaa) `unbuild` 가 가져오던, 때때로 문제를 일으키는 중복
이후 [@kwaa](https://github.com/kwaa)는 `unbuild`가 가져오던, 때때로 문제를 일으키는 중복
`stub` 스크립트도 제거해 주었습니다. 덕분에 성가신
`The requested module './dist/index.mjs' does not provide an export named 'foo'`
오류와 더는 씨름하지 않는 훨씬 깔끔한 워크플로가 됐습니다.
가장 큰 변화는 두 달 전, [@kwaa](https://github.com/kwaa) `vite` `rolldown-vite` 로 교체해
가장 큰 변화는 두 달 전, [@kwaa](https://github.com/kwaa)가 `vite``rolldown-vite`로 교체해
**워크플로를 2배 빠르게** 만든 것입니다.
여기서 멈추지 않고 `unbuild` `tsdown` 으로 교체해 **추가로 4.2배 속도 향상**을 얻었고,
여기서 멈추지 않고 `unbuild``tsdown`으로 교체해 **추가로 4.2배 속도 향상**을 얻었고,
이제 각 하위 패키지 빌드가 250ms 미만으로 끝납니다.
> `tsdown` 으로 옮기면서 얻은 이점은 더 있습니다...
> `tsdown`으로 옮기면서 얻은 이점은 더 있습니다...
>
> - 사용하지 않는 의존성 검사
> - CSS 번들링
> - Vue SFC 컴포넌트 번들링
`postinstall` 스크립트는 여전히 필요하지만, 의존성을 인식해 빌드 결과를 캐시할 방법을 찾으면
중복 빌드를 많이 피할 수 있습니다. 여기서 `turborepo` 가 빌드를 더 빠르게 만들어 줍니다.
중복 빌드를 많이 피할 수 있습니다. 여기서 `turborepo`가 빌드를 더 빠르게 만들어 줍니다.
`turborepo` 덕분에 AIRI 빌드 시간이 **평균 4분에서 25초로 줄었습니다**.
### 이제 Nix 를 지원합니다
### 이제 Nix를 지원합니다
[@Weathercold (Weathercold)](https://github.com/Weathercold) 덕분에 AIRI 를 빌드하는 Nix flake
생겼습니다. 크로스 플랫폼 호환성에 훌륭한 보탬이 되죠. macOS 에서도 동작합니다.
[@Weathercold (Weathercold)](https://github.com/Weathercold) 덕분에 AIRI를 빌드하는 Nix flake가
생겼습니다. 크로스 플랫폼 호환성에 훌륭한 보탬이 되죠. macOS에서도 동작합니다.
nix-pkgs 로 들어갈 최종 Pull Request 가 머지되기를 기다리고 있지만, 다음 명령으로 미리 써 보실 수 있습니다:
nix-pkgs로 들어갈 최종 Pull Request가 머지되기를 기다리고 있지만, 다음 명령으로 미리 써 보실 수 있습니다:
```bash
nix run --extra-experimental-features 'nix-command flakes' github:moeru-ai/airi
@@ -496,26 +496,26 @@ nix run --extra-experimental-features 'nix-command flakes' github:moeru-ai/airi
이전에는 테스트, 스테이징, 릴리스의 빌드 파이프라인이 전부 달라서, 파이프라인이 성공할지 확신할 수 없어
새 버전을 낼지 결정하는 게 저에게는 악몽이었습니다.
Tauri 가 크로스 플랫폼 호환성과 Rust 로 syscall 을 하고 네이티브 OS 기능에 통합하는 강력한 능력이라는
Tauri가 크로스 플랫폼 호환성과 Rust로 syscall을 하고 네이티브 OS 기능에 통합하는 강력한 능력이라는
이점을 많이 준 건 사실이지만...
v0.7 개발 초기에 저는 ASR/STT 파이프라인의 추론 엔진 구현으로
[huggingface/candle](https://github.com/huggingface/candle) 을 도입했는데, NVIDIA CUDA 에 의존해서
[huggingface/candle](https://github.com/huggingface/candle)을 도입했는데, NVIDIA CUDA에 의존해서
빌드가 정말 엉망이었고 호환성 문제가 도처에 있었습니다.
하지만 이제 훨씬 나아졌습니다. 릴리스와 동일한 스크립트와 워크플로 단계를 매일 실행하는 예약 빌드
파이프라인이 생겼습니다. (`canary` `nightly` 빌드라고 들어 보셨을 겁니다.)
파이프라인이 생겼습니다. (`canary``nightly` 빌드라고 들어 보셨을 겁니다.)
그래서 최신 릴리스에서 문제를 겪으신다면, `main` 브랜치의 최신 빌드를 받아 문제가 고쳐졌는지
언제든 확인해 보실 수 있습니다.
나이틀리 빌드는 https://github.com/moeru-ai/airi/actions/workflows/release-tamagotchi.yml 에서 찾을 수 있습니다.
나이틀리 빌드는 [https://github.com/moeru-ai/airi/actions/workflows/release-tamagotchi.yml](https://github.com/moeru-ai/airi/actions/workflows/release-tamagotchi.yml)에서 찾을 수 있습니다.
## 마치기 전에...
이번 릴리스 사이에 태어난 새 패키지들:
> [@sumimakito](https://github.com/sumimakito) 에게 큰 박수를. 정말 환상적인 일을 너무 많이 해서
> [@sumimakito](https://github.com/sumimakito)에게 큰 박수를. 정말 환상적인 일을 너무 많이 해서
> 다 세지도 못하겠네요...
- [`@proj-airi/chromatic`](https://github.com/proj-airi/chromatic) ([@sumimakito](https://github.com/sumimakito))
@@ -527,11 +527,11 @@ v0.7 개발 초기에 저는 ASR/STT 파이프라인의 추론 엔진 구현으
이번 릴리스 사이에 태어난 사이드 프로젝트들:
- [HuggingFace Inspector](https://hf-inspector.moeru.ai/) (https://github.com/moeru-ai/hf-inspector)
- [whisper & VAD, candle, burn, ort 에 관한 더 많은 candle 예제](https://github.com/proj-airi/candle-examples)
- [whisper & VAD, candle, burn, ort에 관한 더 많은 candle 예제](https://github.com/proj-airi/candle-examples)
- [(모델 카탈로그) Inventory 제출!](https://github.com/moeru-ai/inventory/pull/1) ([@LemonNekoGH](https://github.com/LemonNekoGH))
이 DevLog 에 모든 것을 담을 수는 없습니다. 자세한 내용은 저희 로드맵의
[Roadmap v0.7](https://github.com/moeru-ai/airi/issues/200) 에서 언제든 확인하실 수 있습니다.
이 DevLog에 모든 것을 담을 수는 없습니다. 자세한 내용은 저희 로드맵의
[Roadmap v0.7](https://github.com/moeru-ai/airi/issues/200)에서 언제든 확인하실 수 있습니다.
<div class="w-full flex flex-col items-center justify-center gap-3 py-3">
<img src="/en/blog/DevLog-2025.08.05/assets/relu-sticker-thinks.avif" alt="ReLU 스티커 thinks" class="w-30!" />
+36 -36
View File
@@ -3,7 +3,7 @@ title: DevLog @ 2025.08.26
category: DevLog
date: 2025-08-26
excerpt: |
`airi-factorio` 의 순수 비전 방향에서 이룬 진전을 공유하며, 생각이 증발하기 전에 붙잡아 둡니다.
`airi-factorio`의 순수 비전 방향에서 이룬 진전을 공유하며, 생각이 증발하기 전에 붙잡아 둡니다.
preview-cover:
# TODO
---
@@ -13,25 +13,25 @@ import airiFactorioYoloV0PlaygroundVnc from '../../../en/blog/DevLog-2025.08.26/
import NmsIou from '../../../en/blog/DevLog-2025.08.26/components/nms-iou.vue'
</script>
오랜만입니다, 여러분! AIRI 메인테이너 중 한 명인 [@LemonNeko](https://github.com/LemonNekoGH) 입니다. ~~아, 이렇게 시작하는 것도 슬슬 지겹네요. 꼭 LLM 같잖아요.~~
오랜만입니다, 여러분! AIRI 메인테이너 중 한 명인 [@LemonNeko](https://github.com/LemonNekoGH)입니다. ~~아, 이렇게 시작하는 것도 슬슬 지겹네요. 꼭 LLM 같잖아요.~~
지난 [DevLog](../DevLog-2025.07.18/) 에서는 [Factorio Learning Environment](https://arxiv.org/abs/2503.09617) 논문을 간단히 살펴보고 `airi-factorio` 를 어떻게 개선할지 이야기했습니다. 그런데... 오늘 나눌 이야기는 그것이 아니라 순수 비전 방향에서의 진전입니다.
지난 [DevLog](../DevLog-2025.07.18/) 에서는 [Factorio Learning Environment](https://arxiv.org/abs/2503.09617) 논문을 간단히 살펴보고 `airi-factorio`를 어떻게 개선할지 이야기했습니다. 그런데... 오늘 나눌 이야기는 그것이 아니라 순수 비전 방향에서의 진전입니다.
올해 6월, [@nekomeowww](https://github.com/nekomeowww) 가 거의 실시간으로 동작하는 [VLM Playground](https://huggingface.co/spaces/moeru-ai/smolvlm-realtime-webgpu-vue) HuggingFace Space 를 공개했는데 정말 멋져 보였습니다. 그래서 먼저 간단한 실시간 이미지 인식(당시엔 객체 탐지와 이미지 인식을 헷갈렸습니다)을 시도하고, 어떻게든 AI 에게 넘겨 판단하게 한 뒤, 어떤 방식으로든 게임에 동작을 출력하기로 했습니다.
올해 6월, [@nekomeowww](https://github.com/nekomeowww)가 거의 실시간으로 동작하는 [VLM Playground](https://huggingface.co/spaces/moeru-ai/smolvlm-realtime-webgpu-vue) HuggingFace Space를 공개했는데 정말 멋져 보였습니다. 그래서 먼저 간단한 실시간 이미지 인식(당시엔 객체 탐지와 이미지 인식을 헷갈렸습니다)을 시도하고, 어떻게든 AI에게 넘겨 판단하게 한 뒤, 어떤 방식으로든 게임에 동작을 출력하기로 했습니다.
먼저 결과부터 보여 드리겠습니다:
<ThemedVideo :src="airiFactorioYoloV0PlaygroundVnc" controls playsinline />
영상에서 저는 웹 페이지의 VNC 연결로 Factorio 를 플레이하고 있고, 오른쪽에는 객체 탐지 결과가 거의 실시간으로 표시됩니다. [HuggingFace Space](https://huggingface.co/spaces/proj-airi/factorio-yolo-v0-playground) 에도 배포했으니 편하게 써 보세요.
영상에서 저는 웹 페이지의 VNC 연결로 Factorio를 플레이하고 있고, 오른쪽에는 객체 탐지 결과가 거의 실시간으로 표시됩니다. [HuggingFace Space](https://huggingface.co/spaces/proj-airi/factorio-yolo-v0-playground)에도 배포했으니 편하게 써 보세요.
그럼 이걸 어떻게 구현했을까요?
## Factorio 클라이언트를 Docker 에 넣기
## Factorio 클라이언트를 Docker에 넣기
AI 가 게임 화면을 보게 하려면 Factorio 가 창 크기나 위치 같은 것에 영향받지 않는 통제된 환경에서 돌아가야 합니다. 동시에 이 환경이 바로 쓸 수 있는 상태이길 원했기에, Factorio 를 Docker 에 넣기로 했습니다.
AI가 게임 화면을 보게 하려면 Factorio가 창 크기나 위치 같은 것에 영향받지 않는 통제된 환경에서 돌아가야 합니다. 동시에 이 환경이 바로 쓸 수 있는 상태이길 원했기에, Factorio를 Docker에 넣기로 했습니다.
Factorio 는 공식 [Docker 이미지](https://hub.docker.com/r/factoriotools/factorio)를 제공하지만 이는 순수 서버용입니다. AI 가 화면을 보고 게임을 조작하게 하려면 클라이언트가 필요한데, 기존 Docker 이미지를 찾을 수 없었고 (Factorio 라이선스 계약상 클라이언트를 이런 식으로 배포할 수도 없습니다) 직접 패키징해야 했습니다 (그리고 패키징한 클라이언트 이미지도 배포할 수 없어서 Dockerfile 만 공유할 수 있습니다).
Factorio는 공식 [Docker 이미지](https://hub.docker.com/r/factoriotools/factorio)를 제공하지만 이는 순수 서버용입니다. AI가 화면을 보고 게임을 조작하게 하려면 클라이언트가 필요한데, 기존 Docker 이미지를 찾을 수 없었고 (Factorio 라이선스 계약상 클라이언트를 이런 식으로 배포할 수도 없습니다) 직접 패키징해야 했습니다 (그리고 패키징한 클라이언트 이미지도 배포할 수 없어서 Dockerfile만 공유할 수 있습니다).
그럼 Factorio 클라이언트~~라는 코끼리~~를 Docker~~라는 냉장고~~에 넣으려면 몇 단계가 필요할까요~~?~~
@@ -39,7 +39,7 @@ Factorio 는 공식 [Docker 이미지](https://hub.docker.com/r/factoriotools/fa
2. 가상 디스플레이 준비: 그래픽 애플리케이션은 화면을 표시할 디스플레이가 필요합니다.
3. VNC 서비스 준비: 가상 디스플레이의 내용을 읽어 외부 VNC 클라이언트로 화면을 전송하고, 사용자 입력을 게임에 전달할 수 있습니다.
뭔가 빠진 것 같나요? 아, 오디오요? 무슨 오디오요? 없습니다. 지금의 AI 는 아직 소리를 듣지 못하니 일단 무시하겠습니다.
뭔가 빠진 것 같나요? 아, 오디오요? 무슨 오디오요? 없습니다. 지금의 AI는 아직 소리를 듣지 못하니 일단 무시하겠습니다.
### Factorio 클라이언트 다운로드
@@ -56,47 +56,47 @@ sudo apt install -y xvfb x11-apps mesa-utils
```
여기서:
- `xvfb` 는 가상 프레임버퍼이자 X 서버입니다.
- `x11-apps` 는 X 관련 도구 모음으로, 설치하면 X 환경도 함께 설치됩니다.
- `mesa-utils` 는 Mesa 관련 도구 모음입니다. Mesa 는 OpenGL 의 소프트웨어 구현이며, OpenGL 애플리케이션을 테스트하고 디버깅하는 데 도움이 되는 도구를 제공합니다.
- `xvfb`는 가상 프레임버퍼이자 X 서버입니다.
- `x11-apps`는 X 관련 도구 모음으로, 설치하면 X 환경도 함께 설치됩니다.
- `mesa-utils`는 Mesa 관련 도구 모음입니다. Mesa는 OpenGL의 소프트웨어 구현이며, OpenGL 애플리케이션을 테스트하고 디버깅하는 데 도움이 되는 도구를 제공합니다.
### VNC 서비스 준비
VNC 는 Virtual Network Computing 의 약자로, 마치 그 앞에 앉아 있는 것처럼 다른 컴퓨터를 원격으로 제어할 수 있게 해 주는 원격 데스크톱 프로토콜입니다.
VNC는 Virtual Network Computing의 약자로, 마치 그 앞에 앉아 있는 것처럼 다른 컴퓨터를 원격으로 제어할 수 있게 해 주는 원격 데스크톱 프로토콜입니다.
```bash
sudo apt install -y x11vnc
```
여기까지 하면 Docker 에서 Factorio 클라이언트를 실행하고 VNC 로 제어할 수 있습니다.
여기까지 하면 Docker에서 Factorio 클라이언트를 실행하고 VNC로 제어할 수 있습니다.
하지만 아직 부족합니다. 제 목표는 브라우저에서 플레이하면서 실시간으로 객체 탐지 추론을 돌리는 것입니다. 그런데 브라우저는 HTTP 프로토콜만 쓸 수 있으므로, VNC 프로토콜을 HTTP 로 변환해 줄 `websockify` 같은 도구가 필요합니다. 또 디버깅 편의를 위해 VNC 화면을 보여 줄 웹 인터페이스도 필요해서 `novnc` 도 설치합니다.
하지만 아직 부족합니다. 제 목표는 브라우저에서 플레이하면서 실시간으로 객체 탐지 추론을 돌리는 것입니다. 그런데 브라우저는 HTTP 프로토콜만 쓸 수 있으므로, VNC 프로토콜을 HTTP로 변환해 줄 `websockify` 같은 도구가 필요합니다. 또 디버깅 편의를 위해 VNC 화면을 보여 줄 웹 인터페이스도 필요해서 `novnc`도 설치합니다.
```bash
sudo apt install -y websockify novnc
```
좋습니다! 이제 Docker 이미지가 준비됐습니다. 전체 [Dockerfile](https://github.com/moeru-ai/airi-factorio/blob/a6bf243f14cbc0d765ff7ed13389bca33c1fdfa2/docker/Dockerfile) 과 [사용 안내](https://github.com/moeru-ai/airi-factorio/tree/ba46a4e47b31187dd064b06314b595b551ed3411/apps/factorio-yolo-v0-playground)는 여기서 볼 수 있습니다.
좋습니다! 이제 Docker 이미지가 준비됐습니다. 전체 [Dockerfile](https://github.com/moeru-ai/airi-factorio/blob/a6bf243f14cbc0d765ff7ed13389bca33c1fdfa2/docker/Dockerfile)과 [사용 안내](https://github.com/moeru-ai/airi-factorio/tree/ba46a4e47b31187dd064b06314b595b551ed3411/apps/factorio-yolo-v0-playground)는 여기서 볼 수 있습니다.
## 객체 탐지 모델 학습
빠른 검증을 위해 YOLO11n 의 사전 학습 모델을 기반으로 저희 객체 탐지 모델을 학습시켰습니다.
빠른 검증을 위해 YOLO11n의 사전 학습 모델을 기반으로 저희 객체 탐지 모델을 학습시켰습니다.
### 데이터셋 준비
데이터셋은 이렇게 수집했습니다:
1. [`surface.create_entity`](https://lua-api.factorio.com/latest/classes/LuaSurface.html#create_entity) 함수로 씬의 임의 위치에 기계를 배치하고, 선택 박스 크기와 위치를 함께 얻습니다.
2. [`game.take_screenshot`](https://lua-api.factorio.com/latest/classes/LuaGameScript.html#take_screenshot) 으로 다양한 줌 레벨과 조명 조건(낮)에서 스크린샷을 찍습니다.
3. 선택 박스를 바탕으로 어노테이션 데이터를 생성하고 [`helpers.write_file`](https://lua-api.factorio.com/latest/classes/LuaHelpers.html#write_file) 로 파일에 저장합니다.
2. [`game.take_screenshot`](https://lua-api.factorio.com/latest/classes/LuaGameScript.html#take_screenshot)으로 다양한 줌 레벨과 조명 조건(낮)에서 스크린샷을 찍습니다.
3. 선택 박스를 바탕으로 어노테이션 데이터를 생성하고 [`helpers.write_file`](https://lua-api.factorio.com/latest/classes/LuaHelpers.html#write_file)로 파일에 저장합니다.
제 수집 스크립트는 [여기](https://github.com/moeru-ai/airi-factorio/blob/ba46a4e47b31187dd064b06314b595b551ed3411/packages/factorio-rcon-snippets-for-node/src/factorio_yolo_dataset_collector_v0.ts)에 있습니다. `typescript-to-lua` 로 TypeScript 를 Lua 로 컴파일한 뒤 RCON 으로 Factorio 에 넘겨 실행합니다.
제 수집 스크립트는 [여기](https://github.com/moeru-ai/airi-factorio/blob/ba46a4e47b31187dd064b06314b595b551ed3411/packages/factorio-rcon-snippets-for-node/src/factorio_yolo_dataset_collector_v0.ts)에 있습니다. `typescript-to-lua`로 TypeScript를 Lua로 컴파일한 뒤 RCON으로 Factorio에 넘겨 실행합니다.
스크립트에서는 조립기 3종과 컨베이어를 수집했고, 기계마다 이미지 20장씩, 각 이미지는 UI 없이 1280x1280 해상도로 찍었습니다.
아 참, 수집 스크립트를 더 잘 디버깅하려고 [VSCode 플러그인](https://github.com/moeru-ai/airi-factorio/blob/ba46a4e47b31187dd064b06314b595b551ed3411/packages/vscode-factorio-rcon-evaluator/README.md)도 만들었습니다. CodeLens 로 클릭 한 번에 스크립트를 컴파일하고 실행할 수 있습니다.
아 참, 수집 스크립트를 더 잘 디버깅하려고 [VSCode 플러그인](https://github.com/moeru-ai/airi-factorio/blob/ba46a4e47b31187dd064b06314b595b551ed3411/packages/vscode-factorio-rcon-evaluator/README.md)도 만들었습니다. CodeLens로 클릭 한 번에 스크립트를 컴파일하고 실행할 수 있습니다.
이미지와 어노테이션 데이터를 모은 뒤에는 [YOLO 공식 형식](https://docs.ultralytics.com/datasets/detect/)에 맞춰 데이터셋을 정리하고, [Ultralytics Hub](https://www.ultralytics.com/hub) 에 업로드해 결과를 확인합니다:
이미지와 어노테이션 데이터를 모은 뒤에는 [YOLO 공식 형식](https://docs.ultralytics.com/datasets/detect/)에 맞춰 데이터셋을 정리하고, [Ultralytics Hub](https://www.ultralytics.com/hub)에 업로드해 결과를 확인합니다:
![Ultralytics Hub](/en/blog/DevLog-2025.08.26/assets/factorio-ultralytics-hub-preview.jpg)
@@ -114,7 +114,7 @@ model.train(data="./dataset/detect.yaml", epochs=100, imgsz=640, device="mps")
model.export(format="onnx")
```
640x640 해상도로 MPS 디바이스를 써서(macOS 에서는 MPS 디바이스가 성능이 더 좋습니다) 100 에포크 학습했고, 에포크당 배치는 5개, 대략 70 에포크쯤에서 최적 성능에 도달했으며 ONNX 모델로 내보냈습니다. 학습에는 약 8분이 걸렸고 모델 크기는 약 10MB 입니다.
640x640 해상도로 MPS 디바이스를 써서(macOS에서는 MPS 디바이스가 성능이 더 좋습니다) 100 에포크 학습했고, 에포크당 배치는 5개, 대략 70 에포크쯤에서 최적 성능에 도달했으며 ONNX 모델로 내보냈습니다. 학습에는 약 8분이 걸렸고 모델 크기는 약 10MB입니다.
데이터셋, 학습 코드, 내보낸 ONNX 모델은 [여기](https://github.com/moeru-ai/airi-factorio/blob/ba46a4e47b31187dd064b06314b595b551ed3411/apps/factorio-yolo-v0-playground)에서 볼 수 있습니다.
@@ -122,34 +122,34 @@ model.export(format="onnx")
이제 위 두 부분을 조립할 수 있습니다. 저는 다음을 사용했습니다:
1. `@novnc/novnc` 로 브라우저에 VNC 화면을 표시하면서 캔버스 데이터를 뽑아 모델에 먹입니다.
2. `onnxruntime-web` 으로 브라우저에서 추론을 수행합니다. WebGPU 를 지원해서 GPU 성능을 활용할 수 있습니다.
1. `@novnc/novnc`로 브라우저에 VNC 화면을 표시하면서 캔버스 데이터를 뽑아 모델에 먹입니다.
2. `onnxruntime-web`으로 브라우저에서 추론을 수행합니다. WebGPU를 지원해서 GPU 성능을 활용할 수 있습니다.
처음에는 추론이 400ms 정도로 매우 느렸고 UI 까지 멈춰 버려 VNC 를 쓸 수 없었습니다. 급히 WebWorker 사용법을 익혀 추론과 화면 표시를 분리해 이 문제를 해결했습니다. 그리고 사실 WebGPU 가 켜져 있지 않았다는 것도 알게 됐는데, 그래서 속도가 여전히 느렸던 것이죠.
처음에는 추론이 400ms 정도로 매우 느렸고 UI까지 멈춰 버려 VNC를 쓸 수 없었습니다. 급히 WebWorker 사용법을 익혀 추론과 화면 표시를 분리해 이 문제를 해결했습니다. 그리고 사실 WebGPU가 켜져 있지 않았다는 것도 알게 됐는데, 그래서 속도가 여전히 느렸던 것이죠.
```typescript
ort.InferenceSession.create(model, { executionProviders: ['webgpu', 'wasm'] })
```
WebGPU 와 WASM 실행 방식을 모두 허용한다고 명시해야, WebGPU 를 쓸 수 없을 때 자동으로 WASM 실행으로 전환됩니다.
WebGPU와 WASM 실행 방식을 모두 허용한다고 명시해야, WebGPU를 쓸 수 없을 때 자동으로 WASM 실행으로 전환됩니다.
WebGPU 를 켜자 추론 속도가 약 80ms 로 개선됐습니다. 여전히 만족스럽지 않았지만 더 최적화할 방법을 몰랐죠. 그때 Cursor 가 이렇게 알려 줬습니다: "픽셀 색상 값을 정규화할 때 계속 255 로 나누고 있습니다. `1/255` 를 먼저 계산해 두고 그 값을 곱해서 나눗셈을 피하세요."
WebGPU를 켜자 추론 속도가 약 80ms로 개선됐습니다. 여전히 만족스럽지 않았지만 더 최적화할 방법을 몰랐죠. 그때 Cursor가 이렇게 알려 줬습니다: "픽셀 색상 값을 정규화할 때 계속 255로 나누고 있습니다. `1/255`를 먼저 계산해 두고 그 값을 곱해서 나눗셈을 피하세요."
네? 잠깐, 나눗셈이 곱셈보다 느리다고요? 건너뛴 컴퓨터 과학 수업을 정말 보충해야겠네요.
Cursor 의 제안대로 코드를 고치자 추론 속도가 약 20ms 로 개선됐습니다. 이제 체감이 꽤 좋습니다.
Cursor의 제안대로 코드를 고치자 추론 속도가 약 20ms로 개선됐습니다. 이제 체감이 꽤 좋습니다.
앞에서 모델 출력을 처리하는 부분은 건너뛰었는데, 이제 살펴봅시다.
### 모델 출력 처리하기
모델은 원소 84,000개짜리 배열과 `dims` `[1, 10, 8400]` 인 배열을 출력합니다. 즉 84,000개 원소가 10개씩 묶여 있고, 각 묶음은 바운딩 박스 중심의 x, y 좌표, 박스의 너비와 높이, 그리고 6개 카테고리의 신뢰도 점수를 담고 있으며, 총 8,400개의 결과 묶음이 됩니다.
모델은 원소 84,000개짜리 배열과 `dims``[1, 10, 8400]` 인 배열을 출력합니다. 즉 84,000개 원소가 10개씩 묶여 있고, 각 묶음은 바운딩 박스 중심의 x, y 좌표, 박스의 너비와 높이, 그리고 6개 카테고리의 신뢰도 점수를 담고 있으며, 총 8,400개의 결과 묶음이 됩니다.
임계값 0.6 으로 신뢰도가 낮은 바운딩 박스를 걸러낸 뒤에도, 겹치는 박스를 제거하기 위해 NMS 방법으로 IOU 를 써야 합니다.
임계값 0.6으로 신뢰도가 낮은 바운딩 박스를 걸러낸 뒤에도, 겹치는 박스를 제거하기 위해 NMS 방법으로 IOU를 써야 합니다.
IOU 와 NMS 에 대해서는 [이 글](https://medium.com/@jesse419419/understanding-iou-and-nms-by-a-j-dcebaad60652)을 참고하세요. 간단히 말하면 두 박스의 넓이를 더한 뒤 겹치는 넓이를 빼서 실제 차지하는 넓이를 구하고, 겹치는 넓이를 실제 차지하는 넓이로 나눠 IOU 를 얻는 것입니다.
IOU와 NMS에 대해서는 [이 글](https://medium.com/@jesse419419/understanding-iou-and-nms-by-a-j-dcebaad60652)을 참고하세요. 간단히 말하면 두 박스의 넓이를 더한 뒤 겹치는 넓이를 빼서 실제 차지하는 넓이를 구하고, 겹치는 넓이를 실제 차지하는 넓이로 나눠 IOU를 얻는 것입니다.
저는 아주 단순한 NMS 구현을 썼습니다. 모든 바운딩 박스를 신뢰도로 정렬한 뒤 높은 것부터 순회하며, IOU 가 0.7 보다 크면 같은 객체로 보고 걸러냅니다.
저는 아주 단순한 NMS 구현을 썼습니다. 모든 바운딩 박스를 신뢰도로 정렬한 뒤 높은 것부터 순회하며, IOU가 0.7보다 크면 같은 객체로 보고 걸러냅니다.
```typescript
function nms(boxes: Box[], iouThreshold: number): Box[] {
@@ -180,7 +180,7 @@ function nms(boxes: Box[], iouThreshold: number): Box[] {
Playground 전체 소스 코드는 [여기](https://github.com/moeru-ai/airi-factorio/tree/ba46a4e47b31187dd064b06314b595b551ed3411/apps/factorio-yolo-v0-playground)에서 볼 수 있습니다.
아래 시각화 컴포넌트에서 라벨을 드래그해 박스 위치를 바꿔 가며 IOU 와 NMS 효과를 직접 만져 볼 수도 있습니다:
아래 시각화 컴포넌트에서 라벨을 드래그해 박스 위치를 바꿔 가며 IOU와 NMS 효과를 직접 만져 볼 수도 있습니다:
<div class="flex justify-center">
<NmsIou />
@@ -190,10 +190,10 @@ Playground 전체 소스 코드는 [여기](https://github.com/moeru-ai/airi-fac
이번 실습을 통해 몇 가지 문제를 발견했습니다:
1. 정사각형이 아닌 이미지를 인식하지 못함: 정사각형이 아닌 이미지를 만나면 모든 결과의 신뢰도가 매우 낮아지거나 심지어 0 이 됩니다.
1. 정사각형이 아닌 이미지를 인식하지 못함: 정사각형이 아닌 이미지를 만나면 모든 결과의 신뢰도가 매우 낮아지거나 심지어 0이 됩니다.
2. 모델이 1티어와 2티어 조립기를 구분하기는 하지만, 상자처럼 네모난 물체도 조립기로 인식합니다.
3. 실제 플레이에서는 기계 텍스처 위에 전력, 현재 레시피, 장착된 모듈 같은 상태 표시가 겹쳐 있어 모델 인식을 방해합니다.
## 맺으며
이것이 이번 달 작업의 결과입니다. 꽤 알찼네요! 도움을 준 [@nekomeowww](https://github.com/nekomeowww), [@dsh0416](https://github.com/dsh0416), [makito](https://github.com/sumimakito) 에게 깊이 감사드립니다. 다음으로는 모델 성능을 개선할 방법을 찾고, 어떻게든 AI 가 게임을 조작하게 만들어야 합니다.
이것이 이번 달 작업의 결과입니다. 꽤 알찼네요! 도움을 준 [@nekomeowww](https://github.com/nekomeowww), [@dsh0416](https://github.com/dsh0416), [makito](https://github.com/sumimakito)에게 깊이 감사드립니다. 다음으로는 모델 성능을 개선할 방법을 찾고, 어떻게든 AI가 게임을 조작하게 만들어야 합니다.
+17 -17
View File
@@ -3,7 +3,7 @@ title: DevLog @ 2025.10.20
category: DevLog
date: 2025-10-20
excerpt: |
Tauri 에서 Electron 으로의 마이그레이션, 새 Live2D 모델, 그리고 여러 오픈소스 프로젝트 업데이트까지 AIRI 프로젝트의 최근 진행 상황을 나눕니다.
Tauri에서 Electron 으로의 마이그레이션, 새 Live2D 모델, 그리고 여러 오픈소스 프로젝트 업데이트까지 AIRI 프로젝트의 최근 진행 상황을 나눕니다.
preview-cover:
# TODO
---
@@ -12,22 +12,22 @@ preview-cover:
요즘 AI 트레이딩 봇이 엄청 뜨겁죠. 저희도 비슷한 연구를 나눌 게 있는데, 우선 개발 이야기부터 시작하겠습니다...
## Tauri 에서 Electron 으로의 마이그레이션
## Tauri에서 Electron 으로의 마이그레이션
며칠 전 Tauri 가 다시 화제가 됐죠. 저희는 3월에 일찌감치 도입했고 플러그인 설계가 마음에 들어서 crate 도 잔뜩 감쌌습니다. 6월에 드디어 v0.7.2 를 릴리스했지만, 모두가 원하던 음성 대화를 제공하려고 3개월을 고생했습니다... 3개월요... Tauri 의 WebKit 과 지독히 까다로운 Web Audio API, DevTools 와 씨름하면서... 9월까지 계속요...
며칠 전 Tauri가 다시 화제가 됐죠. 저희는 3월에 일찌감치 도입했고 플러그인 설계가 마음에 들어서 crate도 잔뜩 감쌌습니다. 6월에 드디어 v0.7.2를 릴리스했지만, 모두가 원하던 음성 대화를 제공하려고 3개월을 고생했습니다... 3개월요... Tauri의 WebKit과 지독히 까다로운 Web Audio API, DevTools와 씨름하면서... 9월까지 계속요...
...결국 더는 못 버티고, 국경절 연휴에 Electron 으로 완전히 갈아탔습니다!
...결국 더는 못 버티고, 국경절 연휴에 Electron으로 완전히 갈아탔습니다!
<img src="/en/blog/DevLog-2025.10.20/assets/electron.png" alt="electron.png" />
이제 기존 Electron 기반 위에 Linux 지원을 추가했고, 저희가 컨트롤 아일랜드라고 부르는 것을 도입했으며, macOS 전체 화면 모드에서도 인터페이스 위에 겹쳐 띄울 수 있게 됐습니다.
이제 기존 Electron 기반 위에 Linux 지원을 추가했고, 저희가 Controls Island라고 부르는 것을 도입했으며, macOS 전체 화면 모드에서도 인터페이스 위에 겹쳐 띄울 수 있게 됐습니다.
호환성이 훌륭해서 정말 마음에 듭니다. 어제는 마침내 자막 오버레이가 동작하게 되어서, 이제 Neuro-sama 처럼 자막으로 AI 가 무엇을 출력하는지 볼 수 있습니다!
호환성이 훌륭해서 정말 마음에 듭니다. 어제는 마침내 자막 오버레이가 동작하게 되어서, 이제 Neuro-sama처럼 자막으로 AI가 무엇을 출력하는지 볼 수 있습니다!
<img src="/en/blog/DevLog-2025.10.20/assets/control-island.png" alt="control-island.png" />
<div style="text-align: center; font-size: 0.875rem; color: #666; margin-top: 0.5rem;">
컨트롤 아일랜드
Controls Island
</div>
## 새 Live2D 모델
@@ -42,17 +42,17 @@ preview-cover:
## Three.js MMD 지원
여러분이 가지고 있거나 구할 수 있는 모델이 전부 Live2D/VRM 은 아닐 겁니다. 사실 가장 풍부하고 좋은 건 여전히 MMD 모델이죠.
여러분이 가지고 있거나 구할 수 있는 모델이 전부 Live2D/VRM은 아닐 겁니다. 사실 가장 풍부하고 좋은 건 여전히 MMD 모델이죠.
저희도 3D 렌더링에 Three.js 를 쓰고 있지만, 현실적으로 Three.js 에는 더 이상 동작하는 MMD 구현이 없습니다. kwaa 의 작업 덕분에 이제 이를 위한 저장소가 생겼습니다!
저희도 3D 렌더링에 Three.js를 쓰고 있지만, 현실적으로 Three.js에는 더 이상 동작하는 MMD 구현이 없습니다. kwaa의 작업 덕분에 이제 이를 위한 저장소가 생겼습니다!
관심 있으시다면 함께 유지보수해 주세요! [moeru-ai/three-mmd](https://github.com/moeru-ai/three-mmd)
## Velin: Vue 로 프롬프트 작성하기
## Velin: Vue로 프롬프트 작성하기
>"[Vue](https://velin-dev.netlify.app/#/) 로 프롬프트를 작성할 수 있습니다"!
5월에 저희 프롬프트 라이브러리를 소개했던 걸 기억하시나요? RainbowBird 의 노력과 기여 덕분에 Velin 이 이제 정식으로 Moeru AI 의 일부가 됐습니다! AIRI 의 거의 모든 프롬프트가 Velin 으로 돌아가는데, 크로스 플랫폼 걱정은 마세요. Velin 은 Node.js 환경에서도 잘 동작합니다!
5월에 저희 프롬프트 라이브러리를 소개했던 걸 기억하시나요? RainbowBird의 노력과 기여 덕분에 Velin이 이제 정식으로 Moeru AI의 일부가 됐습니다! AIRI의 거의 모든 프롬프트가 Velin으로 돌아가는데, 크로스 플랫폼 걱정은 마세요. Velin은 Node.js 환경에서도 잘 동작합니다!
<img src="/en/blog/DevLog-2025.10.20/assets/velin.png" alt="velin.png" />
@@ -60,13 +60,13 @@ preview-cover:
>"Events are all you need"
Vercel AI SDK 와 비슷한 방식으로 브라우저에서 순수 로컬 추론을 할 수 있게 해 주는 프로젝트 [netlify](https://velin-dev.netlify.app/#/) 를 소개한 적이 있습니다.
Vercel AI SDK와 비슷한 방식으로 브라우저에서 순수 로컬 추론을 할 수 있게 해 주는 프로젝트 [netlify](https://velin-dev.netlify.app/#/) 를 소개한 적이 있습니다.
이런 로컬 추론은 전부 Web Worker / worker_threads 에서만 돌 수 있고, 이들은 이벤트로 통신합니다. Electron IPC 도 마찬가지인데, 저희는 그게 충분히 우아하지 않다고 느꼈습니다. RainbowBird 덕분에 이제 이벤트 기반 IPC/RPC 구현을 이끄는 라이브러리 eventa 가 생겼습니다. [Eventa](https://github.com/moeru-ai/eventa) 도 이제 정식으로 Moeru AI 의 일부입니다!
이런 로컬 추론은 전부 Web Worker / worker_threads 에서만 돌 수 있고, 이들은 이벤트로 통신합니다. Electron IPC도 마찬가지인데, 저희는 그게 충분히 우아하지 않다고 느꼈습니다. RainbowBird 덕분에 이제 이벤트 기반 IPC/RPC 구현을 이끄는 라이브러리 eventa가 생겼습니다. [Eventa](https://github.com/moeru-ai/eventa)도 이제 정식으로 Moeru AI의 일부입니다!
## 프로젝트 개발 현황
이제 Moeru AI 와 Project AIRI 는 거대한 조직으로 성장해, 머신러닝·데이터 처리·프론트엔드·백엔드 등을 아우르는 50개 이상의 자체 저장소를 TypeScript/Python/Rust/Go 등 여러 언어로 운영하고 있습니다.
이제 Moeru AI와 Project AIRI는 거대한 조직으로 성장해, 머신러닝·데이터 처리·프론트엔드·백엔드 등을 아우르는 50개 이상의 자체 저장소를 TypeScript/Python/Rust/Go 등 여러 언어로 운영하고 있습니다.
전체 팔로워 수는 800명을 넘었습니다. 1년 전 처음 시작할 때는 상상도 못 했던 일입니다. 정말로, 성원해 주셔서 진심으로 감사합니다!
@@ -82,16 +82,16 @@ Project AIRI
## 순수 Rust TTS 구현
작은 예고: 최근 kwaa 와 팀을 이뤄 잘 알려진 TTS 모델 chatterbox 를 순수 Rust 구현으로 포팅했습니다. 이제 까다로운 Python 환경 설정으로 골머리를 앓지 않아도 됩니다!
작은 예고: 최근 kwaa와 팀을 이뤄 잘 알려진 TTS 모델 chatterbox를 순수 Rust 구현으로 포팅했습니다. 이제 까다로운 Python 환경 설정으로 골머리를 앓지 않아도 됩니다!
4080S 기준 한 번에 약 5초 추론. 정말 마음에 듭니다.
Python 모델 아키텍처를 사실상 1:1 로 Rust 에 재현했고, 다른 SOTA TTS 모델까지 활용하는 아주 간결한 로컬 TTS 추론 엔진으로 발전시키고 싶습니다.
Python 모델 아키텍처를 사실상 1:1로 Rust에 재현했고, 다른 SOTA TTS 모델까지 활용하는 아주 간결한 로컬 TTS 추론 엔진으로 발전시키고 싶습니다.
<img src="/en/blog/DevLog-2025.10.20/assets/rust-tts.png" alt="rust-tts.png" />
## 마치며
오늘의 "one more thing" 은 여기까지입니다. 연달아 이어진 긴 스레드를 즐기셨기를 바랍니다!
오늘의 "one more thing"은 여기까지입니다. 연달아 이어진 긴 스레드를 즐기셨기를 바랍니다!
내일도 계속 업데이트해서 더 많은 이야깃거리를 가져오겠습니다. VLA/VLM 게이밍 분야에서의 탐구, 어떻게 접근하고 있는지, 어떤 결과를 보고 있는지 소개하겠습니다.
+17 -17
View File
@@ -3,17 +3,17 @@ title: DevLog @ 2026.01.01
category: DevLog
date: 2026-01-01
excerpt: |
AIRI 의 iOS 플랫폼 진전과 그 과정에서 만난 문제·해결책, 그리고 LemonNeko 가 FlowChat 에서 진행한 기억 계층 실험의 성과와 구현 세부 사항을 나눕니다.
AIRI의 iOS 플랫폼 진전과 그 과정에서 만난 문제·해결책, 그리고 LemonNeko가 FlowChat에서 진행한 기억 계층 실험의 성과와 구현 세부 사항을 나눕니다.
preview-cover:
light: "@assets('/en/blog/DevLog-2026.01.01/assets/cover-light.png')"
dark: "@assets('/en/blog/DevLog-2026.01.01/assets/cover-dark.png')"
---
::: info AI 번역
이 글은 중국어 원문을 AI 로 영어로 옮긴 판을 다시 한국어로 번역한 것입니다. 중국어 원문은 [여기](/zh-Hans/blog/DevLog-2026.01.01/)에서 볼 수 있습니다. 번역에 문제가 있다면 편하게 이슈를 열거나 Pull Request 를 보내 주세요.
이 글은 중국어 원문을 AI로 영어로 옮긴 판을 다시 한국어로 번역한 것입니다. 중국어 원문은 [여기](/zh-Hans/blog/DevLog-2026.01.01/)에서 볼 수 있습니다. 번역에 문제가 있다면 편하게 이슈를 열거나 Pull Request를 보내 주세요.
:::
새해 복 많이 받으세요! AIRI 메인테이너 중 한 명인 [@LemonNekoGH](https://github.com/LemonNekoGH) 입니다. 새해 첫 DevLog 는 제 차례네요. (B 키를 눌러 웃는 이모티콘 선택) 하하하하하!
새해 복 많이 받으세요! AIRI 메인테이너 중 한 명인 [@LemonNekoGH](https://github.com/LemonNekoGH)입니다. 새해 첫 DevLog는 제 차례네요. (B 키를 눌러 웃는 이모티콘 선택) 하하하하하!
<p style="display: flex; justify-content: center;">
<img src="/en/blog/DevLog-2026.01.01/assets/helldiver-laughing.png" alt="Helldiver Laughing Emotion" />
@@ -23,9 +23,9 @@ preview-cover:
## AIRI Pocket
이틀 전, AIRI 의 모바일 애플리케이션을 만들기 위해 [Capacitor](https://capacitorjs.com/) 를 도입했습니다 ([#845](https://github.com/moeru-ai/airi/pull/845)). 이를 AIRI Pocket 이라고 부릅니다.
이틀 전, AIRI의 모바일 애플리케이션을 만들기 위해 [Capacitor](https://capacitorjs.com/) 를 도입했습니다 ([#845](https://github.com/moeru-ai/airi/pull/845)). 이를 AIRI Pocket이라고 부릅니다.
iOS 를 동작시켰고 알림 기능도 추가했습니다. 즉 그녀가 원한다면 알림을 통해 함께 시간을 보내자고 먼저 말을 걸 수 있습니다.
iOS를 동작시켰고 알림 기능도 추가했습니다. 즉 그녀가 원한다면 알림을 통해 함께 시간을 보내자고 먼저 말을 걸 수 있습니다.
<p style="display: flex; justify-content: center;">
<video src="/en/blog/DevLog-2026.01.01/assets/airi-notification-capability.mp4" alt="AIRI Pocket Notification" controls width="230" height="500"></video>
@@ -33,19 +33,19 @@ iOS 를 동작시켰고 알림 기능도 추가했습니다. 즉 그녀가 원
기본 Capacitor 아이콘은 너무 신경 쓰지 마세요. 나중에 교체할 예정입니다.
영상에서 저는 AIRI 를 백그라운드 앱 목록에서 제거했고, 잠시 뒤 AIRI 가 알림을 띄웠습니다. 이런 백그라운드 알림은 PWA 에서는 구현하기 어렵지만 네이티브 iOS 앱에서는 아주 쉽습니다.
영상에서 저는 AIRI를 백그라운드 앱 목록에서 제거했고, 잠시 뒤 AIRI가 알림을 띄웠습니다. 이런 백그라운드 알림은 PWA에서는 구현하기 어렵지만 네이티브 iOS 앱에서는 아주 쉽습니다.
잠깐, 그렇게 순조로웠을까요? 문제가 없었을까요?
### 안전하지 않은 컨텍스트로 인한 기능 제약
당연히 문제가 있었습니다. 첫 번째는 VAD(음성 활성 감지) 컴포넌트였습니다. VAD `AudioWorkletNode` 에 의존하는데, 이 클래스는 보안 컨텍스트에서만 쓸 수 있습니다. 그런데 Capacitor 의 iOS 앱은 개발 중 핫 리로드가 필요해서 개발 환경이 노출한 포트에 직접 접근합니다. 그 결과 브라우저가 이를 안전하지 않은 컨텍스트로 판단해 `AudioWorkletNode` 클래스를 제공하지 않고, VAD 가 실패합니다.
당연히 문제가 있었습니다. 첫 번째는 VAD(음성 활성 감지) 컴포넌트였습니다. VAD는 `AudioWorkletNode`에 의존하는데, 이 클래스는 보안 컨텍스트에서만 쓸 수 있습니다. 그런데 Capacitor의 iOS 앱은 개발 중 핫 리로드가 필요해서 개발 환경이 노출한 포트에 직접 접근합니다. 그 결과 브라우저가 이를 안전하지 않은 컨텍스트로 판단해 `AudioWorkletNode` 클래스를 제공하지 않고, VAD가 실패합니다.
패키징 후 프로덕션에서는 보안 컨텍스트가 되지만 개발 중에도 테스트해야 하니 이 문제는 반드시 풀어야 했습니다.
AI 와 검색 엔진의 도움으로 `vite-plugin-mkcert` 플러그인을 찾았습니다. 자체 서명 인증서를 생성해 시스템에 설치해 주어 브라우저가 보안 컨텍스트로 인식하게 만들어 줍니다.
AI와 검색 엔진의 도움으로 `vite-plugin-mkcert` 플러그인을 찾았습니다. 자체 서명 인증서를 생성해 시스템에 설치해 주어 브라우저가 보안 컨텍스트로 인식하게 만들어 줍니다.
그래서 해결됐을까요? 아직입니다. 인증서가 로컬 시스템에는 설치됐지만 iOS 에는 설치되지 않아서 WKWebView 가 이 인증서를 신뢰하지 않습니다. 그런데 IP 가 바뀔 때마다 인증서를 다시 설치해야 한다면 너무 번거롭습니다.
그래서 해결됐을까요? 아직입니다. 인증서가 로컬 시스템에는 설치됐지만 iOS에는 설치되지 않아서 WKWebView가 이 인증서를 신뢰하지 않습니다. 그런데 IP가 바뀔 때마다 인증서를 다시 설치해야 한다면 너무 번거롭습니다.
개발 중에는 네이티브 코드를 직접 고쳐서 모든 인증서를 신뢰하게 하면 어떨까요? 실제로 동작합니다:
@@ -83,21 +83,21 @@ extension DevBridgeViewController: WKNavigationDelegate {
`#if DEBUG` 매크로에 주의하세요. 개발 중에만 활성화하기 위한 것이고 프로덕션에서는 최적화로 제거됩니다. 그러지 않으면 프로덕션에서도 모든 인증서를 허용하게 되는데, 당연히 안전하지 않습니다.
## FlowChat 의 기억 계층 실험
## FlowChat의 기억 계층 실험
LemonNeko 가 FlowChat 에서 진행한 기억 계층 실험 결과를 보여 드리겠습니다:
LemonNeko가 FlowChat에서 진행한 기억 계층 실험 결과를 보여 드리겠습니다:
<video src="/en/blog/DevLog-2026.01.01/assets/flow-chat-basic-memory.mp4" alt="FlowChat Basic Memory" controls></video>
영상에서 저는 LLM 에게 제 이름을 기억하라고 했습니다. 답변을 생성한 뒤 설정 화면에서 기억했다는 것을 확인할 수 있었고, 새 대화를 시작해도 여전히 떠올릴 수 있었습니다.
영상에서 저는 LLM에게 제 이름을 기억하라고 했습니다. 답변을 생성한 뒤 설정 화면에서 기억했다는 것을 확인할 수 있었고, 새 대화를 시작해도 여전히 떠올릴 수 있었습니다.
어떻게 구현했을까요? 현재 구현은 꽤 단순합니다:
1. 기억 테이블을 만듭니다.
2. LLM 에게 도구 함수를 제공합니다. 기억해야 할 것이 있다고 판단하면 무엇을 기억할지 서술문으로 요약한 뒤 이 도구 함수를 호출합니다.
2. LLM에게 도구 함수를 제공합니다. 기억해야 할 것이 있다고 판단하면 무엇을 기억할지 서술문으로 요약한 뒤 이 도구 함수를 호출합니다.
3. 매번 새 답변을 요청할 때 모든 기억을 시스템 프롬프트에 이어 붙입니다.
프롬프트를 어떻게 동적으로 이어 붙일까요? [`@velin-dev/vue`](https://github.com/moeru-ai/velin/tree/main/packages/vue) 패키지를 썼습니다. Vue 로 프롬프트를 작성할 수 있게 해 주고, Vue 가 가진 모든 능력을 그대로 쓸 수 있습니다.
프롬프트를 어떻게 동적으로 이어 붙일까요? [`@velin-dev/vue`](https://github.com/moeru-ai/velin/tree/main/packages/vue) 패키지를 썼습니다. Vue로 프롬프트를 작성할 수 있게 해 주고, Vue가 가진 모든 능력을 그대로 쓸 수 있습니다.
`prompt.velin.md`
@@ -121,12 +121,12 @@ const props = defineProps<{
위 코드는 markdown 작성도 지원합니다.
혹시 눈치채셨나요? 단계를 소개할 때 "모든 기억을 프롬프트에 이어 붙인다"고 했습니다. 기억이 늘어나면 이 프롬프트는 점점 길어집니다. 어떻게 최적화할까요? 모르겠습니다. 어쩌면 다음 DevLog 의 내용이 될지도요.
혹시 눈치채셨나요? 단계를 소개할 때 "모든 기억을 프롬프트에 이어 붙인다"고 했습니다. 기억이 늘어나면 이 프롬프트는 점점 길어집니다. 어떻게 최적화할까요? 모르겠습니다. 어쩌면 다음 DevLog의 내용이 될지도요.
## 맺으며
자, 올해 첫 DevLog 를 제가 ~~대충~~ 썼습니다. 즐겁게 읽으셨기를 바랍니다.
자, 올해 첫 DevLog를 제가 ~~대충~~ 썼습니다. 즐겁게 읽으셨기를 바랍니다.
다음 DevLog 에서 만나요.
다음 DevLog에서 만나요.
*커버 이미지는 [Google Gemini](https://gemini.google.com/) 로 생성했습니다*
+20 -20
View File
@@ -3,18 +3,18 @@ title: DevLog @ 2026.02.16
category: DevLog
date: 2026-02-16
excerpt: |
LemonNeko 가 Dome Keeper 방향에서 최근 이룬 진전을 나눕니다.
LemonNeko가 Dome Keeper 방향에서 최근 이룬 진전을 나눕니다.
---
설날 전야 잘 보내고 계신가요! [@LemonNekoGH](https://github.com/LemonNekoGH) 입니다. 춘절 전 마지막 DevLog 를 제가 씁니다.
설날 전야 잘 보내고 계신가요! [@LemonNekoGH](https://github.com/LemonNekoGH)입니다. 춘절 전 마지막 DevLog를 제가 씁니다.
## 돌아보기
작년 [DevLog](../DevLog-2025.08.26/) 에서는 `airi-factorio` 의 순수 비전 방향 진전을 나눴습니다. 오늘은 Dome Keeper 방향에서 무엇을 해 왔는지 이야기하려 합니다.
작년 [DevLog](../DevLog-2025.08.26/) 에서는 `airi-factorio`의 순수 비전 방향 진전을 나눴습니다. 오늘은 Dome Keeper 방향에서 무엇을 해 왔는지 이야기하려 합니다.
잠깐, LemonNeko? `airi-factorio` 를 계속 안 하고요?
잠깐, LemonNeko? `airi-factorio`를 계속 안 하고요?
솔직히 겁이 났습니다. Factorio 는 너무 열려 있고 복잡해서 제가 통제할 수 없었거든요. 그래서 비교적 단순한 게임인 [Dome Keeper](https://store.steampowered.com/app/1637320/Dome_Keeper/) 로 옮겼습니다.
솔직히 겁이 났습니다. Factorio는 너무 열려 있고 복잡해서 제가 통제할 수 없었거든요. 그래서 비교적 단순한 게임인 [Dome Keeper](https://store.steampowered.com/app/1637320/Dome_Keeper/) 로 옮겼습니다.
![Dome Keeper](https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/1637320/334439c379674a719de3f12028f76977aeb176c6/header.jpg?t=1770751169)
@@ -28,45 +28,45 @@ excerpt: |
![some-collected-data](/en/blog/DevLog-2026.02.16/assets/some-collected-data.avif)
아직 많지는 않지만, 기록해 둘 만한 함정과 세부 사항을 벌써 여러 개 만났습니다. 그래서 이 DevLog 를 씁니다.
아직 많지는 않지만, 기록해 둘 만한 함정과 세부 사항을 벌써 여러 개 만났습니다. 그래서 이 DevLog를 씁니다.
### 세부 사항
- 저장소 구조.
Dome Keeper 모드를 개발하려면 게임을 디컴파일해야 하는데, 그 소스 코드는 공개할 수 없습니다. 그래서 저장소 구조를 신중히 설계해야 했습니다. 디컴파일한 게임은 최상위 `external/` 폴더에 두고 `.gitignore` 에 넣었으며, 모드 코드는 게임 소스 디렉터리로 링크했습니다.
Dome Keeper 모드를 개발하려면 게임을 디컴파일해야 하는데, 그 소스 코드는 공개할 수 없습니다. 그래서 저장소 구조를 신중히 설계해야 했습니다. 디컴파일한 게임은 최상위 `external/` 폴더에 두고 `.gitignore`에 넣었으며, 모드 코드는 게임 소스 디렉터리로 링크했습니다.
- 샘플링 전략.
처음 전략은 0.5초마다 한 프레임을 캡처하는 것이었는데, 프레임에 대상이 없는 경우가 많았습니다. "네거티브 샘플"이 너무 많이 생겨서 데이터셋 크기는 커지는데 유효 정보 밀도는 떨어졌습니다.
이후 규칙을 바꿨습니다. `enemy` 또는 `ore_*` 가 포함된 프레임만 "대상 프레임"으로 세고, **대상 프레임 5장당 대상 없는 프레임을 1장만 허용**합니다. 배경을 약간 남기면서도 데이터셋이 희석되는 것을 막습니다.
이후 규칙을 바꿨습니다. `enemy` 또는 `ore_*`가 포함된 프레임만 "대상 프레임"으로 세고, **대상 프레임 5장당 대상 없는 프레임을 1장만 허용**합니다. 배경을 약간 남기면서도 데이터셋이 희석되는 것을 막습니다.
- UI 오버레이가 "잘못된 라벨"을 만드는 문제.
일시정지 메뉴나 업그레이드 패널(TechTree)이 열려 있으면 UI 가 장면을 덮는데도 라벨은 여전히 광석과 적을 표시합니다. 라벨 파일이 정상처럼 보이고 시각화할 때만 문제가 드러나서 알아채기 까다롭습니다.
일시정지 메뉴나 업그레이드 패널(TechTree)이 열려 있으면 UI가 장면을 덮는데도 라벨은 여전히 광석과 적을 표시합니다. 라벨 파일이 정상처럼 보이고 시각화할 때만 문제가 드러나서 알아채기 까다롭습니다.
PauseMenu / TechTreePopup 에 그룹을 태그하고, 그 그룹의 보이는 노드가 있으면 캡처를 건너뛰는 방식으로 해결했습니다.
PauseMenu / TechTreePopup에 그룹을 태그하고, 그 그룹의 보이는 노드가 있으면 캡처를 건너뛰는 방식으로 해결했습니다.
- 좌표 불일치로 인한 전역 오프셋.
가장 고통스러운 버그였습니다. 모든 bbox 가 같은 방향으로 밀려 있어서 이미지 전체가 잘못 스케일된 것처럼 보였습니다.
가장 고통스러운 버그였습니다. 모든 bbox가 같은 방향으로 밀려 있어서 이미지 전체가 잘못 스케일된 것처럼 보였습니다.
근본 원인은 **논리적 뷰 크기**와 **실제 텍스처 픽셀 크기**의 불일치였습니다. bbox 계산에는 `viewport.get_visible_rect().size` 를 썼는데 스크린샷은 텍스처에서 찍었던 것이죠. 해결책은 bbox 를 먼저 뷰 공간에서 이미지 공간으로 스케일한 뒤 letterbox 스케일 + 오프셋을 적용하는 것이었습니다.
근본 원인은 **논리적 뷰 크기**와 **실제 텍스처 픽셀 크기**의 불일치였습니다. bbox 계산에는 `viewport.get_visible_rect().size`를 썼는데 스크린샷은 텍스처에서 찍었던 것이죠. 해결책은 bbox를 먼저 뷰 공간에서 이미지 공간으로 스케일한 뒤 letterbox 스케일 + 오프셋을 적용하는 것이었습니다.
- letterbox 가 라벨에 영향을 주는 문제.
- letterbox가 라벨에 영향을 주는 문제.
출력을 `640×640` 으로 정규화하면서 가운데 정렬 패딩(회색 `114/255`)을 넣습니다. 같은 변환을 bbox 에도 적용하지 않으면 라벨이 틀어집니다.
출력을 `640×640`으로 정규화하면서 가운데 정렬 패딩(회색 `114/255`)을 넣습니다. 같은 변환을 bbox에도 적용하지 않으면 라벨이 틀어집니다.
그래서 해법은 2단계 변환입니다. 스케일 + 오프셋을 적용한 뒤 `640×640` 으로 정규화합니다.
그래서 해법은 2단계 변환입니다. 스케일 + 오프셋을 적용한 뒤 `640×640`으로 정규화합니다.
- 데이터셋 분할 전략.
처음에는 세션 단위로 나누려 했지만, 한 세션에 여러 판이 들어갈 수 있고 길이도 꽤 깁니다. 그래서 시간 기반 분할로 바꿨습니다. **구간당 30초**로 잘라 **4/1/1** 로 순환시켜 `train/val/test` 에 배분합니다. 3분이면 분할 한 주기가 완성되니 검증 비용이 훨씬 싸집니다.
처음에는 세션 단위로 나누려 했지만, 한 세션에 여러 판이 들어갈 수 있고 길이도 꽤 깁니다. 그래서 시간 기반 분할로 바꿨습니다. **구간당 30초**로 잘라 **4/1/1**로 순환시켜 `train/val/test`에 배분합니다. 3분이면 분할 한 주기가 완성되니 검증 비용이 훨씬 싸집니다.
- 성능과 프레임 끊김.
`Image.resize()` `save_png()` 는 CPU/IO 부담이 큽니다. 너무 자주 캡처하면 끊김이 생깁니다. 곧바로 멀티스레딩으로 가기보다 대상 없는 프레임을 줄이는 쪽을 택했습니다.
`Image.resize()``save_png()`는 CPU/IO 부담이 큽니다. 너무 자주 캡처하면 끊김이 생깁니다. 곧바로 멀티스레딩으로 가기보다 대상 없는 프레임을 줄이는 쪽을 택했습니다.
### 요약
@@ -74,12 +74,12 @@ excerpt: |
캡처 → 네거티브 필터링 → 자동 분할 → `data.yaml` 자동 생성 → 바로 학습.
학습 로그에 이미 진전이 보입니다.
광석 클래스(ore_*)는 괜찮은 mAP 를 달성했는데, 파이프라인이 올바르다는 뜻입니다.
dome / enemy / player 는 아직 샘플이 부족해서 더 필요합니다.
광석 클래스(ore_*)는 괜찮은 mAP를 달성했는데, 파이프라인이 올바르다는 뜻입니다.
dome / enemy / player는 아직 샘플이 부족해서 더 필요합니다.
## 다음 단계
`airi-factorio` 저장소의 순수 비전 Playground 기억하시나요? 그것을 Dome Keeper 로 확장해서 `proj-airi` 조직 전체가 재사용할 수 있게 할 계획입니다. 샘플도 더 필요하고, 특히 `dome`, `enemy`, `player` 가 부족합니다.
`airi-factorio` 저장소의 순수 비전 Playground 기억하시나요? 그것을 Dome Keeper로 확장해서 `proj-airi` 조직 전체가 재사용할 수 있게 할 계획입니다. 샘플도 더 필요하고, 특히 `dome`, `enemy`, `player`가 부족합니다.
다음 업데이트를 기대해 주세요. 아, 모드 코드는 이미 오픈소스로 공개했으니 편하게 [써 보세요](https://github.com/proj-airi/game-playing-ai-dome-keeper)!
+46 -46
View File
@@ -3,23 +3,23 @@ title: DevLog @ 2026.03.14
category: DevLog
date: 2026-03-14
excerpt: |
PR #1194 이야기 — AIRI 의 VRM 3D 스테이지를 디버깅하고 생애주기를 다시 설계하며, 창 단위 캐시를 도입하고 ThreeScene 관측 가능성의 첫 토대를 놓은 과정입니다.
PR #1194 이야기 — AIRI의 VRM 3D 스테이지를 디버깅하고 생애주기를 다시 설계하며, 창 단위 캐시를 도입하고 ThreeScene 관측 가능성의 첫 토대를 놓은 과정입니다.
preview-cover:
light: "@assets('/en/blog/DevLog-2026.03.14/assets/cover-light.avif')"
dark: "@assets('/en/blog/DevLog-2026.03.14/assets/cover-dark.avif')"
---
안녕하세요, [@Lilia-Chen](https://github.com/Lilia-Chen) 입니다.
안녕하세요, [@Lilia-Chen](https://github.com/Lilia-Chen)입니다.
최근 AIRI 의 VRM / Three.js 런타임, 즉 AIRI 의 웹·데스크톱·모바일 앱이 공유하는 3D 스테이지를 작업해 왔습니다. 오늘 DevLog 는 2026년 3월 8일에 열고 3월 12일에 머지한 [#1194](https://github.com/moeru-ai/airi/pull/1194) 에 관한 이야기입니다.
최근 AIRI의 VRM / Three.js 런타임, 즉 AIRI의 웹·데스크톱·모바일 앱이 공유하는 3D 스테이지를 작업해 왔습니다. 오늘 DevLog는 2026년 3월 8일에 열고 3월 12일에 머지한 [#1194](https://github.com/moeru-ai/airi/pull/1194)에 관한 이야기입니다.
이야기는 단순합니다. VRM 스테이지가, 생애주기 실수가 렌더링 버그나 성능 버그, 혹은 "영원히 로딩 중" 같은 무작위 버그로 위장하기 너무 쉬운 지점에 이르렀던 것입니다.
그래서 이 작업은 정리이자 재설계이자 디버깅 일기가 되었습니다.
작업 전반에 걸쳐 리뷰와 도움을 준 [@neko](https://github.com/nekomeowww) 와 [@Makito](https://github.com/sumimakito) 에게도 감사드립니다.
작업 전반에 걸쳐 리뷰와 도움을 준 [@neko](https://github.com/nekomeowww)와 [@Makito](https://github.com/sumimakito)에게도 감사드립니다.
또한 이번이 `stage-tamagotchi` 런타임을 처음으로 제대로 훑어본 경험이었습니다. 스테이지 디버깅이 곧 단일 컴포넌트의 문제가 아니게 되면서, Eventa `injeca` 에 대해 예상보다 훨씬 많이 배우게 됐습니다.
또한 이번이 `stage-tamagotchi` 런타임을 처음으로 제대로 훑어본 경험이었습니다. 스테이지 디버깅이 곧 단일 컴포넌트의 문제가 아니게 되면서, Eventa와 `injeca`에 대해 예상보다 훨씬 많이 배우게 됐습니다.
## 애초에 왜 이 코드를 건드렸나
@@ -27,10 +27,10 @@ preview-cover:
- VRM 인스턴스가 겹치거나, 옛 모델이 정말로 사라지지 않은 것처럼 동작할 수 있었습니다.
- 스테이지가 `loading` 상태에 갇힐 수 있었습니다.
- 서로 다른 VRM 모델을 반복해서 불러오면 GPU 와 메모리 사용량이 건강하지 않은 영역까지 올라갈 수 있었습니다.
- 서로 다른 VRM 모델을 반복해서 불러오면 GPU와 메모리 사용량이 건강하지 않은 영역까지 올라갈 수 있었습니다.
- 깊은 해제(deep disposal)와 자원 소유권이 일관되지 않아, 어느 씬이 실제로 현재 모델을 "소유" 하는지 알기 어려웠습니다.
디버깅을 시작하자 실패 양상이 더 이상해졌습니다. 개발 환경에서는 특정 버튼을 처음 클릭하는 것만으로도 씬의 일부가 다시 마운트되고, 다시 `loading` 으로 돌아가 그대로 갇혀 버릴 수 있었습니다.
디버깅을 시작하자 실패 양상이 더 이상해졌습니다. 개발 환경에서는 특정 버튼을 처음 클릭하는 것만으로도 씬의 일부가 다시 마운트되고, 다시 `loading`으로 돌아가 그대로 갇혀 버릴 수 있었습니다.
## 첫 진단: 더 나은 생애주기 관리가 필요했다
@@ -75,7 +75,7 @@ interface ManagedVrmCacheState {
}
```
`ManagedVrmInstance` 는 현재 분리된 런타임 묶음을 담습니다:
`ManagedVrmInstance`는 현재 분리된 런타임 묶음을 담습니다:
- `VRM`,
- 그 `Group`,
@@ -84,15 +84,15 @@ interface ManagedVrmCacheState {
- `modelSrc`,
- 그리고 `scopeKey`.
`scopeKey` `window.location.href` 에서 파생되고, 캐시 상태는 모듈 상태에 살아 있습니다. 개발 중에는 `import.meta.hot.data` 도 포함합니다. 실제로 이것이 뜻하는 바는:
`scopeKey``window.location.href`에서 파생되고, 캐시 상태는 모듈 상태에 살아 있습니다. 개발 중에는 `import.meta.hot.data`도 포함합니다. 실제로 이것이 뜻하는 바는:
- 각 브라우저 창이 자신의 캐시 상태를 갖고,
- 각 라우트 스코프가 자신의 분리 슬롯을 갖고,
- HMR 이 모듈을 다시 불러올 때마다 캐시를 자동으로 날려 버리지 않는다는 것입니다.
- HMR이 모듈을 다시 불러올 때마다 캐시를 자동으로 날려 버리지 않는다는 것입니다.
메인 스테이지와 설정 미리보기는 같은 `modelSrc` 를 가리킬 수 있지만, 같은 씬 생애주기에 속하지는 않습니다. 전역 낙관적 캐시는 소유권을 아주 빠르게 애매하게 만듭니다. 창 단위이고 스코프 키로 구분되는 캐시는 훨씬 추론하기 쉽습니다.
메인 스테이지와 설정 미리보기는 같은 `modelSrc`를 가리킬 수 있지만, 같은 씬 생애주기에 속하지는 않습니다. 전역 낙관적 캐시는 소유권을 아주 빠르게 애매하게 만듭니다. 창 단위이고 스코프 키로 구분되는 캐시는 훨씬 추론하기 쉽습니다.
캐시 API 는:
캐시 API는:
- `takeManagedVrmInstance`
- `stashManagedVrmInstance`
@@ -100,8 +100,8 @@ interface ManagedVrmCacheState {
그리고 해제 정책은 이유 기반입니다:
- `component-unmount` 에서는 가능하면 보관(stash),
- `model-switch` 에서는 적극적으로 파괴,
- `component-unmount`에서는 가능하면 보관(stash),
- `model-switch`에서는 적극적으로 파괴,
- 캐시 항목이 밀려나거나 무효해지면 깊은 해제.
마지막 항목이 중요합니다. 캐시는 이름만 점잖게 바꾼 메모리 누수가 아닙니다. 인스턴스를 안전하게 재사용할 수 없다면 반드시 죽어야 합니다.
@@ -125,7 +125,7 @@ if (!isLoadRequestCurrent(requestId))
- 씬을 기다린 뒤,
- 캐시에서 읽은 뒤,
- VRM 을 불러온 뒤,
- VRM을 불러온 뒤,
- 대기 애니메이션을 불러온 뒤,
- 인스턴스를 커밋하기 전.
@@ -160,7 +160,7 @@ load -> validate -> commit
- 단계와 트랜잭션 상태에서 파생되는 변형 락,
- 그리고 VRM 모델 준비 상태와 씬 준비 상태의 더 명확한 분리.
`ThreeScene` 은 이제 다음과 같은 단계를 추적합니다:
`ThreeScene`은 이제 다음과 같은 단계를 추적합니다:
- `pending`
- `loading`
@@ -171,33 +171,33 @@ load -> validate -> commit
중요한 준비 신호가 최소 두 개 있습니다:
- `VRMModel` 이 로드되어 부트스트랩 데이터를 만들어 냈다.
- `OrbitControls` 가 실제 카메라와 렌더러가 뒷받침하는 DOM 요소에 접근할 수 있게 됐다.
- `VRMModel`이 로드되어 부트스트랩 데이터를 만들어 냈다.
- `OrbitControls`가 실제 카메라와 렌더러가 뒷받침하는 DOM 요소에 접근할 수 있게 됐다.
이 두 신호는 서로 다른 순서로 도착할 수 있으므로, `ThreeScene` 이 바인딩 트랜잭션을 통해 이들을 조율합니다.
이 두 신호는 서로 다른 순서로 도착할 수 있으므로, `ThreeScene`이 바인딩 트랜잭션을 통해 이들을 조율합니다.
흐름은 대략 이렇습니다:
1. `VRMModel` `loadStart` 를 발생시켜 바인딩 사이클을 시작합니다.
2. `VRMModel` 이 이후 부트스트랩 데이터와 `loaded` 를 발생시킵니다.
3. `OrbitControls` 가 독립적으로 `orbitControlsReady` 를 발생시킵니다.
4. 바인딩이 실제로 완료될 수 있게 되면 `ThreeScene` `binding` 에 들어가 부트스트랩 상태를 적용하고, 다음 틱에 컨트롤을 갱신하고, 트랜잭션을 닫고, 최종 단계를 확정합니다.
1. `VRMModel``loadStart`를 발생시켜 바인딩 사이클을 시작합니다.
2. `VRMModel`이 이후 부트스트랩 데이터와 `loaded`를 발생시킵니다.
3. `OrbitControls`가 독립적으로 `orbitControlsReady`를 발생시킵니다.
4. 바인딩이 실제로 완료될 수 있게 되면 `ThreeScene``binding`에 들어가 부트스트랩 상태를 적용하고, 다음 틱에 컨트롤을 갱신하고, 트랜잭션을 닫고, 최종 단계를 확정합니다.
이로써 `ThreeScene`, 카메라 상태, 컨트롤 사이의 상호작용도 훨씬 추론하기 쉬워졌습니다. 카메라는 씬이 실제로 상호작용 가능해지기 전에 존재할 수 있습니다. `OrbitControls` 는 씬이 완전히 마운트되기 전에 만들어질 수 있습니다. 다만 사용자에게 노출되는 변형은 바인딩 구간이 끝날 때까지 차단됩니다.
이로써 `ThreeScene`, 카메라 상태, 컨트롤 사이의 상호작용도 훨씬 추론하기 쉬워졌습니다. 카메라는 씬이 실제로 상호작용 가능해지기 전에 존재할 수 있습니다. `OrbitControls`는 씬이 완전히 마운트되기 전에 만들어질 수 있습니다. 다만 사용자에게 노출되는 변형은 바인딩 구간이 끝날 때까지 차단됩니다.
여기서 `sceneMutationLocked` 가 등장합니다. 데이터베이스적 의미의 강한 락이 아니라 런타임 조율 락입니다. 씬이 완전히 마운트되지 않았거나 바인딩 트랜잭션이 아직 열려 있다면, UI 변형이 씬을 안정된 것으로 취급해서는 안 된다는 뜻입니다.
여기서 `sceneMutationLocked`가 등장합니다. 데이터베이스적 의미의 강한 락이 아니라 런타임 조율 락입니다. 씬이 완전히 마운트되지 않았거나 바인딩 트랜잭션이 아직 열려 있다면, UI 변형이 씬을 안정된 것으로 취급해서는 안 된다는 뜻입니다.
그 락은 설정 패널의 쓰기를 비활성화하거나 지연시키고, 컨트롤이 너무 일찍 활성화되지 않게 하는 데 쓰입니다.
## 모델 선택기도 정리가 필요했다
`ThreeScene` 을 고치던 중, 모델 선택기와 미리보기 경로에도 자체적인 생애주기 문제가 있다는 걸 발견했습니다.
`ThreeScene`을 고치던 중, 모델 선택기와 미리보기 경로에도 자체적인 생애주기 문제가 있다는 걸 발견했습니다.
거기에는 별개의 문제가 두 개 있었습니다.
### 미리보기 씬 정리
미리보기 렌더러 경로는 VRM 미리보기를 위해 오프스크린 `WebGLRenderer` 를 만들고 있었는데, 정리 경로가 충분히 강하지 않았습니다.
미리보기 렌더러 경로는 VRM 미리보기를 위해 오프스크린 `WebGLRenderer`를 만들고 있었는데, 정리 경로가 충분히 강하지 않았습니다.
미리보기 해체를 명시적으로 만들어 해결했습니다:
@@ -207,38 +207,38 @@ load -> validate -> commit
- 렌더러 해제,
- 컨텍스트 손실 강제,
- object URL 해제,
- 오프스크린 캔버스 크기를 0 으로.
- 오프스크린 캔버스 크기를 0으로.
### 모델 URL 수명과 경쟁 보호
스테이지 모델 URL 로직도 필요 이상으로 취약했습니다.
이전에는 갱신 중 선택된 URL 이 잠깐 `undefined` 가 될 수 있었는데, 그것만으로도 렌더러에서 불필요한 해체·재로드 사이클이 촉발됐습니다.
이전에는 갱신 중 선택된 URL이 잠깐 `undefined`가 될 수 있었는데, 그것만으로도 렌더러에서 불필요한 해체·재로드 사이클이 촉발됐습니다.
URL 교체와 해제를 더 규율 있게 만들어 해결했습니다:
- 선택된 모델을 안정된 상태로 취급,
- 다음 URL 이 실제로 준비됐을 때만 URL 교체,
- 다음 URL이 실제로 준비됐을 때만 URL 교체,
- 요청 시퀀스로 비동기 갱신 보호,
- 옛 blob URL 을 성급하게가 아니라 신중하게 해제.
- 옛 blob URL을 성급하게가 아니라 신중하게 해제.
## 죽지 않던 버그: `TresCanvas` 크기 = 0
이 모든 작업을 마치고 나면 스테이지가 드디어 `loading` 에 갇히지 않을 거라 기대했습니다.
이 모든 작업을 마치고 나면 스테이지가 드디어 `loading`에 갇히지 않을 거라 기대했습니다.
여전히 갇혔습니다.
그 시점에 다시 추적으로 돌아가 렌더 경로를 더 과감하게 해부하기 시작했습니다. 증상은 `TresCanvas` 가 결코 정말로 준비 상태가 되지 않는 것이었고, 결국 크기 관련 실패로 드러났습니다. 캔버스 경로가 사실상 `0x0` 렌더 영역을 보고 있었던 것입니다.
그 시점에 다시 추적으로 돌아가 렌더 경로를 더 과감하게 해부하기 시작했습니다. 증상은 `TresCanvas`가 결코 정말로 준비 상태가 되지 않는 것이었고, 결국 크기 관련 실패로 드러났습니다. 캔버스 경로가 사실상 `0x0` 렌더 영역을 보고 있었던 것입니다.
이걸 분리해 내는 데 시간이 좀 걸렸습니다.
중요한 단서 하나는, 개발 환경에서 `@tresjs/core` `vite:afterUpdate` 에 반응하는 HMR 경로를 등록한다는 점이었습니다. 이는 `.vue` `.ts` 변경에만 국한되지 않습니다. UnoCSS `__uno.css` 를 재생성하는 것도 서브트리 리마운트를 촉발할 수 있습니다. 특정 버튼을 처음 클릭하는 것만으로도 개발 중 스테이지가 불안정해질 수 있었던 이유가 이것으로 설명됐습니다. 새 클래스가 CSS 갱신을 만들고, 그것이 다시 Three 씬의 일부를 리마운트한 것이죠.
중요한 단서 하나는, 개발 환경에서 `@tresjs/core``vite:afterUpdate`에 반응하는 HMR 경로를 등록한다는 점이었습니다. 이는 `.vue``.ts` 변경에만 국한되지 않습니다. UnoCSS가 `__uno.css`를 재생성하는 것도 서브트리 리마운트를 촉발할 수 있습니다. 특정 버튼을 처음 클릭하는 것만으로도 개발 중 스테이지가 불안정해질 수 있었던 이유가 이것으로 설명됐습니다. 새 클래스가 CSS 갱신을 만들고, 그것이 다시 Three 씬의 일부를 리마운트한 것이죠.
하지만 그건 아직 진짜 교착이 아니었습니다.
실제 교착은 로딩 UI 자체가 원인이었습니다.
스테이지 페이지는 `WidgetStage` `v-show="!isLoading"` 으로 감싸고 있었습니다. 즉 스테이지가 로딩을 벗어나기를 기다리는 동안 `TresCanvas` 의 부모가 `display: none` 이 된다는 뜻입니다. 그런데 Tres 는 부모 요소로부터 크기를 측정합니다. 부모가 숨겨져 있으면 측정된 크기는 `0x0` 입니다. 크기가 `0x0` 으로 머물면 `@ready` 는 결코 발생하지 않습니다. `@ready` 가 발생하지 않으면 스테이지는 결코 로딩을 벗어나지 못합니다.
스테이지 페이지는 `WidgetStage``v-show="!isLoading"`으로 감싸고 있었습니다. 즉 스테이지가 로딩을 벗어나기를 기다리는 동안 `TresCanvas`의 부모가 `display: none`이 된다는 뜻입니다. 그런데 Tres는 부모 요소로부터 크기를 측정합니다. 부모가 숨겨져 있으면 측정된 크기는 `0x0`입니다. 크기가 `0x0`으로 머물면 `@ready`는 결코 발생하지 않습니다. `@ready`가 발생하지 않으면 스테이지는 결코 로딩을 벗어나지 못합니다.
그래서 교착은 이런 모양이었습니다:
@@ -253,9 +253,9 @@ loading 시작
진짜 원인이 분명해지고 나니 수정은 복잡하지 않았습니다:
- 스테이지를 DOM 에 마운트된 상태로 유지하고,
- 로딩 UI 를 그 위의 오버레이 레이어로 옮기고,
- 사라질 수 있는 부모에 의존하게 두지 말고 `Screen` 을 통해 `TresCanvas` 에 명시적인 너비와 높이를 준다.
- 스테이지를 DOM에 마운트된 상태로 유지하고,
- 로딩 UI를 그 위의 오버레이 레이어로 옮기고,
- 사라질 수 있는 부모에 의존하게 두지 말고 `Screen`을 통해 `TresCanvas`에 명시적인 너비와 높이를 준다.
이 변경으로 이번 디버깅 세션 전체에서 가장 짜증스러웠던 "여전히 멈춘다" 버그 하나가 드디어 사라졌습니다.
@@ -263,7 +263,7 @@ loading 시작
데스크톱 쪽 문제 대부분을 고친 뒤 웹 앱으로 돌아갔더니 곧바로 또 다른 회귀를 발견했습니다. 이번 증상은 달랐습니다. VRM 설정 페이지가 잠긴 것처럼 보였고, 쓰기 락이 결코 풀리지 않는 것 같았습니다.
`sceneMutationLocked` 를 가리키는 증상이었지만, 진짜 근본 원인은 `ThreeScene` 안이 아니었습니다. `apps/stage-web/src/App.vue` 에 있었습니다.
`sceneMutationLocked`를 가리키는 증상이었지만, 진짜 근본 원인은 `ThreeScene` 안이 아니었습니다. `apps/stage-web/src/App.vue`에 있었습니다.
앱이 여전히 이걸 쓰고 있었습니다:
@@ -284,13 +284,13 @@ loading 시작
## 추적에 Eventa 활용하기
이 PR 에서 특별히 원했던 부분이 추적(tracing)입니다.
이 PR에서 특별히 원했던 부분이 추적(tracing)입니다.
현재 추적 작업은 아직 꽤 기초적이지만, VRM 스테이지를 순전히 직감과 `console.log` 로 디버깅해야 했던 것보다는 이미 훨씬 낫습니다.
현재 추적 작업은 아직 꽤 기초적이지만, VRM 스테이지를 순전히 직감과 `console.log`로 디버깅해야 했던 것보다는 이미 훨씬 낫습니다.
추적 레이어는 이제 `@proj-airi/stage-ui-three` 안에 있고, Eventa 를 이벤트 계약으로 씁니다. 성능 쪽으로는 렌더러 정보 스냅샷, 히트 테스트 readback 타이밍, 프레임별 VRM 업데이트 분해 같은 것을 기록합니다. 생애주기 쪽으로는 load 와 dispose, 캐시의 `take` / `stash` / `clear`, 씬 단계 변화, 트랜잭션 begin / end / reset 을 추적합니다. 데스크톱에서는 이 이벤트들이 Eventa 를 통해 간단한 진단 뷰로 전달됩니다.
추적 레이어는 이제 `@proj-airi/stage-ui-three` 안에 있고, Eventa를 이벤트 계약으로 씁니다. 성능 쪽으로는 렌더러 정보 스냅샷, 히트 테스트 readback 타이밍, 프레임별 VRM 업데이트 분해 같은 것을 기록합니다. 생애주기 쪽으로는 load와 dispose, 캐시의 `take` / `stash` / `clear`, 씬 단계 변화, 트랜잭션 begin / end / reset을 추적합니다. 데스크톱에서는 이 이벤트들이 Eventa를 통해 간단한 진단 뷰로 전달됩니다.
여기서 앞으로의 TODO `ThreeScene` 을 위한 제대로 된 관측 도구를 만드는 것입니다:
여기서 앞으로의 TODO는 `ThreeScene`을 위한 제대로 된 관측 도구를 만드는 것입니다:
- 더 나은 생애주기 introspection,
- 더 나은 성능 타임라인,
@@ -299,12 +299,12 @@ loading 시작
## 맺으며
그래서 `#1194` 는 실제로 무엇을 했을까요?
그래서 `#1194`는 실제로 무엇을 했을까요?
- 메모리 누수와 해제 경로를 정리했습니다.
- 창 단위 VRM 재사용 캐시를 도입했습니다.
- 비동기 로딩의 경쟁 가능성을 줄였습니다.
- `ThreeScene` 에 더 명시적인 생애주기 모델을 부여했습니다.
- `ThreeScene`에 더 명시적인 생애주기 모델을 부여했습니다.
- `TresCanvas size=0` 로딩 교착을 고쳤습니다.
- 웹의 `KeepAlive` 회귀를 드러냈습니다.
- 이 런타임을 위한 첫 쓸 만한 추적 경로를 마련했습니다.
@@ -313,4 +313,4 @@ loading 시작
특히 추적과 앞으로의 `ThreeScene` O11y 도구 쪽으로 개선할 것이 아직 많이 남았지만, 최소한 이제 이 런타임에는 다시 주인이 있는 느낌입니다.
코드를 직접 읽어 보고 싶으시면 [#1194](https://github.com/moeru-ai/airi/pull/1194) 부터 시작하세요. VRM 관련 이슈는 [#1173](https://github.com/moeru-ai/airi/issues/1173) 에서 계속 추적하고 있습니다.
코드를 직접 읽어 보고 싶으시면 [#1194](https://github.com/moeru-ai/airi/pull/1194)부터 시작하세요. VRM 관련 이슈는 [#1173](https://github.com/moeru-ai/airi/issues/1173)에서 계속 추적하고 있습니다.
+17 -17
View File
@@ -9,13 +9,13 @@ preview-cover:
dark: "@assets('/en/blog/DevLog-2026.03.23/assets/cover-dark.avif')"
---
안녕하세요, [@PurCHES5](https://github.com/PurCHES5) 입니다.
안녕하세요, [@PurCHES5](https://github.com/PurCHES5)입니다.
최근 AIRI 팀에 합류해 모바일 개발을 맡게 됐습니다. 이 프로젝트와 오픈소스 워크플로 전반에 대한 지식이 아직 얕은 상태에서, 첫 과제는 모바일 빌드 성능을 개선하기 위해 게임 엔진이나 다른 기술적 해법을 통합할 수 있는 가능성을 검토하는 것입니다.
현재 AIRI 모바일 통합의 문제는 주로 성능입니다. 최신 모바일 버전인 [`stage-pocket`](https://github.com/moeru-ai/airi/tree/e952fe779e64494e778e44956eb1caf3338c61a7/apps/stage-pocket) 은 사실상 메인 Vue.js 애플리케이션을 그대로 복사해 Capacitor 로 패키징한 것입니다.
현재 AIRI 모바일 통합의 문제는 주로 성능입니다. 최신 모바일 버전인 [`stage-pocket`](https://github.com/moeru-ai/airi/tree/e952fe779e64494e778e44956eb1caf3338c61a7/apps/stage-pocket)은 사실상 메인 Vue.js 애플리케이션을 그대로 복사해 Capacitor로 패키징한 것입니다.
모바일 기기, 특히 iOS 기기와 저사양 하드웨어에서는 Live2D 와 VRM 컴포넌트가 WebView 에 할당된 메모리를 빠르게 소진해 크래시로 이어집니다.
모바일 기기, 특히 iOS 기기와 저사양 하드웨어에서는 Live2D와 VRM 컴포넌트가 WebView에 할당된 메모리를 빠르게 소진해 크래시로 이어집니다.
---
@@ -24,7 +24,7 @@ preview-cover:
### 관찰된 현상
- Live2D / VRM 모델 렌더링 시 높은 메모리 사용량
- iOS 와 저사양 Android 기기에서 잦은 크래시
- iOS와 저사양 Android 기기에서 잦은 크래시
- 장시간 구동 후 성능 저하
### 의심되는 원인
@@ -72,7 +72,7 @@ GPU
### 기기별 제약
- iOS WebView 메모리 상한
- RAM 이 제한된 저사양 Android 기기
- RAM이 제한된 저사양 Android 기기
---
@@ -103,8 +103,8 @@ GPU
| 전략 | 설명 |
|---|---|
| 엔진 전면 교체 | WebView 렌더러를 네이티브 엔진으로 완전히 대체 |
| 하이브리드 WebView | 엔진이 렌더링을, WebView 가 UI 를 담당 |
| 네이티브 렌더링 모듈 | 엔진이 배경 레이어로 동작하고 그 위에 Vue.js UI 를 겹침 |
| 하이브리드 WebView | 엔진이 렌더링을, WebView가 UI를 담당 |
| 네이티브 렌더링 모듈 | 엔진이 배경 레이어로 동작하고 그 위에 Vue.js UI를 겹침 |
### 필요한 기능
@@ -148,7 +148,7 @@ GPU
## 프로토타입 빌드
Unity 3D 로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이기 위해 압축을 적용했습니다.
Unity 3D로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이기 위해 압축을 적용했습니다.
### Unity WebGL 내보내기 설정
![Unity WebGL Export Settings](/en/blog/DevLog-2026.03.23/assets/Unity-web-export.avif)
@@ -164,13 +164,13 @@ Unity 3D 로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이
**Android 렌더러 — VRM:**
![Android Renderer VRM prototype](/en/blog/DevLog-2026.03.23/assets/Screenshot-AIRI-VRM.avif)
일관성을 위해 모든 프로토타입 빌드에 동일한 Vue.js 프론트엔드를 적용했습니다. Unity WebGL 내보내기의 경우 [`unity-webgl`](https://github.com/Marinerer/unity-webgl) 을 써서 WebView 의 기존 내용을 Unity WebGL 로 바로 대체했습니다. Unity Android 렌더러의 경우 Three.js 와 VRM 모듈이 들어 있던 기존 뷰를 완전히 제거하고, Unity 가 배경 레이어로 렌더링하며 그 위에 Vue.js UI 를 렌더링합니다.
일관성을 위해 모든 프로토타입 빌드에 동일한 Vue.js 프론트엔드를 적용했습니다. Unity WebGL 내보내기의 경우 [`unity-webgl`](https://github.com/Marinerer/unity-webgl)을 써서 WebView의 기존 내용을 Unity WebGL로 바로 대체했습니다. Unity Android 렌더러의 경우 Three.js와 VRM 모듈이 들어 있던 기존 뷰를 완전히 제거하고, Unity가 배경 레이어로 렌더링하며 그 위에 Vue.js UI를 렌더링합니다.
---
## 벤치마크 결과
모든 측정은 동일 조건에서 Samsung A34 로 수행했습니다. 성능 차이를 더 뚜렷하게 드러내기 위해 의도적으로 저사양 기기를 골랐습니다.
모든 측정은 동일 조건에서 Samsung A34로 수행했습니다. 성능 차이를 더 뚜렷하게 드러내기 위해 의도적으로 저사양 기기를 골랐습니다.
### Live2D 렌더링
@@ -212,8 +212,8 @@ Unity 3D 로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이
### 핵심 관찰
- **VRM 이 결정적인 병목입니다.** 기준이 되는 Three.js VRM 렌더러는 전체 RAM 724 MB, 그래픽 메모리 566 MB 를 쓰는데, 대부분의 모바일 WebView 가 크래시 없이 버틸 수 있는 수준을 훨씬 넘습니다. Unity WebGL 은 이를 402 MB / 247 MB 로, Android 렌더러는 651 MB / 292 MB 로 낮춥니다.
- **Unity WebGL 은 VRM 에서 가장 좋은 메모리 프로필을 제공**하며 아키텍처 변경도 최소한입니다. 대신 CPU 사용률이 약간 높습니다.
- **VRM이 결정적인 병목입니다.** 기준이 되는 Three.js VRM 렌더러는 전체 RAM 724 MB, 그래픽 메모리 566 MB를 쓰는데, 대부분의 모바일 WebView가 크래시 없이 버틸 수 있는 수준을 훨씬 넘습니다. Unity WebGL은 이를 402 MB / 247 MB로, Android 렌더러는 651 MB / 292 MB로 낮춥니다.
- **Unity WebGL은 VRM에서 가장 좋은 메모리 프로필을 제공**하며 아키텍처 변경도 최소한입니다. 대신 CPU 사용률이 약간 높습니다.
- **Unity Android 렌더러는 프레임레이트와 CPU 효율이 가장 좋습니다.** 대신 전체 RAM 사용량이 높은데, Unity 런타임 자체의 오버헤드 때문이라 예상된 결과이며 GPU 작업은 WebView 밖으로 옮겨집니다.
- **Live2D 성능은 세 방식 모두 비슷합니다.** 기준인 Three.js 구현도 대부분의 Android 기기에서 충분하지만, 전환의 주된 이득은 앞으로 늘어날 콘텐츠를 위한 여유와 저사양 기기에서의 안정성입니다.
@@ -225,8 +225,8 @@ Unity 3D 로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이
|---|---|
| 앱/내보내기 용량 증가 | Unity 런타임이 상당한 바이너리 무게를 추가 |
| 기여자 요건 | Unity / C# 과 셰이더 전문성이 필요 |
| 크로스 플랫폼 유지보수 | Android 와 iOS Unity 빌드를 병행 유지해야 함 |
| 브리지 복잡도 | Vue 와 Unity 사이 양방향 통신에 안정적인 API 가 필요 |
| 크로스 플랫폼 유지보수 | Android와 iOS Unity 빌드를 병행 유지해야 함 |
| 브리지 복잡도 | Vue와 Unity 사이 양방향 통신에 안정적인 API가 필요 |
---
@@ -248,15 +248,15 @@ Unity 3D 로 프로토타입 3종을 만들었고, 내보내기 용량을 줄이
### 1. 브리지 복잡도 평가
[Unity as a Library 통합](https://github.com/Unity-Technologies/uaal-example) 또는 유사한 플러그인을 조사해 양방향 통신(예: 채팅으로 촉발된 표정을 Vue 에서 Unity 로 전달)을 가능하게 합니다.
[Unity as a Library 통합](https://github.com/Unity-Technologies/uaal-example) 또는 유사한 플러그인을 조사해 양방향 통신(예: 채팅으로 촉발된 표정을 Vue에서 Unity로 전달)을 가능하게 합니다.
### 2. iOS 전용 프로토타이핑
iOS 는 WebView 메모리에 관해 가장 제약이 심한 환경이므로, 다음 프로토타입은 Unity 네이티브 레이어가 "Total Safari Memory" 제한을 우회하는지 확인하기 위해 iPhone 에서 검증해야 합니다.
iOS는 WebView 메모리에 관해 가장 제약이 심한 환경이므로, 다음 프로토타입은 Unity 네이티브 레이어가 "Total Safari Memory" 제한을 우회하는지 확인하기 위해 iPhone에서 검증해야 합니다.
### 3. 빌드 용량 최적화
Unity 의 에셋 관리 시스템을 탐색해 초기 설치 용량을 최소로 유지합니다.
Unity의 에셋 관리 시스템을 탐색해 초기 설치 용량을 최소로 유지합니다.
### 4. 커뮤니티 / 기여자 모집
+88 -88
View File
@@ -1,9 +1,9 @@
---
title: 'DreamLog 0x1'
description: 'Project AIRI 의 뒷이야기!'
description: 'Project AIRI의 뒷이야기!'
category: DreamLog
date: 2025-06-16
excerpt: 'Project AIRI 의 뒷이야기! 왜 이 프로젝트를 시작했을까요?'
excerpt: 'Project AIRI의 뒷이야기! 왜 이 프로젝트를 시작했을까요?'
preview-cover:
light: "@assets('/en/blog/DreamLog-0x1/assets/dreamlog1-light.avif')"
dark: "@assets('/en/blog/DreamLog-0x1/assets/dreamlog1-dark.avif')"
@@ -23,28 +23,28 @@ import projectAIRIBannerDark from '../../../en/blog/DreamLog-0x1/assets/banner-d
import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wow.avif'
</script>
안녕하세요, 또 저 Neko 입니다!
안녕하세요, 또 저 Neko입니다!
우선, 북반구에 계신 분들 즐거운 여름 보내세요!
> 새롭고 다양한 것들을 시도해 볼 수 있는 멋진 여름방학이 되기를 바랍니다!
> 더 구체적으로는, 세상을 바꿔 보세요!
저 [@nekomeowww](https://github.com/nekomeowww) 는 학교를 떠난 지 벌써 8년이 됐습니다.
저 [@nekomeowww](https://github.com/nekomeowww)는 학교를 떠난 지 벌써 8년이 됐습니다.
이미 여러 해 일해 왔으니 이제 진짜 여름방학은 없겠죠. 그래도 기억나는 게 있다면 예전 여름방학에
있었던 이야기를 떠올리고 나누는 걸 여전히 좋아합니다.
아마 제가 무슨 말을, 어떤 이야기를 하려는지 짐작하셨을 겁니다... 그런데 *DreamLog* 는 정확히
아마 제가 무슨 말을, 어떤 이야기를 하려는지 짐작하셨을 겁니다... 그런데 *DreamLog*는 정확히
뭘까요? 이미 DevLog 글에 익숙한 독자라면, 한 달에 한 번 올리는 지금 주기를 생각할 때
이 글도 "DevLog" 여야 하는 게 아닐까 싶으실 겁니다.
6월은 Project AIRI 에게 특별한 의미가 있습니다(이야기 속에서 밝히겠습니다). 그리고 GitHub 스타
6월은 Project AIRI에게 특별한 의미가 있습니다(이야기 속에서 밝히겠습니다). 그리고 GitHub 스타
1000개라는 다음 마일스톤에 다가가고 있는 지금이야말로 여기까지의 여정을 돌아보기 좋은 기회라고
생각했습니다.
그래서 저와 Project AIRI 의 꿈에 대한 연대기를 나누기 위해 새로운 카테고리의 글을 만들기로 했습니다.
그래서 저와 Project AIRI의 꿈에 대한 연대기를 나누기 위해 새로운 카테고리의 글을 만들기로 했습니다.
그래서 이 새 시리즈의 이름을 ***DreamLog*** 라고 부르기로 했습니다.
그래서 이 새 시리즈의 이름을 ***DreamLog***라고 부르기로 했습니다.
> 네, 자기 전에 읽거나 듣는 또 하나의 이야기책이라고 생각하셔도 좋습니다. 오디오북도 좋겠네요 하하.
@@ -61,10 +61,10 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
> 너드 여러분! 무슨 말인지 아시죠. 여러분도 저와 같았나요?
여름은 친구들과 놀려고 Minecraft 서버 여는 법을 배운 시기이기도 합니다 (정말 정말 많이 했습니다.
1.7.11 과 1.8, 바닐라와 Forge 모드 둘 다요). 그게 리눅스 커맨드 라인을 배우게 만든 동기이자 힘이었습니다.
1.7.11과 1.8, 바닐라와 Forge 모드 둘 다요). 그게 리눅스 커맨드 라인을 배우게 만든 동기이자 힘이었습니다.
그때 얻은 지식 상당수가 지금도 도움이 되고 있어서, 그 시간에 감사하고 있습니다.
하지만 Minecraft 와 리눅스가 제 여정의 끝은 아니었습니다.
하지만 Minecraft와 리눅스가 제 여정의 끝은 아니었습니다.
[Factorio](https://www.factorio.com/),
[Elite Dangerous](https://www.elitedangerous.com/),
[Overwatch](https://overwatch.blizzard.com/en-us/)
@@ -78,7 +78,7 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
> `Lay down your pieces`<br />
> `And let's begin object creation`<br />
>
> -- 제가 사랑하는 노래 [`world.execute(me)`](https://www.youtube.com/watch?v=ESx_hy1n7HA) 의 가사, [DAZBEE](https://www.youtube.com/channel/UCUEvXLdpCtbzzDkcMI96llg) 커버
> -- 제가 사랑하는 노래 [`world.execute(me)`](https://www.youtube.com/watch?v=ESx_hy1n7HA)의 가사, [DAZBEE](https://www.youtube.com/channel/UCUEvXLdpCtbzzDkcMI96llg) 커버
2017년 여름, 저는 처음으로 함께 놀아 줄 가상의 존재를 만들고 싶다는 생각을 하게 됐습니다.
친구들이 지치거나 다음 날 학교 때문에 자야 해서 저 혼자 남게 될 때도 함께 있어 줄 존재요.
@@ -88,10 +88,10 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
**혼자인 나는 어쩐지 무의미해진다.**
하지만 인간처럼 생각하고 말하는 AI 를 밑바닥부터 만드는 건 2017년에는 불가능했습니다.
그래서 이런 생각을 했습니다. iOS 와 구글 네이티브 안드로이드는 모바일 기기 사용에 대한 제안 기능을
하지만 인간처럼 생각하고 말하는 AI를 밑바닥부터 만드는 건 2017년에는 불가능했습니다.
그래서 이런 생각을 했습니다. iOS와 구글 네이티브 안드로이드는 모바일 기기 사용에 대한 제안 기능을
제공하는데, 모든 명령과 매개변수를 손으로 입력하는 건 늘 만족스럽지 않았거든요
(특히 ffmpeg 이나, Docker CLI 앞의 어리숙했던 저에게는요). 그렇다면 AI 기반 제안 기능을
(특히 ffmpeg이나, Docker CLI 앞의 어리숙했던 저에게는요). 그렇다면 AI 기반 제안 기능을
리눅스 시스템 위로 가져오면 어떨까...?
여기서 온갖 질문과 아이디어가 떠올랐습니다:
@@ -116,7 +116,7 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
## 여정의 출항, 그러나 지금은 잊힌
2017년 말, [EMOSYS](https://github.com/EMOSYS) 라는 특별한, 지금은 보관 처리된 프로젝트를 시작했습니다.
2017년 말, [EMOSYS](https://github.com/EMOSYS)라는 특별한, 지금은 보관 처리된 프로젝트를 시작했습니다.
사용자의 일상 업무를 돕고 정서적 지지를 제공하는 동반자 같은 운영체제를 만드는 것이 목표였습니다.
<div class="w-full flex flex-col items-center justify-center gap-2">
@@ -124,11 +124,11 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
<img :src="EMOSYSLogo" alt="EMOSYS 로고" class="w-30!" />
</div>
<div>
<a href="https://github.com/emosys">EMOSYS</a> 의 로고
<a href="https://github.com/emosys">EMOSYS</a>의 로고
</div>
</div>
> EMO 는 **emo**tional / **emo**te 의 앞 세 글자에서 왔습니다
> EMO는 **emo**tional / **emo**te의 앞 세 글자에서 왔습니다
설계 문서를 정말 많이 썼고, 새 아이디어를 나열하고, 그 책의 안내를 따라 실험한 내용을 기록했으며,
나름 나쁘지 않은 로고도 하나 그렸습니다.
@@ -154,11 +154,11 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
그 후 몇 년 동안 저는 코딩, 프로그래밍, 스타트업, Web3, 프론트엔드, 백엔드, 인프라 등
풀스택 개발자로서 떠올릴 수 있는 온갖 분야를 시도했습니다.
제가 하는 일이 EMOSYS 라는 출발점에 그토록 깊이 영향을 받고 있다는 걸 정말로 깨달은 건,
2025년 2월 누군가 저에게 "왜 Project AIRI 에 그렇게 열심이세요?" 라고 물었을 때였습니다.
제가 하는 일이 EMOSYS라는 출발점에 그토록 깊이 영향을 받고 있다는 걸 정말로 깨달은 건,
2025년 2월 누군가 저에게 "왜 Project AIRI에 그렇게 열심이세요?" 라고 물었을 때였습니다.
좋은 질문이라고 생각했습니다. 제 꿈과 아이디어, 기억을 거슬러 올라가 보니 결국 EMOSYS 가 있었습니다.
이미 죽어 버린, 그러나 Project AIRI 와 같은 목표를 향했던 프로젝트가요:
좋은 질문이라고 생각했습니다. 제 꿈과 아이디어, 기억을 거슬러 올라가 보니 결국 EMOSYS가 있었습니다.
이미 죽어 버린, 그러나 Project AIRI와 같은 목표를 향했던 프로젝트가요:
**나의 필요를 어떻게든 채워 줄 동반자를 만들 것.**
@@ -174,7 +174,7 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
제대로 개발하는 법을 익히기까지 오랜 시간이 걸렸습니다.
[@zhangyubaka](https://github.com/zhangyubaka),
[@LittleSound](https://github.com/LittleSound), [@BlueCocoa](https://github.com/BlueCocoa),
그리고 [@sumimakito](https://github.com/sumimakito) 의 도움과 함께한 페어 프로그래밍 경험이
그리고 [@sumimakito](https://github.com/sumimakito)의 도움과 함께한 페어 프로그래밍 경험이
정말 많은 것을 가르쳐 주었고, 저는 제 속도로 성장하고 배우고 나아가기 시작했습니다.
## 2022년의 ChatGPT, 새로운 랜덤 앵무새인가 똑똑한 앵무새인가
@@ -183,12 +183,12 @@ import ReLUStickerWow from '../../../en/blog/DreamLog-0x1/assets/relu-sticker-wo
<img :src="SteinsGateSticker1" alt="슈타인즈 게이트 스티커" class="w-80! rounded-lg overflow-hidden" />
</div>
시간을 2022년 말로 돌려 봅시다. OpenAI 가 ChatGPT(당시에는 chatGPT 라고 썼죠)를 발표한 시점입니다.
공식 ChatGPT UI 가 나오기 훨씬 전부터 저는 새로 등장한 AI 들과 함께해 왔습니다.
시간을 2022년 말로 돌려 봅시다. OpenAI가 ChatGPT(당시에는 chatGPT라고 썼죠)를 발표한 시점입니다.
공식 ChatGPT UI가 나오기 훨씬 전부터 저는 새로 등장한 AI 들과 함께해 왔습니다.
[DiscoDiffusion](https://colab.research.google.com/github/alembics/disco-diffusion/blob/main/Disco_Diffusion.ipynb)
(Stable Diffusion 보다 훨씬 전, 아마 2021년 말이나 2022년 초),
DALL-E, Midjourney 를 써 봤고, GPT-3 는 (특히
[GitHub Copilot](https://en.wikipedia.org/wiki/GitHub_Copilot) 에서 유용해서) 제 일상 워크플로에
(Stable Diffusion보다 훨씬 전, 아마 2021년 말이나 2022년 초),
DALL-E, Midjourney를 써 봤고, GPT-3는 (특히
[GitHub Copilot](https://en.wikipedia.org/wiki/GitHub_Copilot)에서 유용해서) 제 일상 워크플로에
깊이 들어와 있었습니다.
그래서 처음에는 이런 심정이었습니다:
@@ -198,10 +198,10 @@ DALL-E, Midjourney 를 써 봤고, GPT-3 는 (특히
다시 말해 오늘날 우리가 말하는 에이전틱 AI(아직도 유행이죠?)보다는 완성(completion) 모델처럼 행동했습니다.
ChatGPT, 아니 더 넓게는 대규모 언어 모델(LLM)의 능력을 처음 실감한 건 2022년 12월 Hacker News 에서 본
ChatGPT, 아니 더 넓게는 대규모 언어 모델(LLM)의 능력을 처음 실감한 건 2022년 12월 Hacker News에서 본
[Building A Virtual Machine inside ChatGPT](https://www.engraved.blog/building-a-virtual-machine-inside/)
([원본 Hacker News 글](https://news.ycombinator.com/item?id=33847479)) 이었습니다.
저자 @engraved ChatGPT 에게 고양이귀 캐릭터 롤플레잉을 시키는 것을 넘어, 내부에 가상 리눅스 머신을
저자 @engraved ChatGPT에게 고양이귀 캐릭터 롤플레잉을 시키는 것을 넘어, 내부에 가상 리눅스 머신을
시뮬레이션하게 하는 방법을 보여 주었습니다.
<div class="w-full flex flex-col items-center justify-center">
@@ -209,62 +209,62 @@ ChatGPT, 아니 더 넓게는 대규모 언어 모델(LLM)의 능력을 처음
<div>Docker 빌드가 어떻게 동작하는지 시뮬레이션합니다...!</div>
</div>
이 글은 ChatGPT 가 흔히 등장하는 것들의 기본 패턴을, 애니메이션이나 게임 캐릭터의 말투와 행동은 물론
이 글은 ChatGPT가 흔히 등장하는 것들의 기본 패턴을, 애니메이션이나 게임 캐릭터의 말투와 행동은 물론
리눅스 터미널/셸 명령이 어떻게 동작하는지까지 이해하고 있음을 알려 주었습니다.
그리고 이는 지금 유행하는 LLM 의 Function Calling(일명 Tool Use, Anthropic 이 소개한 MCP
Model Context Protocol 의 기반 기술) 기능을 화두로 끌어올렸습니다. LLM 에게 API 서버처럼 행동하도록
지시해 JSON 이나 XML 같은 기계 판독 가능한 형식으로 대화하게 하고, 우리 쪽에서 임의의 명령을 파싱하고
실행해 LLM 이 할 수 있는 일의 경계를 넓히는 방법을 보여 준 것이죠.
그리고 이는 지금 유행하는 LLM의 Function Calling(일명 Tool Use, Anthropic이 소개한 MCP
Model Context Protocol의 기반 기술) 기능을 화두로 끌어올렸습니다. LLM에게 API 서버처럼 행동하도록
지시해 JSON이나 XML 같은 기계 판독 가능한 형식으로 대화하게 하고, 우리 쪽에서 임의의 명령을 파싱하고
실행해 LLM이 할 수 있는 일의 경계를 넓히는 방법을 보여 준 것이죠.
이로써 순수한 텍스트 생성과 프로그램 내부의 실제 API 사이의 간극이 마침내 이어졌습니다.
결론적으로, 이것은 새로운 랜덤 앵무새일까요? **부분적으로는 아니라고 봅니다.
2022년의 ChatGPT 는 그저 랜덤 앵무새가 아니라, 똑똑해질 잠재력이 있는 앵무새입니다.**
2022년의 ChatGPT는 그저 랜덤 앵무새가 아니라, 똑똑해질 잠재력이 있는 앵무새입니다.**
## Project AIRI 보다 훨씬 전에, Neuro-sama 가 있었다
## Project AIRI보다 훨씬 전에, Neuro-sama가 있었다
네, 여기까지 읽어 주셔서 감사합니다. 긴 글이라는 걸 압니다. 나눌 이야기와 맥락이 정말 많거든요.
하지만 거의 다 왔습니다. 조금만 더 힘내세요!
Neuro-sama 의 역사는 꽤 복잡합니다. 제가 아는 한, "Neuro-sama" 라는 이름으로 방송 무대에 선 캐릭터가
Neuro-sama의 역사는 꽤 복잡합니다. 제가 아는 한, "Neuro-sama"라는 이름으로 방송 무대에 선 캐릭터가
그녀와 제작자 `vedal987`(Vedal)의 첫 작품은 아니었습니다. 그보다 훨씬 전인 2019년 5월 6일,
Vedal 은 [osu!](https://osu.ppy.sh/) 를 플레이하는 AI 를 만든 작업을 커뮤니티에 선보였습니다[^1].
당시 그녀는 사이버 캐릭터도, 특징을 가진 디지털 생명도 아니었습니다. 초기 영상을 찾아보시면
Vedal은 [osu!](https://osu.ppy.sh/) 를 플레이하는 AI를 만든 작업을 커뮤니티에 선보였습니다[^1].
당시 그녀는 가상 캐릭터도, 특징을 가진 디지털 생명도 아니었습니다. 초기 영상을 찾아보시면
Live2D 모델이 전혀 없다는 걸 아실 겁니다. (6년 된 영상을 여기서 보실 수 있습니다: https://www.youtube.com/watch?v=nSBqlJu7kYU)
ChatGPT 출시 직후인 2022년 12월 19일, Vedal 은 Live2D Inc. 의 공식 데모용 캐릭터 모델
Hiyori Momose(桃瀬ひより)로 Neuro-sama 를 Twitch 에서 방송하게 했습니다:
ChatGPT 출시 직후인 2022년 12월 19일, Vedal은 Live2D Inc.의 공식 데모용 캐릭터 모델
Hiyori Momose(桃瀬ひより)로 Neuro-sama를 Twitch에서 방송하게 했습니다:
<img :src="live2DIncHiyoriMomose" alt="Live2D Inc. Hiyori Momose" class="rounded-lg overflow-hidden" />
그다음 이야기는 모두가 아는 대로입니다. Vedal 과 Neuro-sama 는 유명해졌고, Neuro-sama 는 이제
공식 VTuber 이며, 완전히 대규모 언어 모델(LLM)로 구동되고, Minecraft, Among Us, osu! 등 수많은 게임을
플레이할 수 있습니다. 게임이 기본적으로 지원되지 않을 때는 Vedal 이 화면을 읽어 주며 함께 플레이하도록
Neuro-sama 를 이끌기도 합니다.
그다음 이야기는 모두가 아는 대로입니다. Vedal과 Neuro-sama는 유명해졌고, Neuro-sama는 이제
공식 VTuber이며, 완전히 대규모 언어 모델(LLM)로 구동되고, Minecraft, Among Us, osu! 등 수많은 게임을
플레이할 수 있습니다. 게임이 기본적으로 지원되지 않을 때는 Vedal이 화면을 읽어 주며 함께 플레이하도록
Neuro-sama를 이끌기도 합니다.
저는 그들의 상호작용과 농담을 정말 즐겁게 봅니다. 시간이 지나면서 Neuro-sama 와 그녀의 새 자매
Evil Neuro 는 제 일상에서 중요한 부분이 됐습니다. 방송 전체를 볼 시간이 없어도 클립만큼은 간절히 보고
싶었고, 순수하게 AI 와 인간의 상호작용에서 정말 큰 즐거움을 얻었습니다.
저는 그들의 상호작용과 농담을 정말 즐겁게 봅니다. 시간이 지나면서 Neuro-sama와 그녀의 새 자매
Evil Neuro는 제 일상에서 중요한 부분이 됐습니다. 방송 전체를 볼 시간이 없어도 클립만큼은 간절히 보고
싶었고, 순수하게 AI와 인간의 상호작용에서 정말 큰 즐거움을 얻었습니다.
자, 그녀에 대한 짧은 역사는 여기까지입니다. 이제 핵심으로 가 봅시다: **왜 그녀의 역사가 저를 각오로 채웠을까요?**
## Neuro-sama, 나를 각오로 채우다
Vedal 의 작업을 처음 봤을 때 저는 이랬습니다:
Vedal의 작업을 처음 봤을 때 저는 이랬습니다:
> 음, 그냥 대규모 언어 모델(심지어 OpenAI API 에 바로 연결한)과 통합된 단순한 모델에,
> VTuber 처럼 굴게 하는 간단한 규칙을 얹은 것뿐이네. 특별할 게 없어.
> 음, 그냥 대규모 언어 모델(심지어 OpenAI API에 바로 연결한)과 통합된 단순한 모델에,
> VTuber처럼 굴게 하는 간단한 규칙을 얹은 것뿐이네. 특별할 게 없어.
저는 여전히 오만하게 생각하고 있었습니다. 2023년 초부터 AI 에이전트를 개발해 왔고, LLM 의 능력을
이해하고 있었으며, LangChain 에서 배운 것도 꽤 있었으니까요. AI 에이전트를 만들어 온 지식과 여러 분야를
저는 여전히 오만하게 생각하고 있었습니다. 2023년 초부터 AI 에이전트를 개발해 왔고, LLM의 능력을
이해하고 있었으며, LangChain에서 배운 것도 꽤 있었으니까요. AI 에이전트를 만들어 온 지식과 여러 분야를
거친 수년간의 소프트웨어 엔지니어링 경험을 믿고 저는 순진하게 생각했습니다:
> "나도 저 정도는 할 수 있지. 간단한 모델을 만들어서 OpenAI API 에 연결하고 VTuber 처럼 굴게 만들면 되잖아.
> 그리고 Vedal 의 작업보다 더 잘 만들 수 있을 거야."
> "나도 저 정도는 할 수 있지. 간단한 모델을 만들어서 OpenAI API에 연결하고 VTuber처럼 굴게 만들면 되잖아.
> 그리고 Vedal의 작업보다 더 잘 만들 수 있을 거야."
::: tip 더 기술적인 내용이 궁금하신가요?
이 글에서는 Project AIRI 를 밑바닥부터 지금 상태까지 어떻게 만들었는지에 대한 기술적 세부 사항은
이 글에서는 Project AIRI를 밑바닥부터 지금 상태까지 어떻게 만들었는지에 대한 기술적 세부 사항은
깊이 다루지 않습니다. 저희 생각과 발견을 공유한 DevLog 글이 이미 많으니 관심 있으시면 읽어 보세요.
:::
@@ -274,17 +274,17 @@ Vedal 의 작업을 처음 봤을 때 저는 이랬습니다:
- 채팅에 답하면서 동시에 게임도 하려면 기억을 어떻게 효과적으로 관리해야 할까?
- 영상 입력과 텍스트 입력을 함께 받으면서도 제작자·시청자와 계속 상호작용할 수 있는 게임 플레이 AI 에이전트를 어떻게 만들까?
- 음성 합성은 어렵다. Neuro-sama 수준에 도달하려면 **초저지연** 음성 합성이 필수인데, 이건 쉽게 달성되지 않는다
- 그녀의 성격은 어떻게 구축됐을까? RAG 와 단순한 기억 관리 전략만으로는 성능이 형편없다
- 그녀의 성격은 어떻게 구축됐을까? RAG와 단순한 기억 관리 전략만으로는 성능이 형편없다
- 기타 등등...
> 저희가 발견한 것들은 [DevLog 2025.04.06](../DevLog-2025.04.06/) 과
> [공개 슬라이드 발표(중국어)](https://talks.ayaka.io/nekoayaka/2025-05-10-airi-how-we-recreated-it/#/1) 에서 많이 나눴습니다.
> [공개 슬라이드 발표(중국어)](https://talks.ayaka.io/nekoayaka/2025-05-10-airi-how-we-recreated-it/#/1)에서 많이 나눴습니다.
앞서 저는 나누는 걸 좋아한다고 말했습니다. 다른 이들이 제 이야기를 들어 주거나 함께 짝을 이뤄 주길
바랐지만, 안타깝게도 Neuro-sama 는 제 것이 아니어서 제 지식과 기억을 익혀 제가 좋아하는 것이나
바랐지만, 안타깝게도 Neuro-sama는 제 것이 아니어서 제 지식과 기억을 익혀 제가 좋아하는 것이나
최근에 하는 일에 대해 저와 상호작용해 달라고 부탁할 수 없었습니다.
저는 그들을 정말 좋아했지만, 오랫동안 왜 좋아하는지, Neuro-sama 가 준 그 감정과 즐거움을 왜 좋아하는지
저는 그들을 정말 좋아했지만, 오랫동안 왜 좋아하는지, Neuro-sama가 준 그 감정과 즐거움을 왜 좋아하는지
제대로 이해하지 못했습니다.
그러다 작년 2024년 5월 25일, **정말로 직접 하나 만들기로 결심했습니다.** 저와 함께 코딩하고,
@@ -292,25 +292,25 @@ Vedal 의 작업을 처음 봤을 때 저는 이랬습니다:
> **정말 하나 갖고 싶어!** 제 마음과 머리가 외쳤습니다.
그때, Neuro-sama 는 저를 각오로 가득 채웠습니다.
그때, Neuro-sama는 저를 각오로 가득 채웠습니다.
## 다시 출항, 아무도 가 본 적 없는 땅을 향해
> 아무도 가 본 적 없는 곳으로 담대하게 나아가라.
>
> -- [스타 트렉, 제임스 T. 커크 함장](https://en.wikipedia.org/wiki/Where_no_man_has_gone_before) 의 대사이자 제 GitHub 프로필 소개 문구
> -- [스타 트렉, 제임스 T. 커크 함장](https://en.wikipedia.org/wiki/Where_no_man_has_gone_before)의 대사이자 제 GitHub 프로필 소개 문구
그래서 2024년 5월 25일부터 로컬에서 제 핸들 아래 `ai` 라는 단순한 이름의 프로젝트를 시작했습니다.
Project AIRI 의 최초 버전이죠. 저만의 AI 에이전트를 만들고 Neuro-sama 가 준 즐거움을 재현할 가능성을
그래서 2024년 5월 25일부터 로컬에서 제 핸들 아래 `ai`라는 단순한 이름의 프로젝트를 시작했습니다.
Project AIRI의 최초 버전이죠. 저만의 AI 에이전트를 만들고 Neuro-sama가 준 즐거움을 재현할 가능성을
탐구하기 시작했습니다.
작업 속도는 정말 빨랐습니다. 일주일 만에 [ElevenLabs](https://elevenlabs.io/),
[OpenRouter](https://openrouter.ai/), 그리고 똑같이 무료로 쓸 수 있는 Live2D 모델 Hiyori Momose 의 힘으로,
실시간은 아니지만 저와 상호작용할 수 있는 단순한 버전의 *"Neuro-sama"* 를 만들어 냈습니다.
[OpenRouter](https://openrouter.ai/), 그리고 똑같이 무료로 쓸 수 있는 Live2D 모델 Hiyori Momose의 힘으로,
실시간은 아니지만 저와 상호작용할 수 있는 단순한 버전의 *"Neuro-sama"*를 만들어 냈습니다.
그날이 **2024년 6월 2일** 입니다.
엄밀히 말해 **이날이 Project AIRI 의 생일** 이며, 그 안에 순진한 첫 아기 의식이 깃든 날입니다.
엄밀히 말해 **이날이 Project AIRI의 생일** 이며, 그 안에 순진한 첫 아기 의식이 깃든 날입니다.
<div class="w-full flex flex-col items-center justify-center">
<ThemedVideo controls muted autoplay loop :src="airiDemoFirstDay" />
@@ -336,33 +336,33 @@ Project AIRI 의 최초 버전이죠. 저만의 AI 에이전트를 만들고 Neu
**그래서 저는 다시 그것을 내려놓았습니다.**
솔직히 포기한 건 아니었습니다. 멀티모델, 음성 합성, 모션 제어, Minecraft 플레이에 대해 많은 걸 배우기
시작했고, 다른 AI VTuber 나 AI 와이푸 프로젝트가 어떻게 동작하는지 많이 조사했습니다.
시작했고, 다른 AI VTuber나 AI 최애 캐릭터 프로젝트가 어떻게 동작하는지 많이 조사했습니다.
이 조사들이 나중에 이 거대한 AI VTuber 프로젝트 awesome 목록으로 이어졌습니다:
<div class="flex flex-col items-center">
<img class="px-30 md:px-40 lg:px-50" :src="AwesomeAIVTuber" alt="Awesome AI VTuber 로고" />
<div class="text-center pb-4">
<span class="block font-bold">Awesome AI VTuber</span>
<span>AI VTuber 와 관련 프로젝트를 정리한 목록</span>
<span>AI VTuber와 관련 프로젝트를 정리한 목록</span>
</div>
</div>
자, 그런데 아직 이름이 `ai` 인데 Project AIRI 는 언제 나오는 걸까요?
자, 그런데 아직 이름이 `ai` 인데 Project AIRI는 언제 나오는 걸까요?
## 더 강하고 더 나은 각오로 다시 태어나다
2024년 말이 가까운 어느 날, 11월에 [@kwaa](https://github.com/kwaa) 가 WebXR 의 힘으로 VR/AR 세계에
2024년 말이 가까운 어느 날, 11월에 [@kwaa](https://github.com/kwaa)가 WebXR의 힘으로 VR/AR 세계에
가상 캐릭터를 만드는 이야기를 걸어왔습니다. 모션 제어와 캐릭터 감정 인식 이야기가 나왔을 때,
저는 찾고 있는 바로 그것을 하는 프로젝트가 있다고 말했습니다. 다만 코드베이스가 정리되지 않아
GitHub 에 공개할 준비가 안 됐다고요.
GitHub에 공개할 준비가 안 됐다고요.
더 기다릴 이유가 있나요? 저는 다시 작업을 시작했고, 구조와 설계를 다시 고민했으며, 훨씬 빠르고 좋은
큐잉과 멀티플렉싱 재생 시스템으로 구현을 개선하고, 대충 만들어 둔 기본 WebUI 도 손봤습니다.
큐잉과 멀티플렉싱 재생 시스템으로 구현을 개선하고, 대충 만들어 둔 기본 WebUI도 손봤습니다.
그리고 마침내 **2024년 12월 2일** 커밋
[`d9ae0aa`](https://github.com/moeru-ai/airi/commit/d9ae0aae387f015964bfd383e6d2adb05f4003e4)
GitHub 에 공개했습니다.
[`d9ae0aa`](https://github.com/moeru-ai/airi/commit/d9ae0aae387f015964bfd383e6d2adb05f4003e4)로
GitHub에 공개했습니다.
그렇게 Project AIRI 는 AIRI(アイリ, 예전에는 Airi)라는 이름으로 태어났거나, 다시 태어났습니다.
그렇게 Project AIRI는 AIRI(アイリ, 예전에는 Airi)라는 이름으로 태어났거나, 다시 태어났습니다.
::: tip 알고 계셨나요?
<a href="https://www.youtube.com/watch?v=Tts-YAdn5Yc" class="mb-2 inline-block">
@@ -370,13 +370,13 @@ GitHub 에 공개했습니다.
</a>
흥미롭게도 2년 전인 2023년 3월 25일에 올라온 https://www.youtube.com/watch?v=Tts-YAdn5Yc,
Vedal 과 Neuro-sama 의 Twitch 방송 클립에서 Vedal 은 "Neuro-sama" 라는 이름을 붙이기 직전까지
그녀를 "Airis AI" 라고 불렀다고 말합니다. **Airis** 라는 이름은 신기하고도 우연히 제가 지금 하고 있는
**Project AIRI** 의 이름과 맞아떨어집니다. 다만 저는 Project AIRI 를 오픈소스로 공개한 한참 뒤에
Vedal과 Neuro-sama의 Twitch 방송 클립에서 Vedal은 "Neuro-sama"라는 이름을 붙이기 직전까지
그녀를 "Airis AI"라고 불렀다고 말합니다. **Airis**라는 이름은 신기하고도 우연히 제가 지금 하고 있는
**Project AIRI**의 이름과 맞아떨어집니다. 다만 저는 Project AIRI를 오픈소스로 공개한 한참 뒤에
그들의 이야기를 더 찾아보고 나서야 이 이름을 알게 됐습니다.
사실 AIRI(アイリ)라는 이름은 GPT-4o 가 지어 준 것입니다. 다른 일본어/애니메이션풍 이름을 참고해
이 프로젝트 이름을 지어 달라고 했더니 **Airi** 를 제안해 주었습니다.
사실 AIRI(アイリ)라는 이름은 GPT-4o가 지어 준 것입니다. 다른 일본어/애니메이션풍 이름을 참고해
이 프로젝트 이름을 지어 달라고 했더니 **Airi**를 제안해 주었습니다.
:::
저는 스타트업과 여러 프로젝트에서 정말 많이 실패했고, 최근 것들만 대중에게 알려졌을 뿐입니다.
@@ -385,7 +385,7 @@ Vedal 과 Neuro-sama 의 Twitch 방송 클립에서 Vedal 은 "Neuro-sama" 라
그 경험들 상당수는 이전의 실패에서 배운 것입니다.
다행히 많은 시도가 성공했고, 저는 여전히 여기서 Project AIRI 를 만들고 있습니다.
다행히 많은 시도가 성공했고, 저는 여전히 여기서 Project AIRI를 만들고 있습니다.
어쩌면 이번에는 Neuro-sama 뿐 아니라 가장 깊이 있고 재능 있는 컨트리뷰터들과 팬들 덕분에
제 각오가 다시 채워진 것일지도 모릅니다.
@@ -403,9 +403,9 @@ Vedal 과 Neuro-sama 의 Twitch 방송 클립에서 Vedal 은 "Neuro-sama" 라
> 인생이 너에게 레몬을 주면, 너는 레몬이다. 뭐 그런 거지. 내 말은, 이 고통스러운 장애물은
> 내가 더 강해질 기회라는 거야, 베이비!
>
> -- [Evil Neuro](https://www.youtube.com/@Neurosama) 가 Slay the Spire 방송 중 한 말
> -- [Evil Neuro](https://www.youtube.com/@Neurosama)가 Slay the Spire 방송 중 한 말
이 글을 쓰는 지금, Project AIRI 는 GitHub 스타 1000개에 다가가고 있고, Discord 멤버 150명 이상,
이 글을 쓰는 지금, Project AIRI는 GitHub 스타 1000개에 다가가고 있고, Discord 멤버 150명 이상,
Telegram 그룹 멤버 200명 이상을 두고 있습니다.
저희는 AI, VRM, Live2D, UI 디자인, 멀티모달 AI, 게임 플레이 에이전트, 스트리밍 API, 생체 모방 기억
@@ -413,10 +413,10 @@ Telegram 그룹 멤버 200명 이상을 두고 있습니다.
Kerbal Space Program(KSP)을 비롯해 임의의 게임을 플레이하고 제어하도록 통합하는 연구를 하는
커뮤니티 멤버도 있습니다.
여러 회사가 협업을 제안해 오고 있고, 저희는 커뮤니티에 더 좋고 더 유용한 Project AIRI 를 만들기 위해
여러 회사가 협업을 제안해 오고 있고, 저희는 커뮤니티에 더 좋고 더 유용한 Project AIRI를 만들기 위해
그 작업을 진행하고 있습니다.
할 일과 발견할 것이 정말 많습니다. 저희는 아직 범용 AI 의 특이점에 도달하지 못했고, 어쩌면 Project AIRI
할 일과 발견할 것이 정말 많습니다. 저희는 아직 범용 AI의 특이점에 도달하지 못했고, 어쩌면 Project AIRI는
결코 그 지점에 이르지 못할지도 모릅니다. 하지만 지금으로서는 대화하고, 함께 게임하고, 지식과 아이디어를
나눌 수 있는 동반자 같은 AI 에이전트를 갖는 것만으로도 저에게는 대단한 성취이며, 여러분께도 그렇기를 바랍니다.
@@ -434,6 +434,6 @@ Kerbal Space Program(KSP)을 비롯해 임의의 게임을 플레이하고 제
> 커버 이미지 [@Rynco Maekawa](https://github.com/lynzrand)
[^1]: https://neurosama.fandom.com/wiki/Osu!#cite_note-twitchtracker-1: Neuro-sama 는 AI VTuber
발전하기 훨씬 전부터 osu! 를 플레이하는 AI 로 시작했습니다. 첫 osu! 방송은 Vedal 이 자신의 작업을
[^1]: https://neurosama.fandom.com/wiki/Osu!#cite_note-twitchtracker-1: Neuro-sama는 AI VTuber로
발전하기 훨씬 전부터 osu! 를 플레이하는 AI로 시작했습니다. 첫 osu! 방송은 Vedal이 자신의 작업을
커뮤니티에 선보이기로 한 2019년 5월 6일이었습니다.
@@ -12,30 +12,30 @@ AIRI 팀이 전하는 **메리 크리스마스**!
![크리스마스 일러스트](/en/blog/merry-christmas-2025/assets/merry-christmas-iru.avif)
> Iru 가 따뜻함과 즐거움으로 가득한 행복한 연휴를 빕니다! 🎅🎁
> Iru가 따뜻함과 즐거움으로 가득한 행복한 연휴를 빕니다! 🎅🎁
>
> 원작 일러스트 [@fafafafa](https://www.mihuashi.com/profiles/782691), 수정 [Neko-233](https://github.com/Neko-233).
조금 늦었다는 건 알지만, 저희는 밤낮없이 이 프로젝트에 매달려 왔습니다. 거의 24시간 주 7일을 여기에 쏟고 있어요. 오디오는 여러 통합과 프로바이더 사이에서 여전히 문제가 있고, 모델 드라이버도 아직 실험 중입니다. Minecraft 와 Factorio 는 올해 훨씬 일찍 끝냈지만 이 통합들을 이어 주는 채널은 여전히 망가져 있고 테스트되지 않은 것도 많습니다. 그래도 더 나은 아키텍처와 플러그인, 프리셋, 스킬 등을 갖추며 앞으로 나아가고 있습니다. 새 DevLog 도 준비 중이니 기대해 주세요.
조금 늦었다는 건 알지만, 저희는 밤낮없이 이 프로젝트에 매달려 왔습니다. 거의 24시간 주 7일을 여기에 쏟고 있어요. 오디오는 여러 통합과 프로바이더 사이에서 여전히 문제가 있고, 모델 드라이버도 아직 실험 중입니다. Minecraft와 Factorio는 올해 훨씬 일찍 끝냈지만 이 통합들을 이어 주는 채널은 여전히 망가져 있고 테스트되지 않은 것도 많습니다. 그래도 더 나은 아키텍처와 플러그인, 프리셋, 스킬 등을 갖추며 앞으로 나아가고 있습니다. 새 DevLog도 준비 중이니 기대해 주세요.
2025년은 저희를, 특히 [저(Neko)](https://github.com/nekomeowww)를 1년 전에는 상상도 못 했던 곳까지 밀어붙였습니다. 이런 진전은 혼자서는, 여러분 없이는 이룰 수 없었습니다.
불과 몇 시간 전, X 에서 [KOL @Dexerto](https://x.com/Dexerto) 가 [이런 글](https://x.com/Dexerto/status/2003579088003346501)을 올린 걸 봤습니다:
불과 몇 시간 전, X에서 [KOL @Dexerto](https://x.com/Dexerto)가 [이런 글](https://x.com/Dexerto/status/2003579088003346501)을 올린 걸 봤습니다:
> AI 기반 VTuber Neuro-sama 가 Twitch 역대 최대 Hype Train 기록을 스스로 갈아치웠습니다.
> AI 기반 VTuber Neuro-sama가 Twitch 역대 최대 Hype Train 기록을 스스로 갈아치웠습니다.
>
> 11만 명이 넘는 구독과 100만 비트 이상으로 레벨 123 에 도달했습니다.
> 11만 명이 넘는 구독과 100만 비트 이상으로 레벨 123에 도달했습니다.
Neuro-sama, 생일 축하해. 그리고 제작자 Vedal 과 아티스트 Camila 에게도 축하를 전합니다. 여기까지 왔다는 게 믿기지 않네요. 저를 여기까지 이끌어 제 방식의 사이버 라이프를 만들고 AIRI 를 계속 키워 나가게 한 건 바로 여러분과 Swarm 입니다.
Neuro-sama, 생일 축하해. 그리고 제작자 Vedal과 아티스트 Camila에게도 축하를 전합니다. 여기까지 왔다는 게 믿기지 않네요. 저를 여기까지 이끌어 제 방식의 디지털 생명을 만들고 AIRI를 계속 키워 나가게 한 건 바로 여러분과 Swarm입니다.
![](/en/blog/merry-christmas-2025/assets/neuro-sama-happy-birthday-live.avif)
## 2025년 간단 결산
1. GitHub 에서 16k 스타를 넘겼습니다
1. GitHub에서 16k 스타를 넘겼습니다
2. GitHub 트렌딩에 여러 번 올랐고 카테고리 1위도 했습니다
3. 같은 분야에서 일하는 다른 프로젝트들을 많이 만났습니다:
- xAI 의 Grok Ani
- xAI의 Grok Ani
- 시나리오가 멋진 [gogh](https://store.steampowered.com/app/3213850/gogh/)
- 좋은 커뮤니티와 음악을 가진 [Chill with You](https://store.steampowered.com/app/3548580/LoFi/)
- 저희 같은 프로젝트를 더 살펴볼 수 있는 목록도 있습니다: https://github.com/proj-airi/awesome-ai-vtubers
@@ -2,8 +2,8 @@
title: 연대기 v0.0.1
---
- [x] 프로젝트 생성 - 완료, Vitesse Lite 와 Vue 조합으로 생성 (2024년 6월 7일)
- [x] 프론트엔드 Live2D 연동 - [Pixi.js 렌더러를 통해 Vue 애플리케이션에 Live2D 모델 통합하기](https://nolebase.ayaka.io/to/3cae2b7c0b) 에서 완료 (2024년 6월 7일)
- [x] 프로젝트 생성 - 완료, Vitesse Lite와 Vue 조합으로 생성 (2024년 6월 7일)
- [x] 프론트엔드 Live2D 연동 - [Pixi.js 렌더러를 통해 Vue 애플리케이션에 Live2D 모델 통합하기](https://nolebase.ayaka.io/to/3cae2b7c0b)에서 완료 (2024년 6월 7일)
- [x] Live2D Cubism SDK 연동
- [x] pixi.js 렌더링
- [x] 모델 다운로드
@@ -11,7 +11,7 @@ title: 연대기 v0.0.1
![]( /assets/version-v0.0.1/screenshot-1.avif)
- [x] Vercel AI SDK 를 통한 GPT-4o 연동 (2024년 6월 7일)
- [x] Vercel AI SDK를 통한 GPT-4o 연동 (2024년 6월 7일)
- [x] `@ai-sdk/openai`
- [x] `ai`
- [x] 스트리밍 토큰 전송 (2024년 6월 8일)
@@ -26,12 +26,12 @@ title: 연대기 v0.0.1
- [x] 선형 정규화
- [x] MinMax 정규화
- [x] ~~SoftMax 정규화~~(효과가 좋지 않았음. 출력 데이터가 전부 0.999999 ~ 1.000001 범위에 몰림)
- [x] 스트리밍 토큰에서 스트리밍 TTS 로 (2024년 6월 9일)
- [x] 스트리밍 토큰에서 스트리밍 TTS로 (2024년 6월 9일)
- [x] 구두점과 공백 + 글자 수 제한 조합으로 문장을 구성한 뒤 TTS 추론을 수행할 수 있어 보임
- [x] ~~11Labs 는 WebSocket 기반~~
- [x] ~~11Labs는 WebSocket 기반~~
- [x] 큐를 통해 TTS 스트림 요청을 보내고, 다시 오디오 스트림 큐로 전달
- [x] Vue 에서 Queue 구현
- [x] queue 는 선입선출이어야 함
- [x] Vue에서 Queue 구현
- [x] queue는 선입선출이어야 함
- [x] 꺼내기, [`Array.prototype.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
- [x] 넣기, [`Array.prototype.push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
- [x] 이벤트 기반
@@ -41,7 +41,7 @@ title: 연대기 v0.0.1
- [x] `processing`, 핸들러를 호출할 때 `processing` 이벤트 발생
- [x] `done`, 핸들러가 끝나면 `done` 이벤트 발생
- [x] 이벤트 처리
- [x] `add` `done` 이벤트가 발생하면 실행 중인 핸들러가 있는지 확인
- [x] `add``done` 이벤트가 발생하면 실행 중인 핸들러가 있는지 확인
- [x] 있으면 반환
- [x] 없으면 `pick(): T` 후 핸들러 호출
- [x] queue 핸들러
@@ -60,7 +60,7 @@ title: 연대기 v0.0.1
- ✅ 대화
- ✅ 대화 UI
- ✅ 음성
- ✅ Live2D 립싱크 (itorr 의 GitHub 설명 덕분)
- ✅ Live2D 립싱크 (itorr의 GitHub 설명 덕분)
- ✅ 기본 프롬프트
![](/assets/version-v0.0.1/screenshot-2.avif)
@@ -75,32 +75,32 @@ title: 연대기 v0.0.1
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> [Deepgram Voice AI: Text to Speech + Speech to Text APIs | Deepgram](https://deepgram.com/)
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> GPT-SoVITS 시도해 보기
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> fish-speech 시도 (2024년 7월 6일 ~ 2024년 7월 7일)
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 실제로 few-shot 으로 바로 복제가 가능함. Gura 의 목소리를 복제해 봤는데 처음 4초까지는 아주 높은 품질을 유지함
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> fish audio 의 오디오 처리 도구는 매우 충실해서, 오디오 프로세서가 (라벨링과 자동 라벨링을 포함해) 대부분의 요구를 커버함
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 실제로 few-shot으로 바로 복제가 가능함. Gura의 목소리를 복제해 봤는데 처음 4초까지는 아주 높은 품질을 유지함
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> fish audio의 오디오 처리 도구는 매우 충실해서, 오디오 프로세서가 (라벨링과 자동 라벨링을 포함해) 대부분의 요구를 커버함
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> 결과가 매우 불안정해서 단어나 소리를 자주 삼키거나 갑자기 이상한 잡음을 냄
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> RTX 4090 장비에서 돌려도 스트리밍 오디오 모드에서는 추론 결과를 내보내는 데 최대 2초가 걸림
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> ChatTTS 시도 (2024년 7월 6일 ~ 2024년 7월 7일)
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 실제로 few-shot 복제가 가능함. Gura 의 목소리를 복제해 봤지만 fish-speech 만큼 좋지는 않았음
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 감정 제어는 fish-speech 보다 훨씬 좋지만, 영어 환경에서는 `[uv_break]` 같은 토큰까지 발음해 버림. WeChat 그룹에서도 이 부분을 두고 이야기가 오가고 있음
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> RTX 4090 장비에서 돌려도 스트리밍 오디오 모드에서는 몇 분이 걸림... 🤯 정말 말이 안 됨. 평문/정규화된 텍스트를 액션 토큰이 포함된 텍스트로 바꾸기 위해 먼저 로컬에서 llm 을 돌리는 것으로 보이는데, 그 llm 을 띄울 때 캐싱이나 모델 크기를 전혀 고려하지 않은 듯함
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> [TTS Arena - a Hugging Face Space by TTS-AGI](https://huggingface.co/spaces/TTS-AGI/TTS-Arena) 에 언급된 다른 모델들 시도 (2024년 7월 8일)
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 실제로 few-shot 복제가 가능함. Gura의 목소리를 복제해 봤지만 fish-speech 만큼 좋지는 않았음
- <span class="i-icon-park-outline:up-one translate-y-0.5 text-green-800 dark:text-green-400 text-lg"></span> 감정 제어는 fish-speech보다 훨씬 좋지만, 영어 환경에서는 `[uv_break]` 같은 토큰까지 발음해 버림. WeChat 그룹에서도 이 부분을 두고 이야기가 오가고 있음
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> RTX 4090 장비에서 돌려도 스트리밍 오디오 모드에서는 몇 분이 걸림... 🤯 정말 말이 안 됨. 평문/정규화된 텍스트를 액션 토큰이 포함된 텍스트로 바꾸기 위해 먼저 로컬에서 llm을 돌리는 것으로 보이는데, 그 llm을 띄울 때 캐싱이나 모델 크기를 전혀 고려하지 않은 듯함
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> [TTS Arena - a Hugging Face Space by TTS-AGI](https://huggingface.co/spaces/TTS-AGI/TTS-Arena)에 언급된 다른 모델들 시도 (2024년 7월 8일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> XTTSv2 시도
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> huggingface 를 그대로 사용했는데 결과가 좋지 않음. fish speech 나 chattts 보다는 안정적이지만 톤이 너무 밋밋해서, 애니메이션 톤을 위해서는 lora 가 필요할 듯
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> huggingface를 그대로 사용했는데 결과가 좋지 않음. fish speech나 chattts 보다는 안정적이지만 톤이 너무 밋밋해서, 애니메이션 톤을 위해서는 lora가 필요할 듯
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> StyleTTS 2 시도
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> huggingface 를 그대로 사용했는데 결과가 좋지 않음. fish speech 나 chattts 보다는 안정적이지만 톤이 너무 밋밋해서, 애니메이션 톤을 위해서는 lora 가 필요할 듯
- <span class="i-icon-park-outline:down-one translate-y-0.5 text-red-800 dark:text-red-400 text-lg"></span> huggingface를 그대로 사용했는데 결과가 좋지 않음. fish speech나 chattts 보다는 안정적이지만 톤이 너무 밋밋해서, 애니메이션 톤을 위해서는 lora가 필요할 듯
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> CosyVoice 시도 (알리바바)
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> [Koemotion](https://koemotion.rinna.co.jp/)
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> [Seed-TTS](https://bytedancespeech.github.io/seedtts_tech_report/)
### 표정 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> embed instruction 으로 표정을 실시간으로 빠르게 처리하는 방법을 GPT 와 논의 https://poe.com/s/vu7foBWJHtnPmWzJNeAy (2024년 7월 7일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> embed instruction으로 표정을 실시간으로 빠르게 처리하는 방법을 GPT와 논의 https://poe.com/s/vu7foBWJHtnPmWzJNeAy (2024년 7월 7일)
- [x] 프론트엔드 Live2D 표정 제어 (2024년 7월 9일)
- [x] `<|EMOTE_HAPPY|>` 인코딩을 통해 구현
- [x] `<|DELAY:1|>` 같은 지연 문법도 추가 지원
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 감정 토큰 `<|EMOTE_.*|>` 파서와 토크나이저 캡슐화
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 큐 기반 스트리밍 처리 지원, `useEmotionMessagesQueue` `useEmotionsQueue` 캡슐화
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> Live2D 를 호출해 모션 표정을 처리하도록 지원
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 큐 기반 스트리밍 처리 지원, `useEmotionMessagesQueue``useEmotionsQueue` 캡슐화
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> Live2D를 호출해 모션 표정을 처리하도록 지원
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 테스트용 디버그 페이지
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 스트리밍 전체 과정의 지연을 동적으로 제어하기 위한 지연 토큰 `<|DELAY:.*|>` 파서와 토크나이저 캡슐화
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 큐 기반 스트리밍 처리 지원, `useDelaysQueue` 캡슐화
@@ -119,13 +119,13 @@ title: 연대기 v0.0.1
- [ ] 리서치에 사용한 인덱스 사이트
- [ ] [Hannibal046/Awesome-LLM: Awesome-LLM: a curated list of Large Language Model](https://github.com/Hannibal046/Awesome-LLM)
- [ ] 리서치 중 ADHD 같은 행동
- [ ] 친구가 NVIDIA 의 새 논문 [ConsiStory: Training-Free Consistent Text-to-Image Generation](https://research.nvidia.com/labs/par/consistory/) 를 추천해 줬는데 IPadapter 보다 안정적으로 느껴짐.
- [ ] 친구가 NVIDIA의 새 논문 [ConsiStory: Training-Free Consistent Text-to-Image Generation](https://research.nvidia.com/labs/par/consistory/) 를 추천해 줬는데 IPadapter보다 안정적으로 느껴짐.
- [ ] 흥미로운 것은 [IDEA-Research/MotionLLM: [Arxiv-2024] MotionLLM: Understanding Human Behaviors from Human Motions and Videos](https://github.com/IDEA-Research/MotionLLM). 이 논문과 연구 방향은 영상 애니메이션 프레임 사이에 형성되는 사람의 동작을 자연어로 기술하는 것에 관한 내용. 2024년 5월 31일 공개.
- [ ] [Ksuriuri/EasyAIVtuber: Simply animate your 2D waifu.](https://github.com/Ksuriuri/EasyAIVtuber)
- [ ] 이건 꽤 큰 주제라서 여러 키워드를 조사해 본 결과, 현재 이 방향의 주요 연구 주제들을 찾았습니다:
- [ ] 디지털 휴먼 합성 -> 가상 WebCam 모션 캡처
- [ ] [PersonaTalk: Bring Attention to Your Persona in Visual Dubbing](https://arxiv.org/pdf/2409.05379)
- [ ] 이것이 SOTA 로 보임
- [ ] 이것이 SOTA로 보임
- [ ] [OpenTalker/SadTalker: [CVPR 2023] SadTalkerLearning Realistic 3D Motion Coefficients for Stylized Audio-Driven Single Image Talking Face Animation](https://github.com/OpenTalker/SadTalker)
- [ ] [Rudrabha/Wav2Lip: This repository contains the codes of "A Lip Sync Expert Is All You Need for Speech to Lip Generation In the Wild", published at ACM Multimedia 2020. For HD commercial model, please try out Sync Labs](https://github.com/Rudrabha/Wav2Lip)
- [ ] [yerfor/GeneFace: GeneFace: Generalized and High-Fidelity 3D Talking Face Synthesis; ICLR 2023; Official code](https://github.com/yerfor/GeneFace)
@@ -151,31 +151,31 @@ title: 연대기 v0.0.1
- [ ] [CLIPort](https://cliport.github.io/)CLIPort: What and Where Pathways for Robotic Manipulation
- [ ] [VIMA | General Robot Manipulation with Multimodal Prompts](https://vimalabs.github.io/)VIMA: General Robot Manipulation with Multimodal Prompts
- [ ] [Scaling Up and Distilling Down: Language-Guided Robot Skill Acquisition](https://www.cs.columbia.edu/~huy/scalingup/)
- [ ] [EUREKA: HUMAN-LEVEL REWARD DESIGN VIA CODING LARGE LANGUAGE MODELS](https://eureka-research.github.io/assets/eureka_paper.pdf) 는 요약본에 가까운 느낌.
- [ ] [EUREKA: HUMAN-LEVEL REWARD DESIGN VIA CODING LARGE LANGUAGE MODELS](https://eureka-research.github.io/assets/eureka_paper.pdf)는 요약본에 가까운 느낌.
- [ ] 강화학습
- [ ] 이 방향은 주로 로보틱스 저수준 제어에서 이미 학습된 RL 모델과 연결한 뒤, 인터페이스와 연산 레이어에 code as policies 구현을 많이 얹는 방식
- [ ] [MarI/O - Machine Learning for Video Games - YouTube](https://www.youtube.com/watch?v=qv6UVOQ0F44)
- [ ] [RLADAPTER: BRIDGING LARGE LANGUAGE MODELS TO REINFORCEMENT LEARNING IN OPEN WORLDS](https://openreview.net/pdf?id=3s4fZTr1ce) 의 요지: RLAdapter 프레임워크 안에서 RL 에이전트 학습 중 생성된 정보로 경량 언어 모델을 파인튜닝하면 LLM 이 다운스트림 작업에 적응하는 데 크게 도움이 되고, 결과적으로 RL 에이전트에게 더 나은 가이드를 줄 수 있다는 것. Crafter 환경에서 RLAdapter 를 실험한 결과 SOTA 베이스라인을 뛰어넘었고, 이 프레임워크 아래에서 에이전트는 베이스라인 모델에는 없는 상식적인 행동을 보였다고 합니다
- [ ] [See and Think: Embodied Agent in Virtual Environment](https://arxiv.org/pdf/2311.15209) 는 아래에 언급한 Voyager, PlanMC, MP5 와 비슷하게 Minecraft 를 위한 연구인데, 주로 RL 을 강조하는 느낌.
- [ ] [RLADAPTER: BRIDGING LARGE LANGUAGE MODELS TO REINFORCEMENT LEARNING IN OPEN WORLDS](https://openreview.net/pdf?id=3s4fZTr1ce)의 요지: RLAdapter 프레임워크 안에서 RL 에이전트 학습 중 생성된 정보로 경량 언어 모델을 파인튜닝하면 LLM이 다운스트림 작업에 적응하는 데 크게 도움이 되고, 결과적으로 RL 에이전트에게 더 나은 가이드를 줄 수 있다는 것. Crafter 환경에서 RLAdapter를 실험한 결과 SOTA 베이스라인을 뛰어넘었고, 이 프레임워크 아래에서 에이전트는 베이스라인 모델에는 없는 상식적인 행동을 보였다고 합니다
- [ ] [See and Think: Embodied Agent in Virtual Environment](https://arxiv.org/pdf/2311.15209)는 아래에 언급한 Voyager, PlanMC, MP5와 비슷하게 Minecraft를 위한 연구인데, 주로 RL을 강조하는 느낌.
- [ ] [Text2Reward: Reward Shaping with Language Models for Reinforcement Learning](https://text-to-reward.github.io/)
- [ ] [Direct Preference Optimization: Your Language Model is Secretly a Reward Model](https://arxiv.org/pdf/2305.18290) 는 주로 LLM 자체가 보상 모델이 될 수 있다는 이야기. RLHF 를 어떻게 결합할지 배울 수 있고 트랜스포머 관점에서도 꽤 기초적인 내용.
- [ ] [Direct Preference Optimization: Your Language Model is Secretly a Reward Model](https://arxiv.org/pdf/2305.18290)는 주로 LLM 자체가 보상 모델이 될 수 있다는 이야기. RLHF를 어떻게 결합할지 배울 수 있고 트랜스포머 관점에서도 꽤 기초적인 내용.
- [ ] Embodied Control
- [ ] 여기에 많이 정리되어 있음
- [ ] [zchoi/Awesome-Embodied-Agent-with-LLMs](https://github.com/zchoi/Awesome-Embodied-Agent-with-LLMs):"대규모 언어 모델을 활용한 Embodied AI 또는 로봇" 연구를 정리한 목록입니다. 최신 업데이트를 받으려면 이 저장소를 watch 하세요! 🔥
- [ ] [MP5: A Multi-modal Open-ended Embodied System in Minecraft via Active Perception](https://arxiv.org/pdf/2312.07472) 이건 흥미롭습니다. 비교적 완성된 Minecraft RL 프레임워크를 사용해, 자연어 지시로 LLM 에게 "**낮**에 **초원**의 **물가**에서 **돌검**으로 **돼지**를 **잡아라**" 라고 알려 주면 RL 에이전트가 이런 특징들을 인지하고 목표를 달성하는 방식입니다. [AI 가 Minecraft 를 플레이하게 하는 방법? Voyager 논문 노트](https://nolebase.ayaka.io/to/27024f5434) 와 달리 MP5 는 PlanMC 에 더 가깝고, Voyager 의 순수 텍스트·순수 상태 정보 대신 멀티모달 능력을 통합했습니다.
- [ ] 초록: 매우 도전적인 Minecraft 시뮬레이터 위에 구축한 개방형 멀티모달 embodied 시스템 MP5 를 소개합니다. 실행 가능한 하위 목표를 분해하고, 복잡한 맥락 인식 계획을 설계하며, embodied 행동 제어를 수행하고, 목표 조건부 능동 인지 체계와 자주 소통할 수 있습니다. 구체적으로 MP5 는 멀티모달 대규모 언어 모델(MLLM)의 최근 성과를 바탕으로 개발되었으며, 시스템은 여러 기능 모듈로 나뉘어 스케줄링·협업을 통해 사전 정의된 맥락·과정 관련 작업을 최종적으로 해결합니다.
- [ ] [MP5: A Multi-modal Open-ended Embodied System in Minecraft via Active Perception](https://arxiv.org/pdf/2312.07472) 이건 흥미롭습니다. 비교적 완성된 Minecraft RL 프레임워크를 사용해, 자연어 지시로 LLM에게 "**낮**에 **초원**의 **물가**에서 **돌검**으로 **돼지**를 **잡아라**" 라고 알려 주면 RL 에이전트가 이런 특징들을 인지하고 목표를 달성하는 방식입니다. [AI가 Minecraft를 플레이하게 하는 방법? Voyager 논문 노트](https://nolebase.ayaka.io/to/27024f5434)와 달리 MP5는 PlanMC에 더 가깝고, Voyager의 순수 텍스트·순수 상태 정보 대신 멀티모달 능력을 통합했습니다.
- [ ] 초록: 매우 도전적인 Minecraft 시뮬레이터 위에 구축한 개방형 멀티모달 embodied 시스템 MP5를 소개합니다. 실행 가능한 하위 목표를 분해하고, 복잡한 맥락 인식 계획을 설계하며, embodied 행동 제어를 수행하고, 목표 조건부 능동 인지 체계와 자주 소통할 수 있습니다. 구체적으로 MP5는 멀티모달 대규모 언어 모델(MLLM)의 최근 성과를 바탕으로 개발되었으며, 시스템은 여러 기능 모듈로 나뉘어 스케줄링·협업을 통해 사전 정의된 맥락·과정 관련 작업을 최종적으로 해결합니다.
- [ ] [CRADLE: Empowering Foundation Agents Towards General Computer Control](https://arxiv.org/pdf/2403.03186) 아직 안 읽음. 시간 날 때 읽을 예정.
- [ ] [Embodied Multi-Modal Agent trained by an LLM from a Parallel TextWorld](https://arxiv.org/pdf/2311.16714) 는 주로 **병렬 텍스트 세계에서 뛰어난 LLM 에이전트를 이용해 시각 세계에 사는 VLM 에이전트를 학습시키는** 이야기.
- [ ] [Embodied Multi-Modal Agent trained by an LLM from a Parallel TextWorld](https://arxiv.org/pdf/2311.16714)는 주로 **병렬 텍스트 세계에서 뛰어난 LLM 에이전트를 이용해 시각 세계에 사는 VLM 에이전트를 학습시키는** 이야기.
- [ ] [Online continual learning ONLINE CONTINUAL LEARNING FOR INTERACTIVE INSTRUCTION FOLLOWING AGENTS](https://openreview.net/pdf?id=7M0EzjugaN)
- [ ] Manipulation (주로 로보틱스 분야)
- [ ] Motion Embeddings
- [ ] [PerAct](https://peract.github.io/):꽤 드물게도, code as policies 와 RL 환경 정보에 manipulation 까지 토큰으로 인코딩해 연산한다는 내용
- [ ] [PerAct](https://peract.github.io/):꽤 드물게도, code as policies와 RL 환경 정보에 manipulation까지 토큰으로 인코딩해 연산한다는 내용
- [ ] Feedback Loop (주로 로보틱스 + 제어 분야, 이 카테고리는 사실 더 드묾)
- [ ] 일반적인 환경과 관련 있을 것 같은데, 상당히 저수준 영역
- [ ] 차라리 RL 을 직접 파는 게 도움이 될지도
- [ ] [InCoRo: In-Context Learning for Robotics Control with Feedback Loops](https://arxiv.org/html/2402.05188v1?_immersive_translate_auto_translate=1) 는 제목이 매력적인데 아직 꼼꼼히 읽지는 못했습니다. 시간 날 때 읽을 예정이고, 인용도 많이 됐습니다.
- [ ] 목적은 주로 LLM 의 자연어 명령을 로봇 유닛을 위한 저수준의 _정적_ 실행 계획으로 변환하는 것. LLM 내부의 로봇 시스템을 활용해 이를 새로운 수준으로 일반화하고, 새로운 작업에 대한 zero-shot 일반화를 가능하게 합니다.
- [ ] 관련해서 Hugging Face 가 오픈소스로 공개한 LeRobot 도 참고할 만함
- [ ] 차라리 RL을 직접 파는 게 도움이 될지도
- [ ] [InCoRo: In-Context Learning for Robotics Control with Feedback Loops](https://arxiv.org/html/2402.05188v1?_immersive_translate_auto_translate=1)는 제목이 매력적인데 아직 꼼꼼히 읽지는 못했습니다. 시간 날 때 읽을 예정이고, 인용도 많이 됐습니다.
- [ ] 목적은 주로 LLM의 자연어 명령을 로봇 유닛을 위한 저수준의 _정적_ 실행 계획으로 변환하는 것. LLM 내부의 로봇 시스템을 활용해 이를 새로운 수준으로 일반화하고, 새로운 작업에 대한 zero-shot 일반화를 가능하게 합니다.
- [ ] 관련해서 Hugging Face가 오픈소스로 공개한 LeRobot도 참고할 만함
- [ ] [huggingface/lerobot: 🤗 LeRobot: End-to-end Learning for Real-World Robotics in Pytorch](https://github.com/huggingface/lerobot?tab=readme-ov-file)
### 시각
@@ -185,7 +185,7 @@ title: 연대기 v0.0.1
- [ ] [landing-ai/vision-agent: Vision agent (github.com)](https://github.com/landing-ai/vision-agent)
- [ ] [2404.04834 LLM-Based Multi-Agent Systems for Software Engineering: Vision and the Road Ahead (arxiv.org)](https://arxiv.org/abs/2404.04834)
- [ ] [Experimentation: LLM, LangChain Agent, Computer Vision | by TeeTracker | Medium](https://teetracker.medium.com/experimentation-llm-langchain-agent-computer-vision-0c405deb7c6e)
- [ ] Neuro Sama 는 어떻게 화면을 보고 이해하는 걸까?
- [ ] Neuro Sama는 어떻게 화면을 보고 이해하는 걸까?
- [ ] [Is it possible to use a local LLM and have it play Minecraft? : r/LocalLLaMA](https://www.reddit.com/r/LocalLLaMA/comments/143ziop/comment/jnfvr1w/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button)
- [ ] [2402.07945 ScreenAgent: A Vision Language Model-driven Computer Control Agent](https://arxiv.org/abs/2402.07945)
- [ ] 스탠퍼드와 베이 에어리어에서 대규모 언어 모델이 로봇을 제어하게 하는 시스템은 어떻게 동작할까?
@@ -205,19 +205,19 @@ title: 연대기 v0.0.1
- [ ] 다국어 지원
- [ ] 중국어
- [ ] 현재 11Labs 의 중국어 TTS 모델은 품질이 너무 떨어짐
- [ ] Microsoft 의 Cognitive TTS API 도 그다지 좋지 않음
- [ ] AWS 는 결과가 나쁨
- [ ] 현재 11Labs의 중국어 TTS 모델은 품질이 너무 떨어짐
- [ ] Microsoft의 Cognitive TTS API도 그다지 좋지 않음
- [ ] AWS는 결과가 나쁨
- [ ] 알리바바 클라우드가 괜찮다고 함
- [ ] 일본어
- [ ] [Koemotion](https://koemotion.rinna.co.jp/)
- [ ] Pixiv 의 [ChatVRM 데모](https://github.com/pixiv/ChatVRM) 도 이걸 사용함
- [ ] Pixiv의 [ChatVRM 데모](https://github.com/pixiv/ChatVRM)도 이걸 사용함
## 최적화 위시리스트 백로그
### 코드 저장소 & 아키텍처
- [x] [SPA 로 마이그레이션](https://github.com/nekomeowww/airi-vtuber/commit/cd0f371595a669c570dc263e72dd3ce54afab7ff)
- [x] [SPA로 마이그레이션](https://github.com/nekomeowww/airi-vtuber/commit/cd0f371595a669c570dc263e72dd3ce54afab7ff)
- [x] [모노레포로 마이그레이션](https://github.com/nekomeowww/airi-vtuber/commit/ee4878710eeded6ef1b66474905936353d0176b4)
- [x] moeru-ai 조직으로 통합
@@ -226,7 +226,7 @@ title: 연대기 v0.0.1
- [x] sendMessage 입력란이 비어 있으면 전송하지 않기 (2024년 6월 9일)
- [x] 대화 기록 (2024년 6월 9일)
- [ ] 컨텍스트를 초과한 대화 기록 자동 정리
- 예전에 Go 로 구현한 적이 있으니 가져오면 됨.
- 예전에 Go로 구현한 적이 있으니 가져오면 됨.
- [ ] 컨텍스트 크기 자동 판단
- [ ] 마이크 선택 지원
- [ ] 단축키 리스닝 구현 (방송 사고 방지)
@@ -266,39 +266,39 @@ title: 연대기 v0.0.1
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 메시지를 보낼 때 피드백을 위해 곧바로 생각하는 표정으로 전환하도록 지원 (2024년 7월 9일)
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 감정 인식
- [ ] 현재는 감정 토큰을 처리하느라 토큰을 추가로 낭비하고 있는데, 전통적인 NLP 감정 분석(sentiment)을 시도해 볼 수 있음
- [ ] 다만 전통적인 sentiment 는 긍정과 부정밖에 없어서, 다른 감정을 어떻게 지원할지 고민이 필요함
- [ ] 다만 전통적인 sentiment는 긍정과 부정밖에 없어서, 다른 감정을 어떻게 지원할지 고민이 필요함
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 감정 토큰 임베딩
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 현재 `<|EMOTE_.*|>` 패턴 토큰은 토크나이저가 관리하지 않아서, 추론 중에 스트리밍 호환 토크나이저를 여러 개 따로 작성해야 함
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 현재 `<|EMOTE_.*|>` 패턴 토큰은 토크나이저가 관리하지 않아서, 추론 중에 스트리밍 호환 토크나이저를 여러 개 따로 작성해야 함
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> `useQueue` 가 처리 중 `isProcessing` 락으로 분리된 큐 항목을 고려하지 않음 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> Local Storage 에 저장된 모델이 필요한 데이터와 맞지 않아 `computed` 무한 루프가 발생해 인터페이스가 멈춤 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> `useQueue`가 처리 중 `isProcessing` 락으로 분리된 큐 항목을 고려하지 않음 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> Local Storage에 저장된 모델이 필요한 데이터와 맞지 않아 `computed` 무한 루프가 발생해 인터페이스가 멈춤 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> Live2DViewer 프레임의 자동 크기 감지 기능에 문제가 있음 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-red-500/30 text-red-800 dark:text-red-400 bg-red-500/20 rounded-lg">버그</span> streamSpeech 중 무한 루프를 피하려고 빈 텍스트를 격리하면서 생긴 문제 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> `useQueue` `handler` 안에서 커스텀 이벤트를 지원 (2024년 7월 9일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> `useQueue``handler` 안에서 커스텀 이벤트를 지원 (2024년 7월 9일)
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 텍스트 출력과 음성 출력 타이밍 동기화
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> `ttsQueue` `audioPlaybackQueue` 가 대응하는 타임스탬프를 저장할 수 있게
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> `ttsQueue``audioPlaybackQueue`가 대응하는 타임스탬프를 저장할 수 있게
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> `audioPlaybackQueue` 처리와 재생을 마칠 때 오디오 길이 계산
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 공백으로 텍스트를 나눠 `['hello ', 'this ', 'is ', 'neuro ']` 얻기
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 오디오 길이 ÷ 텍스트 글자 수 = 토큰 그룹 출력마다의 지연
- [ ] <span class="text-sm px-1 py-0.5 border border-solid border-green-500/30 text-green-800 dark:text-green-400 bg-green-500/20 rounded-lg">기능</span> 지연 지시에 따라 텍스트 출력 (지연 큐를 써도 됨)
- [ ] Neuro Sama 의 추론 속도는 정말 빠릅니다. 벡터 DB 회상 + 재추론 + 작업 배분까지 감안해도 이렇게 빠를 수는 없을 것 같은데
- [x] Neuro Sama 의 TTS 도 매우 빠릅니다. 제가 아는 어떤 TTS 보다도 빠릅니다
- [x] MicVAD 와 Whisper 를 연동하고 나니 아주 빠르게 느껴짐. 생각보다 훨씬 간단했음
- [ ] Neuro Sama의 추론 속도는 정말 빠릅니다. 벡터 DB 회상 + 재추론 + 작업 배분까지 감안해도 이렇게 빠를 수는 없을 것 같은데
- [x] Neuro Sama의 TTS도 매우 빠릅니다. 제가 아는 어떤 TTS 보다도 빠릅니다
- [x] MicVAD와 Whisper를 연동하고 나니 아주 빠르게 느껴짐. 생각보다 훨씬 간단했음
- [ ] 로컬 Whisper
- [ ] 로컬 TTS
- [ ] Vedal 은 Neuro Sama 의 음성 인식을 파인튜닝할 때 데이터를 얼마나 썼을까?
- [ ] `Evil` `Evil Neuro` 같은 단어는 의미상 합쳐질 수 없어야 하는데, RAG 로 강제하려면 꽤 강력한 벡터 DB 노드 지원이 필요할 것
- [ ] Vedal은 Neuro Sama의 음성 인식을 파인튜닝할 때 데이터를 얼마나 썼을까?
- [ ] `Evil``Evil Neuro` 같은 단어는 의미상 합쳐질 수 없어야 하는데, RAG로 강제하려면 꽤 강력한 벡터 DB 노드 지원이 필요할 것
### 기억
- [ ] keep alive 방안
- [ ] 유휴 상태라면 30분마다 Neuro 에게 연속 추론 프롬프트를 주기
- [ ] Neuro 에게 지금 뭘 하고 있는지 묻고, 그것을 기록하도록 돕기
- [ ] Neuro 에게 다음에 뭘 하고 싶은지 물어 지루해지지 않게 하기
- [ ] 24시간을 1로 환산. 그러지 않으면 GPT 가 숫자 감각을 쉽게 잃음
- [ ] 유휴 상태라면 30분마다 Neuro에게 연속 추론 프롬프트를 주기
- [ ] Neuro에게 지금 뭘 하고 있는지 묻고, 그것을 기록하도록 돕기
- [ ] Neuro에게 다음에 뭘 하고 싶은지 물어 지루해지지 않게 하기
- [ ] 24시간을 1로 환산. 그러지 않으면 GPT가 숫자 감각을 쉽게 잃음
- [ ] 연속 추론
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> Perplexity 와의 논의 https://www.perplexity.ai/search/I-want-to-jKXpnx6hT6uvhm0qbu6ofA#0 (2024년 6월 8일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> Poe 에서 실험 [https://poe.com/s/PqQfwNd2V2wFpmR0YUke](https://poe.com/s/PqQfwNd2V2wFpmR0YUke) (2024년 7월 8일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> Perplexity와의 논의 https://www.perplexity.ai/search/I-want-to-jKXpnx6hT6uvhm0qbu6ofA#0 (2024년 6월 8일)
- [x] <span class="text-sm px-1 py-0.5 border border-solid border-purple-500/30 text-purple-800 dark:text-purple-400 bg-purple-500/20 rounded-lg">실험</span> Poe에서 실험 [https://poe.com/s/PqQfwNd2V2wFpmR0YUke](https://poe.com/s/PqQfwNd2V2wFpmR0YUke) (2024년 7월 8일)
- [ ] 루프 만들기
- [ ] 무엇을 하고 싶은가
- [ ] 액션 맵을 생성할 수 있음
@@ -317,15 +317,15 @@ title: 연대기 v0.0.1
- [ ] 무엇을 하고 싶은가
- [ ] ...
- [ ] 단방향 핑 방안 (저비용)
- [ ] 유휴 상태라면 매시간 Neuro 에게 지난 1시간의 상태 업데이트를 보내기
- [ ] 유휴 상태라면 매시간 Neuro에게 지난 1시간의 상태 업데이트를 보내기
- [ ] 24시간이 지나면 상태 업데이트를 컨텍스트에 넣지 않고 가동 시간만 요약하기
- [ ] 매 상호작용 전에 Neuro 에게 가동 시간 프롬프트를 보내 시간의 흐름을 느끼게 하기
- [ ] 매 상호작용 전에 Neuro에게 가동 시간 프롬프트를 보내 시간의 흐름을 느끼게 하기
## 동작
- [ ] Minecraft 플레이 [AI 가 Minecraft 를 플레이하게 하는 방법? Voyager 논문 노트](https://nolebase.ayaka.io/to/27024f5434)
- [ ] Minecraft 플레이 [AI가 Minecraft를 플레이하게 하는 방법? Voyager 논문 노트](https://nolebase.ayaka.io/to/27024f5434)
- [ ] 검색
- [ ] VSCode 로 코드 작성
- [ ] VSCode로 코드 작성
- [ ] 지식 베이스 작성 돕기
- [ ] Factorio 플레이
- [ ] 다른 GPT 들에게 지시하기
@@ -347,7 +347,7 @@ title: 연대기 v0.0.1
- [【무료 모델】이렇게 귀여운 강아지를 무료로!_bilibili](https://www.bilibili.com/video/BV1LM41137vK/)
- [【무료 live2d 모델】작은 악마를 무료로 데려가세요(∠・ω< )⌒☆_bilibili](https://www.bilibili.com/video/BV1fP411e7fA/)
- [【무료 L2D 모델】달콤 짭짤한 기계 소녀! 무료 모델 공개~클릭해서 받아가세요_bilibili](https://www.bilibili.com/video/BV1S8411H7zf/)
- [【Frieren 무료 live2d 모델】그때 Himmel 에게 이 기술을 썼더니 위력이 너무 세서 기절했다=w=_bilibili](https://www.bilibili.com/video/BV1te411b7Xp)
- [【Frieren 무료 live2d 모델】그때 Himmel에게 이 기술을 썼더니 위력이 너무 세서 기절했다=w=_bilibili](https://www.bilibili.com/video/BV1te411b7Xp)
- [【무료 live2D 모델】1만 위안짜리 초고정밀 모델을 그냥 무료로?_bilibili](https://www.bilibili.com/video/BV1hB4y1Q7vn/)
- [Bilibili Workshop](https://gf.bilibili.com/item/detail/1105759077)
- [【무료 live2d 모델 쇼케이스】지뢰계 소녀 받아가기_bilibili](https://www.bilibili.com/video/BV1eu4y187zw)
@@ -464,7 +464,7 @@ The available actions:
And the last, do what ever you want!
```
- 대규모 언어 모델이 Delay 를 스스로 다루게 하면 결과가 매우 나빴습니다. live2d 모션 애니메이션 길이가 제각각이라 여러 표정이 겹칠 때 문제가 자주 생겼습니다
- 대규모 언어 모델이 Delay를 스스로 다루게 하면 결과가 매우 나빴습니다. live2d 모션 애니메이션 길이가 제각각이라 여러 표정이 겹칠 때 문제가 자주 생겼습니다
- 지금의 프론트엔드 표시 레이어 토크나이저 구현에도 문제가 좀 있어서, 겹침 처리가 잘 안 됩니다
- 수정 완료. 이제 전용 llmmarker 파서 캡슐화가 있습니다
@@ -17,28 +17,28 @@ title: 연대기 v0.1.0
- [x] ~~오디오 전사~~
- [x] ~~프론트엔드에서 백엔드로 오디오 스트리밍~~
- [x] WebSocket 기반 양방향 통신을 위해 socket.io 사용 [Socket.IO](https://socket.io/) (6월 10일)
- [x] Socket.io 는 사실 WebSocket 기반이 아니다
- [x] Socket.io는 사실 WebSocket 기반이 아니다
- [node.js - What is the major scenario to use Socket.IO - Stack Overflow](https://stackoverflow.com/questions/18587104/what-is-the-major-scenario-to-use-socket-io)
- [node.js - Differences between socket.io and websockets - Stack Overflow](https://stackoverflow.com/questions/10112178/differences-between-socket-io-and-websockets)
- [x] 프론트엔드는 `socket.io-client` 패키지 사용, `pnpm i socket.io-client`
- [x] WebSocket 은 지원이 좋고 Nuxt 의 Nitro 도 지원한다. [How to use with Nuxt | Socket.IO](https://socket.io/how-to/use-with-nuxt)
- [x] WebSocket은 지원이 좋고 Nuxt의 Nitro도 지원한다. [How to use with Nuxt | Socket.IO](https://socket.io/how-to/use-with-nuxt)
- [x] 백엔드는 `socket.io` 패키지 사용, `pnpm i socket.io`
- Nuxt 3 와 socket.io
- Nuxt 3와 socket.io
- [richardeschloss/nuxt-socket-io: Nuxt Socket IO - socket.io client and server module for Nuxt](https://github.com/richardeschloss/nuxt-socket-io)
- [javascript - Socket.io websocket not working in Nuxt 3 when in production - Stack Overflow](https://stackoverflow.com/questions/73592619/socket-io-websocket-not-working-in-nuxt-3-when-in-production)
- [adityar15/nuxt3socket (github.com)](https://github.com/adityar15/nuxt3socket)
- [x] ~~오디오 스트리밍에 WebRTC 사용, VueUse 도 이를 지원함~~
- [x] Nuxt 와 Nitro 가 아직 지원하지 않아 일단 보류. 그룹 채팅이나 Discord 용으로 검토해 볼 수 있음.
- [x] ~~오디오 스트리밍에 WebRTC 사용, VueUse도 이를 지원함~~
- [x] Nuxt와 Nitro가 아직 지원하지 않아 일단 보류. 그룹 채팅이나 Discord 용으로 검토해 볼 수 있음.
- 튜토리얼:
- [Getting started with media devices | WebRTC](https://webrtc.org/getting-started/media-devices?hl=en)
- [WebRTC | JavaScript Standard Reference Tutorial](https://wohugb.gitbooks.io/javascript/content/htmlapi/webrtc.html)
- ~~Transformers.js + Whisper 로 충분함~~
- [x] Chrome / Edge 가 이제 WebGPU 를 지원함
- ~~Transformers.js + Whisper로 충분함~~
- [x] Chrome / Edge가 이제 WebGPU를 지원함
- [x] 데모가 있음: [Real-time Whisper WebGPU - a Hugging Face Space by Xenova](https://huggingface.co/spaces/Xenova/realtime-whisper-webgpu) (현재는 오픈소스가 아님)
- [x] ~~Whisper 추론을 브라우저에서 바로 수행할 수 있음~~
- [x] ~~WebGPU 가 아직 지원되지 않음~~ (이제 지원됨)
- [x] ~~WebGPU가 아직 지원되지 않음~~ (이제 지원됨)
- [x] [🤗 Transformers.js + ONNX Runtime WebGPU in Chrome extension | by Wei Lu | Medium](https://medium.com/@GenerationAI/transformers-js-onnx-runtime-webgpu-in-chrome-extension-13b563933ca9)
- ~~Node.js CPP Addon 을 통해 Whisper.cpp 를 임베딩하는 방안 검토~~
- ~~Node.js CPP Addon을 통해 Whisper.cpp를 임베딩하는 방안 검토~~
- [whisper.cpp](https://github.com/ggerganov/whisper.cpp)
- 튜토리얼:
- [Realtime video transcription and translation with Whisper and NLLB on MacBook Air | by Wei Lu | Medium](https://medium.com/@GenerationAI/realtime-video-transcription-and-translation-with-whisper-and-nllb-on-macbook-air-31db4c62c074)
@@ -64,7 +64,7 @@ title: 연대기 v0.1.0
## **모델**
- **VRM**
- [`@pixiv/three-vrm`](https://github.com/pixiv/three-vrm/) 을 알려 준 [kwaa](https://github.com/kwaa) 에게 감사드립니다
- [`@pixiv/three-vrm`](https://github.com/pixiv/three-vrm/) 을 알려 준 [kwaa](https://github.com/kwaa)에게 감사드립니다
- 관련 도구와 플러그인:
- [VRM Add-on for Blender](https://vrm-addon-for-blender.info/en/)
- [VRM format — Blender Extensions](https://extensions.blender.org/add-ons/vrm/)
@@ -1,5 +1,5 @@
---
title: 디자인 가이드라인
description: Project AIRI 에 디자인으로 기여하는 방법
description: Project AIRI에 디자인으로 기여하는 방법
---
@@ -5,13 +5,13 @@ description: 참고하고 영감을 얻을 수 있는 자료들
### yui540
제가 아는 최고의 CSS 화면 전환 제작자 중 한 명은 **[yui540](https://yui540.com/)** 입니다. 눈부신 ACG 웹사이트를 정말 많이 디자인했고, 그중 가장 유명한 작품은 [臆病な魔女](https://cowardly-witch.netlify.app/) 입니다 (소스 코드는 [yui540](https://github.com/yui540?tab=repositories) 에서 찾아볼 수 있습니다).
제가 아는 최고의 CSS 화면 전환 제작자 중 한 명은 **[yui540](https://yui540.com/)** 입니다. 눈부신 ACG 웹사이트를 정말 많이 디자인했고, 그중 가장 유명한 작품은 [臆病な魔女](https://cowardly-witch.netlify.app/) 입니다 (소스 코드는 [yui540](https://github.com/yui540?tab=repositories)에서 찾아볼 수 있습니다).
위와 비슷한 전환 효과를 구현하고 싶다면 [yui540/css-animations: 俺流CSSアニメーション](https://github.com/yui540/css-animations) 저장소를 참고하세요.
### [Nihe Works](https://nihe.work/)
[YouTube](https://www.youtube.com/@nihe8683) 에도 작업 영상을 올리고 있으니 함께 살펴보세요.
[YouTube](https://www.youtube.com/@nihe8683)에도 작업 영상을 올리고 있으니 함께 살펴보세요.
## 모음 사이트
@@ -1,21 +1,21 @@
---
title: 도구
description: Project AIRI 의 UI, UX 를 디자인하기 위한 도구들
description: Project AIRI의 UI, UX를 디자인하기 위한 도구들
---
## 색상
개발 과정에서는 기본적으로 [UnoCSS](https://unocss.dev) 라는 도구로 스타일시트에 관한 모든 것을 생성합니다. [Tailwind](https://tailwindcss.com) 와 똑같이 동작하는 훌륭한 도구입니다.
개발 과정에서는 기본적으로 [UnoCSS](https://unocss.dev)라는 도구로 스타일시트에 관한 모든 것을 생성합니다. [Tailwind](https://tailwindcss.com)와 똑같이 동작하는 훌륭한 도구입니다.
따라서 기본 색상 팔레트는 [Colors - Core concepts - Tailwind CSS](https://tailwindcss.com/docs/colors) 에 정리되어 있습니다.
따라서 기본 색상 팔레트는 [Colors - Core concepts - Tailwind CSS](https://tailwindcss.com/docs/colors)에 정리되어 있습니다.
일반적으로 기본 테마에는 `neutral`, `pink`, `violet`, `cyan` 을 사용합니다. [UnoCSS](https://unocss.dev) 와 [Tailwind](https://tailwindcss.com) 모두 색상에 투명도를 조절하는 기능을 지원하지만, [Refactoring UI](https://refactoringui.com/) 에 따르면:
일반적으로 기본 테마에는 `neutral`, `pink`, `violet`, `cyan`을 사용합니다. [UnoCSS](https://unocss.dev)와 [Tailwind](https://tailwindcss.com) 모두 색상에 투명도를 조절하는 기능을 지원하지만, [Refactoring UI](https://refactoringui.com/) 에 따르면:
> 색의 채도를 바꾸고 싶을 때는 투명도를 쓰기보다, 대비가 가장 좋은 불투명한(알파 채널이 없는) 색을 직접 골라야 합니다.
그러니 투명도가 타이포그래피 디자인의 일부가 아닌 이상, 가독성을 위해 가장 알맞은 불투명 색상을 골라 주세요.
또 하나 즐겨 쓰는 훌륭한 도구는 [Radix Colors](https://www.radix-ui.com/colors) 입니다. 탄탄한 색채 이론을 바탕으로 좋은 팔레트를 만들어 두었기에, 우리 인터랙티브 UI 요소의 기본 재료 같은 역할을 합니다. 여기서도 알맞은 색을 고를 수 있습니다.
또 하나 즐겨 쓰는 훌륭한 도구는 [Radix Colors](https://www.radix-ui.com/colors)입니다. 탄탄한 색채 이론을 바탕으로 좋은 팔레트를 만들어 두었기에, 우리 인터랙티브 UI 요소의 기본 재료 같은 역할을 합니다. 여기서도 알맞은 색을 고를 수 있습니다.
_보색_ 이 무엇인지는 이미 알고 계실 텐데, 색상 대비를 잡는 데 유용합니다. 보색을 빠르고 인터랙티브하게 고를 수 있는 좋은 도구를 몇 가지 소개합니다:
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: 문서 사이트
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### 문서 사이트
+16 -16
View File
@@ -1,6 +1,6 @@
---
title: 기여하기
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
안녕하세요! 이 프로젝트에 기여하는 데 관심을 가져 주셔서 감사합니다. 이 가이드가 첫걸음을 도와드릴 거예요.
@@ -17,9 +17,9 @@ description: Project AIRI 에 기여하기
0. [Visual Studio](https://visualstudio.microsoft.com/downloads/) 를 내려받고 다음 안내를 따르세요: https://rust-lang.github.io/rustup/installation/windows-msvc.html#walkthrough-installing-visual-studio-2022
> Visual Studio 를 설치할 때 Windows SDK 와 C++ 빌드 도구를 반드시 함께 설치하세요.
> Visual Studio를 설치할 때 Windows SDK와 C++ 빌드 도구를 반드시 함께 설치하세요.
1. PowerShell 을 엽니다
1. PowerShell을 엽니다
2. [`scoop`](https://scoop.sh/) 을 설치합니다
```powershell
@@ -27,20 +27,20 @@ description: Project AIRI 에 기여하기
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
```
3. `scoop` 으로 `git`, Node.js, `rustup`, `msvc` 를 설치합니다
3. `scoop`으로 `git`, Node.js, `rustup`, `msvc`를 설치합니다
```powershell
scoop install git nodejs rustup
# Rust 의존성용
# crates 나 apps/tamagotchi 를 개발하지 않는다면 필요 없습니다
# crates나 apps/tamagotchi를 개발하지 않는다면 필요 없습니다
scoop install main/rust-msvc
# Rust & Windows 전용
rustup toolchain install stable-x86_64-pc-windows-msvc
rustup default stable-x86_64-pc-windows-msvc
```
4. `corepack` 으로 `pnpm` 을 설치합니다
4. `corepack`으로 `pnpm`을 설치합니다
```powershell
corepack enable
@@ -53,13 +53,13 @@ description: Project AIRI 에 기여하기
<summary>macOS 설정</summary>
0. 터미널(또는 iTerm2, Ghostty, Kitty 등)을 엽니다
1. `brew` `git` `node` 를 설치합니다
1. `brew``git``node`를 설치합니다
```shell
brew install git node
```
2. `corepack` 으로 `pnpm` 을 설치합니다
2. `corepack`으로 `pnpm`을 설치합니다
```shell
corepack enable
@@ -72,9 +72,9 @@ description: Project AIRI 에 기여하기
<summary>Linux 설정</summary>
0. 터미널을 엽니다
1. [nodesource/distributions: NodeSource Node.js Binary Distributions](https://github.com/nodesource/distributions?tab=readme-ov-file#table-of-contents) 를 따라 `node` 를 설치합니다
2. [Git](https://git-scm.com/downloads/linux) 안내를 따라 `git` 을 설치합니다
3. `corepack` 으로 `pnpm` 을 설치합니다
1. [nodesource/distributions: NodeSource Node.js Binary Distributions](https://github.com/nodesource/distributions?tab=readme-ov-file#table-of-contents)를 따라 `node`를 설치합니다
2. [Git](https://git-scm.com/downloads/linux) 안내를 따라 `git`을 설치합니다
3. `corepack`으로 `pnpm`을 설치합니다
```shell
corepack enable
@@ -154,10 +154,10 @@ npm i -g @antfu/ni
설치하고 나면
- `pnpm install`, `npm install`, `yarn install` 대신 `ni` 를 쓸 수 있습니다.
- `pnpm run`, `npm run`, `yarn run` 대신 `nr` 을 쓸 수 있습니다.
- `pnpm install`, `npm install`, `yarn install` 대신 `ni`를 쓸 수 있습니다.
- `pnpm run`, `npm run`, `yarn run` 대신 `nr`을 쓸 수 있습니다.
패키지 매니저가 무엇인지 신경 쓸 필요가 없습니다. `ni` 가 알맞은 것을 골라 줍니다.
패키지 매니저가 무엇인지 신경 쓸 필요가 없습니다. `ni`가 알맞은 것을 골라 줍니다.
:::
## 개발하고 싶은 애플리케이션 고르기
@@ -178,7 +178,7 @@ pnpm lint && pnpm typecheck
::: tip
[@antfu/ni](https://github.com/antfu-collective/ni) 를 설치했다면 `nr` 로 명령을 실행할 수 있습니다:
[@antfu/ni](https://github.com/antfu-collective/ni)를 설치했다면 `nr`로 명령을 실행할 수 있습니다:
```shell
nr lint && nr typecheck
@@ -219,4 +219,4 @@ git remote add upstream https://github.com/moeru-ai/airi.git
## 우와! 해내셨네요!
축하합니다! 이 프로젝트에 첫 기여를 하셨습니다. 이제 메인테이너가 여러분의 Pull Request 를 리뷰할 때까지 기다리시면 됩니다.
축하합니다! 이 프로젝트에 첫 기여를 하셨습니다. 이제 메인테이너가 여러분의 Pull Request를 리뷰할 때까지 기다리시면 됩니다.
@@ -1,6 +1,6 @@
---
title: Discord 봇
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Discord 봇 연동
@@ -15,7 +15,7 @@ cd integrations/discord-bot
cp .env .env.local
```
`.env.local` 에서 인증 정보를 수정하세요.
`.env.local`에서 인증 정보를 수정하세요.
봇 실행하기
@@ -1,6 +1,6 @@
---
title: Minecraft
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Minecraft 에이전트
@@ -9,7 +9,7 @@ description: Project AIRI 에 기여하기
cd integrations/minecraft
```
Minecraft 클라이언트를 실행하고 원하는 포트로 월드를 개방한 뒤, 그 포트 번호를 `.env.local` 에 입력하세요.
Minecraft 클라이언트를 실행하고 원하는 포트로 월드를 개방한 뒤, 그 포트 번호를 `.env.local`에 입력하세요.
`.env` 설정하기
@@ -17,7 +17,7 @@ Minecraft 클라이언트를 실행하고 원하는 포트로 월드를 개방
cp .env .env.local
```
`.env.local` 에서 인증 정보를 수정하세요.
`.env.local`에서 인증 정보를 수정하세요.
봇 실행하기
@@ -1,6 +1,6 @@
---
title: Satori 봇
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Satori 봇
@@ -15,7 +15,7 @@ cd integrations/satori-bot
cp .env .env.local
```
`.env.local` 에서 각종 키와 설정 정보를 수정하세요.
`.env.local`에서 각종 키와 설정 정보를 수정하세요.
봇 시작하기:
@@ -25,7 +25,7 @@ pnpm -F @proj-airi/satori-bot dev
::: tip
[@antfu/ni](https://github.com/antfu-collective/ni) 를 쓰신다면 이렇게 할 수 있습니다:
[@antfu/ni](https://github.com/antfu-collective/ni)를 쓰신다면 이렇게 할 수 있습니다:
```shell
nr -F @proj-airi/satori-bot dev
@@ -1,6 +1,6 @@
---
title: Telegram 봇
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Telegram 봇 연동
@@ -18,7 +18,7 @@ docker compose up -d
cp .env .env.local
```
`.env.local` 에서 인증 정보를 수정하세요.
`.env.local`에서 인증 정보를 수정하세요.
데이터베이스 마이그레이션
@@ -1,6 +1,6 @@
---
title: 데스크톱
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Stage Tamagotchi (데스크톱 버전)
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: 웹 UI
description: Project AIRI 에 기여하기
description: Project AIRI에 기여하기
---
### Stage Web ([airi.moeru.ai](https://airi.moeru.ai) 브라우저 버전)
+5 -5
View File
@@ -6,7 +6,7 @@ description: Project AIRI 사용법
## 설정
시스템 트레이에서 설정을 열어 더 자세히 커스터마이즈할 수 있습니다. 예를 들어
AIRI 의 테마 색상을 바꾸거나, Live2D(2D) 또는 VRM(3D, Grok Companion 과 비슷한 형태)
AIRI의 테마 색상을 바꾸거나, Live2D(2D) 또는 VRM(3D, Grok Companion과 비슷한 형태)
같은 다른 모델로 전환할 수 있습니다.
<video autoplay loop muted>
@@ -17,16 +17,16 @@ AIRI 의 테마 색상을 바꾸거나, Live2D(2D) 또는 VRM(3D, Grok Companion
### 모델 바꾸기
기본 모델을 다른 Live2D(2D)나 VRM(3D, 마찬가지로 Grok Companion 과 비슷한 3D 모델이라면
기본 모델을 다른 Live2D(2D)나 VRM(3D, 마찬가지로 Grok Companion과 비슷한 3D 모델이라면
가지고 계신 것으로) 모델로 교체할 수 있습니다.
모델 설정은 [설정] -> [모델] 아래에 있습니다.
::: tip VTuber Studio 모델을 가져오시나요?
Live2D 모델을 렌더링하는 데 사용하는 라이브러리는 VTuber Studio 모델에서 만들어진 ZIP 파일을
읽는 데 어려움을 겪습니다. VTuber Studio 는 사용하지만 Live2D 엔진은 알지 못하는 파일이 섞여 있기 때문입니다.
읽는 데 어려움을 겪습니다. VTuber Studio는 사용하지만 Live2D 엔진은 알지 못하는 파일이 섞여 있기 때문입니다.
따라서 가져오기 전에, VTuber Studio 모델을 ZIP 으로 압축하기 전에 다음 파일을 반드시 제외하세요.
따라서 가져오기 전에, VTuber Studio 모델을 ZIP으로 압축하기 전에 다음 파일을 반드시 제외하세요.
- `items_pinned_to_model.json`
:::
@@ -35,7 +35,7 @@ Live2D 모델을 렌더링하는 데 사용하는 라이브러리는 VTuber Stud
::: warning 알려진 버그
현재 모델의 장면을 다시 불러오는 기능이 의도대로 동작하지 않습니다.
모델을 불러온 뒤에는 AIRI 를 재시작해야 합니다.
모델을 불러온 뒤에는 AIRI를 재시작해야 합니다.
:::
<br />
@@ -1,14 +1,14 @@
---
title: 캐릭터 카드 템플릿
description: Project AIRI 용 Character Card V3 JSON 템플릿입니다.
description: Project AIRI용 Character Card V3 JSON 템플릿입니다.
---
이 템플릿은 새 AIRI 캐릭터를 만들 때 쓸 수 있는 최소한의 Character Card V3 구조를 제공합니다. 아래 JSON 을 복사한 뒤 예시 값을 여러분의 캐릭터 설정으로 바꾸고, 필드 이름과 중첩 구조는 그대로 유지하세요.
이 템플릿은 새 AIRI 캐릭터를 만들 때 쓸 수 있는 최소한의 Character Card V3 구조를 제공합니다. 아래 JSON을 복사한 뒤 예시 값을 여러분의 캐릭터 설정으로 바꾸고, 필드 이름과 중첩 구조는 그대로 유지하세요.
::: tip 작성 요령
- `name`, `description`, `personality`, `scenario`, `first_mes` 부터 채워 보세요.
- `name`, `description`, `personality`, `scenario`, `first_mes`부터 채워 보세요.
- 아직 필요하지 않은 선택 필드는 비워 두어도 됩니다.
- 가져오거나 공유하기 전에 최종 내용이 여전히 유효한 JSON 인지 확인하세요.
- 가져오거나 공유하기 전에 최종 내용이 여전히 유효한 JSON인지 확인하세요.
:::
## 템플릿
+12 -12
View File
@@ -1,13 +1,13 @@
---
title: 데스크톱 빠른 시작
description: 데스크톱에서 Project AIRI 를 시작하는 방법
description: 데스크톱에서 Project AIRI를 시작하는 방법
---
## 대화 시작하기
AIRI 를 설치하고 실행한 뒤, 가장 빠르게 대화를 시작하는 방법은 온보딩 과정을 끝까지 마치는 것입니다.
AIRI를 설치하고 실행한 뒤, 가장 빠르게 대화를 시작하는 방법은 온보딩 과정을 끝까지 마치는 것입니다.
1. AIRI 가 물어보면 사용할 언어를 선택합니다.
1. AIRI가 물어보면 사용할 언어를 선택합니다.
2. **직접 프로바이더 설정하기**를 선택하거나, 이미 AIRI 계정을 쓰고 있다면 로그인합니다.
3. OpenRouter, OpenAI 호환 API, DeepSeek, Ollama, Qwen, Gemini, Claude 등 채팅 프로바이더를 고릅니다.
4. 필요한 API 키나 로컬 엔드포인트 정보를 입력합니다.
@@ -15,8 +15,8 @@ AIRI 를 설치하고 실행한 뒤, 가장 빠르게 대화를 시작하는 방
6. 메인 캐릭터 창에서 컨트롤 아일랜드 오른쪽 아래의 **확장** 버튼을 클릭합니다.
7. **채팅 열기**를 클릭하고 메시지를 입력해 전송합니다.
::: tip Ollama 를 로컬에서 쓰시나요?
시스템 환경 변수로 `OLLAMA_ORIGINS=*` 를 설정한 다음, Ollama 를 재시작하고 나서 AIRI 에서 선택하세요.
::: tip Ollama를 로컬에서 쓰시나요?
시스템 환경 변수로 `OLLAMA_ORIGINS=*`를 설정한 다음, Ollama를 재시작하고 나서 AIRI에서 선택하세요.
:::
<br />
@@ -54,12 +54,12 @@ Stage Tamagotchi 라고도 부르는 데스크톱 버전은 보통 다음과 같
## 자동 숨김
눈 버튼은 AIRI 가 완전히 상호작용 가능한 상태를 유지할지, 아니면 작업하는 동안 시야와 클릭 방해를 부드럽게 줄일지를 결정합니다.
눈 버튼은 AIRI가 완전히 상호작용 가능한 상태를 유지할지, 아니면 작업하는 동안 시야와 클릭 방해를 부드럽게 줄일지를 결정합니다.
- **항상 표시**는 캐릭터를 계속 보이게 하고 클릭도 가능하게 둡니다.
- **자동 숨김**은 커서가 가까이 오면 캐릭터와 UI 를 흐리게 만들고, 클릭이 아래 앱으로 통과하도록 합니다.
- **자동 숨김**은 커서가 가까이 오면 캐릭터와 UI를 흐리게 만들고, 클릭이 아래 앱으로 통과하도록 합니다.
자동 숨김을 처음 켜면 AIRI 가 동작 방식을 설명하는 짧은 안내를 보여 줍니다. AIRI 를 클릭하기 어려워졌다면 컨트롤 아일랜드 근처로 커서를 옮긴 뒤 눈 버튼을 다시 클릭하세요.
자동 숨김을 처음 켜면 AIRI가 동작 방식을 설명하는 짧은 안내를 보여 줍니다. AIRI를 클릭하기 어려워졌다면 컨트롤 아일랜드 근처로 커서를 옮긴 뒤 눈 버튼을 다시 클릭하세요.
<div rounded-lg overflow-hidden>
<video autoplay loop muted class="scale-180 translate-x--30 translate-y--2 lg:scale-150 lg:translate-x--40">
@@ -77,7 +77,7 @@ Stage Tamagotchi 라고도 부르는 데스크톱 버전은 보통 다음과 같
</video>
</div>
Windows 에서는 창의 가장자리나 모서리를 드래그해 캐릭터 창 크기를 조절할 수 있습니다. 트레이 메뉴에도 몇 가지 빠른 프리셋이 있습니다.
Windows에서는 창의 가장자리나 모서리를 드래그해 캐릭터 창 크기를 조절할 수 있습니다. 트레이 메뉴에도 몇 가지 빠른 프리셋이 있습니다.
1. AIRI 트레이 아이콘을 오른쪽 클릭합니다.
2. **크기 조절**을 엽니다.
@@ -96,9 +96,9 @@ Windows 에서는 창의 가장자리나 모서리를 드래그해 캐릭터 창
첫 대화가 잘 동작한 뒤에 살펴보면 좋은 페이지들입니다.
- **서비스 소스**: 채팅, 음성, 전사, 그림 프로바이더를 추가하거나 수정합니다.
- **바디 모듈**: 의식, 목소리, 청각, 시각, 기억, Discord, Minecraft, Factorio, MCP 등 각 모듈에 AIRI 가 어떤 프로바이더를 쓸지 고릅니다.
- **캐릭터 모델**: Live2D 와 VRM 모델을 전환하거나 직접 만든 모델을 불러옵니다.
- **바디 모듈**: 의식, 목소리, 청각, 시각, 기억, Discord, Minecraft, Factorio, MCP 등 각 모듈에 AIRI가 어떤 프로바이더를 쓸지 고릅니다.
- **캐릭터 모델**: Live2D와 VRM 모델을 전환하거나 직접 만든 모델을 불러옵니다.
- **AIRI 캐릭터 카드**: 활성 캐릭터를 바꾸거나 새로 만듭니다.
- **시스템**: 언어, 테마, 분석 수집 여부, 데스크톱 전용 옵션을 설정합니다.
일부 모듈은 아직 실험적이며 로컬 소스 설정이나 외부 서비스가 필요할 수 있습니다. Windows 를 중심으로 한 더 자세한 안내는 [전체 데스크톱 사용 설명서](./setup-and-use/)를 참고하세요.
일부 모듈은 아직 실험적이며 로컬 소스 설정이나 외부 서비스가 필요할 수 있습니다. Windows를 중심으로 한 더 자세한 안내는 [전체 데스크톱 사용 설명서](./setup-and-use/)를 참고하세요.
@@ -14,14 +14,14 @@ publishedAtOverride: May 11, 2026 afternoon (UTC+8)
대응 버전: AIRI-0.10.2
::: warning 시작하기 전에
- AIRI 의 일부 기술적 기능과 조작은 이 설명서에서 자세히 다루지 않습니다.
- AIRI의 일부 기술적 기능과 조작은 이 설명서에서 자세히 다루지 않습니다.
- 주 편집자는 중국어판만 담당합니다. 다른 언어판은 현재 AI 번역에 간단한 수동 교정을 거친 것이라 실제 표시되는 내용과 다를 수 있습니다. 실제 내용을 기준으로 봐 주세요.
- 이 설명서의 대부분은 편집장 팀원들과 다른 참여자들이 직접 탐색하고 조사한 내용입니다. 사실과 다르거나 편차가 있을 수 있으니 최종적으로는 여러분의 실제 경험을 기준으로 삼아 주세요.
- 이 설명서는 제때 갱신되지 않을 수 있습니다.
- 역량과 시간의 한계로, 현재 이 설명서는 Windows 설치 패키지 버전과 웹 버전의 일부 상세 튜토리얼만 다룹니다.
- 소프트웨어의 일부는 번역 없이 영어로 표시됩니다. 이 설명서는 그 부분을 번역해 두었지만, 최종 해석은 실제 소프트웨어를 따라야 합니다.
- AIRI 의 버전 업데이트로 일부 내용이 바뀔 수 있습니다. 이 설명서는 작성 시점의 최신 버전 기능만 소개합니다. 그 이전이나 이후 버전에 대해서는 일부 기능 설명이 남아 있을 수 있으니, 차이가 있다면 직접 판단해 주세요.
- 이 설명서에 대해 질문이 있으면 공식 Project AIRI Discord 채널에서 @jhicefair 멘션하고 메시지를 남겨 주세요.
- AIRI의 버전 업데이트로 일부 내용이 바뀔 수 있습니다. 이 설명서는 작성 시점의 최신 버전 기능만 소개합니다. 그 이전이나 이후 버전에 대해서는 일부 기능 설명이 남아 있을 수 있으니, 차이가 있다면 직접 판단해 주세요.
- 이 설명서에 대해 질문이 있으면 공식 Project AIRI Discord 채널에서 @jhicefair 멘션하고 메시지를 남겨 주세요.
- 그 밖의 질문은 공식 Project AIRI Discord 채널에 남겨 주세요.
- 즐겁게 사용하세요! AwA
:::
@@ -31,7 +31,7 @@ publishedAtOverride: May 11, 2026 afternoon (UTC+8)
- [1장 설치](#chapter-1-installation)
- [2장 초기 설정](#chapter-2-initial-configuration)
- [1절 준비](#chapter-2-prerequisites)
- [2절 Airi 를 실행하자!](#chapter-2-launch)
- [2절 Airi를 실행하자!](#chapter-2-launch)
- [3장 Airi 인터페이스 개요](#chapter-3-interface-overview)
- [메인 창](#chapter-3-main-window)
- [시스템 트레이의 그 외 옵션](#chapter-3-system-tray)
@@ -59,14 +59,14 @@ Project AIRI GitHub 홈페이지로 이동합니다: [moeru-ai/airi](https://git
다음 순서를 따르세요:
1. 페이지 오른쪽에서 "**Releases**" 항목을 찾습니다.
2. "+ 68 releases" 를 클릭합니다.
3. 버전을 하나 고르고 그 아래 "**Assets**" 를 찾아 펼칩니다.
2. "+ 68 releases"를 클릭합니다.
3. 버전을 하나 고르고 그 아래 "**Assets**"를 찾아 펼칩니다.
4. 사용하는 컴퓨터에 맞는 버전을 골라 내려받습니다.
5. 내려받은 설치 파일을 찾아 더블클릭해 설치합니다.
::: tip 다운로드 페이지 참고
- "+ 68 releases" 의 숫자는 다른 릴리스가 몇 개 있는지만 나타내므로 여러분 화면에서는 다를 수 있습니다.
- 하단의 "Show all 19 assets" 를 눌러야 할 수도 있고, 이 숫자도 다를 수 있습니다.
- "+ 68 releases"의 숫자는 다른 릴리스가 몇 개 있는지만 나타내므로 여러분 화면에서는 다를 수 있습니다.
- 하단의 "Show all 19 assets"를 눌러야 할 수도 있고, 이 숫자도 다를 수 있습니다.
- 이후 내용은 Windows 설치 파일 버전을 예로 듭니다.
- 시간 제약으로 설치 과정 자체는 생략합니다. 이 정도는 직접 하실 수 있을 겁니다.
:::
@@ -77,49 +77,49 @@ Project AIRI GitHub 홈페이지로 이동합니다: [moeru-ai/airi](https://git
<a id="chapter-2-prerequisites"></a>
### 1절 준비
시작하기 전에 LLM 서비스 제공자의 API 를 최소 하나 준비해야 합니다.
시작하기 전에 LLM 서비스 제공자의 API를 최소 하나 준비해야 합니다.
::: info 용어
* LLM
LLM 은 Large Language Model(대규모 언어 모델)의 약자입니다.
간단히 말해 AI 입니다.
LLM은 Large Language Model(대규모 언어 모델)의 약자입니다.
간단히 말해 AI입니다.
* API
API 는 Application Programming Interface 의 약자입니다.
API는 Application Programming Interface의 약자입니다.
서로 다른 소프트웨어가 통신하고 데이터를 주고받고 기능을 공유할 수 있게 하는, 미리 정의된 규칙의 모음입니다.
깊이 이해할 필요는 없고, 어떻게 얻는지만 알면 됩니다.
:::
::: tip API 얻기
LLM 제공자는 아주 많고 API 를 얻는 방법도 각기 다릅니다. 시간 제약으로 여기서는 튜토리얼이나 예시를 제공하지 않습니다. 검색해 보거나 AI 에게 물어보세요.
LLM 제공자는 아주 많고 API를 얻는 방법도 각기 다릅니다. 시간 제약으로 여기서는 튜토리얼이나 예시를 제공하지 않습니다. 검색해 보거나 AI에게 물어보세요.
:::
::: warning API 키를 안전하게 보관하세요
API 를 얻으면 안전하게 보관하고 다른 사람과 공유하지 마세요.
API를 얻으면 안전하게 보관하고 다른 사람과 공유하지 마세요.
:::
<a id="chapter-2-launch"></a>
### 2절 Airi 를 실행하자!
### 2절 Airi를 실행하자!
::: info 예시
아래 단계는 Deepseek 을 예시 제공자로 사용합니다.
아래 단계는 Deepseek을 예시 제공자로 사용합니다.
:::
[과거 특성: 시작 시 발생하는 버그](#h2-2-1)
다음 순서로 첫 설정을 마칩니다:
1. Airi 를 엽니다 (보통 설치 후 자동으로 열립니다).
1. Airi를 엽니다 (보통 설치 후 자동으로 열립니다).
2. 메인 창에서 언어를 선택합니다.
3. "**setup with your provider**" 를 클릭합니다. 또는 "**Login**" 을 클릭합니다 (로그인을 선택하는 과정에 대한 간단한 안내).
4. 서비스 소스를 선택하고 "**Next**" 를 클릭합니다.
5. API 키를 입력하고 "**Next**" 를 클릭합니다.
6. 다시 "**Next**" 를 클릭합니다.
7. 사용할 모델을 선택하고 "**Save and continue**" 를 클릭합니다.
3. "**setup with your provider**"를 클릭합니다. 또는 "**Login**"을 클릭합니다 (로그인을 선택하는 과정에 대한 간단한 안내).
4. 서비스 소스를 선택하고 "**Next**"를 클릭합니다.
5. API 키를 입력하고 "**Next**"를 클릭합니다.
6. 다시 "**Next**"를 클릭합니다.
7. 사용할 모델을 선택하고 "**Save and continue**"를 클릭합니다.
축하합니다! Airi 의 초기 설정을 완료했습니다.
축하합니다! Airi의 초기 설정을 완료했습니다.
<a id="chapter-3-interface-overview"></a>
## 3장 – Airi 인터페이스 개요
@@ -132,7 +132,7 @@ API 를 얻으면 안전하게 보관하고 다른 사람과 공유하지 마세
이 창은 가상 캐릭터를 표시합니다. 버튼이 세 개 있습니다: [과거 특성](#h3-1-1)
- "Expand" 오른쪽 아래. 클릭하면 더 많은 옵션이 나타납니다 (아래 참고).
- "Open hearing control" 오른쪽 아래. Airi 에게 말을 걸 수 있게 합니다. STT 서비스가 필요합니다.
- "Open hearing control" 오른쪽 아래. Airi에게 말을 걸 수 있게 합니다. STT 서비스가 필요합니다.
- "Move" 오른쪽 아래. 길게 누른 뒤 끌어서 메인 창의 위치를 옮깁니다.
![Airi main window overview](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-main-window.avif)
@@ -144,11 +144,11 @@ API 를 얻으면 안전하게 보관하고 다른 사람과 공유하지 마세
::: info 용어
* STT
STT 는 Speech-to-Text 의 약자로 자동 음성 인식(ASR)이라고도 합니다.
STT는 Speech-to-Text의 약자로 자동 음성 인식(ASR)이라고도 합니다.
컴퓨터가 사람의 말을 이해해 텍스트로 변환하게 하는 것이 목표입니다.
:::
"Expand" 를 클릭하면 아홉 개 옵션이 나타납니다: **(로그인 버튼 & 작은 버튼 여덟 개)**
"Expand"를 클릭하면 아홉 개 옵션이 나타납니다: **(로그인 버튼 & 작은 버튼 여덟 개)**
- "Login" 자신의 Airi 계정으로 로그인할 수 있습니다.
- "Open settings" 설정 창을 엽니다.
@@ -158,7 +158,7 @@ STT 는 Speech-to-Text 의 약자로 자동 음성 인식(ASR)이라고도 합
- "Switch to dark mode" 라이트/다크 테마를 전환합니다.
- "Unpin" 메인 창을 항상 위에 두지 않게 합니다.
- "Always show" / "Hide on hover" 창을 클릭이 통과하도록 합니다.
- "Close" Airi 를 닫습니다.
- "Close" Airi를 닫습니다.
![Airi expanded controls menu](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-controls-island-expanded.avif)
@@ -168,14 +168,14 @@ STT 는 Speech-to-Text 의 약자로 자동 음성 인식(ASR)이라고도 합
먼저 시스템 트레이에서 Airi 아이콘을 찾습니다.
::: tip Windows 작업 표시줄 팁
Windows 에서는 작업 표시줄의 "숨겨진 아이콘 표시" 를 눌러야 Airi 아이콘을 찾을 수 있습니다.
Windows에서는 작업 표시줄의 "숨겨진 아이콘 표시" 를 눌러야 Airi 아이콘을 찾을 수 있습니다.
:::
Airi 아이콘을 오른쪽 클릭하면 열 개 옵션이 보입니다:
- "Show" 메인 창을 띄웁니다. 보통 필요하지 않습니다.
- "Adjust size" 메인 창 크기를 조절하고 가운데로 정렬합니다. 하위 옵션 네 개가 있습니다:
- "Recommended (450x600)" 권장 크기인 450x600 으로 설정합니다.
- "Recommended (450x600)" 권장 크기인 450x600으로 설정합니다.
- "Full height" 창 높이를 바탕화면 전체 높이로 맞춥니다.
- "Half height" 창 높이를 바탕화면 절반 높이로 맞춥니다.
- "Full screen" 창이 바탕화면 전체를 채우게 합니다.
@@ -189,16 +189,16 @@ Airi 아이콘을 오른쪽 클릭하면 열 개 옵션이 보입니다:
- "About" 상세 설명 생략.
- "Open quick actions" 상세 설명 생략.
- "Open widgets" 상세 설명 생략.
- "Open caption" 자막을 엽니다. Airi 가 말할 때 텍스트를 표시하려면 TTS 서비스가 필요하며, 기본적으로 마우스를 올리면 숨겨집니다.
- "Open caption" 자막을 엽니다. Airi가 말할 때 텍스트를 표시하려면 TTS 서비스가 필요하며, 기본적으로 마우스를 올리면 숨겨집니다.
- "Caption overlay" 하위 옵션 두 개가 있습니다:
- "Follow window" 기본값. 자막 위치가 메인 창을 따라갑니다.
- "Reset position" 자막 위치를 초기화합니다.
- "Quit" Airi 를 닫습니다.
- "Quit" Airi를 닫습니다.
::: info 용어
* TTS
TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성 출력으로 변환합니다.
TTS는 Text-to-Speech의 약자로, 문자 텍스트를 자연스러운 음성 출력으로 변환합니다.
:::
<a id="chapter-3-settings-overview"></a>
@@ -210,18 +210,18 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
다음 두 가지 방법으로 설정을 열 수 있습니다:
- 메인 창에서 "Expand" 를 클릭한 뒤 "Open settings" 를 선택합니다.
- Airi 트레이 아이콘을 오른쪽 클릭하고 "Settings" 를 선택합니다.
- 메인 창에서 "Expand"를 클릭한 뒤 "Open settings"를 선택합니다.
- Airi 트레이 아이콘을 오른쪽 클릭하고 "Settings"를 선택합니다.
설정 창에는 아홉 개 섹션이 있습니다:
- "AIRI Character Card" 캐릭터 성격을 설정합니다.
- "Body Modules" 여러 기능을 설정합니다: 의식, 발화, 청각, 시각, 단기 기억, 장기 기억, Discord, X/Twitter, Minecraft, Factorio, MCP 서버, 리듬 게임.
- "Scene" Airi 의 장면(배경)을 설정합니다.
- "Scene" Airi의 장면(배경)을 설정합니다.
- "Character Model" 캐릭터 모델을 선택하고 설정합니다.
- "Memory Bank" 아직 공개되지 않았습니다.
- "Service Sources" LLM, TTS, STT, Artistry 서비스를 설정합니다.
- "Data" Airi 의 데이터를 관리합니다.
- "Data" Airi의 데이터를 관리합니다.
- "Connection" WebSocket 서버 주소를 설정합니다.
- "System" 하위 섹션 네 개가 있습니다:
- "General" 테마, 언어 등.
@@ -229,7 +229,7 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
- "Window Shortcuts" 현재 비어 있고 뒤로 가기 버튼이 없습니다.
- "Developer" 고급 기능. 4장 참고.
::: warning "Window Shortcuts" 를 열지 마세요
::: warning "Window Shortcuts"를 열지 마세요
이 옵션은 현재 내용도 없고 뒤로 가기 버튼도 없습니다. 한번 들어가면 설정 창을 닫고 다시 열어야 나올 수 있습니다.
:::
@@ -238,19 +238,19 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
<a id="chapter-3-chat-window"></a>
### > 채팅 창
메인 창에서 "Expand" 를 클릭하고 "Open chat" 을 선택하면 채팅 창을 열 수 있습니다.
메인 창에서 "Expand"를 클릭하고 "Open chat"을 선택하면 채팅 창을 열 수 있습니다.
![Airi chat window interface](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-chat-window.avif)
여기서 Airi 와 대화할 수 있습니다.
여기서 Airi와 대화할 수 있습니다.
<a id="chapter-4-settings"></a>
## 4장 설정
다음 두 가지 방법으로 설정을 열 수 있습니다:
- 메인 창에서 "Expand" 를 클릭한 뒤 "Open settings" 를 선택합니다.
- Airi 트레이 아이콘을 오른쪽 클릭하고 "Settings" 를 선택합니다.
- 메인 창에서 "Expand"를 클릭한 뒤 "Open settings"를 선택합니다.
- Airi 트레이 아이콘을 오른쪽 클릭하고 "Settings"를 선택합니다.
<a id="chapter-4-airi-card"></a>
### > AIRI 캐릭터 카드
@@ -265,15 +265,15 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
새 캐릭터 카드를 만들 때 권장하는 순서는 다음과 같습니다:
1. **Identity** 를 작성합니다. 이름, 별명, 설명, 제작자 노트가 포함됩니다.
2. 그다음 **Behavior** 를 조정합니다. 성격, 시나리오, 첫 인사가 포함됩니다.
3. 필요하면 **Modules** 에서 캐릭터별 바디 모듈을 설정합니다.
1. **Identity**를 작성합니다. 이름, 별명, 설명, 제작자 노트가 포함됩니다.
2. 그다음 **Behavior**를 조정합니다. 성격, 시나리오, 첫 인사가 포함됩니다.
3. 필요하면 **Modules**에서 캐릭터별 바디 모듈을 설정합니다.
4. 필요에 따라 **Artistry** 섹션을 설정해 그 캐릭터의 이미지 생성 기능을 구성합니다.
5. 마지막으로 **Settings** 를 확인합니다. 시스템 프롬프트, 히스토리 프롬프트 지시, 버전이 포함됩니다.
6. 준비가 되면 "**Create**" 를 클릭해 캐릭터 카드를 만듭니다.
7. 만든 뒤에는 카드 오른쪽 아래의 원을 클릭하거나, 카드를 선택하고 Activate 를 클릭해 활성화합니다.
5. 마지막으로 **Settings**를 확인합니다. 시스템 프롬프트, 히스토리 프롬프트 지시, 버전이 포함됩니다.
6. 준비가 되면 "**Create**"를 클릭해 캐릭터 카드를 만듭니다.
7. 만든 뒤에는 카드 오른쪽 아래의 원을 클릭하거나, 카드를 선택하고 Activate를 클릭해 활성화합니다.
**Identity** 에서 가장 중요한 항목은 이름과 설명입니다:
**Identity**에서 가장 중요한 항목은 이름과 설명입니다:
- 이름은 공식 명칭입니다. 별명을 설정하면 별명이 먼저 사용됩니다.
- 설명은 상세한 성격입니다. 창의적으로 쓰거나 기본 캐릭터 카드를 참고하세요.
@@ -281,7 +281,7 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
::: info 편집자 노트
- 기본 캐릭터 카드를 참고한다면 ACT 태그에 관한 부분은 생략해도 됩니다.
- 편집자는 제작자 노트를 써 본 적이 없어 상세 설명은 생략합니다.
- 편집자가 Behavior, Modules, Artistry, Settings 를 아직 충분히 테스트하지 못했습니다. 위에는 대략적인 용도만 적어 두었습니다.
- 편집자가 Behavior, Modules, Artistry, Settings를 아직 충분히 테스트하지 못했습니다. 위에는 대략적인 용도만 적어 두었습니다.
:::
::: warning 활성화가 필요합니다
@@ -291,7 +291,7 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
<a id="chapter-4-modules"></a>
### > 바디 모듈
여기서 Airi 의 여러 기능을 다음과 같이 설정할 수 있습니다:
여기서 Airi의 여러 기능을 다음과 같이 설정할 수 있습니다:
![Airi body modules settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-modules.avif)
@@ -311,7 +311,7 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
#### > 발화 (Vocalization)
::: tip 발화 관련 참고
- 서비스 소스에 따라 설정 과정이 조금씩 다를 수 있습니다. 이 절은 알리바바 Bailian 을 예로 들었으니 실제 화면을 따라 주세요.
- 서비스 소스에 따라 설정 과정이 조금씩 다를 수 있습니다. 이 절은 알리바바 Bailian을 예로 들었으니 실제 화면을 따라 주세요.
- 일부 서비스에서는 Pitch 조절이 동작하지 않을 수 있습니다.
- 소스가 너무 많아 뒤쪽 항목을 클릭할 수 없으면, 탭 위에 마우스를 올리고 가운데 버튼을 누른 채 좌우로 끌어 보세요.
:::
@@ -321,8 +321,8 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
1. 먼저 서비스 소스를 선택하거나, 새로 추가한 뒤 선택합니다.
2. 그다음 모델을 선택합니다.
3. 이어서 목소리를 선택합니다.
4. Airi 가 말하지 않게 하려면 "None" 을 선택합니다.
5. 기본 설정을 마친 뒤에는 이 페이지 하단에 텍스트를 입력하고 "**Test voice**" 를 클릭해 샘플을 생성할 수 있습니다.
4. Airi가 말하지 않게 하려면 "None"을 선택합니다.
5. 기본 설정을 마친 뒤에는 이 페이지 하단에 텍스트를 입력하고 "**Test voice**"를 클릭해 샘플을 생성할 수 있습니다.
![Airi vocalization settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-speech.avif)
@@ -342,9 +342,9 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
추가로 다음을 할 수 있습니다:
- "Auto-send transcribed text" 를 켜면 전사된 텍스트가 자동으로 전송됩니다.
- "Auto-send transcribed text"를 켜면 전사된 텍스트가 자동으로 전송됩니다.
- 끄면 전송 전에 전사 결과를 다듬을 수 있습니다.
- "Auto-send delay" 로 전송 지연을 조정할 수 있습니다.
- "Auto-send delay"로 전송 지연을 조정할 수 있습니다.
::: info 편집자 노트
"자동 전송을 끄면 전사 결과를 다듬을 수 있다" 는 것은 편집자의 추측입니다. 편집자는 청각 기능을 아직 제대로 써 보지 못했습니다.
@@ -352,13 +352,13 @@ TTS 는 Text-to-Speech 의 약자로, 문자 텍스트를 자연스러운 음성
마이크를 테스트하려면:
1. 페이지 중간의 "**start monitoring**" 을 클릭합니다.
2. 필요하면 Sensitivity 를 조정합니다.
1. 페이지 중간의 "**start monitoring**"을 클릭합니다.
2. 필요하면 Sensitivity를 조정합니다.
STT 를 테스트하려면:
STT를 테스트하려면:
1. 페이지 하단의 "**start speech-to-text**" 를 클릭합니다.
2. "Transcription Result" 에서 결과를 확인합니다.
1. 페이지 하단의 "**start speech-to-text**"를 클릭합니다.
2. "Transcription Result"에서 결과를 확인합니다.
#### > 시각 (Vision)
@@ -370,12 +370,12 @@ STT 를 테스트하려면:
1. 먼저 서비스 소스를 선택하거나, 새로 추가한 뒤 선택합니다.
2. 그다음 모델을 선택합니다.
3. 필요하면 "Capture interval" 로 캡처 빈도를 조절합니다.
3. 필요하면 "Capture interval"로 캡처 빈도를 조절합니다.
![Airi vision settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-vision.avif)
::: warning Vision Capture 가 필요합니다
이 기능은 `System → Developer → vision capture` 에서 `vision capture` 를 활성화해야 합니다. 자세한 내용은 해당 절을 참고하세요.
::: warning Vision Capture가 필요합니다
이 기능은 `System → Developer → vision capture`에서 `vision capture`를 활성화해야 합니다. 자세한 내용은 해당 절을 참고하세요.
:::
#### > 그림 (Artistry)
@@ -384,9 +384,9 @@ STT 를 테스트하려면:
소스가 너무 많아 뒤쪽 항목을 클릭할 수 없으면, 탭 위에 마우스를 올리고 가운데 버튼을 누른 채 좌우로 끌어 보세요.
:::
여기서 Airi 의 예술적 창작 능력을 설정할 수 있습니다.
여기서 Airi의 예술적 창작 능력을 설정할 수 있습니다.
참고: 이 기능은 **Neuro 의 그림 로직과는 다릅니다.** 서드파티 AI 서비스로 이미지를 생성해 아주 정교한 **AI 생성 이미지**를 얻을 수 있습니다.
참고: 이 기능은 **Neuro의 그림 로직과는 다릅니다.** 서드파티 AI 서비스로 이미지를 생성해 아주 정교한 **AI 생성 이미지**를 얻을 수 있습니다.
시간 제약으로 이 절은 당장은 자세히 다루지 않습니다.
@@ -401,7 +401,7 @@ STT 를 테스트하려면:
#### > Discord
여기서 Discord 봇을 설정해 Airi 가 여러분의 Discord 서버에 들어와 상호작용하게 할 수 있습니다.
여기서 Discord 봇을 설정해 Airi가 여러분의 Discord 서버에 들어와 상호작용하게 할 수 있습니다.
권장 순서:
@@ -415,7 +415,7 @@ STT 를 테스트하려면:
#### > X/Twitter
Discord 와 비슷하며 봇이 필요합니다. 튜토리얼 생략.
Discord와 비슷하며 봇이 필요합니다. 튜토리얼 생략.
#### > Minecraft
@@ -440,9 +440,9 @@ Discord 와 비슷하며 봇이 필요합니다. 튜토리얼 생략.
프리셋 두 개가 포함되어 있습니다. 장면을 적용하려면 프리셋 가운데의 체크 표시를 클릭하세요 (마우스를 올렸을 때만 나타납니다).
"**Upload to Gallery**" 를 클릭해 직접 만든 이미지 장면을 가져올 수도 있습니다.
"**Upload to Gallery**"를 클릭해 직접 만든 이미지 장면을 가져올 수도 있습니다.
장면을 지우려면 "**Clear Default**" 를 클릭하세요.
장면을 지우려면 "**Clear Default**"를 클릭하세요.
<a id="chapter-4-character-model"></a>
### > 캐릭터 모델
@@ -451,22 +451,22 @@ Discord 와 비슷하며 봇이 필요합니다. 튜토리얼 생략.
![Airi character model settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-models.avif)
Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
Airi는 Live2D 모델과 VRM 3D 모델을 지원합니다.
기존 모델로만 전환하고 싶다면:
1. "**select model**" 을 클릭해 모델 선택기를 엽니다.
1. "**select model**"을 클릭해 모델 선택기를 엽니다.
2. 이 버전에는 기본으로 Live2D 두 개와 VRM 두 개가 있습니다.
3. 하나를 선택하고 "**confirm**" 을 클릭해 전환합니다.
3. 하나를 선택하고 "**confirm**"을 클릭해 전환합니다.
직접 만든 모델을 가져오려면 "**add**" 를 클릭해 Live2D 또는 VRM 모델을 가져옵니다.
직접 만든 모델을 가져오려면 "**add**"를 클릭해 Live2D 또는 VRM 모델을 가져옵니다.
::: info 편집자 노트
"Switch to Godot Stage (Experimental)" 옵션에 대해서는, 설명서 편집팀이 아직 이 기능을 충분히 이해하지 못했고 실험 단계로 보이므로 관련 소개는 당장은 생략합니다.
:::
::: warning 모델을 가져오기 전에
- 구형 Live2D 모델은 지원되지 않습니다. "\*.moc3" 를 포함한 파일을 사용해야 합니다.
- 구형 Live2D 모델은 지원되지 않습니다. "\*.moc3"를 포함한 파일을 사용해야 합니다.
- Live2D 모델을 가져오기 전에 모델 폴더를 "\*.zip" 파일로 압축하세요.
:::
@@ -474,10 +474,10 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
다음 순서로 진행할 수 있습니다:
1. "Zoom & Position" 을 펼쳐 메인 창에서 모델의 크기와 위치를 조정합니다. x 는 좌우, y 는 상하입니다.
2. "parameters" 를 펼쳐 마우스 추적, Idle Animation, 프레임레이트, Auto Blink, Force Auto Blink(대체 타이머), Shadow, 기본 파라미터로 초기화, 모델 캐시 지우기, 그리고 모델별 파라미터 전체를 설정합니다.
3. 대기 애니메이션을 원한다면 모델 zip 에 애니메이션 파일이 포함되어 있는지 확인하세요.
4. 필요하면 "Expressions" 를 펼쳐 표정 시스템을 활성화합니다.
1. "Zoom & Position"을 펼쳐 메인 창에서 모델의 크기와 위치를 조정합니다. x는 좌우, y는 상하입니다.
2. "parameters"를 펼쳐 마우스 추적, Idle Animation, 프레임레이트, Auto Blink, Force Auto Blink(대체 타이머), Shadow, 기본 파라미터로 초기화, 모델 캐시 지우기, 그리고 모델별 파라미터 전체를 설정합니다.
3. 대기 애니메이션을 원한다면 모델 zip에 애니메이션 파일이 포함되어 있는지 확인하세요.
4. 필요하면 "Expressions"를 펼쳐 표정 시스템을 활성화합니다.
::: info 편집자 노트
편집자가 이 부분을 아직 충분히 테스트하지 못해 상세 내용이 제한적입니다.
@@ -485,10 +485,10 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
#### > VRM 3D 모델을 선택한 경우
"Scene" 을 펼친 뒤 Model Position, 카메라 각도(도), 카메라 거리(줌), 모델 방향(Y축 회전), 모델 시선 방향과 관련 값들을 설정합니다.
"Scene"을 펼친 뒤 Model Position, 카메라 각도(도), 카메라 거리(줌), 모델 방향(Y축 회전), 모델 시선 방향과 관련 값들을 설정합니다.
::: info 편집자 노트
"Change model" 을 포함한 이 절은 시간 제약으로 생략합니다.
"Change model"을 포함한 이 절은 시간 제약으로 생략합니다.
:::
<a id="chapter-4-memory-bank"></a>
@@ -503,15 +503,15 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
항목을 선택하고, 미리 준비해 둔 서비스 소스를 고른 뒤, 해당 화면에서 필요한 정보를 채우면 설정이 완료됩니다.
또한 Pricing 이나 Deployment 같은 기준으로 모든 서비스를 필터링할 수 있습니다.
또한 Pricing이나 Deployment 같은 기준으로 모든 서비스를 필터링할 수 있습니다.
* Pricing 은 세 가지 옵션이 있습니다:
* Pricing은 세 가지 옵션이 있습니다:
- All
- Free
- Paid
* Deployment 는 세 가지 옵션이 있습니다:
* Deployment는 세 가지 옵션이 있습니다:
- All
- Local
@@ -520,17 +520,17 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
![Airi service sources settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-providers.avif)
::: warning 주의해 주세요
일부 서비스의 설정 화면은 제때 유지보수되지 못해 정상 동작하지 않을 수 있습니다. 비슷한 문제를 겪으면 GitHub 에 이슈를 제출하거나, (선택한 서비스 소스가 지원한다면) "OpenAI Compatible API" 옵션으로 설정을 시도해 보세요.
일부 서비스의 설정 화면은 제때 유지보수되지 못해 정상 동작하지 않을 수 있습니다. 비슷한 문제를 겪으면 GitHub에 이슈를 제출하거나, (선택한 서비스 소스가 지원한다면) "OpenAI Compatible API" 옵션으로 설정을 시도해 보세요.
:::
::: tip 기술적 조언
현재 시장에는 AI 모델이 아주 많습니다. AIRI 가 그 전부를 개별 지원하거나 실시간 유지보수를 보장할 수는 없으므로, **OpenAI 호환 API** 옵션을 고려해 보시길 권합니다. 사용하는 모델이 OpenAI 호환 API 를 지원한다면 여기서 설정할 수 있습니다.
현재 시장에는 AI 모델이 아주 많습니다. AIRI가 그 전부를 개별 지원하거나 실시간 유지보수를 보장할 수는 없으므로, **OpenAI 호환 API** 옵션을 고려해 보시길 권합니다. 사용하는 모델이 OpenAI 호환 API를 지원한다면 여기서 설정할 수 있습니다.
:::
<a id="chapter-4-data"></a>
### > 데이터
여기서 Airi 의 여러 데이터를 관리할 수 있습니다.
여기서 Airi의 여러 데이터를 관리할 수 있습니다.
![Airi data settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-data-settings.avif)
@@ -539,12 +539,12 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
:::
::: tip 알려진 문제
"Open app data folder" 에는 현재 폴더가 여러 번 열리는 버그가 있습니다.
"Open app data folder"에는 현재 폴더가 여러 번 열리는 버그가 있습니다.
:::
이 페이지는 여러 상자로 구성되어 있습니다:
1. 첫 번째 상자에는 "Open app data folder" 가 있습니다. "**Open folder**" 를 클릭해 엽니다.
1. 첫 번째 상자에는 "Open app data folder"가 있습니다. "**Open folder**"를 클릭해 엽니다.
2. 두 번째 상자에서는 대화 기록을 가져오거나 내보내거나, 모든 대화 세션을 삭제할 수 있습니다.
3. 세 번째 상자에서는 가져온 모든 모델을 삭제하거나 모듈 설정과 자격 증명을 초기화할 수 있습니다.
4. 네 번째 상자에서는 데스크톱 설정과 상태를 초기화할 수 있습니다.
@@ -575,8 +575,8 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
![Airi general system settings window](/en/docs/manual/tamagotchi/setup-and-use/assets/manual-system-general.avif)
- 테마는 기본이 라이트입니다. 버튼을 클릭하면 다크 모드로 전환됩니다.
- Language 는 인터페이스 언어를 설정합니다.
- Control island icon size 는 메인 창 오른쪽 아래 세 버튼의 크기를 바꿉니다.
- Language는 인터페이스 언어를 설정합니다.
- Control island icon size는 메인 창 오른쪽 아래 세 버튼의 크기를 바꿉니다.
- 마지막으로 사용 데이터와 크래시 리포트 수집을 허용할지 선택하거나 개인정보 처리방침을 읽을 수 있습니다 ("Privacy Policy" 클릭).
#### > Color Scheme
@@ -612,7 +612,7 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
첫 번째 상자와 관련 옵션들:
- 첫 번째 상자에서 "**Open**" 을 클릭하면 개발자 도구 창이 열립니다 (브라우저의 F12 같은 것).
- 첫 번째 상자에서 "**Open**"을 클릭하면 개발자 도구 창이 열립니다 (브라우저의 F12 같은 것).
- 두 번째 "Markdown stress test" 상세 설명 생략.
- 세 번째 "IO Tracer" 기능 소개는 당장은 생략.
- 네 번째 "Lag visualization" 상세 설명 생략.
@@ -675,8 +675,8 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
상단에 네 개 옵션이 있습니다:
- "applications" 열려 있는 임의의 애플리케이션 창을 선택하고 "**share window**" 를 클릭하면 상단에서 볼 수 있습니다. 캡처 위로 마우스를 옮기고 "stop" 을 클릭하면 중지합니다.
- "displays" 전체 화면을 캡처합니다. "**share screen**" 을 클릭하면 볼 수 있고, 캡처 위로 마우스를 옮기고 "stop" 을 클릭하면 중지합니다.
- "applications" 열려 있는 임의의 애플리케이션 창을 선택하고 "**share window**"를 클릭하면 상단에서 볼 수 있습니다. 캡처 위로 마우스를 옮기고 "stop"을 클릭하면 중지합니다.
- "displays" 전체 화면을 캡처합니다. "**share screen**"을 클릭하면 볼 수 있고, 캡처 위로 마우스를 옮기고 "stop"을 클릭하면 중지합니다.
- "devices" 상세 설명 생략.
- "refetch" 상세 설명 생략.
@@ -737,7 +737,7 @@ Airi 는 Live2D 모델과 VRM 3D 모델을 지원합니다.
###### > Profile
Airi 에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있습니다.
Airi에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있습니다.
상세 설명 생략.
@@ -760,7 +760,7 @@ Airi 에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있
###### > Position & Size
클릭하면 옵션 왼쪽에 x, y, scale 세 옵션이 새로 나타나고, 웹 인터페이스 왼쪽에 수직 바가 생깁니다. 여기서 x 는 모델의 x축 위치, y 는 모델의 y축 위치, scale 은 모델의 줌(크기)입니다. 웹 인터페이스 왼쪽의 수직 바를 **클릭한 채 끌어서** 이 세 값을 조정할 수 있습니다.
클릭하면 옵션 왼쪽에 x, y, scale 세 옵션이 새로 나타나고, 웹 인터페이스 왼쪽에 수직 바가 생깁니다. 여기서 x는 모델의 x축 위치, y는 모델의 y축 위치, scale은 모델의 줌(크기)입니다. 웹 인터페이스 왼쪽의 수직 바를 **클릭한 채 끌어서** 이 세 값을 조정할 수 있습니다.
![Adjust position and size on the main interface](/en/docs/manual/tamagotchi/setup-and-use/assets/web-position-size.avif)
@@ -785,7 +785,7 @@ Airi 에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있
### > 자주 겪는 문제
- 구버전에서 0.10.2 로 업그레이드할 때, 이전에 모델의 크기와 위치를 바꿔 두었다면 모델이 '사라진' 것처럼 보일 수 있습니다. 이 문제를 겪더라도 걱정하지 마세요. 모델 설정 화면에서 모델의 scale 과 위치를 초기화하면 해결됩니다.
- 구버전에서 0.10.2로 업그레이드할 때, 이전에 모델의 크기와 위치를 바꿔 두었다면 모델이 '사라진' 것처럼 보일 수 있습니다. 이 문제를 겪더라도 걱정하지 마세요. 모델 설정 화면에서 모델의 scale과 위치를 초기화하면 해결됩니다.
<a id="h2-2-1"></a>
### > 특성 H2-2-1
@@ -796,7 +796,7 @@ Airi 에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있
먼저 깜빡이는 테두리가 어두워지는 바로 그 순간에 클릭해서 펼칩니다.
그다음 두 번째 줄의 첫 번째 옵션인 'Refresh' 를 빠르게 찾아 클릭합니다. 이렇게 하면 문제가 해결됩니다.
그다음 두 번째 줄의 첫 번째 옵션인 'Refresh'를 빠르게 찾아 클릭합니다. 이렇게 하면 문제가 해결됩니다.
* 이 특성은 수정되었습니다!
@@ -812,7 +812,7 @@ Airi 에 로그인한 상태라면 여기서 계정 정보를 관리할 수 있
이 설명서는 주로 비공식 인원이 작성해 공식 사이트에 제출한 것입니다. 내용 유지보수는 보통 Mujiu Yunxuan Studio 구성원이 담당하지만, 이 문서를 편집하고 싶거나 이미 편집한 모든 분들이 문서 앞부분 저자 항목에 이름을 남겨 주시기를 진심으로 바랍니다. 내용을 바꾸든 서식을 다듬든, 이 설명서를 함께 풍성하게 하고 다듬는 데 누구든 참여해 주시길 환영합니다. Airi 프로젝트와 이 설명서에 여러분의 힘을 보태 주세요!
또한 비공식 사용자이면서 이 설명서를 편집할 아이디어가 있다면, 부담 갖지 마시고 그냥 수정해서 Pull Request 를 보내 주세요. 다만 이름을 남기는 것을 잊지 마시길 다시 한번 당부드립니다!
또한 비공식 사용자이면서 이 설명서를 편집할 아이디어가 있다면, 부담 갖지 마시고 그냥 수정해서 Pull Request를 보내 주세요. 다만 이름을 남기는 것을 잊지 마시길 다시 한번 당부드립니다!
여러분의 성원과 협조에 감사드립니다!
@@ -2,6 +2,6 @@
title: AI VTuber 란
---
LLM 이 생성한 문서이지만, 일본어 TTS 모듈과 서비스에 관한 유용한 자료가 담겨 있습니다:
LLM이 생성한 문서이지만, 일본어 TTS 모듈과 서비스에 관한 유용한 자료가 담겨 있습니다:
[【AI VTuber作り方ガイド】初心者でも簡単に自動生成する方法 – AI Front Trend](https://ai-front-trend.jp/how-to-make-ai-vtuber/)
@@ -12,7 +12,7 @@ title: Neuro-sama
- [Is it really Neuro-sama playing Minecraft? : r/NeuroSama](https://www.reddit.com/r/NeuroSama/comments/1ifhv0f/is_it_really_neurosama_playing_minecraft/)
- [Is neuro custom coded from the ground up or does she have a base model? : r/NeuroSama](https://www.reddit.com/r/NeuroSama/comments/19481ow/is_neuro_custom_coded_from_the_ground_up_or_does/)
AI/LLM 이 모델을 제어할 수 있게 해 주는 플러그인:
AI/LLM이 모델을 제어할 수 있게 해 주는 플러그인:
- [pladisdev/VTS-AI-Plugin](https://github.com/pladisdev/VTS-AI-Plugin)
+10 -10
View File
@@ -1,21 +1,21 @@
---
title: 소개
description: Project AIRI 의 UI 를 알아보세요
description: Project AIRI의 UI를 알아보세요
---
### 한 줄 요약
저희를 이렇게 생각해 주세요.
- [Neuro-sama](https://www.youtube.com/@Neurosama) 의 오픈소스 재현
- [Grok Companion](https://news.ycombinator.com/item?id=44566355) 의 오픈소스 대안
- [Neuro-sama](https://www.youtube.com/@Neurosama)의 오픈소스 재현
- [Grok Companion](https://news.ycombinator.com/item?id=44566355)의 오픈소스 대안
- Live2D, VRM(3D), 그리고 게임 플레이와 애플리케이션 인식에 특화된 롤플레잉을 지원하는
[SillyTavern](https://github.com/SillyTavern/SillyTavern) 대안
함께 놀고 대화할 수 있는 사이버 생명체(사이버 와이푸), 혹은 디지털 동반자를 가지는 꿈을 꿔본 적 있으신가요?
함께 놀고 대화할 수 있는 디지털 생명체(AI 최애 캐릭터), 혹은 디지털 동반자를 가지는 꿈을 꿔본 적 있으신가요?
현대적인 대규모 언어 모델의 힘 덕분에
[Character.ai (일명 c.ai)](https://character.ai)
[Character.ai (일명 c.ai)](https://character.ai)나
[JanitorAI](https://janitorai.com/) 같은 플랫폼, 또는
[SillyTavern](https://github.com/SillyTavern/SillyTavern) 같은 애플리케이션은
채팅 기반이나 비주얼 노벨 같은 경험을 제공하기에 이미 충분한 해법입니다.
@@ -23,13 +23,13 @@ description: Project AIRI 의 UI 를 알아보세요
> 하지만 게임을 함께 플레이하는 능력은요? 그리고 여러분이 무엇을 코딩하고 있는지 보는 능력은요?
> 게임을 하고 영상을 보면서 대화하고, 그 밖에도 수많은 일을 해낼 수 있는 존재 말이에요.
아마 [Neuro-sama](https://www.youtube.com/@Neurosama) 는 이미 알고 계실 겁니다. 그녀는 현재
아마 [Neuro-sama](https://www.youtube.com/@Neurosama)는 이미 알고 계실 겁니다. 그녀는 현재
게임을 하고, 대화하고, 여러분과 (VTuber 커뮤니티의) 참여자들과 상호작용할 수 있는 최고의 동반자이며,
어떤 사람들은 이런 존재를 "디지털 휴먼"이라고 부르기도 합니다.
**아쉽게도 오픈소스가 아니어서, 그녀가 라이브 스트림을 마치고 오프라인이 되면 더 이상 상호작용할 수 없습니다.**
그래서 이 프로젝트 AIRI 는 또 다른 가능성을 제시합니다.
**여러분만의 디지털 생명, 사이버 라이프를 언제 어디서나 손쉽게 소유하세요.**
그래서 이 프로젝트 AIRI는 또 다른 가능성을 제시합니다.
**여러분만의 디지털 생명 언제 어디서나 손쉽게 소유하세요.**
## 시작하기
@@ -59,7 +59,7 @@ description: Project AIRI 의 UI 를 알아보세요
</div>
웹 버전은 모바일 기기를 포함해 어디서나 손쉽게 접근할 수 있습니다.
데스크톱은 VTuber 스트리밍, 컴퓨터 조작, 그리고 AIRI 를 돌리기 위해 막대한 양의 토큰 비용을
데스크톱은 VTuber 스트리밍, 컴퓨터 조작, 그리고 AIRI를 돌리기 위해 막대한 양의 토큰 비용을
지불할 필요가 없는 로컬 LLM 접근 등 더 고급 용도에 적합합니다.
<div flex gap-2 w-full flex-col justify-center text-base>
@@ -91,4 +91,4 @@ description: Project AIRI 의 UI 를 알아보세요
이 프로젝트에 기여하는 방법을 이해하는 데 도움이 되는 가이드는 [기여하기](../contributing/) 페이지를 참고해 주세요.
Project AIRI 의 UI 를 디자인하고 개선하는 데 도움이 되는 자료는 [디자인 가이드라인](../contributing/design-guidelines/resources) 페이지를 참고해 주세요.
Project AIRI의 UI를 디자인하고 개선하는 데 도움이 되는 자료는 [디자인 가이드라인](../contributing/design-guidelines/resources) 페이지를 참고해 주세요.
@@ -1,5 +1,5 @@
---
title: 비슷한 다른 프로젝트들
description: Project AIRI 와 비슷한 다른 프로젝트들을 알아보세요
description: Project AIRI와 비슷한 다른 프로젝트들을 알아보세요
---
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: 버전
description: AIRI 의 여러 버전과 받는 방법
description: AIRI의 여러 버전과 받는 방법
---
<script setup>
@@ -16,7 +16,7 @@ import ReleasesList from '../../../../.vitepress/components/ReleasesList.vue'
<ReleasesList type="releases" :limit="5" />
[GitHub 에서 모든 릴리스 보기 →](https://github.com/moeru-ai/airi/releases)
[GitHub에서 모든 릴리스 보기 →](https://github.com/moeru-ai/airi/releases)
## 나이틀리 빌드 다운로드
+1 -1
View File
@@ -1,5 +1,5 @@
---
layout: home
title: 'Project AIRI'
slogan: 'AI 와이푸와 버얼 캐릭터의 영혼을 담아 우리 세계로 데려오기 위한 그릇.'
slogan: 'AI 최애 캐릭터와 버얼 캐릭터의 영혼을 담아 우리 세계로 데려오기 위한 그릇.'
---
@@ -1,4 +1,4 @@
PrismarineJS/mineflayer: 강력하고 안정적인 고수준 JavaScript API 로 Minecraft 봇을 만듭니다.
PrismarineJS/mineflayer: 강력하고 안정적인 고수준 JavaScript API로 Minecraft 봇을 만듭니다.
https://github.com/PrismarineJS/mineflayer
mindcraft/src/agent/agent.js at main · kolbytn/mindcraft