import gradio as gr from huggingface_hub import HfApi, model_info import tempfile import zipfile import os from datetime import datetime api = HfApi() def analyze_model(model_name): """허깅페이스 모델 분석""" if not model_name: return "모델명을 입력해주세요.", None, None try: # 모델 정보 가져오기 info = model_info(model_name) # 파이프라인 태스크 확인 pipeline_tag = getattr(info, 'pipeline_tag', None) # 모델 타입 분석 model_type = "unknown" if hasattr(info, 'config') and info.config: model_type = info.config.get('model_type', 'unknown') # 라이브러리 확인 library = getattr(info, 'library_name', 'transformers') # 언어 확인 languages = getattr(info, 'language', ['en']) if isinstance(languages, str): languages = [languages] analysis_result = f""" ## 🔍 모델 분석 결과 ### 기본 정보 - **모델명**: {model_name} - **태스크**: {pipeline_tag or 'Unknown'} - **모델 타입**: {model_type} - **라이브러리**: {library} - **언어**: {', '.join(languages[:3])} - **다운로드**: {getattr(info, 'downloads', 0):,}회 ### 데모 생성 가능 여부 """ # 지원 가능한 태스크인지 확인 supported_tasks = { 'text-classification': '✅ 텍스트 분류 데모 생성 가능', 'question-answering': '✅ 질의응답 데모 생성 가능', 'text-generation': '✅ 텍스트 생성 데모 생성 가능', 'summarization': '✅ 요약 데모 생성 가능', 'translation': '✅ 번역 데모 생성 가능', 'fill-mask': '✅ 빈칸 채우기 데모 생성 가능', 'token-classification': '✅ 개체명 인식 데모 생성 가능' } if pipeline_tag in supported_tasks: analysis_result += supported_tasks[pipeline_tag] demo_possible = True else: analysis_result += f"⚠️ '{pipeline_tag}' 태스크는 아직 지원되지 않습니다." demo_possible = False return analysis_result, info, demo_possible except Exception as e: return f"❌ 모델 분석 실패: {str(e)}\n\n모델명이 정확한지 확인해주세요.", None, False def generate_demo_code(model_info, model_name, demo_title, demo_description): """태스크별 데모 코드 생성""" if not model_info: return "먼저 모델을 분석해주세요.", None pipeline_tag = getattr(model_info, 'pipeline_tag', None) if not demo_title: demo_title = f"{model_name.split('/')[-1]} Demo" if not demo_description: demo_description = f"Demo for {model_name}" # 태스크별 코드 생성 if pipeline_tag == 'text-classification': app_code = generate_text_classification_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'question-answering': app_code = generate_qa_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'text-generation': app_code = generate_text_generation_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'summarization': app_code = generate_summarization_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'translation': app_code = generate_translation_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'fill-mask': app_code = generate_fill_mask_demo(model_name, demo_title, demo_description) elif pipeline_tag == 'token-classification': app_code = generate_token_classification_demo(model_name, demo_title, demo_description) else: return f"❌ '{pipeline_tag}' 태스크는 아직 지원되지 않습니다.", None return app_code, pipeline_tag def generate_text_classification_demo(model_name, title, description): """텍스트 분류 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 classifier = pipeline("text-classification", model="{model_name}") def classify_text(text): """텍스트 분류 수행""" if not text.strip(): return "텍스트를 입력해주세요." try: results = classifier(text) # 결과 포맷팅 output = "## 🎯 분류 결과\\n\\n" for i, result in enumerate(results): label = result['label'] score = result['score'] confidence = f"{score:.1%}" output += f"**{i+1}. {label}**: {confidence}\\n" return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(scale=1): text_input = gr.Textbox( label="분석할 텍스트", placeholder="여기에 텍스트를 입력하세요...", lines=5 ) classify_btn = gr.Button("🎯 분류하기", variant="primary") # 예시 버튼들 gr.Markdown("### 📝 예시 텍스트") examples = [ ["이 영화 정말 재미있어요! 강력 추천합니다."], ["서비스가 너무 별로네요. 실망스럽습니다."], ["그냥 평범한 제품인 것 같아요."] ] example_btns = [] for example in examples: btn = gr.Button(example[0][:30] + "...", size="sm") btn.click(lambda x=example[0]: x, outputs=text_input) with gr.Column(scale=1): output = gr.Markdown("텍스트를 입력하고 분류 버튼을 클릭하세요.") classify_btn.click( fn=classify_text, inputs=text_input, outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 텍스트 분류 - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_qa_demo(model_name, title, description): """질의응답 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 qa_pipeline = pipeline("question-answering", model="{model_name}") def answer_question(context, question): """질의응답 수행""" if not context.strip() or not question.strip(): return "컨텍스트와 질문을 모두 입력해주세요." try: result = qa_pipeline(question=question, context=context) answer = result['answer'] score = result['score'] confidence = f"{score:.1%}" output = f""" ## 💡 답변 결과 **답변**: {answer} **신뢰도**: {confidence} **시작 위치**: {result.get('start', 'N/A')} **끝 위치**: {result.get('end', 'N/A')} """ return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(): context_input = gr.Textbox( label="📄 컨텍스트 (배경 정보)", placeholder="답변의 근거가 될 텍스트를 입력하세요...", lines=8 ) question_input = gr.Textbox( label="❓ 질문", placeholder="질문을 입력하세요...", lines=2 ) qa_btn = gr.Button("💡 답변 찾기", variant="primary") with gr.Column(): output = gr.Markdown("컨텍스트와 질문을 입력하고 버튼을 클릭하세요.") qa_btn.click( fn=answer_question, inputs=[context_input, question_input], outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 질의응답 - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_text_generation_demo(model_name, title, description): """텍스트 생성 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 generator = pipeline("text-generation", model="{model_name}") def generate_text(prompt, max_length, temperature, top_p): """텍스트 생성 수행""" if not prompt.strip(): return "프롬프트를 입력해주세요." try: results = generator( prompt, max_length=max_length, temperature=temperature, top_p=top_p, num_return_sequences=1, do_sample=True, pad_token_id=generator.tokenizer.eos_token_id ) generated_text = results[0]['generated_text'] # 원본 프롬프트 제거하고 생성된 부분만 표시 if generated_text.startswith(prompt): generated_text = generated_text[len(prompt):] output = f""" ## ✨ 생성된 텍스트 **입력**: {prompt} **생성 결과**: {generated_text} --- *설정: 최대 길이={max_length}, 온도={temperature}, Top-p={top_p}* """ return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(scale=1): prompt_input = gr.Textbox( label="✍️ 프롬프트", placeholder="텍스트 생성을 시작할 문장을 입력하세요...", lines=4 ) gr.Markdown("### ⚙️ 생성 설정") max_length = gr.Slider( label="최대 길이", minimum=10, maximum=200, value=50, step=10 ) temperature = gr.Slider( label="Temperature (창의성)", minimum=0.1, maximum=2.0, value=0.7, step=0.1 ) top_p = gr.Slider( label="Top-p (다양성)", minimum=0.1, maximum=1.0, value=0.9, step=0.1 ) generate_btn = gr.Button("✨ 텍스트 생성", variant="primary") with gr.Column(scale=2): output = gr.Markdown("프롬프트를 입력하고 생성 버튼을 클릭하세요.") generate_btn.click( fn=generate_text, inputs=[prompt_input, max_length, temperature, top_p], outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 텍스트 생성 - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_summarization_demo(model_name, title, description): """요약 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 summarizer = pipeline("summarization", model="{model_name}") def summarize_text(text, max_length, min_length): """텍스트 요약 수행""" if not text.strip(): return "요약할 텍스트를 입력해주세요." if len(text.split()) < 10: return "요약하기에는 텍스트가 너무 짧습니다. 더 긴 텍스트를 입력해주세요." try: results = summarizer( text, max_length=max_length, min_length=min_length, do_sample=False ) summary = results[0]['summary_text'] # 통계 계산 original_words = len(text.split()) summary_words = len(summary.split()) compression_ratio = (1 - summary_words / original_words) * 100 output = f""" ## 📝 요약 결과 **요약문**: {summary} --- ### 📊 통계 - **원문 단어 수**: {original_words:,}개 - **요약문 단어 수**: {summary_words:,}개 - **압축률**: {compression_ratio:.1f}% """ return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(scale=1): text_input = gr.Textbox( label="📄 요약할 텍스트", placeholder="긴 텍스트를 입력하세요...", lines=10 ) gr.Markdown("### ⚙️ 요약 설정") max_length = gr.Slider( label="최대 요약 길이", minimum=20, maximum=150, value=50, step=10 ) min_length = gr.Slider( label="최소 요약 길이", minimum=5, maximum=50, value=10, step=5 ) summarize_btn = gr.Button("📝 요약하기", variant="primary") with gr.Column(scale=1): output = gr.Markdown("텍스트를 입력하고 요약 버튼을 클릭하세요.") summarize_btn.click( fn=summarize_text, inputs=[text_input, max_length, min_length], outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 텍스트 요약 - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_translation_demo(model_name, title, description): """번역 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 translator = pipeline("translation", model="{model_name}") def translate_text(text): """번역 수행""" if not text.strip(): return "번역할 텍스트를 입력해주세요." try: results = translator(text) translated = results[0]['translation_text'] output = f""" ## 🌍 번역 결과 **원문**: {text} **번역문**: {translated} --- *문자 수: {len(text)} → {len(translated)}* """ return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(): text_input = gr.Textbox( label="🌍 번역할 텍스트", placeholder="번역할 텍스트를 입력하세요...", lines=6 ) translate_btn = gr.Button("🌍 번역하기", variant="primary") with gr.Column(): output = gr.Markdown("텍스트를 입력하고 번역 버튼을 클릭하세요.") translate_btn.click( fn=translate_text, inputs=text_input, outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 번역 - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_fill_mask_demo(model_name, title, description): """빈칸 채우기 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 fill_mask = pipeline("fill-mask", model="{model_name}") def predict_mask(text): """마스크 예측 수행""" if not text.strip(): return "텍스트를 입력해주세요." if "[MASK]" not in text: return "텍스트에 [MASK] 토큰을 포함해주세요." try: results = fill_mask(text) output = f"## 🎯 예측 결과\\n\\n**원문**: {text}\\n\\n### 후보들:\\n" for i, result in enumerate(results[:5]): token = result['token_str'] score = result['score'] sequence = result['sequence'] confidence = f"{score:.1%}" output += f"**{i+1}. {token}** ({confidence})\\n" output += f" *{sequence}*\\n\\n" return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(): text_input = gr.Textbox( label="🎯 [MASK] 예측할 텍스트", placeholder="[MASK] 토큰을 포함한 문장을 입력하세요...", lines=4, value="오늘 날씨가 정말 [MASK]네요." ) predict_btn = gr.Button("🎯 예측하기", variant="primary") gr.Markdown("### 📝 예시") examples = [ "오늘 날씨가 정말 [MASK]네요.", "이 영화는 [MASK] 재미있어요.", "한국의 수도는 [MASK]입니다." ] for example in examples: btn = gr.Button(example, size="sm") btn.click(lambda x=example: x, outputs=text_input) with gr.Column(): output = gr.Markdown("[MASK] 토큰을 포함한 텍스트를 입력하고 예측 버튼을 클릭하세요.") predict_btn.click( fn=predict_mask, inputs=text_input, outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 빈칸 채우기 (Fill Mask) - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def generate_token_classification_demo(model_name, title, description): """개체명 인식 데모 코드 생성""" return f'''import gradio as gr from transformers import pipeline # 모델 로드 ner_pipeline = pipeline("token-classification", model="{model_name}", aggregation_strategy="simple") def recognize_entities(text): """개체명 인식 수행""" if not text.strip(): return "텍스트를 입력해주세요." try: results = ner_pipeline(text) if not results: return "인식된 개체가 없습니다." output = f"## 🏷️ 개체명 인식 결과\\n\\n**원문**: {text}\\n\\n### 인식된 개체들:\\n" for i, entity in enumerate(results): word = entity['word'] label = entity['entity_group'] score = entity['score'] start = entity['start'] end = entity['end'] confidence = f"{score:.1%}" output += f"**{i+1}. {word}** → *{label}* ({confidence})\\n" output += f" 위치: {start}-{end}\\n\\n" return output except Exception as e: return f"❌ 오류가 발생했습니다: {{str(e)}}" # Gradio 인터페이스 with gr.Blocks(title="{title}", theme=gr.themes.Soft()) as demo: gr.Markdown("# {title}") gr.Markdown("{description}") with gr.Row(): with gr.Column(): text_input = gr.Textbox( label="🏷️ 개체명 인식할 텍스트", placeholder="사람명, 지명, 기관명 등이 포함된 텍스트를 입력하세요...", lines=5, value="삼성전자의 이재용 회장이 서울에서 기자회견을 열었다." ) ner_btn = gr.Button("🏷️ 개체명 인식", variant="primary") with gr.Column(): output = gr.Markdown("텍스트를 입력하고 인식 버튼을 클릭하세요.") ner_btn.click( fn=recognize_entities, inputs=text_input, outputs=output ) gr.Markdown(f""" ### ℹ️ 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: 개체명 인식 (Named Entity Recognition) - **설명**: {description} """) if __name__ == "__main__": demo.launch()''' def create_demo_package(app_code, pipeline_tag, model_name, demo_title, demo_description): """완전한 데모 패키지 생성""" if not app_code: return "먼저 데모 코드를 생성해주세요.", None try: # 임시 디렉토리 생성 temp_dir = tempfile.mkdtemp() demo_dir = os.path.join(temp_dir, demo_title.lower().replace(' ', '-')) os.makedirs(demo_dir, exist_ok=True) # 1. app.py 저장 with open(os.path.join(demo_dir, "app.py"), 'w', encoding='utf-8') as f: f.write(app_code) # 2. requirements.txt 생성 requirements = """gradio transformers torch """ with open(os.path.join(demo_dir, "requirements.txt"), 'w', encoding='utf-8') as f: f.write(requirements) # 3. README.md 생성 space_name = demo_title.lower().replace(' ', '-') readme_content = f"""--- title: {demo_title} emoji: 🤖 colorFrom: blue colorTo: purple sdk: gradio sdk_version: 5.31.0 app_file: app.py pinned: false models: - {model_name} --- # {demo_title} {demo_description} ## 🚀 사용법 이 데모는 [{model_name}](https://huggingface.co/{model_name}) 모델을 사용합니다. ### 태스크: {pipeline_tag} {get_task_description(pipeline_tag)} ## 🛠️ 로컬 실행 ```bash pip install -r requirements.txt python app.py ``` ## 📝 모델 정보 - **모델**: [{model_name}](https://huggingface.co/{model_name}) - **태스크**: {pipeline_tag} - **라이브러리**: transformers --- *이 데모는 [Demo Generator](https://huggingface.co/spaces/your-username/demo-generator)로 자동 생성되었습니다.* """ with open(os.path.join(demo_dir, "README.md"), 'w', encoding='utf-8') as f: f.write(readme_content) # 4. ZIP 파일 생성 zip_path = os.path.join(temp_dir, f"{space_name}_demo.zip") with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: for root, dirs, files in os.walk(demo_dir): for file in files: file_path = os.path.join(root, file) arcname = os.path.relpath(file_path, demo_dir) zipf.write(file_path, arcname) success_msg = f""" ## ✅ 데모 생성 완료! **{demo_title}** 데모가 성공적으로 생성되었습니다! ### 📦 포함된 파일들: - `app.py`: 메인 데모 애플리케이션 - `requirements.txt`: 필요한 라이브러리 목록 - `README.md`: Space 설명 및 설정 ### 🚀 배포 방법: 1. 아래 ZIP 파일을 다운로드하세요 2. 허깅페이스에서 새 Space를 생성하세요 3. 파일들을 업로드하거나 Git으로 push하세요 4. 자동으로 빌드되고 배포됩니다! ### 🎯 태스크: {pipeline_tag} ### 🤖 모델: {model_name} """ return success_msg, zip_path except Exception as e: return f"❌ 패키지 생성 중 오류가 발생했습니다: {str(e)}", None def get_task_description(pipeline_tag): """태스크별 설명 반환""" descriptions = { 'text-classification': '텍스트를 입력하면 카테고리별로 분류합니다. 감정분석, 주제분류 등에 사용됩니다.', 'question-answering': '컨텍스트와 질문을 입력하면 답변을 찾아줍니다.', 'text-generation': '주어진 프롬프트를 이어서 텍스트를 생성합니다.', 'summarization': '긴 텍스트를 요약해줍니다.', 'translation': '텍스트를 다른 언어로 번역합니다.', 'fill-mask': '[MASK] 토큰이 포함된 문장에서 빈칸을 채워줍니다.', 'token-classification': '텍스트에서 사람명, 지명, 기관명 등의 개체를 인식합니다.' } return descriptions.get(pipeline_tag, '다양한 NLP 태스크를 수행합니다.') # Gradio 인터페이스 with gr.Blocks(title="🎮 Demo Generator", theme=gr.themes.Soft()) as demo: # 상태 저장용 model_info_state = gr.State() demo_possible_state = gr.State() gr.Markdown("# 🎮 Hugging Face Demo Generator") gr.Markdown("모델명만 입력하면 바로 작동하는 데모 Space를 자동으로 생성해드립니다!") with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 🔍 모델 분석") model_name_input = gr.Textbox( label="모델명", placeholder="예: klue/bert-base", info="Hugging Face Hub의 정확한 모델명을 입력하세요" ) analyze_btn = gr.Button("🔍 모델 분석", variant="primary") gr.Markdown("### ⚙️ 데모 설정") demo_title = gr.Textbox( label="데모 제목", placeholder="예: Korean BERT Sentiment Demo", value="" ) demo_description = gr.Textbox( label="데모 설명", placeholder="예: 한국어 감정 분석을 위한 BERT 모델 데모", lines=3 ) generate_btn = gr.Button("🎮 데모 생성", variant="secondary") create_package_btn = gr.Button("📦 완전한 패키지 생성", variant="secondary") with gr.Column(scale=2): gr.Markdown("### 📊 분석 결과") analysis_output = gr.Markdown("모델명을 입력하고 분석 버튼을 클릭하세요.") gr.Markdown("### 💻 생성된 데모 코드") code_output = gr.Code(language="python", label="app.py") gr.Markdown("### 📦 다운로드") download_file = gr.File(label="완전한 데모 패키지", visible=False) # 이벤트 핸들러 def analyze_and_store(model_name): analysis, info, possible = analyze_model(model_name) return analysis, info, possible def generate_and_show_code(info, model_name, title, description): if not info: return "먼저 모델을 분석해주세요." code, task = generate_demo_code(info, model_name, title, description) return code def create_package_and_download(info, model_name, title, description, code): if not info or not code: return "먼저 데모 코드를 생성해주세요.", None pipeline_tag = getattr(info, 'pipeline_tag', 'unknown') result, zip_path = create_demo_package(code, pipeline_tag, model_name, title, description) if zip_path: return result, gr.File(value=zip_path, visible=True) else: return result, None analyze_btn.click( fn=analyze_and_store, inputs=model_name_input, outputs=[analysis_output, model_info_state, demo_possible_state] ) generate_btn.click( fn=generate_and_show_code, inputs=[model_info_state, model_name_input, demo_title, demo_description], outputs=code_output ) create_package_btn.click( fn=create_package_and_download, inputs=[model_info_state, model_name_input, demo_title, demo_description, code_output], outputs=[analysis_output, download_file] ) gr.Markdown(""" ### 💡 사용법 가이드 #### 1️⃣ 모델 분석 - Hugging Face Hub의 정확한 모델명 입력 (예: `klue/bert-base`) - 모델의 태스크와 호환성 자동 확인 #### 2️⃣ 데모 설정 - **제목**: Space에서 보여질 데모 제목 - **설명**: 데모의 용도와 기능 설명 #### 3️⃣ 코드 생성 - 태스크에 맞는 최적화된 Gradio 인터페이스 자동 생성 - 바로 복사해서 사용 가능한 완전한 코드 #### 4️⃣ 패키지 다운로드 - `app.py`, `requirements.txt`, `README.md` 포함 - ZIP 다운로드 후 바로 Space에 업로드 가능 ### 🎯 지원하는 태스크 - **텍스트 분류**: 감정분석, 주제분류, 언어감지 등 - **질의응답**: 문서 기반 QA 시스템 - **텍스트 생성**: 언어모델 기반 텍스트 완성 - **요약**: 긴 텍스트의 핵심 요약 - **번역**: 언어 간 번역 - **빈칸 채우기**: BERT 스타일 마스크 예측 - **개체명 인식**: 사람명, 지명, 기관명 등 추출 ### 🔗 워크플로우 연계 이 도구는 다른 도구들과 완벽하게 연계됩니다: 1. **[Model Search Tool](https://huggingface.co/spaces/your-username/model-search-tool)**: 최적 모델 검색 2. **[Dataset Converter](https://huggingface.co/spaces/your-username/dataset-converter)**: 데이터 준비 3. **Demo Generator**: 데모 생성 ← *현재 도구* 4. **[Model Card Generator](https://huggingface.co/spaces/your-username/model-card-generator)**: 문서화 """) if __name__ == "__main__": demo.launch()