브라우저에서 바로 AI를 활용하고 싶으신가요? 오늘은 Chrome 확장 프로그램으로 HolySheep AI를 연결하는 방법을 초보자도 이해할 수 있도록 단계별로 알려드리겠습니다.
📌 먼저 알아두실 점: HolySheep AI는 지금 가입하면 무료 크레딧을 제공하며, 단일 API 키로 GPT-4.1, Claude, Gemini, DeepSeek 등 모든 주요 모델을 사용할 수 있습니다. 로컬 결제가 지원되어 해외 신용카드 없이도 개발자 친화적으로 시작할 수 있습니다.
왜 Chrome Extension인가?
저는日常 업무에서 웹페이지 텍스트를 번역하거나, 이메일 drafts를 작성할 때마다 새로운 탭을 열어야 하는 번거로움에 지쳐있었습니다. Chrome Extension을 만들면:
- 브라우저 어디에서나 AI 기능 접근 가능
- 웹페이지 내용을 직접 선택하여 번역·요약·분석
- Context Menu(우클릭 메뉴)에 AI 기능 추가
- 별도 웹사이트 방문 불필요
1단계: 프로젝트 구조 설정
먼저 프로젝트 폴더를 만들고 아래 구조를 만드세요:
my-ai-extension/
├── manifest.json
├── background.js
├── content.js
├── popup.html
├── popup.js
├── styles.css
├── icon.png (128x128 PNG)
└── icon-small.png (16x16 PNG)
2단계: Manifest V3 설정
manifest.json 파일을 작성합니다. Manifest V3는 Chrome 확장 프로그램의 최신 버전으로, 보안과 성능이 크게 개선되었습니다.
{
"manifest_version": 3,
"name": "HolySheep AI Assistant",
"version": "1.0.0",
"description": "브라우저에서 바로 HolySheep AI를 활용하세요",
"permissions": [
"activeTab",
"contextMenus",
"storage"
],
"host_permissions": [
"https://api.holysheep.ai/*"
],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icon-small.png",
"128": "icon.png"
}
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": [""],
"js": ["content.js"]
}
],
"icons": {
"16": "icon-small.png",
"128": "icon.png"
}
}
💡 팁:host_permissions에https://api.holysheep.ai/*를 반드시 추가해야 합니다. 그렇지 않으면 API 호출 시 CORS 오류가 발생합니다.
3단계: API 설정 및 응답 처리
Extension의 핵심인 background.js를 작성합니다. HolySheep AI의 게이트웨이 엔드포인트를 사용합니다.
// HolySheep AI API 설정
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const API_KEY = 'YOUR_HOLYSHEEP_API_KEY';
// 메시지 수신 대기
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'callAI') {
callHolySheepAPI(request.prompt, request.selectedText)
.then(response => sendResponse({ success: true, data: response }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // 비동기 응답을 위해 필요
}
});
// HolySheep AI API 호출 함수
async function callHolySheepAPI(prompt, selectedText = '') {
const fullPrompt = selectedText
? 선택된 텍스트: "${selectedText}"\n\n요청: ${prompt}
: prompt;
const response = await fetch(${HOLYSHEEP_BASE_URL}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${API_KEY}
},
body: JSON.stringify({
model: 'gpt-4.1', // HolySheep AI에서 지원되는 모델
messages: [
{
role: 'user',
content: fullPrompt
}
],
max_tokens: 1000,
temperature: 0.7
})
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(API 오류: ${response.status} - ${errorData.error?.message || response.statusText});
}
const data = await response.json();
return data.choices[0].message.content;
}
// Context Menu 설정
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: 'aiAssistant',
title: '🤖 HolySheep AI로 번역하기',
contexts: ['selection']
});
chrome.contextMenus.create({
id: 'aiAssistantSummarize',
title: '📝 HolySheep AI로 요약하기',
contexts: ['selection']
});
});
// Context Menu 클릭 핸들러
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === 'aiAssistant') {
chrome.tabs.sendMessage(tab.id, {
action: 'showPopup',
text: info.selectionText,
mode: 'translate'
});
} else if (info.menuItemId === 'aiAssistantSummarize') {
chrome.tabs.sendMessage(tab.id, {
action: 'showPopup',
text: info.selectionText,
mode: 'summarize'
});
}
});
💰 비용 참고: HolySheep AI의 GPT-4.1은 $8/MTok, Claude Sonnet 4.5는 $15/MTok, Gemini 2.5 Flash는 $2.50/MTok, DeepSeek V3.2는 $0.42/MTok입니다. 비용 최적화를 위해 텍스트 양에 맞는 적절한 모델을 선택하세요.
4단계: Popup UI 만들기
popup.html으로 사용자가 직접 입력할 수 있는 인터페이스를 만듭니다.
HolySheep AI Assistant
🐑 HolySheep AI
브라우저 AI 어시스턴트
AI가 생각중...
응답:
5단계: Popup 로직 구현
popup.js로 UI와 HolySheep AI 간의 통신을 처리합니다.
document.addEventListener('DOMContentLoaded', () => {
const promptInput = document.getElementById('prompt');
const modelSelect = document.getElementById('model');
const sendBtn = document.getElementById('sendBtn');
const loading = document.getElementById('loading');
const responseDiv = document.getElementById('response');
const responseText = document.getElementById('responseText');
const tokensInfo = document.getElementById('tokensInfo');
const errorDiv = document.getElementById('error');
const errorText = document.getElementById('errorText');
// 전송 버튼 클릭 핸들러
sendBtn.addEventListener('click', async () => {
const prompt = promptInput.value.trim();
const model = modelSelect.value;
if (!prompt) {
showError('질문을 입력해주세요.');
return;
}
// UI 상태 업데이트
hideAll();
loading.classList.remove('hidden');
sendBtn.disabled = true;
try {
// Background Script에 메시지 전송
const response = await chrome.runtime.sendMessage({
action: 'callAI',
prompt: prompt,
selectedText: '',
model: model
});
if (response.success) {
showResponse(response.data);
} else {
showError(response.error);
}
} catch (error) {
showError(연결 오류: ${error.message});
} finally {
loading.classList.add('hidden');
sendBtn.disabled = false;
}
});
function showResponse(text) {
responseText.textContent = text;
responseDiv.classList.remove('hidden');
}
function showError(message) {
errorText.textContent = message;
errorDiv.classList.remove('hidden');
}
function hideAll() {
responseDiv.classList.add('hidden');
errorDiv.classList.add('hidden');
}
// Enter 키로 전송 (Shift+Enter는 줄바꿈)
promptInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendBtn.click();
}
});
});
6단계: 스타일링
styles.css로 깔끔한 UI를 만들어보세요.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
width: 350px;
min-height: 400px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
}
.container {
padding: 20px;
background: white;
min-height: 400px;
border-radius: 0 0 12px 12px;
}
header {
text-align: center;
margin-bottom: 20px;
}
header h1 {
font-size: 1.5em;
color: #667eea;
}
.subtitle {
font-size: 0.85em;
color: #666;
margin-top: 4px;
}
.input-section {
margin-bottom: 15px;
}
label {
display: block;
font-size: 0.9em;
font-weight: 600;
margin-bottom: 6px;
color: #444;
}
textarea {
width: 100%;
height: 100px;
padding: 10px;
border: 2px solid #e0e0e0;
border-radius: 8px;
resize: none;
font-size: 0.9em;
transition: border-color 0.3s;
}
textarea:focus {
outline: none;
border-color: #667eea;
}
.model-select {
margin-bottom: 15px;
}
select {
width: 100%;
padding: 10px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 0.9em;
background: white;
}
button {
width: 100%;
padding: 12px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, opacity 0.2s;
}
button:hover:not(:disabled) {
transform: translateY(-2px);
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
#loading {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin-top: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
}
.spinner {
width: 20px;
height: 20px;
border: 3px solid #e0e0e0;
border-top-color: #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
#response {
margin-top: 15px;
padding: 15px;
background: #f0f7ff;
border-radius: 8px;
border-left: 4px solid #667eea;
}
#response h3 {
font-size: 0.9em;
color: #667eea;
margin-bottom: 10px;
}
#responseText {
white-space: pre-wrap;
line-height: 1.6;
}
.tokens-info {
margin-top: 10px;
font-size: 0.8em;
color: #888;
text-align: right;
}
.error {
margin-top: 15px;
padding: 12px;
background: #ffe0e0;
border-radius: 8px;
color: #d32f2f;
font-size: 0.9em;
}
.hidden {
display: none !important;
}
footer {
padding: 10px;
text-align: center;
}
footer a {
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
font-size: 0.85em;
}
footer a:hover {
text-decoration: underline;
}
7단계: Content Script 작성
content.js로 웹페이지에서 선택한 텍스트를 팝업으로 전달합니다.
// 웹페이지에서 메시지 수신
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'showPopup') {
// 선택된 텍스트를 팝업으로 전달
const popup = chrome.extension.getViews({ type: 'popup' })[0];
if (popup) {
popup.postMessage({
selectedText: message.text,
mode: message.mode
}, '*');
}
}
});
// 더블 클릭으로 텍스트 선택 감지
document.addEventListener('mouseup', (e) => {
const selection = window.getSelection();
const selectedText = selection.toString().trim();
if (selectedText.length > 0) {
// 선택된 텍스트 정보 저장
chrome.storage.local.set({ lastSelectedText: selectedText });
}
});
8단계: Chrome에 로드하고 테스트하기
이제 작성한 Extension을 Chrome에 로드해보겠습니다:
- Chrome에서
chrome://extensions접속 - 우측 상단 "Developer mode" 토글 활성화
- "Load unpacked" 버튼 클릭
- 프로젝트 폴더 선택
- Extension 아이콘이 Chrome Toolbar에 나타남
🔧 테스트 방법: 웹페이지에서 텍스트를 선택 후 마우스 우클릭 → "HolySheep AI로 번역하기" 또는 "HolySheep AI로 요약하기" 클릭. 또는 Toolbar 아이콘 클릭하여 직접 질문 입력.
자주 발생하는 오류와 해결책
오류 1: CORS 오류 - "No 'Access-Control-Allow-Origin' header"
이 오류는 API 호출 시 발생하는 교차 출처 리소스 공유 문제입니다.
// ❌ 잘못된 예: 직접 API 호출 (CORS 오류 발생)
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: { 'Authorization': Bearer ${API_KEY} },
body: JSON.stringify({ ... })
});
// ✅ 올바른 예: HolySheep AI 게이트웨이 사용
const response = await fetch('https://api.holysheep.ai/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${API_KEY}
},
body: JSON.stringify({ ... })
});
HolySheep AI의 게이트웨이는 이미 CORS 헤더가 설정되어 있어 Extension에서 바로 호출 가능합니다. 반드시 https://api.holysheep.ai/v1 엔드포인트를 사용하세요.
오류 2: Manifest V3 Service Worker 제한
// ❌ 잘못된 예: Service Worker에서 직접 DOM 조작
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
document.querySelector('#result').textContent = request.data; // 오류!
});
// ✅ 올바른 예: Content Script에 위임
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, {
action: 'displayResult',
data: request.data
});
});
});
// Content Script (content.js)에서 DOM 조작
chrome.runtime.onMessage.addListener((message) => {
if (message.action === 'displayResult') {
document.getElementById('result').textContent = message.data;
}
});
Manifest V3에서는 Service Worker가 DOM에 직접 접근할 수 없습니다. 반드시 Content Script를 통해 페이지와 통신해야 합니다.
오류 3: API Key 미설정 또는 유효하지 않음
// ❌ 잘못된 예: 하드코딩된 Key (보안 위험)
const API_KEY = 'sk-xxxx'; // 공개 저장소에 노출!
// ✅ 올바른 예: Storage API로 안전하게 관리
// manifest.json에权限 추가: "storage"
// 설정 저장
chrome.storage.local.set({ apiKey: 'YOUR_HOLYSHEEP_API_KEY' });
// 설정 읽기
async function getApiKey() {
return new Promise((resolve) => {
chrome.storage.local.get(['apiKey'], (result) => {
if (result.apiKey) {
resolve(result.apiKey);
} else {
// 사용자에게 Key 입력 요청
resolve(prompt('HolySheep AI API Key를 입력하세요:'));
}
});
});
}
// API 호출 시 사용
const API_KEY = await getApiKey();
Extension 코드는 사용자에게 노출되므로 API Key를 하드코딩하지 마세요. HolySheep AI에서 Key를 발급받은 후 지금 가입하여安全管理된 스토리지에 저장하세요.
오류 4: 비동기 응답 처리 누락
// ❌ 잘못된 예: async 콜백에서 응답 즉시 반환
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
fetch('https://api.holysheep.ai/v1/chat/completions', options)
.then(res => res.json())
.then(data => sendResponse({ success: true, data }));
// Promise 완료 전에 응답 반환 → 데이터 누락!
});
// ✅ 올바른 예: return true으로 비동기 응답 활성화
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
fetch('https://api.holysheep.ai/v1/chat/completions', options)
.then(res => res.json())
.then(data => sendResponse({ success: true, data }))
.catch(error => sendResponse({ success: false, error: error.message }));
return true; // 반드시 필요! 비동기 처리 완료를 기다림
});
Chrome Extension의 onMessage 리스너는 동기적으로 동작합니다. 비동기fetch의 결과를 전달하려면 반드시 return true을 추가해야 합니다.
개발 후기
저는 이 Chrome Extension을 만든 뒤日常 업무 효율이 크게 향상되었습니다. 특히 해외 문서를 읽을 때 번거로운 복사-붙여넣기 과정이 사라졌고, 언제든 선택한 텍스트를 AI에게 넘겨 번역·요약·분석할 수 있게 되었습니다.
처음 Manifest V3를 접했을 때 Service Worker의 DOM 접근 제한과 메시지 전달 패턴에戸惑렸지만, Content Script와 Background Script를 적절히 분리하면 생각보다 간단하게 해결할 수 있습니다.
💡 성능 팁: Gemini 2.5 Flash는 $2.50/MTok으로 비용 효율적이면서도 속도가 빠릅니다. 빠른 번역이나 요약에는 Flash 모델, 복잡한 분석에는 GPT-4.1을 추천드립니다.
다음 단계
- 단어 정의 기능 추가 (선택한 단어 의미 설명)
- 多点语言 지원 (日本語→한국어, English→한국어 등)
- API Key 설정 화면 추가
- 응답 히스토리 저장 기능
- Keyboard Shortcut 설정 (단축키로 빠른 실행)
이 튜토리얼이 도움이 되셨나요? HolySheep AI는 다양한 모델을 단일 API 키로 통합하여 제공하므로, 나중에 모델을 교체하고 싶을 때도 코드의 모델 이름만 변경하면 됩니다.
👉 HolySheep AI 가입하고 무료 크레딧 받기