Oja: 나이지리아 피진어 인스타그램 판매 게시물 자동 작성 도구 (Open-Weight Gemma 기반)
요약
Oja는 나이지리아 판매자들이 Instagram이나 WhatsApp에 상품 게시물을 쉽게 자동 작성할 수 있도록 돕는 도구입니다. Gemma 기반으로 작동하며, 제목, 해시태그가 포함된 캡션, 설명 등 다양한 포맷의 콘텐츠를 생성합니다. 특히 현지 언어(Naija Pidgin, Yoruba-flavoured English)와 문화적 맥락을 반영하여 '들리는' 느낌의 결과물을 제공하는 것이 특징입니다.
핵심 포인트
- 나이지리아 판매자 맞춤형 자동 게시물 작성 도구 (Oja)
- Gemma 기반으로 작동하며 다양한 현지 언어/스타일 지원
- Instagram, WhatsApp 등 플랫폼별 최적화된 포맷 제공
- 사용자 피드백을 반영하여 프롬프트 개선 및 완성도 높임
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
제가 만든 것 (What I Built)
나이지리아에서 Instagram이나 WhatsApp으로 판매를 한다면, 이런 문구를 타이핑해 본 적이 있을 겁니다: "Available. DM to order." 하루에 다섯 번째 상품까지도요.
Oja(요루바어로 '시장'을 의미)가 이 게시물을 대신 작성해 줍니다. 사진 1~3장을 업로드하고, 원한다면 힌트(무엇인지, 상태, 생각하는 가격 등)를 추가한 다음, 목소리를 선택하면 다음과 같은 결과물을 얻게 됩니다:
- 제목 (a title)
- 해시태그가 포함된 Instagram 캡션
- 더 긴 설명 (a longer description)
- Open in WhatsApp 버튼이 있는 WhatsApp 상태 메시지
- 대략적인 나이라(Naira) 가격 가이드 (단순 참고용이며, 약속은 아님)
사용 가능한 목소리는 Clear English, Naija Pidgin, 그리고 Yoruba-flavoured English입니다. 이 도구의 사용자들은 고객 사이에서 휴대폰을 사용하기 때문에, 모든 결과물에는 복사 버튼이 달려 있습니다.
Oja 수치로 보기 (Oja in numbers)
- oja-ng.tech에서 라이브하며, 코드는 GitHub에 MIT 라이선스로 공개되어 있습니다.
- 3명의 실제 판매자가 사용해 보았고, 세 명 모두 돈을 지불할 것이라고 말했습니다. 두 명은 구체적인 금액을 언급했는데, 월 약 ₦10,000과 ₦15,000이었습니다.
- CPU 전용 노트북에서 Gemma 3를 로컬로 실행했을 때 게시물당 약 150~215초가 소요되며, Gemma 4로 호스팅할 경우(모델이 다르므로 자세한 내용은 아래 참조) 약 7~34초가 소요됩니다.
- 115개의 테스트를 진행했으며, 제가 테스트한 모든 상태에서 axe 접근성 위반은 0건이었습니다.
저는 대부분의 도구들이 다른 시장을 염두에 두고 만들어져 있기 때문에 나이지리아 판매자들을 위해 이 도구를 만들었습니다. 저는 판매자가 이미 자신처럼 느껴지는 것을 열어보기를 바랐습니다: 그들이 아는 상품, 익숙한 시장, 그리고 고객에게 말하는 방식과 같은 목소리 말입니다. 만약 영어가 가장 편안하지 않다면, 피진어가 그럴 수 있고, 저는 그들이 번역된 느낌이 아니라 '들리는' 느낌을 받기를 바랐습니다.
**
누가 비용을 지불할까? 온라인으로 판매하고 신상품을 정기적으로 게시하는 사람이라면 누구나 할 수 있습니다. Oja를 사용해 본 세 명의 판매자 모두 돈을 낼 것이라고 말했습니다. 두 명은 금액(각각 약 ₦10,000와 ₦15,000/월)을 제시했고, 나머지 한 명은 자신이 파는 물건의 가치에 달려있다고 했습니다(자세한 내용은 My First User 참고).
프롬프트가 잘못되었다고 깨달은 순간
초기에 호스팅된 Pidgin 테스트 상품은 줄무늬 토트백이었습니다. 설명은 다음과 같이 나왔습니다:
이 토트백은 노란색 줄무늬와 청록색 물방울 무늬가 있는 아름다운 녹슨 색상을 가지고 있습니다. 간단하지만 스타일리시합니다. 시장, 직장 또는 외출에 가져갈 수 있습니다. 라고스(Lagos), 아부자(Abuja), 포트하코트(Port Harcourt)로 배송해 드립니다…
좋은 Pidgin이었습니다. 하지만 같은 실행으로 생성된 WhatsApp 상태 메시지는 일반 영어로 나왔고, 캡션은 절반만 음성체였습니다. 설명만 완전히 캐릭터에 맞게 작성되었습니다. 저는 모든 필드가 선택한 스타일에 따르도록 프롬프트를 다시 작성했고, 각 스타일에 대한 작동 예시를 추가했습니다. 여기는 라이브 사이트의 저장된 예시(2026년 10월 16일 gemma-4-26b-a4b-it에 의해 작성되었으며, 수정 후 프롬프트를 사용함)에서 가져온 체리 잼 병에 대한 Pidgin 목록입니다:
캡션: 오야(Oya) 보세요, 멋진 체리 잼! Blue Pearl 브랜드인데, 정말 맛있습니다. 주문하려면 DM 주세요.
설명: 이것은 유리병 속의 Blue Pearl 체리 잼입니다. 체리 그림이 있는 흰색 라벨과 빨간색 패턴 뚜껑을 가지고 있습니다. 주문하려면 DM 주시고, 라고스(Lagos), 아부자(Abuja), 포트하코트(Port Harcourt)로 배송해 드립니다.
WhatsApp 상태: Blue Pearl 체리 잼이 도착했습니다! 유리병 속의 맛있는 잼입니다. 주문하려면 DM 주세요. 전국으로 배송해 드립니다.
가격 가이드: ₦2,500~₦4,500,
호스팅된 데모는 무료 티어 모델 엔드포인트를 사용하므로 때때로 문제가 발생할 수 있습니다. "AI 서비스에 오류가 있었습니다(The AI service had a hiccup)"라는 메시지가 표시되면 버튼을 다시 누르거나, 예제 실행(Try an example) 버튼을 눌러 저장된 결과를 바로 확인해 보세요. (저장된 예제는 제가 마지막 프롬프트 변경 전에 작성되었습니다.)
코드
GitHub logo SeyinAlao / oja
Oja는 나이지리아 판매자들이 인스타그램과 WhatsApp에 올릴 상품 목록을 영어, Naija Pidgin 또는 요루바풍 영어로 자동 작성해 줍니다. Open-weight Gemma 기반이며, OpenAI와 호환되는 엔드포인트를 통해 호스팅 환경이나 로컬에서 실행 가능합니다.
Oja
인스타그램과 WhatsApp에 상품 목록을 올리는 나이지리아 소상공인을 위한 글쓰기 도구입니다. 상품 사진 1~3장을 업로드하고, 선택적 힌트(optional hints)를 추가하며, 목소리(Clear English, Naija Pidgin 또는 Yoruba-flavoured English)를 선택한 후 제목, 해시태그가 포함된 캡션, 설명, WhatsApp 상태 메시지 및 대략적인 가격 가이드를 복사할 준비가 된 형태로 얻을 수 있습니다.
- 실시간 데모: https://oja-ng.tech
- 데모 비디오:
- Hacktoberfest 2026 Open-Source AI Challenge, Week 2 (Side Hustle)를 위해 제작되었습니다.
Next.js (App Router), TypeScript (strict), Tailwind CSS 및 Framer Motion으로 구축되었습니다. AI는 OpenAI와 호환되는 엔드포인트 뒤에 있는 모든 open-weight 비전 모델을 사용할 수 있으며, 기본값은 로컬 Ollama의 gemma3:4b입니다.


두 스크린샷 모두 Google의 OpenAI와 호환되는 엔드포인트를 통해 호스팅된 gemma-4-26b-a4b-it로 생성한 실제 결과물이며, 모형이 아닙니다 (각 이미지에 표시된 모델 배지 참고).
로컬에서 실행하기
ollama pull gemma3:4b
ollama serve # 이미 Ollama가 실행 중이면 생략
pnpm install
pnpm dev # http://localhost:3000
다른 스크립트: pnpm test, pnpm lint, pnpm typecheck, pnpm build…
MIT 라이선스입니다. README에는 Ollama를 사용하여 로컬에서 실행하는 방법, 다른 엔드포인트를 지정하는 방법, Render에 배포하는 방법, 모델 라이선스 및 알려진 제한 사항이 설명되어 있습니다.
제작 과정
동일한 앱을 구동하는 두 가지 방식
| 설정 | 모델 | 목록당 시간 |
|---|---|---|
| 로컬, Ollama, CPU 전용 | gemma3:4b | 서버에서 148 |
| 호스팅, Google AI Studio 무료 등급 | gemma-4-26b-a4b-it | 제 벤치마크 실행 기준 약 7 |
이들은 서로 다른 모델이므로 동일한 모델 속도 테스트로 간주하지 마십시오. 각 설정이 판매자에게 어떤 느낌을 주는지 보여줍니다. 제가 왜 UI 숫자가 서버 벤치마크보다 높은지는 파악하지 못했습니다. Google의 모델 선택기는 Gemma 4 26B A4B를 추론당 약 4B 매개변수를 활성화하는 Mixture-of-Experts (MoE) 모델이라고 설명합니다.
앱. Next.js (App Router), TypeScript (엄격 모드), Tailwind v4, Framer Motion 및 zod으로 구성되었습니다. /api/generate라는 하나의 라우트는 모든 OpenAI 호환 chat/completions 엔드포인트와 통신하며, 세 가지 환경 변수가 모델을 선택합니다:
# Google AI Studio의 Gemma 4 호스팅
AI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
AI_MODEL=gemma-4-26b-a4b-it
...
프롬프팅. 시스템 프롬프트는 나이지리아 상거래에 맞춰 작성되었습니다: Naira 통화 형식,
품질. 저장된 예제 모드를 포함하여 테스트한 모든 상태에서 115개의 단위 테스트(vitest)와 0개 위반의 axe-core 검사를 통과했습니다. 아직 수동 스크린 리더 테스트는 진행하지 않았습니다.
피진어(Pidgin)가 틀리지 않았다는 것을 어떻게 알 수 있나요?
테스터 중 한 명이 정확히 이 질문을 했고, 솔직한 대답은 Oja가 알 수 없다는 것입니다. 제가 할 수 있는 것과 할 수 없는 것은 다음과 같습니다:
- 제가 가진 것: 프롬프트 내 스타일별 작업 예제, 세 텍스트 필드 모두에 음성 마커(voice markers)가 나타나는 자동화된 검사 기능, 그리고 제가 직접 샘플 출력물을 읽는 것입니다. 저는 요루바어(Yoruba) 화자이므로, 요루바 풍의 출력물은 제가 직접 읽습니다.
- 그것이 알려줄 수 없는 것: 마커 검사는 "dey"가 나타나는 것을 볼 수는 있습니다. 하지만 문장이 자연스러운지 또는 제품에 적합한지는 알 수 없습니다. 일부 실행에서는 사진이 뒷받침하지 않는 "여름 의류(summer wear)" 및 "해변(beach)"을 피진어 토트 목록에서 제안했지만, 여전히 음성 검사를 통과했습니다. 또한 피진어와 요루바어는 지역, 연령, 맥락에 따라 다르며, 한 명의 리뷰어가 테스트가 될 수는 없습니다.
- 디자인 선택: 판매자가 게시하기 전에 초안을 읽어볼 수 있도록 Oja가 보여줍니다. 왜냐하면 그들이 자신의 목소리를 가장 잘 판단하는 사람이기 때문입니다. 이제 결과 페이지에 그렇게 명시되어 있습니다.
- 다음 단계: 판매자를 위한 "자연스럽지 않은(doesn't sound right)" 버튼과 원어민이 검토한 피진어 및 요루바어 목록 세트가 필요합니다. 이것은 오픈 웨이트 모델(open-weight model)을 파인튜닝하는 데 필요한 데이터입니다.
제안은 기능이지만, 주장(Claim)은 아닙니다.
제가 처음 사용한 프롬프트는 모델에게 세부 사항을 절대 지어내지 말라고 지시했지만, 그래도 짧은 사용 제안("잼과 함께 빵이나 팬케이크를 즐기세요")을 계속 추가했습니다. 저는 그것이 마음에 들었습니다. 좋은 상점 직원이 하는 말이거든요. 그래서 생각을 바꿨습니다. 이제 프롬프트는 짧고 일반적인 사용 제안 하나를 허용하며, 사진과 힌트가 뒷받침하지 않는 사실(재질, 크기, 브랜드, 진품 여부, 상태, 배터리 세부 정보, 수명 등)을 언급하는 것을 금지합니다. 이는 "오리지널"이거나 "흠집 없음"과 같이 지어낸 내용이 구매자를 오도할 수 있는 향수나 중고 휴대폰 같은 카테고리에서 가장 중요합니다.
저는 두 가지 이미지(잼 병 사진과 토트백의 평면 일러스트)에 대해 스타일별로 10번씩 라이브 생성을 측정했습니다. 변경 전후 비교는 다음과 같습니다:
| 기존 프롬프트 | 새 프롬프트 | |
|---|---|---|
| 지원되지 않는 주장으로 실행된 건수 | 60개 중 2건 | 60개 중 0건 |
| ... |
기존의 두 가지 지원되지 않는 주장은 토트백에 있는 "튼튼한" 손잡이와 "주황색 직물"이었습니다. 제 코딩 에이전트가 모든 120개의 출력을 읽고 정규 표현식(regex)에만 의존하는 대신 개수를 세었습니다. 이는 작은 표본이며, 2건에서 0건으로 줄어든 것이 보장되는 것은 아닙니다. 이것이 Oja가 이제 결과 아래에 다음과 같은 문구를 표시하는 이유입니다: "결과를 검토하고 게시하기 전에 제품에 사실이 아닌 부분이 없는지 수정하세요."
진행 과정 중 잘못된 점들
- 이미지가 작아지면서 상황이 악화되었습니다. 지연 시간(latency)을 줄이기 위해 1024px 대신 768px 사진을 사용해 보았습니다. 제 테스트에서 첫 시도에 유효한 JSON 응답은 9개 중 0개였고, 2개는 아예 실패했습니다. 그래서 1024px를 유지하기로 했습니다.
- 사용할 수 없는 지연 시간 설정. Google의 엔드포인트(endpoint)가 이 모델에 대한 추론 노력(reasoning-effort) 옵션을 거부했습니다 (HTTP 400 또는 500).
- 제가 제 엔드포인트를 유출했습니다. "모델에 도달할 수 없음" 오류 패널이 모델 서버 URL을 브라우저에 반향시켰습니다. 제가 코딩 에이전트에게 작성하게 한 오류 경로 테스트가 방문자가 접근하기 전에 이를 포착했습니다.
- 백슬래시 누락. 에이전트 자체의 수정으로 인해
Retry-After: 1이 0ms를 기다리게 되었습니다. 이 역시 테스트에서 포착되었습니다. - 제 방어 장치가 너무 엄격했습니다. "판매 가능한 제품 없음" 확인 기능이 토트백의 평면 일러스트를
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기