ginipick commited on
Commit
e237613
·
verified ·
1 Parent(s): 5b26d99

Update app-backup1.py

Browse files
Files changed (1) hide show
  1. app-backup1.py +155 -212
app-backup1.py CHANGED
@@ -173,6 +173,130 @@ async def try_openai_api(openai_messages):
173
  raise e
174
 
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  def analyze_code(code: str) -> str:
177
  """코드 분석 결과를 HTML 형식으로 반환"""
178
  analysis = []
@@ -195,13 +319,14 @@ def analyze_code(code: str) -> str:
195
  for line in code.split('\n'):
196
  if line.startswith('import ') or line.startswith('from '):
197
  imports.append(line.strip())
198
- # 패키지 이름 추출
199
  if line.startswith('import '):
200
  package = line.split('import ')[1].split()[0].split('.')[0]
201
  else:
202
  package = line.split('from ')[1].split()[0].split('.')[0]
203
- required_packages.add(package)
204
 
 
205
  if imports:
206
  analysis.append("<h2>📚 필요한 라이브러리</h2>")
207
  analysis.append("<ul>")
@@ -473,109 +598,44 @@ def load_json_data():
473
  return [
474
  # 초급 레벨 (5건) - 기본 문법과 UI 익히기
475
  {
476
- "name": "[초급-1] 구구단 계산기",
477
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
478
  "prompt": "구구단을 계산하고 출력하는 간단한 계산기를 만드세요. 사용자가 숫자를 입력하면 해당 단의 구구단이 출력되고, '전체 구구단 보기' 버튼을 누르면 2~9단까지 모두 표시됩니다."
479
  },
480
  {
481
- "name": "[초급-2] BMI 계산기",
482
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
483
  "prompt": "키(cm)와 몸무게(kg)를 입력받아 BMI를 계산하고, 비만도 판정 결과를 시각적으로 표시하는 앱을 만드세요. 결과는 저체중/정상/과체중/비만으로 구분하여 표시합니다."
484
  },
485
  {
486
- "name": "[초급-3] 할인 계산기",
487
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
488
  "prompt": "상품의 원가와 할인율을 입력받아 할인가를 계산하는 앱을 만드세요. 할인율은 슬라이더로 조절 가능하며, 최종 가격과 절약 금액을 실시간으로 표시합니다."
489
  },
490
  {
491
- "name": "[초급-4] 단위 변환기",
492
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
493
  "prompt": "길이(m/cm/km), 무게(kg/g), 온도(섭씨/화씨) 등 기본적인 단위 변환기를 만드세요. 드롭다운으로 변환 단위를 선택하고 실시간으로 결과가 업데이트됩니다."
494
  },
495
  {
496
- "name": "[초급-5] 랜덤 번호 생성기",
497
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
498
  "prompt": "로또 번호나 랜덤 비밀번호를 생성하는 앱을 만드세요. 사용자가 범위와 개수를 지정할 수 있으며, 생성된 번호는 정렬되어 표시됩니다."
499
  },
500
 
501
- # 중급 레벨 (5건) - 데이터 처리와 시각화
502
- {
503
- "name": "[중급-1] 데이터 시각화 대시보드",
504
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
505
- "prompt": "CSV 파일을 업로드하여 기본 통계(평균, 중앙값, 표준편차)를 계산하고, matplotlib으로 히스토그램, 박스플롯, 산점도를 그리는 대시보드를 만드세요."
506
- },
507
- {
508
- "name": "[중급-2] 주식 데이터 분석기",
509
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
510
- "prompt": "주식 데이터를 분석하여 이동평균선, RSI, MACD 등 기술적 지표를 계산하고 시각화하는 앱을 만드세요. plotly를 사용하여 인터랙티브한 차트를 구현합니다."
511
- },
512
  {
513
- "name": "[중급-3] 이미지 편집기",
514
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
515
  "prompt": "PIL과 numpy를 사용하여 이미지 필터(흑백, 세피아, 블러 등), 회전, 리사이즈 기능이 있는 기본적인 이미지 편집기를 만드세요."
516
  },
517
  {
518
- "name": "[중급-4] 일기예보 대시보드",
519
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
520
  "prompt": "OpenWeatherMap API를 사용하여 도시별 날씨 정보를 가져오고, 온도, 습도, 풍속 등을 시각화하는 대시보드를 만드세요."
521
  },
522
- {
523
- "name": "[중급-5] 음성 파형 분석기",
524
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
525
- "prompt": "librosa를 사용하여 음성 파일을 업로드하고 파형, 스펙트로그램을 표시하며 기본적인 오디오 특성(주파수, 진폭)을 분석하는 앱을 만드세요."
526
- },
527
-
528
- # 고급 레벨 (10건) - 머신러닝/딥러닝 기초
529
- {
530
- "name": "[고급-1] 손글씨 숫자 인식기",
531
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
532
- "prompt": "MNIST 데이터셋으로 학습된 CNN 모델을 사용하여 손으로 그린 숫자를 인식하는 앱을 만드세요. 캔버스에 그림을 그리면 실시간으로 예측합니다."
533
- },
534
- {
535
- "name": "[고급-2] 얼굴 감지기",
536
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
537
- "prompt": "OpenCV와 dlib을 사용하여 이미지에서 얼굴을 감지하고 랜드마크를 표시하는 앱을 만드세요. 나이와 성별도 예측합니다."
538
- },
539
- {
540
- "name": "[고급-3] 텍스트 감성 분석기",
541
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
542
- "prompt": "NLTK와 scikit-learn을 사용하여 텍스트의 감성(긍정/부정)을 분석하고 점수를 매기는 앱을 만드세요."
543
- },
544
- {
545
- "name": "[고급-4] 이미지 세그멘테이션",
546
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
547
- "prompt": "U-Net 모델을 사용하여 이미지의 객체를 분할하고 마스크를 생성하는 앱을 만드세요."
548
- },
549
- {
550
- "name": "[고급-5] 시계열 예측기",
551
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
552
- "prompt": "Prophet을 사용하여 시계열 데이터를 분석하고 미래 값을 예측하는 앱을 만드세요. 계절성과 트렌드를 시각화합니다."
553
- },
554
- {
555
- "name": "[고급-6] 객체 탐지기",
556
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
557
- "prompt": "YOLO 모델을 사용하여 이미지나 비디오에서 객체를 탐지하고 바운딩 박스를 그리는 앱을 만드세요."
558
- },
559
- {
560
- "name": "[고급-7] 음성 인식기",
561
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
562
- "prompt": "DeepSpeech 모델을 사용하여 음성을 텍스트로 변환하는 앱을 만드세요. 실시간 음성 입력도 지원합니다."
563
- },
564
- {
565
- "name": "[고급-8] 이미지 스타일 변환",
566
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
567
- "prompt": "CycleGAN을 사용하여 이미지의 스타일을 다른 화풍으로 변환하는 앱을 만드세요."
568
- },
569
- {
570
- "name": "[고급-9] 포즈 추정기",
571
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
572
- "prompt": "PoseNet을 사용하여 이미지나 비디오에서 사람의 포즈를 추정하고 관절을 표시하는 앱을 만드세요."
573
- },
574
- {
575
- "name": "[고급-10] 이상치 탐지기",
576
- "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
577
- "prompt": "Isolation Forest를 사용하여 데이터셋에서 이상치를 탐지하고 시각화하는 앱을 만드세요."
578
- },
579
 
580
  # 응용 레벨 (20건) - 허깅페이스 모델 통합
581
  {
@@ -974,133 +1034,8 @@ def deploy_to_huggingface(code: str):
974
  except Exception as e:
975
  raise e
976
 
977
- # 4) 코드 정리 및 import 분석
978
  code = code.replace("```python", "").replace("```", "").strip()
979
-
980
- # Import 문 추출 및 requirements.txt 생성을 위한 매핑
981
- import_mapping = {
982
- 'numpy': 'numpy',
983
- 'pandas': 'pandas',
984
- 'torch': 'torch',
985
- 'matplotlib': 'matplotlib',
986
- 'plotly': 'plotly',
987
- 'transformers': 'transformers',
988
- 'PIL': 'Pillow',
989
- 'cv2': 'opencv-python',
990
- 'sklearn': 'scikit-learn',
991
- 'tensorflow': 'tensorflow',
992
- 'scipy': 'scipy',
993
- 'librosa': 'librosa',
994
- 'soundfile': 'soundfile',
995
- 'nltk': 'nltk',
996
- 'spacy': 'spacy',
997
- 'gensim': 'gensim',
998
- 'keras': 'keras',
999
- 'seaborn': 'seaborn',
1000
- 'bokeh': 'bokeh',
1001
- 'requests': 'requests',
1002
- 'beautifulsoup4': 'beautifulsoup4',
1003
- 'scikit-image': 'scikit-image',
1004
- 'opencv-python': 'opencv-python',
1005
- 'tqdm': 'tqdm',
1006
- 'streamlit': 'streamlit',
1007
- 'dash': 'dash',
1008
- 'flask': 'flask',
1009
- 'django': 'django',
1010
- 'sqlalchemy': 'sqlalchemy',
1011
- 'pymongo': 'pymongo',
1012
- 'redis': 'redis',
1013
- 'psycopg2': 'psycopg2-binary',
1014
- 'mysql-connector': 'mysql-connector-python',
1015
- 'pytest': 'pytest',
1016
- 'unittest': 'unittest2',
1017
- 'sphinx': 'sphinx',
1018
- 'jupyter': 'jupyter',
1019
- 'ipython': 'ipython',
1020
- 'fastapi': 'fastapi',
1021
- 'uvicorn': 'uvicorn',
1022
- 'aiohttp': 'aiohttp',
1023
- 'websockets': 'websockets',
1024
- 'pyyaml': 'pyyaml',
1025
- 'json': 'json5',
1026
- 'xml': 'lxml',
1027
- 'html': 'html5lib',
1028
- 'urllib3': 'urllib3',
1029
- 'cryptography': 'cryptography',
1030
- 'bcrypt': 'bcrypt',
1031
- 'jwt': 'pyjwt',
1032
- 'pillow': 'Pillow',
1033
- 'imageio': 'imageio',
1034
- 'moviepy': 'moviepy',
1035
- 'ffmpeg': 'ffmpeg-python',
1036
- 'pydub': 'pydub',
1037
- 'wave': 'wave',
1038
- 'pyaudio': 'pyaudio',
1039
- 'sounddevice': 'sounddevice',
1040
- 'pygame': 'pygame',
1041
- 'kivy': 'kivy',
1042
- 'pyqt5': 'PyQt5',
1043
- 'tkinter': 'tk',
1044
- 'wx': 'wxPython',
1045
- 'pyside2': 'PySide2',
1046
- 'deap': 'deap',
1047
- 'gym': 'gym',
1048
- 'stable-baselines3': 'stable-baselines3',
1049
- 'optuna': 'optuna',
1050
- 'hyperopt': 'hyperopt',
1051
- 'ray': 'ray',
1052
- 'dask': 'dask',
1053
- 'vaex': 'vaex',
1054
- 'modin': 'modin',
1055
- 'cupy': 'cupy',
1056
- 'jax': 'jax',
1057
- 'numba': 'numba',
1058
- 'cython': 'cython',
1059
- 'sympy': 'sympy',
1060
- 'statsmodels': 'statsmodels',
1061
- 'prophet': 'prophet',
1062
- 'lightgbm': 'lightgbm',
1063
- 'xgboost': 'xgboost',
1064
- 'catboost': 'catboost',
1065
- 'shap': 'shap',
1066
- 'lime': 'lime',
1067
- 'eli5': 'eli5',
1068
- 'yellowbrick': 'yellowbrick',
1069
- 'altair': 'altair',
1070
- 'plotnine': 'plotnine',
1071
- 'folium': 'folium',
1072
- 'geopandas': 'geopandas',
1073
- 'shapely': 'shapely',
1074
- 'rasterio': 'rasterio',
1075
- 'networkx': 'networkx',
1076
- 'graphviz': 'graphviz',
1077
- 'pydot': 'pydot',
1078
- 'pygraphviz': 'pygraphviz'
1079
- }
1080
-
1081
- required_packages = set()
1082
-
1083
- # 코드에서 import 문 분석
1084
- import_pattern = r'^(?:from\s+(\S+)|import\s+([^,\s]+)(?:\s*,\s*([^,\s]+))*)'
1085
-
1086
- for line in code.split('\n'):
1087
- line = line.strip()
1088
- if line.startswith('import ') or line.startswith('from '):
1089
- matches = re.match(import_pattern, line)
1090
- if matches:
1091
- if matches.group(1): # from ... import ...
1092
- package = matches.group(1).split('.')[0]
1093
- if package in import_mapping:
1094
- required_packages.add(import_mapping[package])
1095
- else: # import ...
1096
- packages = [p.strip() for p in re.findall(r'[\w.]+', line[7:])]
1097
- for package in packages:
1098
- package = package.split('.')[0]
1099
- if package in import_mapping:
1100
- required_packages.add(import_mapping[package])
1101
-
1102
- # gradio는 항상 포함
1103
- required_packages.add('gradio==5.5.0')
1104
 
1105
  # 5) 전체 애플리케이션 코드 생성
1106
  if "demo.launch()" not in code:
@@ -1119,8 +1054,21 @@ def deploy_to_huggingface(code: str):
1119
  repo_type="space"
1120
  )
1121
 
1122
- # requirements.txt 생성 및 업로드
1123
- requirements = '\n'.join(sorted(required_packages))
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
  with open("requirements.txt", "w") as f:
1125
  f.write(requirements)
1126
 
@@ -1131,7 +1079,7 @@ def deploy_to_huggingface(code: str):
1131
  repo_type="space"
1132
  )
1133
 
1134
- # 7) 결과 반환
1135
  space_url = f"https://huggingface.co/spaces/{username}/{space_name}"
1136
  return f'배포 완료! Private Space로 생성되었습니다. <a href="{space_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">여기를 클릭하여 Space 열기</a>'
1137
 
@@ -1201,7 +1149,6 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1201
  # UI 수정 부분 - antd.Col(span=24, md=8) 내부의 버튼 컨테이너에 배포 버튼 추가:
1202
  with antd.Flex(gap="small", justify="space-between"):
1203
  btn = antd.Button("Send", type="primary", size="large")
1204
- execute_btn = antd.Button("Code 실행", type="default", size="large")
1205
  deploy_btn = antd.Button("실행하기", type="default", size="large") # 추가
1206
  clear_btn = antd.Button("Clear", type="default", size="large")
1207
 
@@ -1250,11 +1197,7 @@ with gr.Blocks(css_paths="app.css",theme=theme) as demo:
1250
  return None, gr.update(active_key="empty")
1251
 
1252
  # 이벤트 핸들러들
1253
- execute_btn.click(
1254
- fn=execute_code,
1255
- inputs=[input],
1256
- outputs=[sandbox, state_tab]
1257
- )
1258
 
1259
  codeBtn.click(
1260
  lambda: gr.update(open=True),
 
173
  raise e
174
 
175
 
176
+ # Import to Package Name Mapping Dictionary
177
+ IMPORT_TO_PACKAGE = {
178
+ 'PIL': 'pillow',
179
+ 'cv2': 'opencv-python',
180
+ 'sklearn': 'scikit-learn',
181
+ 'bs4': 'beautifulsoup4',
182
+ 'yaml': 'pyyaml',
183
+ 'tensorflow': 'tensorflow-cpu',
184
+ 'tf': 'tensorflow-cpu',
185
+ 'wx': 'wxPython',
186
+ 'cairo': 'pycairo',
187
+ 'MySQLdb': 'mysqlclient',
188
+ 'psycopg2': 'psycopg2-binary',
189
+ 'magic': 'python-magic',
190
+ 'Image': 'pillow',
191
+ 'skimage': 'scikit-image',
192
+ 'matplotlib.pyplot': 'matplotlib',
193
+ 'plt': 'matplotlib',
194
+ 'np': 'numpy',
195
+ 'pd': 'pandas',
196
+ 'torch': 'pytorch',
197
+ 'transformers': 'transformers',
198
+ 'librosa': 'librosa',
199
+ 'nltk': 'nltk',
200
+ 'spacy': 'spacy',
201
+ 'requests': 'requests',
202
+ 'flask': 'flask',
203
+ 'fastapi': 'fastapi',
204
+ 'aiohttp': 'aiohttp',
205
+ 'imageio': 'imageio',
206
+ 'moviepy': 'moviepy',
207
+ 'networkx': 'networkx',
208
+ 'statsmodels': 'statsmodels',
209
+ 'seaborn': 'seaborn',
210
+ 'bokeh': 'bokeh',
211
+ 'plotly': 'plotly',
212
+ 'dash': 'dash',
213
+ 'streamlit': 'streamlit',
214
+ 'altair': 'altair',
215
+ 'geopandas': 'geopandas',
216
+ 'folium': 'folium',
217
+ 'shapely': 'shapely',
218
+ 'fiona': 'fiona',
219
+ 'rasterio': 'rasterio',
220
+ 'gdal': 'gdal',
221
+ 'pyproj': 'pyproj',
222
+ 'rtree': 'rtree',
223
+ 'cartopy': 'cartopy',
224
+ 'geoplot': 'geoplot',
225
+ 'descartes': 'descartes',
226
+ 'pysal': 'pysal',
227
+ 'geopy': 'geopy',
228
+ 'osmnx': 'osmnx',
229
+ 'contextily': 'contextily',
230
+ 'xarray': 'xarray',
231
+ 'netCDF4': 'netCDF4',
232
+ 'h5py': 'h5py',
233
+ 'tables': 'pytables',
234
+ 'zarr': 'zarr',
235
+ 'dask': 'dask',
236
+ 'numba': 'numba',
237
+ 'sympy': 'sympy',
238
+ 'scipy': 'scipy',
239
+ 'scikit-image': 'scikit-image',
240
+ 'scikit-learn': 'scikit-learn',
241
+ 'keras': 'keras',
242
+ 'theano': 'theano',
243
+ 'caffe': 'caffe',
244
+ 'mxnet': 'mxnet',
245
+ 'chainer': 'chainer',
246
+ 'pytorch': 'torch',
247
+ 'tensorflow-gpu': 'tensorflow-gpu',
248
+ 'cupy': 'cupy',
249
+ 'pycuda': 'pycuda',
250
+ 'pyopencl': 'pyopencl',
251
+ 'pyvista': 'pyvista',
252
+ 'mayavi': 'mayavi',
253
+ 'vtk': 'vtk',
254
+ 'trimesh': 'trimesh',
255
+ 'open3d': 'open3d-python',
256
+ 'pyqt5': 'PyQt5',
257
+ 'pyside2': 'PySide2',
258
+ 'tkinter': 'tk',
259
+ 'kivy': 'kivy',
260
+ 'pygame': 'pygame',
261
+ 'arcade': 'arcade',
262
+ 'pyglet': 'pyglet',
263
+ 'panda3d': 'panda3d',
264
+ 'ursina': 'ursina',
265
+ 'moderngl': 'moderngl',
266
+ 'glfw': 'glfw',
267
+ 'pyopengl': 'PyOpenGL',
268
+ 'pysdl2': 'PySDL2',
269
+ 'pybullet': 'pybullet',
270
+ 'box2d': 'box2d-py',
271
+ 'pymunk': 'pymunk',
272
+ 'pyode': 'pyode',
273
+ 'pyrr': 'pyrr',
274
+ 'noise': 'noise',
275
+ 'wave': 'wave',
276
+ 'sounddevice': 'sounddevice',
277
+ 'pyaudio': 'PyAudio',
278
+ 'simpleaudio': 'simpleaudio',
279
+ 'pygame.mixer': 'pygame',
280
+ 'pydub': 'pydub',
281
+ 'aubio': 'aubio',
282
+ 'music21': 'music21',
283
+ 'pretty_midi': 'pretty_midi',
284
+ 'mido': 'mido',
285
+ 'fluidsynth': 'fluidsynth',
286
+ 'mingus': 'mingus',
287
+ 'pyfluidsynth': 'pyfluidsynth',
288
+ 'python-rtmidi': 'python-rtmidi',
289
+ 'pygame.midi': 'pygame',
290
+ 'soundfile': 'soundfile',
291
+ 'resampy': 'resampy'
292
+ }
293
+
294
+ def get_package_name(import_name):
295
+ """임포트명으로부터 실제 패키지명을 반환"""
296
+ # 점이 있는 경우 첫 부분만 사용 (예: matplotlib.pyplot -> matplotlib)
297
+ base_import = import_name.split('.')[0]
298
+ return IMPORT_TO_PACKAGE.get(base_import, base_import)
299
+
300
  def analyze_code(code: str) -> str:
301
  """코드 분석 결과를 HTML 형식으로 반환"""
302
  analysis = []
 
319
  for line in code.split('\n'):
320
  if line.startswith('import ') or line.startswith('from '):
321
  imports.append(line.strip())
322
+ # 패키지 이름 추출 및 변환
323
  if line.startswith('import '):
324
  package = line.split('import ')[1].split()[0].split('.')[0]
325
  else:
326
  package = line.split('from ')[1].split()[0].split('.')[0]
327
+ required_packages.add(get_package_name(package))
328
 
329
+
330
  if imports:
331
  analysis.append("<h2>📚 필요한 라이브러리</h2>")
332
  analysis.append("<ul>")
 
598
  return [
599
  # 초급 레벨 (5건) - 기본 문법과 UI 익히기
600
  {
601
+ "name": "[기본] 구구단 계산기",
602
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
603
  "prompt": "구구단을 계산하고 출력하는 간단한 계산기를 만드세요. 사용자가 숫자를 입력하면 해당 단의 구구단이 출력되고, '전체 구구단 보기' 버튼을 누르면 2~9단까지 모두 표시됩니다."
604
  },
605
  {
606
+ "name": "[기본] BMI 계산기",
607
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
608
  "prompt": "키(cm)와 몸무게(kg)를 입력받아 BMI를 계산하고, 비만도 판정 결과를 시각적으로 표시하는 앱을 만드세요. 결과는 저체중/정상/과체중/비만으로 구분하여 표시합니다."
609
  },
610
  {
611
+ "name": "[기본] 할인 계산기",
612
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
613
  "prompt": "상품의 원가와 할인율을 입력받아 할인가를 계산하는 앱을 만드세요. 할인율은 슬라이더로 조절 가능하며, 최종 가격과 절약 금액을 실시간으로 표시합니다."
614
  },
615
  {
616
+ "name": "[기본] 단위 변환기",
617
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
618
  "prompt": "길이(m/cm/km), 무게(kg/g), 온도(섭씨/화씨) 등 기본적인 단위 변환기를 만드세요. 드롭다운으로 변환 단위를 선택하고 실시간으로 결과가 업데이트됩니다."
619
  },
620
  {
621
+ "name": "[기본] 랜덤 번호 생성기",
622
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
623
  "prompt": "로또 번호나 랜덤 비밀번호를 생성하는 앱을 만드세요. 사용자가 범위와 개수를 지정할 수 있으며, 생성된 번호는 정렬되어 표시됩니다."
624
  },
625
 
 
 
 
 
 
 
 
 
 
 
 
626
  {
627
+ "name": "[기본] 이미지 편집기",
628
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
629
  "prompt": "PIL과 numpy를 사용하여 이미지 필터(흑백, 세피아, 블러 등), 회전, 리사이즈 기능이 있는 기본적인 이미지 편집기를 만드세요."
630
  },
631
  {
632
+ "name": "[기본] 일기예보 대시보드",
633
  "image_url": "data:image/png;base64," + get_image_base64('mouse.png'),
634
  "prompt": "OpenWeatherMap API를 사용하여 도시별 날씨 정보를 가져오고, 온도, 습도, 풍속 등을 시각화하는 대시보드를 만드세요."
635
  },
636
+
637
+
638
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
639
 
640
  # 응용 레벨 (20건) - 허깅페이스 모델 통합
641
  {
 
1034
  except Exception as e:
1035
  raise e
1036
 
1037
+ # 4) 코드 정리
1038
  code = code.replace("```python", "").replace("```", "").strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1039
 
1040
  # 5) 전체 애플리케이션 코드 생성
1041
  if "demo.launch()" not in code:
 
1054
  repo_type="space"
1055
  )
1056
 
1057
+ # 7) requirements.txt 생성 및 업로드
1058
+ analysis_result = analyze_code(code)
1059
+ requirements = ""
1060
+
1061
+ # HTML에서 requirements.txt 섹션 찾기
1062
+ if "<h3>📋 Requirements.txt</h3>" in analysis_result:
1063
+ start_idx = analysis_result.find("<pre>") + 5
1064
+ end_idx = analysis_result.find("</pre>")
1065
+ if start_idx > 4 and end_idx > 0:
1066
+ requirements = analysis_result[start_idx:end_idx].strip()
1067
+
1068
+ # requirements가 비어있으면 기본값 설정
1069
+ if not requirements:
1070
+ requirements = 'gradio==5.5.0'
1071
+
1072
  with open("requirements.txt", "w") as f:
1073
  f.write(requirements)
1074
 
 
1079
  repo_type="space"
1080
  )
1081
 
1082
+ # 8) 결과 반환
1083
  space_url = f"https://huggingface.co/spaces/{username}/{space_name}"
1084
  return f'배포 완료! Private Space로 생성되었습니다. <a href="{space_url}" target="_blank" style="color: #1890ff; text-decoration: underline; cursor: pointer;">여기를 클릭하여 Space 열기</a>'
1085
 
 
1149
  # UI 수정 부분 - antd.Col(span=24, md=8) 내부의 버튼 컨테이너에 배포 버튼 추가:
1150
  with antd.Flex(gap="small", justify="space-between"):
1151
  btn = antd.Button("Send", type="primary", size="large")
 
1152
  deploy_btn = antd.Button("실행하기", type="default", size="large") # 추가
1153
  clear_btn = antd.Button("Clear", type="default", size="large")
1154
 
 
1197
  return None, gr.update(active_key="empty")
1198
 
1199
  # 이벤트 핸들러들
1200
+
 
 
 
 
1201
 
1202
  codeBtn.click(
1203
  lambda: gr.update(open=True),