youdie006 commited on
Commit
aa58f77
·
1 Parent(s): c36a566

Fix: Add-multi env

Browse files
Files changed (5) hide show
  1. Dockerfile +27 -19
  2. README.md +1 -1
  3. docker-compose.yml +43 -8
  4. main.py +242 -22
  5. start.sh +84 -0
Dockerfile CHANGED
@@ -1,14 +1,13 @@
1
  # Dockerfile
2
 
3
- # 1. 베이스 이미지 설정
4
  FROM python:3.10-slim
5
 
6
- # 2. 메타데이터
7
  LABEL maintainer="[email protected]"
8
- LABEL description="SimSimi-based Conversational AI Agent"
9
  LABEL version="1.0.0"
10
 
11
- # 3. 시스템 의존성 설치
12
  RUN apt-get update && apt-get install -y \
13
  gcc \
14
  g++ \
@@ -18,36 +17,45 @@ RUN apt-get update && apt-get install -y \
18
  && git lfs install \
19
  && rm -rf /var/lib/apt/lists/*
20
 
21
- # 4. 작업 디렉토리 설정
22
  WORKDIR /app
23
 
24
- # 5. 환경 변수 설정
25
  ENV HF_HOME=/app/cache
26
  ENV HF_DATASETS_CACHE=/app/cache
27
  ENV TRANSFORMERS_CACHE=/app/cache
 
 
 
28
 
29
- # 6. Python 의존성 설치
30
  COPY requirements.txt .
31
  RUN pip install --upgrade pip
32
  RUN pip install --no-cache-dir -r requirements.txt
33
 
34
- # 7. 데이터 다운로드를 빌드 단계에서 미리 실행
 
 
 
 
 
 
 
35
  RUN huggingface-cli download \
36
  youdie006/simsimi-ai-agent-data \
37
  --repo-type dataset \
38
  --local-dir /app/data \
39
- --local-dir-use-symlinks False
40
- RUN chmod -R 777 /app/data /app/cache
41
 
42
- # 8. 애플리케이션 코드 복사
43
- COPY . .
 
44
 
45
- # 9. 포트 노출
46
- EXPOSE 8000
47
 
48
- # 10. [최종 수정] 헬스체크 시작 대기 시간을 모델 로딩 시간보다 넉넉하게 변경
49
- HEALTHCHECK --interval=60s --timeout=30s --start-period=300s --retries=3 \
50
- CMD curl -f http://localhost:8000/api/v1/health || exit 1
51
 
52
- # 11. 운영용 서버 실행 (타임아웃 프리로드 적용)
53
- CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--timeout", "300", "--preload", "-b", "0.0.0.0:8000", "main:app"]
 
1
  # Dockerfile
2
 
 
3
  FROM python:3.10-slim
4
 
5
+ # 메타데이터
6
  LABEL maintainer="[email protected]"
7
+ LABEL description="SimSimi AI Agent - Multi Environment Support"
8
  LABEL version="1.0.0"
9
 
10
+ # 시스템 의존성 설치
11
  RUN apt-get update && apt-get install -y \
12
  gcc \
13
  g++ \
 
17
  && git lfs install \
18
  && rm -rf /var/lib/apt/lists/*
19
 
 
20
  WORKDIR /app
21
 
22
+ # 환경 변수 설정
23
  ENV HF_HOME=/app/cache
24
  ENV HF_DATASETS_CACHE=/app/cache
25
  ENV TRANSFORMERS_CACHE=/app/cache
26
+ ENV PYTHONPATH=/app
27
+ ENV PYTHONDONTWRITEBYTECODE=1
28
+ ENV PYTHONUNBUFFERED=1
29
 
30
+ # Python 의존성 설치
31
  COPY requirements.txt .
32
  RUN pip install --upgrade pip
33
  RUN pip install --no-cache-dir -r requirements.txt
34
 
35
+ # 애플리케이션 코드 복사
36
+ COPY . .
37
+
38
+ # 필요한 디렉토리 생성
39
+ RUN mkdir -p /app/data /app/cache /app/logs /app/static
40
+ RUN chmod -R 777 /app/data /app/cache /app/logs
41
+
42
+ # 조건부 데이터 다운로드
43
  RUN huggingface-cli download \
44
  youdie006/simsimi-ai-agent-data \
45
  --repo-type dataset \
46
  --local-dir /app/data \
47
+ --local-dir-use-symlinks False || echo "⚠️ 데이터 다운로드 실패 - 런타임에 생성"
 
48
 
49
+ # 스마트 시작 스크립트 복사
50
+ COPY start.sh /app/start.sh
51
+ RUN chmod +x /app/start.sh
52
 
53
+ # 포트 노출 (7860 고정)
54
+ EXPOSE 7860
55
 
56
+ # 헬스체크
57
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=300s --retries=3 \
58
+ CMD curl -f http://localhost:7860/api/v1/health || exit 1
59
 
60
+ # 🎯 스마트 시작 - 환경 자동 감지!
61
+ CMD ["/app/start.sh"]
README.md CHANGED
@@ -6,7 +6,7 @@ emoji: 💙
6
  colorFrom: purple
7
  colorTo: blue
8
  sdk: docker
9
- app_port: 8000
10
  pinned: false
11
  ---
12
 
 
6
  colorFrom: purple
7
  colorTo: blue
8
  sdk: docker
9
+ app_port: 7860
10
  pinned: false
11
  ---
12
 
docker-compose.yml CHANGED
@@ -1,3 +1,5 @@
 
 
1
  services:
2
  simsimi-ai-agent:
3
  build:
@@ -5,26 +7,28 @@ services:
5
  dockerfile: Dockerfile
6
  container_name: simsimi_ai_agent
7
  ports:
8
- - "8000:8000"
9
  volumes:
10
- # 소스코드 실시간 반영 (개발용)
11
  - ./src:/app/src
12
  - ./scripts:/app/scripts
13
  - ./main.py:/app/main.py
14
- # 데이터 영구 저장
 
 
15
  - ./data:/app/data
16
  - ./logs:/app/logs
17
- # [추가] 캐시 데이터 영구 저장
18
- # 이렇게 하면 컨테이너를 껐다 켜도 매번 모델을 새로 다운로드하지 않습니다.
19
  - ./cache:/app/cache
20
- # 환경변수 (로컬에서만)
 
21
  - ./.env:/app/.env:ro
22
  environment:
23
  - PYTHONPATH=/app
24
  - PYTHONDONTWRITEBYTECODE=1
25
  - PYTHONUNBUFFERED=1
26
- # [추가] Hugging Face 캐시 디렉토리 환경 변수
27
  - HF_HOME=/app/cache
 
 
28
  env_file:
29
  - .env
30
  restart: unless-stopped
@@ -33,6 +37,37 @@ services:
33
  networks:
34
  - simsimi_network
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  networks:
37
  simsimi_network:
38
- driver: bridge
 
 
 
 
 
1
+ # docker-compose.yml - 로컬 개발 최적화
2
+
3
  services:
4
  simsimi-ai-agent:
5
  build:
 
7
  dockerfile: Dockerfile
8
  container_name: simsimi_ai_agent
9
  ports:
10
+ - "7860:7860" # 허깅페이스와 동일한 포트
11
  volumes:
12
+ # 🔄 소스코드 실시간 반영 (개발용)
13
  - ./src:/app/src
14
  - ./scripts:/app/scripts
15
  - ./main.py:/app/main.py
16
+ - ./static:/app/static
17
+
18
+ # 💾 데이터 영구 저장
19
  - ./data:/app/data
20
  - ./logs:/app/logs
 
 
21
  - ./cache:/app/cache
22
+
23
+ # 🔑 환경변수 (로컬에서만)
24
  - ./.env:/app/.env:ro
25
  environment:
26
  - PYTHONPATH=/app
27
  - PYTHONDONTWRITEBYTECODE=1
28
  - PYTHONUNBUFFERED=1
 
29
  - HF_HOME=/app/cache
30
+ - LOCAL_DEV=true # 🏠 로컬 개발 환경 표시
31
+ - DEVELOPMENT_MODE=true # 🔧 개발 모드 활성화
32
  env_file:
33
  - .env
34
  restart: unless-stopped
 
37
  networks:
38
  - simsimi_network
39
 
40
+ # 🚀 프로덕션 테스트용 (옵션)
41
+ simsimi-production-test:
42
+ build:
43
+ context: .
44
+ dockerfile: Dockerfile
45
+ container_name: simsimi_production_test
46
+ ports:
47
+ - "7861:7860" # 다른 포트로 동시 실행
48
+ volumes:
49
+ - ./data:/app/data
50
+ - ./logs:/app/logs
51
+ - ./cache:/app/cache
52
+ - ./.env:/app/.env:ro
53
+ environment:
54
+ - PYTHONPATH=/app
55
+ - PYTHONDONTWRITEBYTECODE=1
56
+ - PYTHONUNBUFFERED=1
57
+ - HF_HOME=/app/cache
58
+ - PRODUCTION=true # 🏭 프로덕션 모드 테스트
59
+ env_file:
60
+ - .env
61
+ restart: unless-stopped
62
+ profiles:
63
+ - production-test # docker-compose --profile production-test up
64
+ networks:
65
+ - simsimi_network
66
+
67
  networks:
68
  simsimi_network:
69
+ driver: bridge
70
+
71
+ # 사용법:
72
+ # 개발: docker-compose up
73
+ # 프로덕션 테스트: docker-compose --profile production-test up
main.py CHANGED
@@ -1,61 +1,281 @@
1
- # main.py
2
 
3
- """
4
- 청소년 공감형 AI 챗봇 메인 서버
5
- """
6
- from fastapi import FastAPI
7
- from fastapi.middleware.cors import CORSMiddleware
8
- from fastapi.responses import JSONResponse, HTMLResponse
9
- from fastapi.staticfiles import StaticFiles
10
  import os
11
  import sys
12
  from datetime import datetime
13
  from dotenv import load_dotenv
 
 
 
 
14
 
15
  # 환경 변수 로드
16
  load_dotenv()
17
 
18
- # FastAPI 앱 생성
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  app = FastAPI(
20
  title="💙 마음이 - 청소년 상담 챗봇",
21
- description="13-19세 청소년을 위한 AI 공감 상담사",
22
- version=os.getenv("VERSION", "2.0.0")
 
 
 
23
  )
24
 
25
- # CORS 설정
26
  app.add_middleware(
27
  CORSMiddleware,
28
- allow_origins=["*"],
29
  allow_credentials=True,
30
  allow_methods=["*"],
31
  allow_headers=["*"],
32
  )
33
 
34
- # 정적 파일 서빙
35
- try:
36
- app.mount("/static", StaticFiles(directory="static"), name="static")
37
- print("✅ 정적 파일 서빙 설정 완료")
38
- except RuntimeError:
39
- print("정적 파일 디렉토리를 찾을 수 없습니다. API 서버는 계속 실행됩니다.")
40
 
41
- # 라우터 등록
 
 
 
 
 
 
 
 
 
42
  try:
43
  from src.api import chat, openai, vector
 
44
  app.include_router(chat.router, prefix="/api/v1/chat", tags=["💙 Teen Chat"])
45
  app.include_router(openai.router, prefix="/api/v1/openai", tags=["🤖 OpenAI GPT-4"])
46
  app.include_router(vector.router, prefix="/api/v1/vector", tags=["🗄️ Vector Store"])
47
  print("✅ API 라우터 등록 완료")
48
  except ImportError as e:
49
  print(f"⚠️ API 라우터 import 실패: {e}")
 
50
 
 
 
51
  @app.get("/", response_class=HTMLResponse)
52
  async def root():
 
53
  html_file_path = "static/index.html"
54
  if os.path.exists(html_file_path):
55
  with open(html_file_path, "r", encoding="utf-8") as f:
56
  return HTMLResponse(content=f.read())
57
- return HTMLResponse(content="<h1>Welcome to 마음이 AI</h1><p>UI not found, but API is running. Access docs at /docs.</p>")
 
58
 
59
  @app.get("/api/v1/health")
60
  async def health_check():
61
- return {"status": "healthy"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # main.py - 환경 자동 감지 및 최적화
2
 
 
 
 
 
 
 
 
3
  import os
4
  import sys
5
  from datetime import datetime
6
  from dotenv import load_dotenv
7
+ from fastapi import FastAPI
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ from fastapi.responses import JSONResponse, HTMLResponse
10
+ from fastapi.staticfiles import StaticFiles
11
 
12
  # 환경 변수 로드
13
  load_dotenv()
14
 
15
+
16
+ # 🌍 환경 감지
17
+ class EnvironmentDetector:
18
+ @staticmethod
19
+ def detect_environment():
20
+ """실행 환경 자동 감지"""
21
+ if os.getenv("SPACE_ID") or os.getenv("SPACE_AUTHOR_NAME"):
22
+ return "huggingface"
23
+ elif os.getenv("LOCAL_DEV") == "true" or os.getenv("DEVELOPMENT_MODE") == "true":
24
+ return "local_dev"
25
+ elif os.getenv("PRODUCTION") == "true":
26
+ return "production"
27
+ else:
28
+ return "default"
29
+
30
+ @staticmethod
31
+ def get_environment_config(env_type: str) -> dict:
32
+ """환경별 설정 반환"""
33
+ configs = {
34
+ "huggingface": {
35
+ "debug": False,
36
+ "reload": False,
37
+ "log_level": "info",
38
+ "cors_origins": ["*"],
39
+ "description": "🤗 허깅페이스 Spaces에서 실행 중",
40
+ "features": {
41
+ "static_files": True,
42
+ "api_docs": True,
43
+ "debug_routes": False
44
+ }
45
+ },
46
+ "local_dev": {
47
+ "debug": True,
48
+ "reload": True,
49
+ "log_level": "debug",
50
+ "cors_origins": ["*"],
51
+ "description": "🏠 로컬 개발 환경에서 실행 중",
52
+ "features": {
53
+ "static_files": True,
54
+ "api_docs": True,
55
+ "debug_routes": True
56
+ }
57
+ },
58
+ "production": {
59
+ "debug": False,
60
+ "reload": False,
61
+ "log_level": "warning",
62
+ "cors_origins": ["https://yourdomain.com"],
63
+ "description": "🏭 프로덕션 환경에서 실행 중",
64
+ "features": {
65
+ "static_files": True,
66
+ "api_docs": False,
67
+ "debug_routes": False
68
+ }
69
+ },
70
+ "default": {
71
+ "debug": False,
72
+ "reload": False,
73
+ "log_level": "info",
74
+ "cors_origins": ["*"],
75
+ "description": "🔧 기본 환경에서 실행 중",
76
+ "features": {
77
+ "static_files": True,
78
+ "api_docs": True,
79
+ "debug_routes": False
80
+ }
81
+ }
82
+ }
83
+ return configs.get(env_type, configs["default"])
84
+
85
+
86
+ # 환경 감지 및 설정
87
+ ENVIRONMENT = EnvironmentDetector.detect_environment()
88
+ CONFIG = EnvironmentDetector.get_environment_config(ENVIRONMENT)
89
+
90
+ print(f"🌍 감지된 환경: {ENVIRONMENT}")
91
+ print(f"📋 설정: {CONFIG['description']}")
92
+
93
+ # FastAPI 앱 생성 (환경별 설정 적용)
94
  app = FastAPI(
95
  title="💙 마음이 - 청소년 상담 챗봇",
96
+ description=f"13-19세 청소년을 위한 AI 공감 상담사 ({CONFIG['description']})",
97
+ version=os.getenv("VERSION", "2.0.0"),
98
+ docs_url="/docs" if CONFIG["features"]["api_docs"] else None,
99
+ redoc_url="/redoc" if CONFIG["features"]["api_docs"] else None,
100
+ debug=CONFIG["debug"]
101
  )
102
 
103
+ # CORS 설정 (환경별)
104
  app.add_middleware(
105
  CORSMiddleware,
106
+ allow_origins=CONFIG["cors_origins"],
107
  allow_credentials=True,
108
  allow_methods=["*"],
109
  allow_headers=["*"],
110
  )
111
 
112
+ # 정적 파일 서빙 (환경별)
113
+ if CONFIG["features"]["static_files"]:
114
+ try:
115
+ static_dir = "static"
116
+ if not os.path.exists(static_dir):
117
+ os.makedirs(static_dir)
118
 
119
+ index_path = os.path.join(static_dir, "index.html")
120
+ if not os.path.exists(index_path):
121
+ create_default_html(index_path)
122
+
123
+ app.mount("/static", StaticFiles(directory=static_dir), name="static")
124
+ print("✅ 정적 파일 서빙 설정 완료")
125
+ except Exception as e:
126
+ print(f"⚠️ 정적 파일 설정 실패: {e}")
127
+
128
+ # 라우터 등록 (오류 처리 포함)
129
  try:
130
  from src.api import chat, openai, vector
131
+
132
  app.include_router(chat.router, prefix="/api/v1/chat", tags=["💙 Teen Chat"])
133
  app.include_router(openai.router, prefix="/api/v1/openai", tags=["🤖 OpenAI GPT-4"])
134
  app.include_router(vector.router, prefix="/api/v1/vector", tags=["🗄️ Vector Store"])
135
  print("✅ API 라우터 등록 완료")
136
  except ImportError as e:
137
  print(f"⚠️ API 라우터 import 실패: {e}")
138
+ add_demo_routes()
139
 
140
+
141
+ # 기본 라우트들
142
  @app.get("/", response_class=HTMLResponse)
143
  async def root():
144
+ """메인 페이지"""
145
  html_file_path = "static/index.html"
146
  if os.path.exists(html_file_path):
147
  with open(html_file_path, "r", encoding="utf-8") as f:
148
  return HTMLResponse(content=f.read())
149
+ return HTMLResponse(content=get_default_html())
150
+
151
 
152
  @app.get("/api/v1/health")
153
  async def health_check():
154
+ """헬스 체크 (환경 정보 포함)"""
155
+ return {
156
+ "status": "healthy",
157
+ "environment": ENVIRONMENT,
158
+ "config": CONFIG['description'],
159
+ "features": CONFIG['features'],
160
+ "timestamp": datetime.now().isoformat(),
161
+ "python_version": sys.version.split()[0],
162
+ "debug_mode": CONFIG["debug"]
163
+ }
164
+
165
+
166
+ @app.get("/api/v1/environment")
167
+ async def get_environment_info():
168
+ """환경 정보 조회"""
169
+ return {
170
+ "environment": ENVIRONMENT,
171
+ "config": CONFIG,
172
+ "env_vars": {
173
+ "SPACE_ID": bool(os.getenv("SPACE_ID")),
174
+ "LOCAL_DEV": os.getenv("LOCAL_DEV"),
175
+ "DEVELOPMENT_MODE": os.getenv("DEVELOPMENT_MODE"),
176
+ "PRODUCTION": os.getenv("PRODUCTION"),
177
+ "OPENAI_API_KEY_SET": bool(os.getenv("OPENAI_API_KEY"))
178
+ }
179
+ }
180
+
181
+
182
+ # 디버그 라우트 (개발 환경에서만)
183
+ if CONFIG["features"]["debug_routes"]:
184
+ @app.get("/api/v1/debug/reload")
185
+ async def debug_reload():
186
+ """개발용: 서버 재시작 없이 모듈 리로드"""
187
+ return {"message": "개발 모드에서만 사용 가능", "environment": ENVIRONMENT}
188
+
189
+
190
+ @app.get("/api/v1/debug/logs")
191
+ async def debug_logs():
192
+ """개발용: 최근 로그 조회"""
193
+ try:
194
+ with open("/app/logs/app.log", "r") as f:
195
+ logs = f.readlines()[-50:] # 최근 50줄
196
+ return {"logs": logs}
197
+ except FileNotFoundError:
198
+ return {"logs": ["로그 파일이 없습니다."]}
199
+
200
+
201
+ def create_default_html(file_path: str):
202
+ """기본 HTML 파일 생성"""
203
+ html_content = get_default_html()
204
+ with open(file_path, "w", encoding="utf-8") as f:
205
+ f.write(html_content)
206
+
207
+
208
+ def get_default_html() -> str:
209
+ """환경별 기본 HTML 반환"""
210
+ env_emoji = {
211
+ "huggingface": "🤗",
212
+ "local_dev": "🏠",
213
+ "production": "🏭",
214
+ "default": "🔧"
215
+ }
216
+
217
+ return f'''
218
+ <!DOCTYPE html>
219
+ <html lang="ko">
220
+ <head>
221
+ <meta charset="UTF-8">
222
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
223
+ <title>마음이 AI | {CONFIG['description']}</title>
224
+ <style>
225
+ body {{ font-family: 'Noto Sans KR', sans-serif; background: #f4f7f6; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; }}
226
+ .container {{ text-align: center; background: white; padding: 40px; border-radius: 20px; box-shadow: 0 8px 32px rgba(0,0,0,0.1); }}
227
+ .title {{ color: #8A2BE2; font-size: 2rem; margin-bottom: 20px; }}
228
+ .env {{ color: #666; font-size: 1rem; margin-bottom: 15px; }}
229
+ .message {{ color: #666; font-size: 1.1rem; margin-bottom: 30px; }}
230
+ .status {{ padding: 10px 20px; background: #e8f5e8; color: #4a5e4a; border-radius: 8px; display: inline-block; }}
231
+ {"" if not CONFIG['debug'] else ".debug { background: #fff3cd; color: #856404; padding: 10px; border-radius: 5px; margin-top: 20px; }"}
232
+ </style>
233
+ </head>
234
+ <body>
235
+ <div class="container">
236
+ <h1 class="title">💙 마음이 AI</h1>
237
+ <div class="env">{env_emoji.get(ENVIRONMENT, "🔧")} {CONFIG['description']}</div>
238
+ <p class="message">청소년 공감 상담 챗봇이 곧 시작됩니다!</p>
239
+ <div class="status">시스템 초기화 중...</div>
240
+ {"" if not CONFIG['debug'] else '<div class="debug">🔧 개발 모드 - 디버그 정보 활성화</div>'}
241
+ <script>
242
+ setTimeout(() => {{
243
+ window.location.reload();
244
+ }}, 5000);
245
+ </script>
246
+ </div>
247
+ </body>
248
+ </html>
249
+ '''
250
+
251
+
252
+ def add_demo_routes():
253
+ """데모용 라우터 추가"""
254
+
255
+ @app.post("/api/v1/chat/teen-chat")
256
+ async def demo_chat(request: dict):
257
+ return {
258
+ "response": f"안녕! 마음이가 곧 준비될 예정이야. ({ENVIRONMENT} 환경) 💙",
259
+ "status": "demo_mode",
260
+ "environment": ENVIRONMENT
261
+ }
262
+
263
+
264
+ # 환경별 실행 (스크립트로 직접 실행할 때)
265
+ if __name__ == "__main__":
266
+ import uvicorn
267
+
268
+ port = int(os.getenv("API_PORT", 7860))
269
+
270
+ print(f"🚀 {CONFIG['description']} 서버 시작")
271
+ print(f"📍 포트: {port}")
272
+ print(f"🔧 디버그 모드: {CONFIG['debug']}")
273
+ print(f"🔄 리로드: {CONFIG['reload']}")
274
+
275
+ uvicorn.run(
276
+ "main:app" if not CONFIG['reload'] else app,
277
+ host="0.0.0.0",
278
+ port=port,
279
+ reload=CONFIG['reload'],
280
+ log_level=CONFIG['log_level']
281
+ )
start.sh ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # start.sh - 환경 자동 감지 스마트 시작 스크립트
3
+
4
+ echo "🚀 마음이 AI 시작 중..."
5
+
6
+ # 환경 감지
7
+ if [ -n "$SPACE_ID" ] || [ -n "$SPACE_AUTHOR_NAME" ]; then
8
+ echo "🤗 허깅페이스 Spaces 환경 감지"
9
+ ENVIRONMENT="huggingface"
10
+ PORT=7860
11
+ WORKERS=1
12
+ RELOAD=""
13
+ elif [ "$DEVELOPMENT_MODE" = "true" ] || [ -f "/.dockerenv" ] && [ -n "$LOCAL_DEV" ]; then
14
+ echo "🏠 로컬 개발 환경 감지"
15
+ ENVIRONMENT="local_dev"
16
+ PORT=7860
17
+ WORKERS=1
18
+ RELOAD="--reload"
19
+ elif [ -n "$PRODUCTION" ]; then
20
+ echo "🏭 프로덕션 환경 감지"
21
+ ENVIRONMENT="production"
22
+ PORT=7860
23
+ WORKERS=2
24
+ RELOAD=""
25
+ else
26
+ echo "🔧 기본 환경으로 시작"
27
+ ENVIRONMENT="default"
28
+ PORT=7860
29
+ WORKERS=1
30
+ RELOAD=""
31
+ fi
32
+
33
+ echo "📊 환경 정보:"
34
+ echo " - 환경: $ENVIRONMENT"
35
+ echo " - 포트: $PORT"
36
+ echo " - 워커 수: $WORKERS"
37
+ echo " - 리로드: ${RELOAD:-"비활성화"}"
38
+
39
+ # Python 환경 확인
40
+ echo "🐍 Python 환경 확인:"
41
+ python --version
42
+ pip show fastapi uvicorn | grep Version
43
+
44
+ # 필수 디렉토리 확인
45
+ echo "📁 디렉토리 확인:"
46
+ mkdir -p /app/data /app/cache /app/logs /app/static
47
+ ls -la /app/
48
+
49
+ # 환경별 시작 방식
50
+ case $ENVIRONMENT in
51
+ "huggingface")
52
+ echo "🤗 허깅페이스 모드로 시작..."
53
+ exec python -m uvicorn main:app \
54
+ --host 0.0.0.0 \
55
+ --port $PORT \
56
+ --timeout-keep-alive 300 \
57
+ --log-level info
58
+ ;;
59
+ "local_dev")
60
+ echo "🏠 로컬 개발 모드로 시작..."
61
+ exec python -m uvicorn main:app \
62
+ --host 0.0.0.0 \
63
+ --port $PORT \
64
+ --reload \
65
+ --log-level debug
66
+ ;;
67
+ "production")
68
+ echo "🏭 프로덕션 모드로 시작..."
69
+ exec gunicorn main:app \
70
+ -w $WORKERS \
71
+ -k uvicorn.workers.UvicornWorker \
72
+ --bind 0.0.0.0:$PORT \
73
+ --timeout 300 \
74
+ --preload \
75
+ --log-level info
76
+ ;;
77
+ *)
78
+ echo "🔧 기본 모드로 시작..."
79
+ exec python -m uvicorn main:app \
80
+ --host 0.0.0.0 \
81
+ --port $PORT \
82
+ --log-level info
83
+ ;;
84
+ esac