Spaces:
Sleeping
feat: Add ZeroGPU support for Llama-2-Ko 7B
Browse files✨ Features:
- ZeroGPU integration with @spaces.GPU decorator
- Llama-2-Ko 7B model with dynamic GPU allocation
- NVIDIA H200 hardware (70GB VRAM)
- Float16 optimization for GPU efficiency
🔧 Technical Changes:
- Add 'spaces' package to requirements.txt
- Implement GPU request with 120s duration
- Global model caching for efficiency
- Korean-optimized conversation formatting
📚 Documentation:
- Updated README with ZeroGPU setup guide
- Added cost comparison and optimization tips
- Included usage examples and limitations
⚠️ Requirements:
- Hugging Face PRO subscription ($9/month)
- ZeroGPU hardware selection in Space settings
- Daily limit: 25 minutes free usage
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- README.md +109 -111
- app.py +98 -88
- requirements.txt +1 -0
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
emoji: 🤖
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: purple
|
|
@@ -10,162 +10,160 @@ pinned: false
|
|
| 10 |
license: mit
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# 🤖
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
-
## ✨ 주요
|
| 18 |
|
| 19 |
-
-
|
| 20 |
-
-
|
| 21 |
-
-
|
| 22 |
-
-
|
| 23 |
-
- **완전 무료**: API 비용 없음, 오픈소스
|
| 24 |
|
| 25 |
-
## 🎯
|
| 26 |
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
|
| 32 |
-
|
| 33 |
-
4. **Llama-2-Ko 7B** - Llama 2 기반 한글 대화형 모델 (~14GB, 고사양)
|
| 34 |
-
5. **KoT-Llama2-7B-Chat** - 한국어 최적화 Llama 2 대화 모델 (~14GB, 고사양)
|
| 35 |
-
6. **KoAlpaca 5.8B** - 한글 대화형 모델 (~12GB, 고사양)
|
| 36 |
-
7. **KULLM-Polyglot 5.8B** - 고려대 NLP 연구실 한글 대화 모델 (~12GB, 고사양)
|
| 37 |
|
| 38 |
-
|
| 39 |
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
git clone <repository-url>
|
| 44 |
-
cd simple-chatbot-gradio
|
| 45 |
-
```
|
| 46 |
-
|
| 47 |
-
### 2. 의존성 설치
|
| 48 |
|
| 49 |
-
```bash
|
| 50 |
-
pip install -r requirements.txt
|
| 51 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
-
|
| 56 |
|
| 57 |
-
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
```
|
| 62 |
|
| 63 |
-
|
| 64 |
-
1. [Hugging Face](https://huggingface.co)에 로그인
|
| 65 |
-
2. Settings → Access Tokens 메뉴로 이동
|
| 66 |
-
3. "New token" 클릭하여 토큰 생성
|
| 67 |
|
| 68 |
-
|
|
|
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
| 72 |
```
|
| 73 |
|
| 74 |
-
|
| 75 |
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
-
###
|
| 79 |
|
| 80 |
-
1.
|
| 81 |
-
2.
|
| 82 |
-
3.
|
| 83 |
-
4. 파일 업로드:
|
| 84 |
-
- `app.py`
|
| 85 |
-
- `requirements.txt`
|
| 86 |
-
- `README.md`
|
| 87 |
-
5. (선택사항) Private 모델 사용 시: Settings → Repository secrets에서 `HF_TOKEN` 추가
|
| 88 |
-
6. 자동 빌드 및 배포 대기 (첫 빌드는 5-10분 소요)
|
| 89 |
|
| 90 |
-
|
| 91 |
|
| 92 |
```bash
|
| 93 |
-
#
|
| 94 |
-
git
|
|
|
|
| 95 |
|
| 96 |
-
#
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
```
|
| 101 |
|
| 102 |
-
|
| 103 |
|
| 104 |
-
|
| 105 |
-
- **ML 라이브러리**: Transformers, PyTorch
|
| 106 |
-
- **언어**: Python 3.10+
|
| 107 |
-
- **주요 라이브러리**:
|
| 108 |
-
- `gradio` - 웹 인터페이스
|
| 109 |
-
- `transformers` - 모델 로딩 및 추론
|
| 110 |
-
- `torch` - 딥러닝 프레임워크
|
| 111 |
-
- `python-dotenv` - 환경 변수 관리
|
| 112 |
|
| 113 |
-
|
| 114 |
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
├── requirements.txt # Python 의존성
|
| 119 |
-
├── README.md # 프로젝트 문서
|
| 120 |
-
├── .env # 환경 변수 (git ignored)
|
| 121 |
-
└── CLAUDE.md # 개발 가이드
|
| 122 |
-
```
|
| 123 |
|
| 124 |
-
|
| 125 |
|
| 126 |
-
|
| 127 |
-
-
|
| 128 |
-
-
|
| 129 |
-
- **첫 실행**: 모델 다운로드로 시간 소요 (350MB~14GB)
|
| 130 |
|
| 131 |
-
|
| 132 |
-
- **영어 모델**: 한글 입력 시 부자연스러운 응답
|
| 133 |
-
- **한글 모델 (Llama 2 기반)**: 대화 품질 우수하지만 메모리 많이 필요 (14GB+)
|
| 134 |
-
- **한글 모델 (Polyglot 기반)**: 중간 크기, 대화 품질 양호 (12GB+)
|
| 135 |
-
- **모든 한글 모델**: CPU 환경에서 매우 느림, GPU 권장
|
| 136 |
|
| 137 |
-
###
|
| 138 |
-
- **무료 tier**: CPU 인스턴스만 제공 (16GB RAM)
|
| 139 |
-
- **Space Sleep**: 48시간 비활성 시 자동 sleep, 첫 로딩 느림
|
| 140 |
-
- **메모리 제한**: 한글 모델들은 무료 tier에서 실행 불가 (12-14GB 필요)
|
| 141 |
-
- **첫 실행**: 모델 다운로드로 1-5분 소요
|
| 142 |
-
- **권장 모델**: DialoGPT Small/Medium, GPT-2만 무료 tier에서 안정적
|
| 143 |
-
- **한글 대화**: 무료 tier에서는 한글 모델 사용 불가, 유료 GPU tier 필요
|
| 144 |
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
-
|
|
|
|
|
|
|
| 148 |
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
-
|
| 162 |
|
| 163 |
-
|
|
|
|
|
|
|
| 164 |
|
| 165 |
## 📄 라이선스
|
| 166 |
|
| 167 |
MIT License
|
| 168 |
|
| 169 |
-
## 🙋♂️
|
| 170 |
|
| 171 |
이슈나 질문이 있으시면 GitHub Issues를 통해 문의해주세요.
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Llama-2-Ko Chatbot
|
| 3 |
emoji: 🤖
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: purple
|
|
|
|
| 10 |
license: mit
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# 🤖 Llama-2-Ko 7B Chatbot (ZeroGPU)
|
| 14 |
|
| 15 |
+
한국어에 최적화된 Llama-2-Ko 7B 모델을 사용한 대화형 챗봇입니다. ZeroGPU를 활용하여 무료로 GPU 가속 추론을 제공합니다.
|
| 16 |
|
| 17 |
+
## ✨ 주요 특징
|
| 18 |
|
| 19 |
+
- **🇰🇷 한글 대화 최적화**: Llama-2-Ko 7B 모델 사용
|
| 20 |
+
- **⚡ GPU 가속**: NVIDIA H200 ZeroGPU로 빠른 응답 (3-5초)
|
| 21 |
+
- **💰 경제적**: PRO 구독 시 하루 25분 무료 사용 가능
|
| 22 |
+
- **🔄 자동 GPU 할당**: 요청 시 자동으로 GPU 할당 및 해제
|
|
|
|
| 23 |
|
| 24 |
+
## 🎯 모델 정보
|
| 25 |
|
| 26 |
+
- **모델**: `beomi/llama-2-ko-7b`
|
| 27 |
+
- **크기**: ~14GB
|
| 28 |
+
- **특징**: 한글 대화에 특화된 Llama 2 기반 모델
|
| 29 |
+
- **하드웨어**: NVIDIA H200 (70GB VRAM)
|
| 30 |
|
| 31 |
+
## 🚀 사용 방법
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
### Hugging Face Spaces에서 사용
|
| 34 |
|
| 35 |
+
1. 이 Space에 접속
|
| 36 |
+
2. 한글로 메시지 입력
|
| 37 |
+
3. 첫 응답은 모델 로딩으로 10-15초 소요
|
| 38 |
+
4. 이후 응답은 3-5초 내로 생성
|
| 39 |
|
| 40 |
+
### 테스트 예시
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
|
|
|
|
|
|
| 42 |
```
|
| 43 |
+
안녕하세요
|
| 44 |
+
인공지능에 대해 설명해주세요
|
| 45 |
+
오늘 날씨가 어때요?
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
## ⚙️ 기술 스택
|
| 49 |
|
| 50 |
+
- **프레임워크**: Gradio 5.x
|
| 51 |
+
- **ML 라이브러리**: Transformers, PyTorch
|
| 52 |
+
- **GPU 인프라**: Hugging Face ZeroGPU
|
| 53 |
+
- **언어**: Python 3.10+
|
| 54 |
|
| 55 |
+
## 📝 ZeroGPU 설정 방법
|
| 56 |
|
| 57 |
+
### 1. 필수 요구사항
|
| 58 |
|
| 59 |
+
- Hugging Face PRO 구독 ($9/month)
|
| 60 |
+
- ZeroGPU 하드웨어 선택 (Space Settings에서)
|
|
|
|
| 61 |
|
| 62 |
+
### 2. 코드 구조
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
```python
|
| 65 |
+
import spaces # ZeroGPU 데코레이터
|
| 66 |
|
| 67 |
+
@spaces.GPU(duration=120) # GPU 요청 (최대 120초)
|
| 68 |
+
def generate_response(message, history):
|
| 69 |
+
model.to('cuda') # GPU로 모델 이동
|
| 70 |
+
# ... 추론 로직 ...
|
| 71 |
+
return response
|
| 72 |
```
|
| 73 |
|
| 74 |
+
### 3. requirements.txt
|
| 75 |
|
| 76 |
+
```
|
| 77 |
+
gradio==5.9.1
|
| 78 |
+
transformers==4.46.0
|
| 79 |
+
torch==2.1.0
|
| 80 |
+
spaces # ZeroGPU 필수
|
| 81 |
+
```
|
| 82 |
|
| 83 |
+
### 4. Space 설정
|
| 84 |
|
| 85 |
+
1. Space Settings → Hardware 선택
|
| 86 |
+
2. **ZeroGPU** 선택 (PRO 구독자만 가능)
|
| 87 |
+
3. Deploy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
## 🔧 로컬 실행 (GPU 필요)
|
| 90 |
|
| 91 |
```bash
|
| 92 |
+
# 저장소 클론
|
| 93 |
+
git clone <repository-url>
|
| 94 |
+
cd simple-chatbot-gradio
|
| 95 |
|
| 96 |
+
# 의존성 설치
|
| 97 |
+
pip install -r requirements.txt
|
| 98 |
+
|
| 99 |
+
# HF 토큰 설정 (필수)
|
| 100 |
+
export HF_TOKEN=your_hugging_face_token
|
| 101 |
+
|
| 102 |
+
# 실행 (CUDA GPU 필요)
|
| 103 |
+
python app.py
|
| 104 |
```
|
| 105 |
|
| 106 |
+
**참고**: 로컬 실행 시 CUDA GPU가 필요합니다 (최소 16GB VRAM 권장)
|
| 107 |
|
| 108 |
+
## ⚠️ 제한사항
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
+
### ZeroGPU 사용 제한
|
| 111 |
|
| 112 |
+
- **PRO 구독**: 하루 25분 무료 사용
|
| 113 |
+
- **첫 로딩**: 모델 다운로드로 초기 응답 느림 (~10-15초)
|
| 114 |
+
- **대기열**: 사용자가 많을 경우 대기 발생 가능
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
### 모델 특성
|
| 117 |
|
| 118 |
+
- **한글 특화**: 영어 입력 시 한글보다 품질 낮음
|
| 119 |
+
- **대화 길이**: 긴 대화 시 컨텍스트 제한 (최근 3턴만 유지)
|
| 120 |
+
- **응답 길이**: 최대 150 토큰
|
|
|
|
| 121 |
|
| 122 |
+
## 💡 최적화 팁
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
+
### ZeroGPU 효율적 사용
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
+
1. **Duration 설정**: 실제 필요한 시간만큼만 요청
|
| 127 |
+
```python
|
| 128 |
+
@spaces.GPU(duration=60) # 짧은 응답용
|
| 129 |
+
```
|
| 130 |
|
| 131 |
+
2. **모델 캐싱**: 글로벌 변수로 모델 재사용
|
| 132 |
+
```python
|
| 133 |
+
model = None # 전역 변수
|
| 134 |
|
| 135 |
+
def load_model_once():
|
| 136 |
+
global model
|
| 137 |
+
if model is None:
|
| 138 |
+
model = AutoModelForCausalLM.from_pretrained(...)
|
| 139 |
+
```
|
| 140 |
|
| 141 |
+
3. **Float16 사용**: GPU 메모리 절약
|
| 142 |
+
```python
|
| 143 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 144 |
+
...,
|
| 145 |
+
torch_dtype=torch.float16,
|
| 146 |
+
)
|
| 147 |
+
```
|
| 148 |
+
|
| 149 |
+
## 📊 비용 비교
|
| 150 |
+
|
| 151 |
+
| 옵션 | 월 비용 | 하드웨어 | 제약사항 |
|
| 152 |
+
|------|---------|---------|----------|
|
| 153 |
+
| **ZeroGPU (PRO)** | $9 | H200 (70GB) | 하루 25분 |
|
| 154 |
+
| CPU Upgrade (32GB) | $22 | 8 vCPU | 느림 (30초~1분) |
|
| 155 |
+
| T4 Medium GPU | $438 | T4 (30GB) | 제약 없음 |
|
| 156 |
|
| 157 |
+
## 🔗 관련 리소스
|
| 158 |
|
| 159 |
+
- [Llama-2-Ko Model Card](https://huggingface.co/beomi/llama-2-ko-7b)
|
| 160 |
+
- [ZeroGPU Documentation](https://huggingface.co/docs/hub/spaces-zerogpu)
|
| 161 |
+
- [Gradio Documentation](https://www.gradio.app/docs)
|
| 162 |
|
| 163 |
## 📄 라이선스
|
| 164 |
|
| 165 |
MIT License
|
| 166 |
|
| 167 |
+
## 🙋♂️ 문의
|
| 168 |
|
| 169 |
이슈나 질문이 있으시면 GitHub Issues를 통해 문의해주세요.
|
|
@@ -1,122 +1,117 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
-
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
| 7 |
import gradio as gr
|
| 8 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 9 |
import torch
|
| 10 |
-
import
|
| 11 |
-
|
| 12 |
-
# Suppress torch_dtype deprecation warning
|
| 13 |
-
warnings.filterwarnings('ignore', message='.*torch_dtype.*deprecated.*')
|
| 14 |
|
| 15 |
# Get HF token from environment
|
| 16 |
HF_TOKEN = os.getenv("HF_TOKEN", None)
|
| 17 |
|
| 18 |
-
#
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
MODELS = {
|
| 24 |
-
"microsoft/DialoGPT-small": {
|
| 25 |
-
"name": "DialoGPT Small (영어, 빠름)",
|
| 26 |
-
"max_length": 80,
|
| 27 |
-
},
|
| 28 |
}
|
| 29 |
|
| 30 |
-
#
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
|
| 35 |
-
def load_model(model_name):
|
| 36 |
-
"""Load model and tokenizer"""
|
| 37 |
-
if model_name not in loaded_models:
|
| 38 |
-
try:
|
| 39 |
-
print(f"Loading model: {model_name}")
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
token=HF_TOKEN,
|
| 45 |
-
padding_side='left',
|
| 46 |
-
)
|
| 47 |
-
|
| 48 |
-
if tokenizer.pad_token is None:
|
| 49 |
-
tokenizer.pad_token = tokenizer.eos_token
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
model_name,
|
| 54 |
-
token=HF_TOKEN,
|
| 55 |
-
torch_dtype=torch.float32,
|
| 56 |
-
low_cpu_mem_usage=True,
|
| 57 |
-
)
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
|
| 68 |
-
print(f"❌ Failed to load model {model_name}: {e}")
|
| 69 |
-
import traceback
|
| 70 |
-
print(traceback.format_exc())
|
| 71 |
-
return None, None
|
| 72 |
|
| 73 |
-
return
|
| 74 |
|
| 75 |
|
| 76 |
-
|
| 77 |
-
|
|
|
|
| 78 |
if not message or not message.strip():
|
| 79 |
return history
|
| 80 |
|
| 81 |
try:
|
| 82 |
-
|
| 83 |
-
|
| 84 |
|
| 85 |
-
if
|
| 86 |
return history + [[message, "❌ 모델을 로드할 수 없습니다."]]
|
| 87 |
|
| 88 |
-
|
|
|
|
| 89 |
|
| 90 |
# Build conversation context
|
| 91 |
conversation = ""
|
| 92 |
-
for user_msg, bot_msg in history:
|
| 93 |
if user_msg:
|
| 94 |
-
conversation += f"{user_msg}\n"
|
| 95 |
if bot_msg:
|
| 96 |
-
conversation += f"{bot_msg}\n"
|
| 97 |
|
| 98 |
-
conversation += f"{message}\n"
|
| 99 |
|
| 100 |
# Tokenize
|
| 101 |
-
inputs =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
|
| 103 |
# Generate response
|
| 104 |
with torch.no_grad():
|
| 105 |
-
outputs =
|
| 106 |
inputs,
|
| 107 |
-
max_new_tokens=
|
| 108 |
-
temperature=0.
|
|
|
|
| 109 |
do_sample=True,
|
| 110 |
-
pad_token_id=
|
| 111 |
-
eos_token_id=
|
| 112 |
)
|
| 113 |
|
| 114 |
# Decode response
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
if not response:
|
| 119 |
-
response = "
|
| 120 |
|
| 121 |
return history + [[message, response]]
|
| 122 |
|
|
@@ -130,43 +125,58 @@ def chat_response(message, history):
|
|
| 130 |
return history + [[message, f"❌ 오류: {error_msg[:200]}"]]
|
| 131 |
|
| 132 |
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
# Create Gradio interface
|
| 136 |
-
with gr.Blocks(title="🤖
|
| 137 |
gr.Markdown("""
|
| 138 |
-
# 🤖
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
-
|
| 141 |
-
-
|
| 142 |
-
-
|
|
|
|
| 143 |
""")
|
| 144 |
|
| 145 |
chatbot = gr.Chatbot(height=400, type="tuples", show_label=False)
|
| 146 |
|
| 147 |
with gr.Row():
|
| 148 |
msg = gr.Textbox(
|
| 149 |
-
placeholder="
|
| 150 |
show_label=False,
|
| 151 |
scale=9,
|
| 152 |
)
|
| 153 |
-
btn = gr.Button("
|
| 154 |
|
| 155 |
-
clear = gr.Button("🗑️
|
| 156 |
|
| 157 |
def submit(message, history):
|
| 158 |
-
return
|
| 159 |
|
| 160 |
-
btn.click(submit, [msg, chatbot], [chatbot, msg]
|
| 161 |
-
msg.submit(submit, [msg, chatbot], [chatbot, msg]
|
| 162 |
-
clear.click(lambda: [], outputs=chatbot
|
| 163 |
|
| 164 |
gr.Markdown("""
|
| 165 |
---
|
| 166 |
-
|
| 167 |
-
-
|
| 168 |
-
-
|
| 169 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
""")
|
| 171 |
|
| 172 |
if __name__ == "__main__":
|
|
|
|
| 1 |
"""
|
| 2 |
+
ZeroGPU version: Llama-2-Ko 7B with dynamic GPU allocation
|
| 3 |
+
Requires: PRO subscription + ZeroGPU hardware selection in Space settings
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
| 7 |
import gradio as gr
|
| 8 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 9 |
import torch
|
| 10 |
+
import spaces # ZeroGPU decorator
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
# Get HF token from environment
|
| 13 |
HF_TOKEN = os.getenv("HF_TOKEN", None)
|
| 14 |
|
| 15 |
+
# Model configuration
|
| 16 |
+
MODEL_NAME = "beomi/llama-2-ko-7b"
|
| 17 |
+
MODEL_CONFIG = {
|
| 18 |
+
"name": "Llama-2-Ko 7B (한글 대화형)",
|
| 19 |
+
"max_length": 150,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
}
|
| 21 |
|
| 22 |
+
# Global model cache (loaded once)
|
| 23 |
+
model = None
|
| 24 |
+
tokenizer = None
|
|
|
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
+
def load_model_once():
|
| 28 |
+
"""Load model and tokenizer once at startup"""
|
| 29 |
+
global model, tokenizer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
+
if model is None:
|
| 32 |
+
print(f"🔄 Loading model: {MODEL_NAME}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
+
# Load tokenizer
|
| 35 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 36 |
+
MODEL_NAME,
|
| 37 |
+
token=HF_TOKEN,
|
| 38 |
+
trust_remote_code=True,
|
| 39 |
+
)
|
| 40 |
|
| 41 |
+
if tokenizer.pad_token is None:
|
| 42 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 43 |
|
| 44 |
+
# Load model - will be moved to GPU by @spaces.GPU decorator
|
| 45 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 46 |
+
MODEL_NAME,
|
| 47 |
+
token=HF_TOKEN,
|
| 48 |
+
torch_dtype=torch.float16, # Use float16 for GPU
|
| 49 |
+
low_cpu_mem_usage=True,
|
| 50 |
+
trust_remote_code=True,
|
| 51 |
+
)
|
| 52 |
|
| 53 |
+
print(f"✅ Model {MODEL_NAME} loaded successfully")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
return model, tokenizer
|
| 56 |
|
| 57 |
|
| 58 |
+
@spaces.GPU(duration=120) # Request GPU for 120 seconds max
|
| 59 |
+
def generate_response(message, history):
|
| 60 |
+
"""Generate chatbot response with GPU acceleration"""
|
| 61 |
if not message or not message.strip():
|
| 62 |
return history
|
| 63 |
|
| 64 |
try:
|
| 65 |
+
# Ensure model is loaded
|
| 66 |
+
current_model, current_tokenizer = load_model_once()
|
| 67 |
|
| 68 |
+
if current_model is None or current_tokenizer is None:
|
| 69 |
return history + [[message, "❌ 모델을 로드할 수 없습니다."]]
|
| 70 |
|
| 71 |
+
# Move model to GPU (ZeroGPU handles this automatically)
|
| 72 |
+
current_model.to('cuda')
|
| 73 |
|
| 74 |
# Build conversation context
|
| 75 |
conversation = ""
|
| 76 |
+
for user_msg, bot_msg in history[-3:]: # Last 3 turns for context
|
| 77 |
if user_msg:
|
| 78 |
+
conversation += f"사용자: {user_msg}\n"
|
| 79 |
if bot_msg:
|
| 80 |
+
conversation += f"어시스턴트: {bot_msg}\n"
|
| 81 |
|
| 82 |
+
conversation += f"사용자: {message}\n어시스턴트:"
|
| 83 |
|
| 84 |
# Tokenize
|
| 85 |
+
inputs = current_tokenizer.encode(
|
| 86 |
+
conversation,
|
| 87 |
+
return_tensors="pt",
|
| 88 |
+
truncate=True,
|
| 89 |
+
max_length=512,
|
| 90 |
+
).to('cuda')
|
| 91 |
|
| 92 |
# Generate response
|
| 93 |
with torch.no_grad():
|
| 94 |
+
outputs = current_model.generate(
|
| 95 |
inputs,
|
| 96 |
+
max_new_tokens=MODEL_CONFIG["max_length"],
|
| 97 |
+
temperature=0.7,
|
| 98 |
+
top_p=0.9,
|
| 99 |
do_sample=True,
|
| 100 |
+
pad_token_id=current_tokenizer.pad_token_id,
|
| 101 |
+
eos_token_id=current_tokenizer.eos_token_id,
|
| 102 |
)
|
| 103 |
|
| 104 |
# Decode response
|
| 105 |
+
full_response = current_tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 106 |
+
|
| 107 |
+
# Extract only the assistant's response
|
| 108 |
+
if "어시스턴트:" in full_response:
|
| 109 |
+
response = full_response.split("어시스턴트:")[-1].strip()
|
| 110 |
+
else:
|
| 111 |
+
response = full_response[len(conversation):].strip()
|
| 112 |
|
| 113 |
if not response:
|
| 114 |
+
response = "죄송합니다. 응답을 생성할 수 없었습니다."
|
| 115 |
|
| 116 |
return history + [[message, response]]
|
| 117 |
|
|
|
|
| 125 |
return history + [[message, f"❌ 오류: {error_msg[:200]}"]]
|
| 126 |
|
| 127 |
|
| 128 |
+
def chat_wrapper(message, history):
|
| 129 |
+
"""Wrapper for Gradio ChatInterface"""
|
| 130 |
+
return generate_response(message, history)
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
print("✅ App initialized - ZeroGPU will allocate GPU on demand")
|
| 134 |
|
| 135 |
# Create Gradio interface
|
| 136 |
+
with gr.Blocks(title="🤖 Llama-2-Ko Chatbot") as demo:
|
| 137 |
gr.Markdown("""
|
| 138 |
+
# 🤖 Llama-2-Ko 7B Chatbot (ZeroGPU)
|
| 139 |
+
|
| 140 |
+
**모델**: Llama-2-Ko 7B (한글 대화형 모델)
|
| 141 |
+
**하드웨어**: NVIDIA H200 (ZeroGPU - 자동 할당)
|
| 142 |
|
| 143 |
+
**특징**:
|
| 144 |
+
- ⚡ GPU 가속으로 빠른 응답 (3-5초)
|
| 145 |
+
- 🇰🇷 한글 대화에 최적화
|
| 146 |
+
- 🔄 첫 응답은 모델 로딩으로 조금 더 소요될 수 있습니다
|
| 147 |
""")
|
| 148 |
|
| 149 |
chatbot = gr.Chatbot(height=400, type="tuples", show_label=False)
|
| 150 |
|
| 151 |
with gr.Row():
|
| 152 |
msg = gr.Textbox(
|
| 153 |
+
placeholder="한글로 메시지를 입력하세요...",
|
| 154 |
show_label=False,
|
| 155 |
scale=9,
|
| 156 |
)
|
| 157 |
+
btn = gr.Button("전송", scale=1, variant="primary")
|
| 158 |
|
| 159 |
+
clear = gr.Button("🗑️ 대화 초기화", size="sm")
|
| 160 |
|
| 161 |
def submit(message, history):
|
| 162 |
+
return chat_wrapper(message, history), ""
|
| 163 |
|
| 164 |
+
btn.click(submit, [msg, chatbot], [chatbot, msg])
|
| 165 |
+
msg.submit(submit, [msg, chatbot], [chatbot, msg])
|
| 166 |
+
clear.click(lambda: [], outputs=chatbot)
|
| 167 |
|
| 168 |
gr.Markdown("""
|
| 169 |
---
|
| 170 |
+
**참고사항**:
|
| 171 |
+
- ZeroGPU는 요청 시 자동으로 GPU를 할당합니다
|
| 172 |
+
- PRO 구독자는 하루 25분 무료 사용 가능
|
| 173 |
+
- 첫 응답은 모델 로딩 시간 포함 (~10-15초)
|
| 174 |
+
- 이후 응답은 빠르게 생성됩니다 (~3-5초)
|
| 175 |
+
|
| 176 |
+
**테스트 예시**:
|
| 177 |
+
- "안녕하세요"
|
| 178 |
+
- "인공지능에 대해 설명해주세요"
|
| 179 |
+
- "오늘 날씨가 어때요?"
|
| 180 |
""")
|
| 181 |
|
| 182 |
if __name__ == "__main__":
|
|
@@ -3,3 +3,4 @@ transformers==4.46.0
|
|
| 3 |
torch==2.1.0
|
| 4 |
safetensors==0.4.5
|
| 5 |
accelerate==0.26.1
|
|
|
|
|
|
| 3 |
torch==2.1.0
|
| 4 |
safetensors==0.4.5
|
| 5 |
accelerate==0.26.1
|
| 6 |
+
spaces
|