Hyun1008.log

프로젝트

#프로젝트

깃허브 데모

어느샌가.. 사운드클라우드 업로드 제한인 3시간을 거의 다 쓰게 되었습니다.

음원 배포를 위해 사용했던 계정이라면 아이고 나는 정말 대단해...! 하면서 유료 결제할 마음이 있었습니다만

아무래도 그 계정은 습작들 백업하는 용도의 계정이었고.. 대부분의 음원이 private 상태였어요.

이런 계정을 위해 돈을 쓰는 건 매우 큰 출혈 이었고, 결국 저는 대안을 찾으러 가기로 했습니다.

그냥 github에 올려버리기로 한 것이지요(어차피 습작이니까...)

처음에 이 프로젝트는 정적 페이지로 사운드클라우드-like 사이트를 만들어보는 것이었습니다.

그렇게 2시간만에 이런 걸 완성했었습니다. 파형을 바 형태로 보여주는 게 사운드클라우드랑 꽤 비슷한 물건이었죠.

음원 개별 페이지도 있습니다. 공유용으로요.

어차피 습작 백업하는 용도의 쓰레기통이니 저만 만족하면 되니까요.

그런데..

  • 친구 1: 재생버튼을 못찾겠다고 함. 그냥 파형에 대고 클릭하면 재생이 된다고 하니까 처음부터 재생할 수 없어서 아쉽다고 함
  • 친구 2: 랑 디코를 하는데 볼륨버튼이 없으니 소리를 줄여둘 수 없어서 브라우저 레벨에서 줄였음. 이건 아닌 것 같아서 새로 만들기로 결정..

(...)

그래서 기능을 붙이려고 했습니다. 하지만 저 UI 어디에 재생버튼, 볼륨버튼 을 달겠습니까...

어쩔 수 없이 파형 보여주는 것을 포기하고 UI를 새로 만들기로 했습니다.(사실 그게 캔버스 없어서 더 편-안함)

그러다 보니, 굳이 사운드클라우드 라는 틀 안에 남아있을 필요가 없을 것 같아 아예 플레이어 형식으로 옮겨 탔어요.

다행히! 제가 예전에 피치타르트 플레이어 만들던 JS 파일이 남아있어서 그걸로 기능을 달았습니다. 금방 되더라구요.

그리고 미디어세션이라는 게 있어서 이걸 붙이면 폰에서 백그라운드 재생할 때 앨범아트나 미디어 정보들을 보여줄 수 있다는 거예요. 어떻게 그냥 지나칩니까!

아무튼....

여러분이 만약에 사운드클라우드에 비공개로 습작만 올리는 편인데 3시간 제한에 지쳐있다면, 이 레포지토리 포크해서 사용하시는 것도 좋은 방법입니다...

그리고 사클에는 깔끔하게 완성된 음원만 올리세요.

그럼 이만...

#프로젝트 #NodeJS #블로그

CabinetKey(이하 캐비닛키)는, 자작 캐릭터와 이에 얽힌 배경 설정을 체계적으로 정리할 수 있게 돕는 도구입니다.

따로 데이터베이스가 구현되어 있지 않으므로 어떤 서버에도 연합되지 않은 순정 Misskey에 연결해서 사용합니다.

주요 기능

  • 계정 생성 후 자신의 계정에 최대 100개까지 '캐비닛'을 생성할 수 있습니다.
  • 캐비닛은 private, public 으로 설정할 수 있습니다.
    • 이 구분은 메인 페이지 노출과만 관련이 있으므로, private이라고 하더라도 자신의 계정 페이지에는 노출됩니다.

캐릭터, 장소 관련

  • 연도별 캐릭터 생존현황과 장소의 변화를 조회할 수 있습니다.
  • 캐릭터의 세부사항, 연표, 다른 캐릭터와의 관계를 자유롭게 설정할 수 있습니다.
  • 지도를 불러와 그 위 좌표별로 장소를 설정할 수 있습니다.

시리즈, 자료실 관련

  • 작품을 올리는 공간인 시리즈, 참고자료나 작중 주요 문헌 등을 올리는 공간인 라이브러리를 만들 수 있습니다.
    • 시리즈나 라이브러리 안에 회차별로 글, 그림을 업로드할 수 있습니다.
  • 유튜브, 사운드클라우드에 업로드되어 있는 곡을 사운드트랙으로서 가져올 수 있습니다.
    • 해당 곡이 어떤 캐릭터와 관련된 것인지 설정할 수 있습니다.
  • 시리즈나 라이브러리에 업로드된 회차에 사운드트랙 중 한 곡을 BGM으로서 불러올 수 있습니다.
  • 시리즈나 라이브러리에 업로드된 회차에 관련 캐릭터를 지정할 수 있습니다.

TODO

  • UI 다듬기
  • 작품 글자수 제한 없애기 (현재는 3000자)

create, update ...

  • 캐비닛 create, update, delete
  • 캐릭터 create, update, delete
  • 장소 create, update, delete
  • 테마송 create, update, delete
  • 시리즈 create, update, delete
  • 레퍼런스 create, update, delete
  • 글 create, update, delete

#프로젝트 #NodeJS #블로그

샘플 위키 깃허브 리포지토리

  • 개발 시작: 2024.09.06. – 2024.09.09.
  • 개발 기간: 4일

정적 위키?

Github의 정적 페이지 호스팅 서비스(pages)를 사용하여 배포하는 위키입니다. 데이터베이스로는 구글 스프레드시트를 사용해요.

그러니까 사실은 구글 스프레드시트 파서 에 가깝다고 해도, 할 말이 없습니다.

이전 프로젝트의 취약점

이전 프로젝트는 클라이언트 사이드에서 바닐라JS만 사용하여, API키가 그대로 노출되는 문제점이 있었습니다.

또 사소한 문제였지만 라우팅 기능이 없었기 때문에 경로가 아닌 쿼리스트링 상에서 모든 것을 처리했던 문제도 있었습니다. 그래서 각 문서들의 주소가 복잡했어요.

Nuxt.js와 Github Actions

이번 버전의 초코스프레드 위키는 Nuxt로 작성되었습니다.

Nuxt는 Vue 기반의 프레임워크로, 일단 node를 사용하지만, Github pages로 배포할 경우에는 Actions에 의해 정적 페이지로 렌더된 사이트가 배포됩니다.

이 방식은 서버를 사용하지는 않지만, secret에 입력한 프라이빗 키를 가지고 Action에서 자동으로 렌더 되기 때문에 훨씬 안전하고, 페이지 로딩도 빠릅니다.

또 정적 페이지긴 하지만 나름대로의 동적 라우팅도 구현할 수 있습니다.

개선점 1. 인증키

스프레드시트의 보기/편집 권한을 얻기 위해서 두 가지 인증 방식을 사용합니다.

  1. 위키를 보여주는 서비스 계정의 인증
  2. 위키 편집을 위한 사용자 계정의 인증

(1) 은 Google Action을 통해 서버사이드에서 처리한 것을 정적 렌더링하기 때문에 인증키가 보이지 않고, (2) 의 경우 구글 공식문서에서 제시하고 있는 클라이언트 사이드 인증을 사용하기 때문에 인증키가 필요없어요.

스프레드시트의 권한 설정을 제한된 편집자들에게만 공개하고, 외부 공유 링크는 막아둘 수 있다는 점도 개선된 점 중 하나입니다.

개선점 2. 라우팅

예전 버전의 초코스프레드 위키에서 대문 문서로 접속하기 위한 주소는 다음과 같았습니다.

https://wiki.rongo.moe/?d=대문

하지만 지금은 기존의 다른 위키 서비스들과 동일하게,

https://wiki.rongo.moe/대문/

으로 접속할 수 있습니다.

그래서 문서 제목은 / 를 포함할 수 없습니다. 샘플 위키의 경우 . 으로 /의 역할을 대신하고 있습니다.

아쉬운 점

물론 서버를 사용하지 않기 때문에, 실제 위키의 동작을 완전히 따라하지 못하는 면이 있습니다.

대표적인 것이 편집 내용이 실시간으로 반영되지 않는다는 것입니다. 현재 리포지토리에서 설정된 자동 배포는 5분마다이며, 실제로는 5분에서 10분 정도의 간격으로 배포됩니다. 스프레드시트에서 편집된 내용이 위키에 반영되기까지는 최대 10분 정도가 소요됩니다.

편집자들이 스프레드시트, 즉 데이터베이스에 직접 접속할 수 있다는 점도 한계라고 할 수 있습니다. 스프레드시트에 직접 접속해 시트를 삭제하거나, 내용을 전부 없던 일로 만들어버리거나 버전을 왜곡할 수 있습니다. 하지만 이런 것은 스프레드시트 자체의 버전 관리 기능을 통해 어느 정도 극복할 수 있습니다.

그럼에도 불구하고 무료로 위키를 제작할 수 있기 때문에, 한정된 주제를 가진 최대 3-4인 정도 되는 소규모 그룹에서 운영된다면 나름 좋은 솔루션이 될 수 있다고 생각합니다.

#프로젝트 #NodeJS #버튜버

지난번 포스트에 이어 두 개의 카메라로부터 얻은 VMC 신호를 믹싱해주는 노드 앱을 만들었어요. 첫번째 카메라는 Webcam Motion Capture, 두번째 카메라는 TDPT 라는 어플에 연결했어요.

1. 과정

1.1 평균 내기

두 개의 신호를 단순히 받아서 섞어주기만 하면 되는 게 아니에요. 두 신호의 프레임률이 다르다 보니 한쪽에서 신호가 많이 들어온다고 다른 한쪽에서 그만큼 들어오는 게 아니었어요.

그래서 양쪽에서 서로 다른 포트로 신호를 받은 다음에 소프트웨어 태그를 붙여서 데이터 가공 포트로 신호를 보내기로 했어요. 그리고 이 신호들을 태그별로 묶어서 일정 시간 동안 받은 뒤 그것을 평균 내고, 그것을 양쪽 소프트웨어에서 실행하고 평균을 내고 있어요.

1.2 쿼터니온은 그대로 두기

그런데 일단 쿼터니온은 평균을 내지 않고, 마지막 값만 받아오기로 했어요. 사유는 아마도 쿼터니온 또한 벡터이기 때문에, 이걸 그대로 평균을 내 버리면 다음과 같은 이상한(..) 값이 얻어지는 모양이에요.

그러면 이 값은 어떻게 평균을 내는가? 오른쪽과 같이 각도로 변환을 하는 게 가장 만만한 것 같아요. 양쪽 소프트웨어에서 받아온 마지막 쿼터니온 값을 오일러 앵글로 변환해 준 다음 이 값의 평균을 내 줄 거예요. 아무튼 쿼터니온 값은 최대한 건드리지 말고, 오일러 앵글로 변환해서 건드린 다음 재변환해 주는 것이 나을 것 같습니다.

1.3 파츠별 가중치 주기

사실, 모든 파츠에서 신호를 섞는 것이 아니라, 양팔과 양다리를 경우에 따라 서로 다른 신호에서 읽어오도록 했어요.

일반적으로 왼팔은 왼쪽 카메라가, 오른팔은 오른쪽 카메라가 읽는 것이 자연스럽다고 생각하실 거예요. 하지만 저는 이걸 반대로 두었어요. 왼팔과 왼다리는 보통 오른쪽 카메라가 스캔하고, 오른팔과 오른다리는 보통 왼쪽 카메라가 스캔하도록 했습니다. 왜냐면 그래야 이 포즈에서 값을 읽어올지 말지 결정하기 쉽기 때문이에요.

즉, WMC나 TDPT의 경우 한쪽 팔이 보이지 않을 때 값을 읽지 못하기 때문에 팔을 아래로 떨어뜨린 포즈로 둡니다. 이것을 감지해서 반대쪽 팔이 보이면 그 팔을 읽어오고, 보이지 않으면 읽어오지 않는 것으로 하는 거죠.

팔을 카메라 쪽으로 뻗는 경우에도, 보통은 왼쪽 팔을 앞으로 뻗으면 왼쪽 카메라가, 오른쪽 팔을 앞으로 뻗으면 오른쪽 카메라가 가려지기 때문에 스캔하지 않는 것이 좋아요.

아무튼 여기까지 했으면 기존의 위치값과 오일러 앵글을 가지고 새 위치값과 오일러 앵글을 뽑아낸 다음에, 오일러 앵글에서 쿼터니온으로 변환까지 해 줍니다.

1.4 스무딩

저는 0.1초 간격으로 스캔을 하고 있는데, 이것은 초당 10프레임 정도의 상당히 낮은 프레임률이에요. 따라서 새로 계산한 값으로의 이동을 6프레임으로 쪼개서 60프레임을 만들어 주었습니다.

여기까지 구현해둔 것이 위의 영상이에요. 다만 위 영상에서는 쿼터니온도 평균을 내 버려서 동작이 조금 뚝딱거립니다.

#프로젝트 #VanillaJS #블로그

이미지

링크

  • 개발 시작: 2024.08.23. ~ 2024.08.24.
  • 개발 기간: 이틀

구글 스프레드시트와 깃허브 페이지를 사용하여 제작한 위키입니다.

  • 구글스프레드시트의 '시트 하나' 가 문서 하나가 됩니다. 따라서... 만약 이걸로 수백 개의 문서를 가진 대형 위키를 만들려고 하면 좀 문제가 커집니다. 소형 위키에 사용하고자 합니다.
  • 문서를 편집하기 위해서는 그냥 원본 스프레드시트를 편집하는 방법이 있고(이 경우 기록이 남지 않으므로 추천하지 않아요), 자체 편집 기능을 이용하는 방법이 있습니다.

주의사항

  • API 제한 설정: 구글에서 API키를 받을 때 범위를 특정 웹사이트, 스프레드시트로만 설정합니다.
  • 연결할 스프레드시트의 제목은 어떤 것이어도 괜찮습니다. ID만 제대로 따면 됩니다.
  • 링크가 있는 모든 사람이 볼 수 있음 으로 하고, 링크를 복사한 뒤 d/와 /edit 사이에 있는 문자열 복사

왜 만들었나요?

  • 위키를 벌쳐에서 빼낼 수 있는 방법...
  • 그러나 팬덤 위키나 기존 위키 서비스를 쓰지 않는 방법
  • php 기반 무료호스팅도 안 쓸수있는 방법(이건 도메인 연결도 못함...)

을 찾다가 만들었습니다.

어떻게 만들었나요?

가능한 것

  • 문서 읽기
  • 구글 로그인, 로그아웃
  • 이미 존재하는 문서의 편집

해야하는 것

  • 없던 문서의 생성
  • 문서를 이전 버전으로 되돌리기
  • 자잘한 속성 (몇 번째 버전인지, 언제 마지막으로 수정되었는지)의 표시

#프로젝트 #VanillaJS #연합우주

OpenAI의 API를 이용해서 다양한 기능을 지원하는 Misskey 챗봇을 제작했습니다.

이미지

최근 '파이'를 다시 만들고 있습니다. 거의 처음부터 다시 만들었다고 보시면 됩니다.

'파이'는 이전 피치타르트 시절 웹브라우저에서 구동했었던 챗봇입니다. 파이를 구동하기 위해서는 운영체제 상관 없이 24/7 꺼지지 않는 컴퓨터와 브라우저가 있으면 됩니다. 미스키 계정으로의 액세스 토큰과 챗GPT 토큰은 GET 방식으로 받습니다.

  • 파이 리포지토리: 링크
    • 위 폴더 중 js/main.js 가 중요합니다!

구현한 기능

0. 자동 포스트

정해진 시간마다 한번씩 자동으로 게시글을 남깁니다. 이 때, 매주 매 시간별로 일정을 셋팅하고, 저녁 메뉴와 대화 주제의 경우에는 랜덤 선택지를 두어 다양한 주제의 게시글을 작성하도록 했습니다.

1. 단순 채팅

유저의 멘션에 반응해서 답글을 남깁니다. 이번 버전의 파이는 자신있는 주제가 있고 자신없는 주제가 있어요. 코딩, 수학, 의학 등과 같은 hallucination에 민감한 소재는 피하도록 했습니다.

2. 하루 채팅 제한

하루 20회의 채팅 횟수 제한이 있습니다.

3. 호감도

일반 채팅 포함, 대화 내용이 챗봇의 입장에서 긍정적이었는지 부정적이었는지 평가하여 호감도를 증감 합니다.

호감도가 일정 수준 이상이면 대화의 퀄리티가 증가하게 되며, 특히 멘션을 줄 때마다 자신의 감정에 따른 이미지를 첨부해 줍니다.

4. 맞팔로우

유저로부터 맞팔로우 요청으로 보이는 언급이 있으면 맞팔로우 해 줍니다. 단, 이미 파이를 팔로우한 유저에 한해 맞팔로우 합니다.

5. 리마인더

유저로부터 시각 언급이 있으면(몇 시, 몇시간 후 둘 다 가능) 자동으로 그 시각을 저장해 두었다가 리마인드 해 줍니다.

코드의 흐름

  • 유저가 파이에게 질문을 합니다.
  • 브라우저의 페이지는 주기적으로 멘션창을 확인하고, 유저의 질문을 감지합니다.
  • 로컬스토리지에서 질문한 사람의 호감도와, 오늘의 잔여 질문 횟수를 읽습니다.
  • 질문 횟수가 남아있으면 gpt-4o 에게 메인 프롬프트, 호감도에 따른 프롬프트, 질문한 사람의 이름을 전달합니다.
  • 프롬프트와 챗봇의 답변을 gpt-4o-mini 에게 전달하여, 대화가 긍정적이었는지 부정적이었는지 / 리마인더 언급이 있었는지 / 맞팔 요청이 있었는지 / 드라이브의 이미지 중 뭘 쓰는 게 좋은지 간단한 json 형식으로 반환합니다.
  • 대화가 긍정적이었는지 부정적이었는지 여부에 따라 호감도를 재설정하고, 잔여 질문 횟수도 조정합니다.
  • 리마인더 언급이 있을 경우 해당 데이터를 로컬스토리지에 저장합니다.
  • 반환된 드라이브의 이미지를 사용해서 유저에게 답변합니다.
  • 맞팔 요청이 있었을 경우 맞팔합니다. 그러나 맞팔로우 이슈가 있을 경우(파이를 팔로우하지 않음, 이미 팔로우한 유저 등) gpt-4o-mini에게 오류 전달 후 유저에게 다시 답변합니다.

이와 같이, 파이에게 멘션 하나를 날리면 이전과 다르게 gpt로의 요청이 최소 두 번, 최대 세 번까지 이루어집니다.

TODO

  • 다른 misskey 서버에서 비슷한 챗봇을 구현할 수 있게, 커스터마이징이 쉽도록 settings.js에 옵션을 추가할 계획입니다.
  • README.md 를 영어로, 친절하게 수정할 계획입니다.
  • 코드 내의 주석 언어를 영어로 수정할 계획입니다.
  • 채팅 제한이 있는 노트에도 멘션을 달아야 합니다. (답해야 할 노트를 멘션 갯수로 판정하기 때문입니다.)