# 底层提交：逐步理解上传、准备与确认

本页面向需要管理文件上传、展示报价或集成平台工作流的开发者，逐步介绍底层公开接口。日常使用可选择 prepare_submission / prepared.confirm；Qiskit 和 PennyLane 用户可使用各自插件。

## 高层已经替你做了哪些工作

| 阶段 | 底层方法 | 返回对象 |
| --- | --- | --- |
| 上传 | upload_job_input | 上传 ID 字符串 |
| 准备 | prepare_job(JobPreparationCreate(...)) | JobPreparationResponse，包含准备 ID |
| 查询准备状态和报价 | get_preparation_result | JobPreparationResultResponse，包含 quote 列表 |
| 确认执行 | create_job(JobCreate(...)) | JobRead 或 SubmissionReceipt |
| 等待并读取 | wait_for_submission + download_job_result | JobRead + UnifiedResult |

高层准备对象会自动传递报价标识、钱包和真机确认信息。使用底层接口时，将这些值依次填入 JobPreparationCreate 和 JobCreate。

## 1. 设置客户端和输入

先按认证页设置平台凭据、组织 ID 和设备 short_code。下面使用逻辑 Bell 程序；需要固定物理布局时，可参考编译与物理布局章节。

```python
import os
from quantum_source_sdk import (
    SchedulerClient, JobPreparationCreate, JobCreate, poll_for_status,
)

scheduler = SchedulerClient(base_url=os.environ["QUANTUM_SOURCE_API_URL"])
organization_id = os.environ["QUANTUM_SOURCE_ORGANIZATION_ID"]
backend_code = os.environ["QUANTUM_SOURCE_BACKEND"]
details = scheduler.get_backend_class(backend_code)
qasm = b'''OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q -> c;
'''
```

## 2. 上传程序

```python
upload_id = scheduler.upload_job_input(file_content=qasm)
print(upload_id)
```

upload_job_input 返回上传记录的 ID。file_content 使用 bytes；普通字符串通过 encode("utf-8") 转成字节。已有文件时，可改用 file_path="bell.qasm"。

## 3. 请求准备

```python
preparation = scheduler.prepare_job(JobPreparationCreate(
    organization_id=organization_id,
    backend_class_id=details.id,
    name="low-level-bell",
    upload_endpoint_id=upload_id,
    job_subcategory_id="oth:oth",
    shots=128,
    input_format="openqasm2",
    configuration_data={"circuit_representation": "logical"},
    currency=scheduler.currency,
))
submission_id = preparation.id
print(submission_id)
```

JobPreparationCreate 包含上传 ID、任务分类、线路配置和钱包等准备信息。currency=scheduler.currency 使用当前客户端选择的钱包，执行方案和队列使用 public/stand 默认值。

## 4. 等待准备结果

get_preparation_result 查询一次准备状态。用 poll_for_status 持续查询时，回调返回 (是否结束, 当前结果)，准备成功或失败后结束等待。

```python
def read_preparation(preparation_id):
    value = scheduler.get_preparation_result(preparation_id)
    done = value.status.casefold() in {"completed", "failed"}
    return done, value

preparation_result = poll_for_status(
    read_preparation, submission_id, interval=2, timeout=300,
)
if preparation_result.status.casefold() != "completed":
    raise RuntimeError("Preparation failed; no task was confirmed.")
print(preparation_result.shots)
```

poll_for_status 默认每 5 秒查询一次，等待上限为 300 秒；本例将查询间隔设为 2 秒。等待超时后，可用同一个 submission_id 继续查询准备进度。

## 5. 选择并展示当前报价

当前平台使用 public + stand。下面从准备响应中选取与客户端钱包一致的方案，并读取对应的队列优先级。确认时使用这份响应中的方案 ID、队列 ID 和报价标识。

```python
plan = next(
    item for item in preparation_result.quote
    if item.name.casefold() == "public" and item.currency == scheduler.currency
)
priority = next(
    item for item in plan.queue_priorities
    if item.name.casefold() == "stand"
)
from quantum_source_sdk import PreparedSubmission

# 将准备结果整理为便于展示的报价摘要。
quoted = PreparedSubmission(preparation_result, plan, priority)
print(quoted.quote)
```

quoted.quote 展示任务数、shots、币种、精确金额和有效期。本例用 quoted 展示报价，在下一步通过 create_job 确认执行。

## 6. 接受报价后，才运行这个单元格

接受上面显示的设备、线路、shots 和费用后，运行本单元提交实验；真机实验会使用设备资源。JobCreate.confirm_hardware 根据目标设备的 is_hardware 设置，报价 ID 和摘要使用上一步取得的值。

```python
receipt_or_job = scheduler.create_job(JobCreate(
    job_preparation_id=submission_id,
    execution_plan_id=plan.execution_plan_id,
    queue_priority_id=priority.queue_priority_id,
    organization_id=organization_id,
    accepted_quote_id=plan.quote_id,
    accepted_quote_hash=plan.quote_hash,
    confirm_hardware=details.is_hardware is True,
))
```

create_job 返回提交回执或 JobRead 任务记录，下一步等待计算结果。若网络超时或提示发送结果待核实，用保存的 submission_id 查询这次提交。

## 7. 沿原提交读取结果

```python
job = scheduler.wait_for_submission(submission_id, timeout_seconds=300)
result = scheduler.download_job_result(job)
print(result.result_kind)
print(result.primary_value)
```

这个等待覆盖平台发送和设备计算阶段。超时后可再次查询同一个 submission_id；只查看一次当前进度时，使用 scheduler.get_submission(submission_id)。

## 可选：发现任务分类

oth:oth 是默认的“其他”分类。需要更细的实验分类时，先读取分类目录，再将选定条目的 ID 填入任务配置。

```python
category_page = scheduler.get_job_categories(limit=20)
for category in category_page.categories:
    print(category.id, category.name)
```

选定 category.id 后，可调用 get_job_subcategories(category_id, limit=20)；两个返回对象都在 .categories 中放条目，在 .pagination.next_cursor 中放下一页位置。

## API 参考与相关章节

上传、准备、报价查询、任务创建及其协议模型的签名与字段，统一在底层协议 API 参考中查阅。

- [底层协议 API](api.html#protocol)
- [接口实现与测试依据](api.html#evidence)

- [更简洁的 Core 入门](core.html)
- [任务提交与报价](job-submission.html)
- [查询、分页与下载](job-query.html)
- [编译与物理布局](compilation.html)

## 下载本页 Jupyter Notebook

收录本页 Python 示例与说明，便于在 Jupyter Notebook 中学习和运行；安装命令保留为说明。

[下载《底层提交协议》Notebook（.ipynb）](../../notebooks/sdk_user_guide_low_level.ipynb)
