Hyun1008.log

vanillajs

#스터디 #VanillaJS

MDN Web Docs의 소개는 다음과 같습니다.

map() 메서드는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 (반복하여) 새로운 배열을 반환합니다.

const array1 = [1, 4, 9, 16];

// Pass a function to map
const map1 = array1.map((x) => x * 2);

console.log(map1);
// Expected output: Array [2, 8, 18, 32]

또는 return을 사용해서 반환할 수도 있습니다.

var numbers = [1, 4, 9];
var doubles = numbers.map(function (num) {
  return num * 2;
});
// doubles는 [2, 8, 18]

map 안의 function에서는 파라미터를 두 개까지 쓸 수 있는데, 두번째 파라미터는 배열의 index를 나타냅니다.

예를 들면

var array = [0, 0, 0]
array.map(function(a, i){
   console.log(i)
})
// 0
// 1
// 2
// 반환되는 새로운 배열은 undefined 로 채워짐

#개발과정 #VanillaJS

포트폴리오 사이트를 만드는 중 프로젝트를 보여줄 때는 가로스크롤을 하는 게 좋을 것 같아서 만들어 보았습니다.

우선 이렇게 구조를 짰습니다.

        <div id="content1">
            <div id="content-scroll">
                <div class="width-fix">
                    <h1>Items.</h1>
                    <div class="overflow-width">
                    </div>
                </div>
            </div>
        </div>

CSS에서는 .overflow-width 에만 position: relative 를 적용해 주었습니다. 그리고 자바스크립트에서는 다음과 같은 코드를 적용했어요.

    document.querySelector('.overflow-width').style.left=`0`;
    // 이게 없으면 후에 style.left 를 불러오지 못합니다.
    document.querySelector('#content-scroll').addEventListener('wheel',function(e){
        if(e.deltaY > 0){
        // 스크롤을 내리고 있으면,
            if (parseInt(document.querySelector('.overflow-width').style.left) > -100) {
                // 가로스크롤이 충분히 진행되지 않았으면(=스크롤이 필요하면)
                e.preventDefault();
                e.stopPropagation();
                // 기존 세로 스크롤을 막습니다.
                document.querySelector('.overflow-width').style.top=`0%`;
                document.querySelector('.overflow-width').style.left = `${parseInt(document.querySelector('.overflow-width').style.left) - 1}%`;
                // 그리고 스크롤 양에 따라 요소의 위치를 옮겨줍니다.
            }
        } else if (e.deltaY < 0) {
        // 스크롤을 올리고 있으면,
            if (parseInt(document.querySelector('.overflow-width').style.left) < 0) {
                // 가로스크롤이 충분히 돌아오지 않았으면(=스크롤이 필요하면)
                // 아래 내용은 동일합니다.
                e.preventDefault();
                e.stopPropagation();
                document.querySelector('.overflow-width').style.top=`0%`;
                document.querySelector('.overflow-width').style.left = `${parseInt(document.querySelector('.overflow-width').style.left) + 1}%`;
            }
        }
    });

남의코드 복붙해야지 히히 하고 들어갔다가 저한테 맞는 방법, 제가 당장 필요한 방법은 따로 있다는 사실을 깨달았습니다.

물론 제가 당장 필요한 방법을 구현해 놓은 포스트가 있었다면 완전 럭키비키겠지만요.

그래도 최대한 제가 만들어보고 남의 손을 빌리는 게 맞는 것 같습니다.

#스터디 #VanillaJS

모르는 내용은 아니지만, 매번 코드를 작성할 때 잊게 되는 것 같아 정리 겸 확실히 하기 위해 적습니다.

  1. false: Boolean
  2. 0: 정수 0
  3. -0: 정수 -0
  4. 0n: BigInt
  5. "": 빈 문자열
  6. null
  7. undefined
  8. NaN

0n: BigInt

정수 리터럴의 뒤에 n을 붙이거나(10n) 함수 BigInt()를 호출해 BigInt를 생성할 수 있습니다. 일반적으로 Int 에서 가장 큰 정수는 9007199254740991 이지만, 그 뒤에 n을 붙이거나 BigInt() 로 감싸면 그 이상의 숫자 9007199254740992n 도 담을 수 있습니다.

undefined에 대한 판정

예를 들어, 어떤 변수에 값이 정의되어 있는지 아닌지에 따라 if 문을 써야 한다면, 절대로

if ( 변수이름 ) {
} else {
}

이렇게 판정하면 안 되고, === 라든가 !== 라든가 typeof 같은 걸 사용하는 것이 맞습니다.

#프로젝트 #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 를 영어로, 친절하게 수정할 계획입니다.
  • 코드 내의 주석 언어를 영어로 수정할 계획입니다.
  • 채팅 제한이 있는 노트에도 멘션을 달아야 합니다. (답해야 할 노트를 멘션 갯수로 판정하기 때문입니다.)