# Space 관리

이 가이드에서는 `huggingface_hub`를 사용하여 Space 런타임([secrets](https://huggingface.co/docs/hub/spaces-overview#managing-secrets), [hardware](https://huggingface.co/docs/hub/spaces-gpus), 볼륨)을 관리하는 방법을 알아봅니다.

## Spaces 검색

Hub에서 [search_spaces()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.search_spaces)를 사용하여 의미론적 검색으로 Spaces를 검색할 수 있습니다. 이 기능은 다중 단어 쿼리에 임베딩 기반 검색을, 단일 단어 쿼리에 전체 텍스트 검색을 사용합니다.

```py
>>> from huggingface_hub import search_spaces
>>> results = list(search_spaces("generate image"))
>>> results[0]
SpaceSearchResult(id='mrfakename/Z-Image-Turbo', title='Z Image Turbo', sdk='gradio', likes=2867, ...)
```

SDK 또는 태그로 결과를 필터링할 수 있습니다:

```py
>>> results = search_spaces("chatbot", sdk="gradio", filter="mcp-server")
```

또는 CLI를 통해:

```bash
>>> hf spaces search "generate image"
>>> hf spaces search "chatbot" --sdk gradio --limit 5
```

## 간단한 예시: 시크릿과 하드웨어 구성

Hub에서 Space를 생성하고 설정하는 끝에서 끝까지의 예제를 보여 드리겠습니다.

### Hub에서 Space 만들기

```py
>>> from huggingface_hub import HfApi
>>> repo_id = "Wauplin/my-cool-training-space"
>>> api = HfApi()

# For example with a Gradio SDK
>>> api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="gradio")
```

> [!TIP]
> Static Spaces는 모든 사용자에게 무료입니다. Gradio 및 Docker Spaces는 컴퓨트에서 실행되며, 무료 `cpu-basic` 하드웨어의 경우 구독이 필요합니다(사용자는 PRO, 조직은 Team 또는 Enterprise). 유료 하드웨어의 경우 결제만 필요합니다(결제 수단 및 선불 크레딧). 구독이 없는 상태에서 `cpu-basic`에서 Gradio 또는 Docker Space를 생성, 복제 또는 이동하면 결제 오류(HTTP 402)가 발생합니다. 자세한 내용은 [pricing](https://huggingface.co/pricing)을 참조하세요.

### Space를 템플릿에서 생성

빈 Space에서 시작하는 대신, Hub에서 제공하는 공식 템플릿(예: JupyterLab, Gradio 챗봇, Streamlit 앱 등) 중 하나를 기반으로 새로운 Space를 생성할 수 있습니다. [list_space_templates()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.list_space_templates)를 사용하여 사용 가능한 템플릿 목록을 확인한 후, 템플릿의 `repo_id`(또는 짧은 `name`)을 [create_repo()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.create_repo)의 `space_template`으로 전달합니다. `space_sdk`는 여전히 필요합니다. 템플릿은 파일을 초기화하고, SDK는 카드 메타데이터를 설정하기 때문입니다.

```py
>>> from huggingface_hub import HfApi
>>> api = HfApi()

# List available templates
>>> for template in api.list_space_templates():
...     print(f"{template.name} ({template.repo_id})")
Streamlit (streamlit/streamlit-template-space)
JupyterLab (SpacesExamples/jupyterlab)
chatbot (gradio-templates/chatbot)
...

# Create a Space from a template, by repo id or by short name
>>> api.create_repo(repo_id=repo_id, repo_type="space", space_template="SpacesExamples/jupyterlab")
>>> api.create_repo(repo_id=repo_id, repo_type="space", space_template="JupyterLab")
```

일부 템플릿은 비공개로 생성하는 것이 권장됩니다(예: JupyterLab). 가시성을 명시적으로 설정하지 않으면, 이러한 Spaces는 자동으로 비공개로 생성됩니다.

CLI에서는 `hf spaces templates`와 `hf repos create --template`를 통해 동일한 기능을 사용할 수 있습니다:

```bash
# List available templates
>>> hf spaces templates
NAME            REPO_ID                                        SDK    PREFERRED_PRIVATE
--------------- ---------------------------------------------- ------ -----------------
Streamlit       streamlit/streamlit-template-space             docker
JupyterLab      SpacesExamples/jupyterlab                      docker ✔
Argilla         argilla/argilla-template-space                 docker
Livebook        livebook-dev/livebook                          docker
...

# Create a Space from a template
>>> hf repos create my-jupyterlab --type space --template jupyterlab
```

### Space 복제

기존 Space를 기반으로 구축하고 싶거나 처음부터 시작하고 싶지 않은 경우 유용할 수 있습니다. 또한 공개 Space의 구성/설정을 직접 제어하고 싶을 때에도 유용합니다. 자세한 내용은 [duplicate_repo()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.duplicate_repo)를 참조하세요.

```py
>>> api.duplicate_repo("multimodalart/dreambooth-training", repo_type="space")
```

### 원하는 솔루션을 사용하여 코드를 업로드하세요

로컬 폴더 `src/`를 컴퓨터에서 Space로 업로드하는 예시입니다:

```py
>>> api.upload_folder(repo_id=repo_id, repo_type="space", folder_path="src/")
```

이 단계에서 앱은 이미 Hub에서 실행 중이어야 합니다. 하지만 secrets와 업그레이드된 하드웨어를 구성하여 앱을 추가로 설정할 수 있습니다.

### 시크릿과 변수 구성

Space에는 작동에 필요한 비밀 키, 토큰 또는 변수가 필요할 수 있습니다. 자세한 내용은 [문서](https://huggingface.co/docs/hub/spaces-overview#managing-secrets)를 참고하세요. 예를 들어, Space에서 생성된 이미지 데이터셋을 Hub에 업로드하기 위한 HF 토큰 등이 있습니다.

```py
>>> api.add_space_secret(repo_id=repo_id, key="HF_TOKEN", value="hf_api_***")
>>> api.add_space_variable(repo_id=repo_id, key="MODEL_REPO_ID", value="user/repo")
```

기존 secrets와 variables를 나열할 수 있습니다. Secret 값은 쓰기 전용이므로 키, 설명, 업데이트 타임스탬프만 반환됩니다:

```py
>>> api.get_space_secrets(repo_id=repo_id)
{'HF_TOKEN': SpaceSecret(key='HF_TOKEN', description=None, updated_at=datetime.datetime(...))}
>>> api.get_space_variables(repo_id=repo_id)
{'MODEL_REPO_ID': SpaceVariable(key='MODEL_REPO_ID', value='user/repo', description=None, updated_at=...)}
```

Secrets와 변수도 삭제할 수 있습니다:
```py
>>> api.delete_space_secret(repo_id=repo_id, key="HF_TOKEN")
>>> api.delete_space_variable(repo_id=repo_id, key="MODEL_REPO_ID")
```

> [!TIP]
> Space 내부에서 secrets는 환경 변수(또는 Streamlit을 사용하는 경우 Streamlit Secrets Management)로 사용할 수 있습니다. API를 통해 가져올 필요가 없습니다!

> [!WARNING]
> Space 구성(시크릿 또는 하드웨어)의 변경 사항은 앱 재시작을 트리거합니다.

**보너스: Space를 생성하거나 복제할 때 secrets와 variables를 설정하세요!**

Secrets와 변수는 space를 생성하거나 복제할 때 설정할 수 있습니다:

```py
>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio",
...     space_secrets=[{"key": "HF_TOKEN", "value": "hf_api_***"}, ...],
...     space_variables=[{"key": "MODEL_REPO_ID", "value": "user/repo"}, ...],
... )
```

```py
>>> api.duplicate_repo(
...     from_id=repo_id,
...     repo_type="space",
...     space_secrets=[{"key": "HF_TOKEN", "value": "hf_api_***"}, ...],
...     space_variables=[{"key": "MODEL_REPO_ID", "value": "user/repo"}, ...],
... )
```

### 하드웨어 구성

기본적으로 Space는 무료 `cpu-basic` 하드웨어에서 실행됩니다(Gradio 및 Docker Space의 경우 구독이 필요하며, 위 내용을 참조하세요). GPU에서 실행하려면 하드웨어를 업그레이드할 수 있습니다. Space 업그레이드를 위해 결제 수단과 선불 크레딧(또는 커뮤니티 보조금)이 필요합니다. 자세한 내용은 [문서](https://huggingface.co/docs/hub/spaces-gpus)를 참조하세요.

```py
# Use `SpaceHardware` enum
>>> from huggingface_hub import SpaceHardware
>>> api.request_space_hardware(repo_id=repo_id, hardware=SpaceHardware.T4_MEDIUM)

# Or simply pass a string value
>>> api.request_space_hardware(repo_id=repo_id, hardware="t4-medium")
```

하드웨어 업데이트는 즉시 수행되지 않으며, Space가 서버에서 다시 로드되어야 합니다. 언제든지 Space가 어떤 하드웨어에서 실행 중인지 확인하여 요청이 처리되었는지 살펴볼 수 있습니다.

```py
>>> runtime = api.get_space_runtime(repo_id=repo_id)
>>> runtime.stage
"RUNNING_BUILDING"
>>> runtime.hardware
"cpu-basic"
>>> runtime.requested_hardware
"t4-medium"
```

이제 완전히 구성된 Space를 갖추셨습니다. 사용을 마친 후에는 Space를 `cpu-basic`으로 다시 하향 조정하는 것을 잊지 마세요.

**보너스: Space를 생성하거나 복제할 때 하드웨어를 요청하세요!**

Space가 빌드되면 업그레이드된 하드웨어가 자동으로 할당됩니다.

```py
>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio",
...     space_hardware="cpu-upgrade",
...     space_sleep_time="7200", # 2 hours in secs
... )
```
```py
>>> api.duplicate_repo(
...     from_id=repo_id,
...     repo_type="space",
...     space_hardware="cpu-upgrade",
...     space_sleep_time="7200", # 2 hours in secs
... )
```

### ZeroGPU 할당량 추적

[ZeroGPU](https://huggingface.co/docs/hub/spaces-zerogpu) Spaces는 온디맨드로 할당되는 공유 GPU에서 실행됩니다. ZeroGPU Space를 UI 또는 API를 통해 사용할 때마다 개인 할당량에서 GPU 사용 시간이 차감되며, 이 할당량은 주기적으로 초기화됩니다. ZeroGPU Spaces를 기반으로 앱, 에이전트 또는 MCP 서버를 구축하고 있다면 [get_zero_gpu_quota()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.get_zero_gpu_quota)를 사용하여 사용량을 추적할 수 있습니다. 값은 GPU-초 단위로 표시됩니다.

```py
>>> quota = api.get_zero_gpu_quota()
>>> quota
ZeroGpuQuota(base=2400, remaining=1810, resets_at=datetime.datetime(2026, 9, 30, 9, 12, 3, tzinfo=datetime.timezone.utc), overquota_used=0)
>>> if quota.remaining < 60:
...     print(f"Less than 1 minute of ZeroGPU left. Quota resets at {quota.resets_at}.")
```

`resets_at`은 마지막 리셋 이후 ZeroGPU를 사용하지 않은 경우 `None`입니다. 세밀한 권한을 가진 토큰을 사용하는 경우, "Billing > Read billing usage and payment method status" 권한이 있어야 합니다. 동일한 정보는 CLI에서 `hf spaces zero-gpu quota`를 통해 확인할 수 있습니다.

할당이 소진되면 PRO, Team 및 Enterprise 사용자는 선불 크레딧을 소모하여 ZeroGPU Spaces를 계속 사용할 수 있습니다. 크레딧은 [billing settings](https://huggingface.co/settings/billing?add-credits=true)에서 구매할 수 있습니다. 자세한 내용은 [Extending quota with credits](https://huggingface.co/docs/hub/spaces-zerogpu#extending-quota-with-credits)을 참조하세요.

### Space 일시 중지 및 재시작

기본적으로 Space가 업그레이드된 하드웨어에서 실행 중이면 절대 중지되지 않습니다. 그러나 요금이 청구되는 것을 피하려면 사용하지 않을 때 일시중지하는 것이 좋습니다. [pause_space()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.pause_space)를 사용하면 가능합니다. 일시중지된 Space는 Space 소유자가 UI를 통해 또는 [restart_space()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.restart_space)를 사용하여 API를 통해 다시 시작할 때까지 비활성 상태가 유지됩니다. 일시중지 모드에 대한 자세한 내용은 [이 섹션](https://huggingface.co/docs/hub/spaces-gpus#pause)을 참조하세요.

```py
# Pause your Space to avoid getting billed
>>> api.pause_space(repo_id=repo_id)
# (...)
# Restart it when you need it
>>> api.restart_space(repo_id=repo_id)
```

다른 방법으로는 Space에 타임아웃을 설정하는 것입니다. Space가 타임아웃 기간보다 오래 비활성 상태면 수면 모드로 전환됩니다. Space에 방문하는 사용자는 Space를 다시 시작합니다. [set_space_sleep_time()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.set_space_sleep_time)을 사용하여 타임아웃을 설정할 수 있습니다. 수면 모드에 대한 자세한 내용은 [이 섹션](https://huggingface.co/docs/hub/spaces-gpus#sleep-time)을 참고하세요.

```py
# Put your Space to sleep after 1h of inactivity
>>> api.set_space_sleep_time(repo_id=repo_id, sleep_time=3600)
```

Note: 'cpu-basic' 하드웨어를 사용하는 경우 커스텀 sleep 시간을 설정할 수 없습니다. Space는 48시간 동안 비활성 상태가 되면 자동으로 일시중지됩니다.

**보너스: 하드웨어 요청 시 수면 시간 설정**

Space가 빌드되면 업그레이드된 하드웨어가 자동으로 할당됩니다.

```py
>>> api.request_space_hardware(repo_id=repo_id, hardware=SpaceHardware.T4_MEDIUM, sleep_time=3600)
```

**보너스: Space를 생성하거나 복제할 때 수면 시간을 설정하세요!**

```py
>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio",
...     space_hardware="t4-medium",
...     space_sleep_time="3600",
... )
```
```py
>>> api.duplicate_repo(
...     from_id=repo_id,
...     repo_type="space",
...     space_hardware="t4-medium",
...     space_sleep_time="3600",
... )
```

### 로그를 읽어서 실패한 Space 디버깅

Space의 빌드가 실패하거나 런타임에 충돌이 발생하면, 브라우저에서 확인하는 로그를 [fetch_space_logs()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.fetch_space_logs)를 통해 프로그래매틱으로도 조회할 수 있습니다. 이는 브라우저 열기가 불가능한 스크립트나 에이전틱 워크플로에서 특히 유용합니다.

```py
# Drain the currently available run logs and return immediately (like `docker logs`)
>>> for line in api.fetch_space_logs(repo_id=repo_id):
...     print(line, end="")

# Read the container build logs instead (useful when the Space is stuck in BUILD_ERROR)
>>> for line in api.fetch_space_logs(repo_id=repo_id, build=True):
...     print(line, end="")

# Stream run logs in real time until the server closes the stream (Ctrl-C to stop)
>>> for line in api.fetch_space_logs(repo_id=repo_id, follow=True):
...     print(line, end="")
```

CLI에서도 동일한 기능을 사용할 수 있습니다:

```bash
hf spaces logs username/my-space             # drain run logs
hf spaces logs username/my-space --build     # read build logs
hf spaces logs username/my-space -f          # stream in real time
hf spaces logs username/my-space -n 50       # last 50 lines only
```

### Space에 SSH 접속(개발 모드)

[Dev Mode](https://huggingface.co/docs/hub/spaces-dev-mode)는 실행 중인 Space 컨테이너에 SSH로 접속하여 실시간 디버깅 및 개발을 수행할 수 있도록 합니다. 터미널에서 세션을 바로 열려면 `hf spaces ssh`를 사용하세요. Space에서 Dev Mode가 아직 활성화되지 않은 경우, CLI가 활성화하도록 프롬프트를 표시합니다(`--auto`를 전달하면 프롬프트를 건너뜁니다).

SSH 공개 키는 [설정](https://huggingface.co/settings/keys)에 등록되어 있어야 합니다.

```bash
# SSH into a Space (enables Dev Mode if needed)
hf spaces ssh username/my-space

# Auto-enable Dev Mode without prompting
hf spaces ssh username/my-space --auto

# Print the SSH command without running it
hf spaces ssh username/my-space --dry-run

# Use a specific SSH key
hf spaces ssh username/my-space -i ~/.ssh/id_ed25519
```

SSH 없이 `hf spaces dev-mode`를 사용하여 Dev Mode를 활성화할 수도 있습니다. 이 명령은 SSH, VS Code, Cursor, Windsurf에 대한 연결 지침을 출력합니다:

```bash
hf spaces dev-mode username/my-space
```

Dev Mode를 활성화하려면 PRO 또는 Team & Enterprise 플랜이 필요합니다. Dev Mode가 켜진 상태에서 구독이 만료된 경우와 같이 비활성화는 항상 허용됩니다:

```bash
hf spaces dev-mode username/my-space --stop
```

### Space에 볼륨 마운트

Hub 리소스(모델, 데이터셋, 스토리지 버킷)를 Space 컨테이너의 볼륨으로 마운트할 수 있습니다. 이를 통해 코드로 리소스를 다운로드할 필요 없이 Space에서 해당 리소스에 직접 파일시스템으로 접근할 수 있습니다. Space를 생성하거나 복제할 때 볼륨을 직접 설정할 수 있습니다:

```py
>>> from huggingface_hub import Volume
>>> api.create_repo(
...     repo_id=repo_id,
...     repo_type="space",
...     space_sdk="gradio",
...     space_volumes=[
...         Volume(type="model", source="username/my-model", mount_path="/models", read_only=True),
...         Volume(type="bucket", source="username/my-bucket", mount_path="/data"),
...     ],
... )
```
```py
>>> api.duplicate_repo(
...     from_id=repo_id,
...     repo_type="space",
...     space_volumes=[
...         Volume(type="model", source="username/my-model", mount_path="/models", read_only=True),
...         Volume(type="bucket", source="username/my-bucket", mount_path="/data"),
...     ],
... )
```

Space 런타임을 통해 현재 마운트된 볼륨을 확인할 수 있습니다:

```py
>>> runtime = api.get_space_runtime(repo_id=repo_id)
>>> runtime.volumes
[Volume(type='model', source='username/my-model', mount_path='/models', read_only=True), ...]
```

기존 Space의 볼륨을 업데이트해야 하는 경우 [set_space_volumes()](/docs/huggingface_hub/v2.4.0/ko/package_reference/hf_api#huggingface_hub.HfApi.set_space_volumes)를 사용하세요. 이전에 마운트된 모든 볼륨이 대체됩니다.

```py
>>> api.set_space_volumes(
...     repo_id=repo_id,
...     volumes=[
...         Volume(type="model", source="username/my-model", mount_path="/models", read_only=True),
...         Volume(type="dataset", source="username/my-dataset", mount_path="/data", read_only=True),
...         Volume(type="bucket", source="username/my-bucket", mount_path="/output"),
...     ],
... )
```

Space에서 모든 볼륨을 제거하려면:

```py
>>> api.delete_space_volumes(repo_id=repo_id)
```

> [!NOTE]
> 모델, 데이터셋, Spaces는 항상 읽기 전용으로 마운트됩니다. 읽기-쓰기 마운트는 스토리지 버킷에서만 지원합니다.

> [!WARNING]
> 볼륨을 설정하면 이전에 마운트된 볼륨이 대체됩니다. 기존 목록에 볼륨을 추가하려면 먼저 런타임에서 현재 볼륨을 읽고 새 목록에 포함해야 합니다.

모든 볼륨 작업은 CLI에서도 사용할 수 있습니다:

```bash
# List current volumes
hf spaces volumes ls username/my-space

# Set (replace) volumes
hf spaces volumes set username/my-space \
    -v hf://models/username/my-model:/models \
    -v hf://buckets/username/my-bucket:/data

# Remove all volumes
hf spaces volumes delete username/my-space
```

## 더 고급: Space를 일시적으로 업그레이드하세요!

Spaces는 다양한 사용 사례를 지원합니다. 때로는 특정 하드웨어에서 Space를 일시적으로 실행하여 작업을 수행한 후 종료하고 싶을 수 있습니다. 이 섹션에서는 온디맨드로 모델을 파인튜닝하기 위해 Spaces를 활용하는 방법을 살펴봅니다. 이는 해당 특정 문제를 해결하는 방법 중 하나일 뿐입니다. 따라서 제안 사항으로 받아들이고 사용 사례에 맞게 조정해야 합니다.

모델을 fine-tuning하기 위한 Space가 있다고 가정해 보겠습니다. 이 Space는 Gradio 앱으로, 모델 id와 데이터셋 id를 입력으로 받습니다. 워크플로우는 다음과 같습니다:

0. (모델과 데이터셋을 사용자에게 입력하도록 요청합니다)
1. Hub에서 모델을 로드합니다.
2. Hub에서 데이터셋을 로드합니다.
3. 데이터셋으로 모델을 Fine-tune합니다.
4. 새 모델을 Hub에 업로드합니다.

Step 3. requires a custom hardware 하지만 유료 GPU에서 Space가 항상 실행되도록 하지는 않습니다. 해결책은 학습을 위해 하드웨어를 동적으로 요청한 후 이후에 종료하는 것입니다. 하드웨어를 요청하면 Space가 재시작되므로, 앱은 현재 수행 중인 작업을 어떤 방식으로든 "기억"해야 합니다. 이를 수행하는 방법은 여러 가지가 있습니다. 이 가이드에서는 Dataset을 "task scheduler"로 사용하는 하나의 해결책을 살펴보겠습니다.

### 앱 스켈레톤

여기 앱의 모습이 있습니다. 시작 시 태스크가 예약되어 있는지 확인하고, 예약되어 있다면 올바른 하드웨어에서 실행합니다. 완료되면 하드웨어를 `cpu-basic` CPU로 되돌리고 사용자에게 새 태스크를 요청합니다.

> [!WARNING]
> 이러한 워크플로우는 일반적인 데모와 달리 동시 액세스를 지원하지 않습니다. 특히 학습이 진행되는 동안 인터페이스가 비활성화됩니다. 사용자가 본인뿐임을 보장하려면 저장소를 비공개로 설정하는 것이 좋습니다.

```py
# Space will need your token to request hardware: set it as a Secret !
HF_TOKEN = os.environ.get("HF_TOKEN")

# Space own repo_id
TRAINING_SPACE_ID = "Wauplin/dreambooth-training"

from huggingface_hub import HfApi, SpaceHardware
api = HfApi(token=HF_TOKEN)

# On Space startup, check if a task is scheduled. If yes, finetune the model. If not,
# display an interface to request a new task.
task = get_task()
if task is None:
    # Start Gradio app
    def gradio_fn(task):
        # On user request, add task and request hardware
        add_task(task)
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.T4_MEDIUM)

    gr.Interface(fn=gradio_fn, ...).launch()
else:
    runtime = api.get_space_runtime(repo_id=TRAINING_SPACE_ID)
    # Check if Space is loaded with a GPU.
    if runtime.hardware == SpaceHardware.T4_MEDIUM:
        # If yes, finetune base model on dataset !
        train_and_upload(task)

        # Then, mark the task as "DONE"
        mark_as_done(task)

        # DO NOT FORGET: set back CPU hardware
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.CPU_BASIC)
    else:
        api.request_space_hardware(repo_id=TRAINING_SPACE_ID, hardware=SpaceHardware.T4_MEDIUM)
```

### 작업 스케줄러

작업 스케줄링은 다양한 방식으로 수행할 수 있습니다. 다음은 Dataset으로 저장된 간단한 CSV를 사용하여 이를 수행하는 예시입니다.

```py
# Dataset ID in which a `tasks.csv` file contains the tasks to perform.
# Here is a basic example for `tasks.csv` containing inputs (base model and dataset)
# and status (PENDING or DONE).
#     multimodalart/sd-fine-tunable,Wauplin/concept-1,DONE
#     multimodalart/sd-fine-tunable,Wauplin/concept-2,PENDING
TASK_DATASET_ID = "Wauplin/dreambooth-task-scheduler"

def _get_csv_file():
    return hf_hub_download(repo_id=TASK_DATASET_ID, filename="tasks.csv", repo_type="dataset", token=HF_TOKEN)

def get_task():
    with open(_get_csv_file()) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',')
        for row in csv_reader:
            if row[2] == "PENDING":
                return row[0], row[1] # model_id, dataset_id

def add_task(task):
    model_id, dataset_id = task
    with open(_get_csv_file()) as csv_file:
        with open(csv_file, "r") as f:
            tasks = f.read()

    api.upload_file(
        repo_id=repo_id,
        repo_type=repo_type,
        path_in_repo="tasks.csv",
        # Quick and dirty way to add a task
        path_or_fileobj=(tasks + f"\n{model_id},{dataset_id},PENDING").encode()
    )

def mark_as_done(task):
    model_id, dataset_id = task
    with open(_get_csv_file()) as csv_file:
        with open(csv_file, "r") as f:
            tasks = f.read()

    api.upload_file(
        repo_id=repo_id,
        repo_type=repo_type,
        path_in_repo="tasks.csv",
        # Quick and dirty way to set the task as DONE
        path_or_fileobj=tasks.replace(
            f"{model_id},{dataset_id},PENDING",
            f"{model_id},{dataset_id},DONE"
        ).encode()
    )
```

