Two Devs and a Copilot Created ClassifierAI: A Prototype Chrome Extension that Automatically Detects AI-Generated Content on DEV!
This is a submission for the GitHub Finish-Up-A-Thon Challenge Note: AI is currently a Hot Topic in...
참고: AI는 현재 개발자 커뮤니티에서 뜨거운 주제입니다. 이 포스트에서 사용된 데이터셋은 dev.to에서 가져온 것이 아니므로, AI 모델이 부정확할 수 있습니다. 이 도구는 향후 다른 사람들에게 유용하게 활용될 수 있는 가능성을 보여주기 위한 것이며, 추후 DEV 플랫폼에 맞게 더욱 정확하게 튜닝될 예정입니다.
저자 주 저자: Francis Tran @francistrdev 공동 저자: Elmar Chavez @codingwithjiro
이 글은 Francis와 Elmar의 팀 제출물입니다.
소개 #
AI가 인터넷의 모든 것을 바꿔놓고 있습니다. 정보 접근 속도가 빨라졌고, 개발 워크플로에 AI를 통합하는 것도 이제 일상이 됐습니다.
물론 긍정적인 면만 있는 건 아닙니다. 지금 인터넷에는 Google 검색 노출을 노리고 순수하게 AI로 찍어낸 콘텐츠가 넘쳐납니다. 불필요한 경쟁을 부추기고, AI가 발전할수록 AI가 쓴 글과 사람이 쓴 글을 구별하기도 점점 어려워집니다. AI 자체보다 AI를 사용하는 방식이 나쁜 이미지를 만들어가는 셈입니다.
DEV 사용자로서 이 상황을 그냥 보고만 싶지 않았습니다. dev.to의 AI 생성 기사를 줄여서 개발자들이 진짜 배움을 얻을 수 있는 공간을 만들고 싶었습니다. 그래서 Elmar와 함께 ClassifierAI를 만들었습니다.

고지사항: 이 프로젝트는 프로토타입입니다. dev.to 외부의 데이터를 사용하기 때문에 모델이 정확하지 않습니다. 이 크롬 확장은 AI 생성 콘텐츠를 완벽하게 필터링하는 솔루션으로 사용되도록 의도된 것이 아닙니다.
무엇을 만들었나 #
ClassifierAI는 DEV의 AI 생성 콘텐츠를 즉시 감지하는 프로토타입 크롬 확장입니다. TensorFlow.js를 사용해 두 가지 기능을 수행합니다:
- 이미지 분류: Google의 Teachable Machine으로 기사 커버 이미지가 AI 생성인지 판별합니다.
- 학습 데이터셋: HuggingFace AI-Generated-vs-Real-Images-Datasets
- 총 866개 이미지(클래스당 433개, "AI"와 "NotAI" 두 클래스)로 학습
866 Images Total
2 Classes Total
- "AI" Class
- "NotAI" Class
Epochs: 30
Batch Size: 16
Learning Rate: 0.0001- 텍스트 분류: 기사 자체가 AI 생성인지 판별합니다.
- 사용 데이터셋: wikipedia-human-ai
초기에는 Google 이미지에서 100개의 이미지를 순차 스캔해 AI 생성 여부를 레이블링하는 확장으로 시작했습니다. 이번 버전에서는 dev.to 전용으로 업데이트해 커버 이미지와 기사 전체를 분류하고 결과를 사용자에게 보여줍니다. DEV에서 기사를 클릭할 때마다 자동으로 동작합니다.

왜 만들었나 #
생성형 AI는 요즘 어디서나 화제입니다. 많은 동료들이 생성형 AI를 불편해하는 건 주로 "일자리를 빼앗을 것"이라는 인식 때문입니다.

GPTZero 같은 도구도 있지만 여전히 문제가 있습니다:
- 확인하려면 텍스트를 일일이 복사해서 붙여넣어야 합니다.
- GPTZero를 우회해 "Human" 판정을 받는 도구도 이미 있습니다. 커뮤니티마다 글쓰기 스타일이 다르다 보니, 시간이 지날수록 AI 생성 글을 잡아내기가 더 어려워집니다.
복사/붙여넣기 없이 AI 생성 콘텐츠를 자동으로 잡아내는 도구가 필요했습니다. 그게 ClassifierAI를 만든 이유입니다. DEV 전용으로 맞춤화했고, 앞으로 수집할 데이터셋으로 정확도를 높여갈 계획입니다.

데모 #
설치 방법 #
빈 폴더를 만들고 VSCode 또는 다른 IDE로 열어주세요.
1) 터미널에서 저장소를 클론합니다:
git clone https://github.com/FrancisTR/ClassifierAI.git
2) 디렉토리로 이동합니다:
cd ClassifierAI
3) 패키지를 설치하고 빌드를 실행합니다:
npm install
npm run build
4) 브라우저에서 확장 페이지로 이동해 개발자 모드를 활성화합니다.
5) dist 폴더를 확장 페이지로 드래그하면 끝입니다!

사용 방법 #
브라우저 오른쪽 상단의 팝업을 열고 스위치를 켭니다.

그다음 dev.to에서 아무 기사나 클릭하면 커버 이미지와 기사를 스캔해 AI 생성 여부를 판별합니다.
커버 이미지는 이미지 분류 모델이 분석해서 이미지 오른쪽 하단에 아이콘을 표시합니다.

세 가지 아이콘이 표시될 수 있습니다:

- 이미지가 AI 생성이 아님

- AI 생성일 수도, 아닐 수도 있음

- AI 생성 이미지
기사 자체의 판별 결과는 팝업 메뉴에서 확인할 수 있습니다:

참고: 현재는 기사의 어느 부분이 AI 생성인지 세부적으로 보여주는 기능은 없습니다.
이렇게 바뀌었다 #
구버전 #
초기 ClassifierAI는 Google 이미지에서 페이지에 로드된 100개 이미지를 순차 스캔해 각각 아이콘으로 레이블을 붙이는 게 목적이었습니다.

팝업에서 스캔을 켜고 Google 이미지 페이지를 스크롤하면 됐습니다. 그게 전부였습니다.

당시 README.md의 "demo" 섹션은 비어 있는 채로 미완성이었고, 이미지 스캔에만 집중하다 보니 "영향력"이 부족하다는 느낌이 들었습니다.
초기 버전은 아래 브랜치에서 확인할 수 있습니다: https://github.com/FrancisTRAlt/ClassifierAI/tree/OldProject
신버전 #
챌린지가 발표되자 Elmar에게 미완성 프로젝트에 함께 참여해달라고 요청했고, 그는 흔쾌히 수락했습니다.
먼저 Vite로 마이그레이션했습니다. 구버전에서는 크롬 확장의 특성상 CDN 링크와 외부 패키지 호출이 제한돼 패키지를 npm 대신 로컬로 설치해야 했습니다. Vite로 넘어오면서 npm을 통한 패키지 설치가 가능해졌고, 코드도 훨씬 깔끔해졌습니다.

Elmar가 Teachable Machine에 쓰이던 ml5.js 라이브러리가 deprecated된 것을 발견했습니다. 문제는 수정했지만 npm install 시 취약점이 남아 있는 상태입니다. npm audit fix --force를 돌리면 오히려 더 많은 문제가 생겼습니다.

Vite 마이그레이션을 마친 뒤, AI 모델 학습이라는 더 큰 작업으로 넘어갔습니다.

처음에는 커버 이미지 스캔에 Teachable Machine 커스텀 모델 대신 Gemma 4를 써보려 했습니다. 그런데 로컬 모델 성능 문제로 크롬 확장이 브라우저 전체를 먹통으로 만드는 사태가 벌어졌습니다. 결국 LLM 대신 기존 데이터셋으로 이미지 분류 모델을 학습시키는 방향으로 선회했습니다.
사용한 이미지 데이터셋은 HuggingFace의 AI-Generated-vs-Real-Images-Datasets입니다. DEV에서 실제로 쓰이는 이미지와 꽤 다르기 때문에 모델이 완벽하진 않지만, 이전보다는 훨씬 다양한 데이터를 활용합니다.
새로 추가한 핵심 기능은 기사 텍스트 분류입니다. 기사 본문 전체를 추출해 모델에 넣습니다:
function getCleanArticleText() {
const root =
document.querySelector(".crayons-article__body") ||
document.querySelector("article");
return root ? normalizeWhitespace(root.innerText) : "";
}Wikipedia 데이터셋 기반으로 분류를 수행하고 인간 작성 대 AI 생성 비율을 사용자에게 보여줍니다:
function detectGPTStyle(text) {
if (!wikipediaDataset || wikipediaDataset.length < 10) {
return baseUnknownResult();
}
const datasetScore = compareDataset(text); // AI %
const devHuman = computeDevHumanScore(text); // Human %
const generalHuman = computeGeneralScore(text); // Human %
const aiPenalty = detectAIPatterns(text); // AI %
let humanScore =
devHuman * 0.40 +
(100 - datasetScore) * 0.35 +
generalHuman * 0.25 -
aiPenalty * 0.25;
humanScore = squashScore(humanScore);
let label =
humanScore <= 33.33
? "AI-generated"
: humanScore >= 66.66
? "Human-written"
: "Mixed";
const finalScore = Number(humanScore.toFixed(2));
return {
label,
averageAIScore: finalScore,
humanPercent: finalScore,
aiPercent: Number((100 - humanScore).toFixed(2)),
mixedPercent:
finalScore > 33.33 && finalScore < 66.66 ? 100 : 0,
};
}UI도 개선해서 chart.js로 결과를 더 깔끔하게 보여줍니다.

현재 이미지 분류와 텍스트 분류의 데이터셋은 주요 기능을 보여주기 위한 플레이스홀더입니다. 앞으로는 dev.to 특화 데이터셋으로 모델을 더 정확하게 만들 계획입니다.
GitHub Copilot 사용 소감 #
고지사항: 이 섹션은 GitHub Copilot 사용 경험에 관한 내용입니다. Elmar는 개발 워크플로에 ChatGPT를 사용하며, 코드베이스 탐색과 버그 수정에 활용했습니다.
GitHub Copilot은 주로 마이그레이션 과정에서 빛을 발했습니다:
- Bootstrap에서 Tailwind CSS로 전환
- ml5.js에서 TensorFlow.js로 이전
- Chrome Extension Manifest V3 준수 확인
예를 들어 "ml5.js에서 tensorflow.js로 마이그레이션해줘"라고 요청하자 작업을 완료해 줬습니다.

마이그레이션은 꽤 순조로웠습니다. 중간에 오류가 나도 전부 되돌리고 다시 프롬프트할 필요 없이 비교적 빠르게 수정할 수 있었습니다.
전반적으로 마이그레이션, 오류 수정, 클린 코드 작업에서 GitHub Copilot이 잘 작동했습니다. 다만 이전에 사용할 때보다 토큰 소비가 더 빨랐습니다.
마치며 #
이 프로젝트는 dev.to의 AI 생성 콘텐츠를 줄이고 개발자들이 다양한 콘텐츠로 배우고 성장할 수 있도록 만든 것입니다.
프로젝트를 진행하면서 배운 것들:
- 프로젝트 메인테이너로서의 책임감
- 시간대가 다른 환경에서의 소통 방법 (미국과 필리핀)
- 코드를 과도하게 설명하지 않고 간결하게 전달하는 방법
Elmar의 소감:
나의 첫 오픈소스 크롬 확장 코드베이스 탐방기 #
다른 사람의 코드베이스에서 작업하는 것은 완전히 다른 도전이었습니다.
때로는 마치 유리 위를 걷는 것처럼 무언가를 망칠까봐 두려웠습니다.
코드베이스를 먼저 읽어야 했고, ChatGPT가 개념과 낯선 코드를 이해하는 데 도움을 줬습니다.
Frontend Mentor를 통해 다른 사람의 코드를 리뷰한 경험이 있었지만, 실제 프로젝트에 기여하는 건 달랐습니다. 모든 변경에는 결과가 따랐습니다.
코드베이스 자체보다 더 많이 배운 건 소통의 중요성이었습니다. 아이디어를 논의하고, 질문하고, 메인테이너에게 확인을 구하는 데 많은 시간을 썼습니다.
적응력의 중요성도 배웠습니다. 프로젝트가 기여 과정에서 발전하면서 가정과 계획도 함께 달라져야 했습니다. 생전 처음으로 실제 머지 충돌을 겪었지만 결국 해결했습니다.
ClassifierAI에 기여하면서 혼자 프로젝트를 만드는 것과 실제 소프트웨어 개발이 얼마나 다른지 훨씬 더 실감하게 됐습니다.
이 경험은 커리어 초반에 읽었던 말을 다시 한 번 증명해줬습니다:
"코드를 읽고 이해하는 능력은 종종 코드를 작성하는 능력보다 더 가치 있다."
현재 과제 #
프로토타입인 이유가 몇 가지 있습니다:
-
모델과 데이터셋이 dev.to에 맞지 않습니다. 텍스트 데이터셋은 Wikipedia, 이미지 데이터셋은 HuggingFace에서 가져왔으며 둘 다 dev.to 플랫폼에 최적화되지 않았습니다. 앞으로 더 많은 협업을 통해 dev.to 데이터를 수집하고 모델을 재학습할 계획입니다.
-
번역이나 문법 교정처럼 AI를 적절하게 쓴 경우를 구별하지 못하며, 기사의 어느 부분이 AI 생성인지 세부적으로 보여주는 기능도 아직 없습니다.

감사합니다 #
읽어주셔서 감사합니다.
기여하고 싶으시다면 아래 저장소를 방문해 주세요. 기능 요청과 버그 제보는 언제든 환영합니다!
저장소: https://github.com/FrancisTR/ClassifierAI
DEVengers 조직 팔로우: https://dev.to/devengers
Elmar Chavez: https://dev.to/codingwithjiro

