이 글은 Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady에 제출하는 글입니다.
제가 만든 것
스크린샷을 찍는 것은 쉽습니다. 하지만 그것들을 다시 찾아보는 것은 별개의 취미인 것 같습니다.
반품 라벨, 콘서트 티켓, 레시피, 할인 코드. 이 모든 것에는 “나중에 처리할게”라는 작은 약속이 담겨 있습니다.
그러다 나중에 그 유용한 물건들은 밈(meme)과 같은 대화 스크린샷 세 장 사이에 어딘가에 놓여 있습니다.
저는 이러한 미완의 과제를 중심으로 Screenshot Séance, 또는 séance를 만들었습니다.
아직 당신을 필요로 하는 몇 안 되는 스크린샷을 찾고, 나머지는 흘려보내세요.
Séance는 Ollama를 통해 로컬에서 실행되는 Gemma 4를 사용하여 스크린샷 폴더를 읽고 이를 다섯 개의 바구니(bucket)로 분류합니다:
| 바구니 | 의미 |
|---|
| Needs you | 조치가 필요한 항목: 물건 반품, 약속 참석, 코드 사용 등 |
| ... | |
| Choose a folder, let it process, and come back to a smaller set of decisions. (폴더를 선택하고 처리하게 한 후, 더 적은 수의 결정 사항을 확인하세요.) | |
“모든 것을 대신 처리하기(Do it all for me)” 버튼을 누르면 실행 가능한 항목들이 목록에 추가되고, 기념품은 보존되며, 처리가 가능한 잡동사니는 '해제 폴더(release folder)'로 이동합니다. 민감하거나 불확실한 것으로 표시된 항목들은 당신을 기다립니다.
버리는 것은 되돌릴 수 있습니다. 파일들은 원본 폴더 옆의 _released_by_seance 폴더로 이동하며, 앱은 절대 영구적으로 삭제하지 않습니다. '되돌리기(Undo)'를 하면 다시 돌아옵니다.
또한 캡션으로 이 경험을 소개하는 나이 든 나무늘보 타로 리더인 Old Ambrose도 있습니다. 당신의 스크린샷들은 영혼들이며, 그중 일부는 미완의 과제를 가지고 있습니다.
네, 저는 스크린샷 폴더에 유령의 집 테마를 적용했습니다.
모든 오싹한 라벨에는 평이한 언어 버전이 존재합니다. Daylight skin은 세앙스 없이 파일 관리를 선호하는 경우 간결하게 유지해 줍니다.
데모
Screenshot Séance 사용하기 →
정렬 실행을 시작하고, 아침 결과를 탐색하며 **“모든 것을 대신 처리하기”**를 시도해 보세요. 개별 항목을 검토하거나 목록을 탐색하고, 해제 및 되돌리기 옵션을 사용해 볼 수도 있습니다.
호스팅된 데모는 12개의 합성 스크린샷과 실제 로컬 파이프라인에서 기록된 분류 결과를 사용합니다. 정렬(Sorting)은 가속화된 리플레이이며, 동작(actions)은 브라우저 메모리 내에서 시뮬레이션됩니다.
이는 사용자님의 스크린샷 폴더에 접근하거나 파일을 이동시키지 않으며, Vercel에서 Gemma를 실행하지도 않습니다.
전체 애플리케이션은 Ollama를 사용하여 사용자의 컴퓨터에서 직접 실행됩니다. 공개 데모는 모델을 설치하거나 개인 스크린샷을 공유할 필요 없이 경험을 탐색해 볼 수 있게 합니다.
코드
GitHub에서 Screenshot Séance 보기
README 및 설정 지침 읽기
애플리케이션 코드는 MIT 라이선스를 따릅니다. 저장소에는 백엔드, 프론트엔드, 합성 스크린샷, 벤치마크 스크립트, 테스트 및 브라우저 데모 구현이 포함되어 있습니다.
README 파일에는 필수 전제 조건 설치 방법, Ollama를 통해 gemma4:e4b를 가져오는 방법, 그리고 로컬 애플리케이션을 실행하는 방법이 설명되어 있습니다.
구축 과정 (How I Built It)
프론트엔드는 React, TypeScript, Vite, Tailwind CSS, Motion을 사용합니다. 로컬 FastAPI 백엔드가 스크린샷 워크플로우를 처리하고, SQLite가 진행 상황을 저장하며, Ollama가 오픈 웨이트 모델인 Gemma 4를 서비스합니다.
파이프라인은 다음과 같이 작동합니다:
- 폴더 스캔. 이미지 메타데이터, 해시 값 및 로컬 썸네일을 기록합니다.
- 근접 중복물 포착. 추가적인 모델 호출을 수행하기 전에 지각 해시(perceptual hashes)를 사용하여 복사본을 식별합니다.
- 이미지 하나씩 읽기. 크기가 조정된 스크린샷을 Ollama의
/api/chat 엔드포인트를 통해 Gemma로 전송합니다.
- 결과 검증. 구조화된 JSON을 요청하고, 응답을 확인하며, 유효하지 않은 출력은 한 번 재시도(retry)합니다.
- 로컬 규칙 적용. 최종 버킷을 할당하기 전에 민감성(sensitivity), 불확실성(uncertainty), 마감일(deadlines)을 해결합니다.
- 진행 상황 저장. 작업 내용을 영구적으로 보존하여 중단된 실행이 재개될 수 있도록 합니다.
Gemma는 스크린샷의 내용물, 어떤 동작을 제안하는지 여부, 그리고 마감일이나 민감한 정보가 포함되어 있는지 등을 해석합니다.
일반적인 Python 코드는 이러한 예측 주변의 규칙을 처리합니다. 민감도 플래그는 실행 가능한 레이블보다 우선권을 갖습니다. 신뢰도가 낮은 결과는 “확실하지 않음(Not sure)”으로 분류됩니다. 만약 모델이 무언가를 실행 가능하다고 표시했지만 어떤 행동인지 식별할 수 없다면, 해당 항목은 검토를 위해 보류됩니다.
이러한 확인 과정들은 여전히 모델이 감지하는 것에 의존합니다. 민감도 감지는 놓치는 것이 있을 수 있으며, 이것이 양방향 파일 이동과 인간의 검토가 중요한 이유 중 하나입니다.
자동으로 처리되는 부분은 중단 상황을 견뎌야 합니다.
작업자(worker)는 SQLite에 진행 상황을 기록하며 재시작 후에도 작업을 재개할 수 있습니다. 초기 정렬이 완료된 후, 감지기(watcher)는 새로 추가된 스크린샷을 감지할 수 있습니다.
컴퓨터가 계속 처리하려면 깨어 있어야 합니다. 만약 컴퓨터가 절전 모드에 들어가거나 앱이 닫히더라도, 저장된 진행 상황 덕분에 나중에 작업이 재개됩니다.
유용한 결과들은 목록으로 정리됩니다. 달력 내보내기(Calendar export)는 날짜가 지정된 항목에는 종일 이벤트로, 날짜가 지정되지 않은 항목에는 할 일 목록으로 구성된 .ics 파일을 생성합니다.
모델 선택은 트레이드오프를 수반했습니다.
RTX 2060, 6 GB VRAM, 32 GB RAM을 갖춘 노트북에서 실제 스크린샷 10개를 대상으로 초기 벤치마킹을 수행하면서, 저는 추론 기능(thinking)을 비활성화하고 이미지를 최대 긴 변이 1024픽셀로 제한한 두 가지 모델을 비교했습니다:
| Model | Median per image | Valid JSON on first attempt | Card-number examples caught |
|---|
gemma4:e4b | 3.39 seconds | 9/10 | 2/2 |
gemma4:e2b | 2.16 seconds | 10/10 | 1/2 |
더 작은 모델이 더 빨랐지만, 민감한 카드/은행 예시 중 하나를 놓쳤습니다. 저는 기본값으로 e4b를 선택했습니다.
이는 일반적인 정확도 주장이 아닌 소규모 로컬 벤치마크입니다. 12개의 합성 샘플을 대상으로 별도로 실행했을 때는 중간 API 지연 시간이 11.64초로 기록되었으므로, 앞서 언급된 시간은 속도를 보장하는 수치가 아닙니다. 이 워크플로우의 경우 처리 시간은 유연할 수 있습니다. 저는 폴더가 요구하는 주의를 줄이는 것에 더 신경을 쓰고 있습니다.
검증 과정에는 모델 파이프라인과 주변 애플리케이션 전체가 포함되었습니다.
실시간 합성 실행은 모델에 의해 11개의 이미지가 분류되었고, 모델 호출 없이 중복된 항목이 1개 식별되었으며, 처리 오류는 0건으로 완료되었습니다. 이는 실행이 완료되었다는 것을 확인시켜 줄 뿐이며, 완벽한 분류 정확도를 보장하는 것은 아닙니다.
백엔드는 목록화(listing), 캘린더 내보내기(calendar export), 출시 및 복원(release and restore), 자동 운전 모드(autopilot), 중단된 실행에 대한 가짜 모델 파이프라인 테스트를 포함하여 24개의 통과한 테스트를 가지고 있습니다. 일반 프론트엔드 빌드와 호스팅 데모 빌드 또한 통과했습니다.
저는 개발 과정에서 GitHub Copilot을 사용했습니다. 이 글의 투명성을 위해, 저는 프로젝트 노트와 저장소에서 작성된 내용을 초안 작성하고 수정하는 데 ChatGPT도 사용했습니다. 벤치마크 수치는 문서화된 로컬 실행에 대한 것이며, 본 게시물을 준비하는 데 사용된 AI 지원과는 별개입니다.
개방형 혁신(Open Innovation)이 중요한 이유?
스크린샷은 호스팅된 모델로 보내기에는 다소 어색한 자료입니다. 폴더 안에는 농담, 결제 정보, 복구 코드, 개인 메시지 등 깜빡하고 넣은 것이 있을 수 있습니다. 누군가 그 컬렉션을 업로드해 달라고 요청하는 것은 제가 만들고자 했던 제품의 종류 자체를 바꿀 것입니다.
Gemma를 Ollama를 통해 로컬에서 실행하면 스크린샷 분류 작업을 파일과 같은 장치에서 수행할 수 있게 됩니다. 종속성과 모델이 설치되면, 로컬 애플리케이션은 오프라인에서도 작동할 수 있습니다. 생성(inference) 계정을 만들 필요도 없고 이미지당 API 요금도 없습니다. 여전히 하드웨어 및 전기 비용은 발생하지만, 긴 분류 작업이라 할지라도 호스팅된 모델 제공업체로부터 사용량 청구서가 누적되지는 않습니다.
또한 개방형 가중치(Open weights)는 제가 선택할 수 있는 실용적인 모델 세트를 제공합니다. 저는 이 작업을 통해 그들을 비교하고, 구성된 Ollama 모델을 변경하며, 주변 애플리케이션은 제 통제 하에 둘 수 있습니다. 애플리케이션 코드도 사용 가능합니다. 누군가는 규칙을 검사하거나, 신뢰 임계값(confidence threshold)을 변경하거나, 마감일 처리 방식을 조정하거나, 폴더를 맡기기 전에 “놓아주기(Let go)”가 정확히 무엇을 하는지 확인할 수 있습니다.
이러한 조합은 아이디어를 실용적으로 만들었습니다: 개인 이미지를 위한 로컬 추론(local inference), 검사 가능한 동작(inspectable behavior), 그리고 기계가 자체 속도로 작업할 수 있는 자유입니다.
챌린지의 'Slow and Steady' 테마는 이 워크플로우에 잘 맞습니다. 분류하는 데 시간이 걸릴 수 있지만, 그동안 저는 다른 일을 할 수 있습니다. 제가 돌아올 때쯤이면 주의를 기울여야 할 부분은 더 작아져 있어야 합니다.
신발은 여전히 제가 직접 반납해야 합니다. 다만 마감일 전에 라벨을 찾고 싶습니다.
수상 부문 (Prize Categories)
- Gemma 활용 최우수: Gemma 4는 Ollama를 통해 로컬에서 실행되며, 애플리케이션의 핵심에서 스크린샷 이해 기능을 수행합니다.
- GitHub Copilot 활용 최우수: 저는 Screenshot Séance 개발 과정 동안 GitHub Copilot을 사용했습니다.
당신의 스크린샷 폴더에는 무엇이 숨겨져 있나요: 잊어버린 할 일 목록, 밈(memes), 아니면 모든 것의 약간일까요?
저는 여러분이 이러한 도구로 처리하기를 원하는 것이 무엇인지—그리고 항상 직접 검토하고 싶은 것이 무엇인지 듣고 싶습니다. 로컬 설정이나 작동 방식에 대한 질문도 환영합니다.