diff --git a/README.md b/README.md index 532bdb2..0c6fac9 100644 --- a/README.md +++ b/README.md @@ -84,69 +84,230 @@ Performs molecular docking using the AutoDock algorithm. | `receptor` | string | Yes | URL or server-accessible path to the receptor file (e.g., PDB format). | | `center_x`, `center_y`, `center_z` | number/string | Yes | Coordinates for the center of the docking box. | | `size_x`, `size_y`, `size_z` | number | No | Dimensions of the docking box. Defaults to 15 for each axis. | -| `ligand` | string | Yes (one of three) | Path to a single ligand file (SDF, PDB). | +| `ligand` | string | Yes (one of three) | Path to a single ligand file (SDF, PDB, URL) single file size should below `10MB`. | | `ligands` | array of strings | Yes (one of three) | A list of paths to multiple ligand files. | | `smiles` | string | Yes (one of three) | A SMILES string (use `\n` for multiple), or a path to a `.txt` file with SMILES strings (one per line). | | `thread` | integer | No | Number of threads. Default is 1200, min is 1000. | **Note**: You must provide exactly one of `ligand`, `ligands`, or `smiles`. -#### Example: Single Ligand File +#### Required Parameters Examples + +- `receptor`: Receptor local file/URL + - Local file: + ```python + # Local file path + path = '/path/to/file/receptor.pdb' + with open(path, 'r') as f: + content = f.read() + receptor = { + 'content': content, + 'name': 'receptor.pdb' + } + ``` + - URL: + ```python + receptor = 'http://www.receptor.pdb' + ``` + +- `center_x`, `center_y`, `center_z`: Docking box center coordinates (can be selected using the web application's molecular structure viewer) +- `size_x`, `size_y`, `size_z`: Docking box dimensions (default is 15 for all) +- Ligand input (choose one of three): + 1. `ligand`: Single ligand, if it's a local file, use key-value (dictionary) object with required `content` field and optional `name` field for easier result viewing; if it's a URL, can be a direct string. (SDF format file, PDB format file, URL link address) File size should not exceed `10MB` + - Local file: + ```python + # Local disk path + path = '/path/to/file/ligand.sdf' + # Read file content + with open(path, 'r') as f: + content = f.read() + ligand = { + 'content': content, + 'name': 'ligand.sdf' + } + ``` + - URL: + ```python + ligand = 'http://www.ligand.sdf' + ``` + + 2. `ligands`: Multiple ligands (multiple files, SDF format, PDB format, URL link addresses), list object, each file size should not exceed `10MB` + - Local files: + ```python + # Local disk multiple ligand file paths + path1 = '/path/to/file/ligand1.sdf' + path2 = '/path/to/file/ligand2.sdf' + # Read file contents + with open(path1, 'r') as f: + content1 = f.read() + with open(path2, 'r') as f: + content2 = f.read() + ligands = [ + {'name': 'ligand1.sdf', + 'content': content1 }, + {'name': 'ligand2.sdf', + 'content': content2} + ] + ``` + - URLs: + ```python + ligands = ['http://www.ligand1.sdf', + 'http://www.ligand2.sdf'] + ``` -**cURL** -```bash -curl -X POST "https://api.quregenai.com/api/autodock_api/autodock_docking" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer " \ - -d '{ - "job_name": "AutoDock_Single_Ligand_Test", - "receptor": "https://files.rcsb.org/download/7RT3.pdb", - "ligand": "/path/to/your/ligand.sdf", - "center_x": -3.52, - "center_y": 5.57, - "center_z": -26.55, - "size_x": 15, - "size_y": 15, - "size_z": 15 - }' -``` + 3. `smiles`: SMILES mode + - SMILES string, use newline `\n` to separate multiple molecules: + ```python + smiles = 'CCO\ncccccc' + ``` + - File path, a `txt` file containing multiple molecular SMILES strings, one molecule SMILES per line: + ```python + # Local file + path = '/path/to/file/smiles.txt' + with open(path, 'r') as f: + content = f.read() + smiles = { + 'content': content + } + # URL + smiles = 'http://www.smiles.txt' + ``` + +#### Example 1.1: Single Ligand File **Python** ```python import requests -import os -BASE_URL = "https://api.quregenai.com" -API_KEY = os.environ.get("QUREGENAI_API_KEY", "") +# Read local ligand file content, file size should not exceed 10MB +with open('ligand.sdf', 'r') as f: + ligand_content = f.read() -HEADERS = { - 'Content-Type': 'application/json', - 'Authorization': f'Bearer {API_KEY}' +# Construct ligand file object +ligand = { + 'content': ligand_content, + 'name': 'ligand.sdf' } def submit_autodock_single_ligand(): url = f"{BASE_URL}/api/autodock_api/autodock_docking" + data = { "job_name": "AutoDock_Single_Ligand_Test", "receptor": "https://files.rcsb.org/download/7RT3.pdb", - "ligand": "/path/to/your/ligand.sdf", - "center_x": -3.52, - "center_y": 5.57, - "center_z": -26.55 + "ligand": ligand, # Use file object format + # "ligand": "https://www.ligand.sdf" # Or use URL link + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 } response = requests.post(url, headers=HEADERS, json=data) if response.status_code == 200: - print("Job submitted successfully:", response.json()) - return response.json() + result = response.json() + print(f"Task submitted successfully, Task ID: {result.get('task_id')}") + return result else: - print(f"Error: {response.status_code}", response.text) + print(f"Request failed: {response.status_code}, {response.text}") return None -# submit_autodock_single_ligand() +# Call example +result = submit_autodock_single_ligand() ``` +#### Example 1.2: Batch Ligand Docking + +**Python** +```python +# Local disk multiple ligand file paths +path1 = '/path/to/file/ligand1.sdf' +path2 = '/path/to/file/ligand2.sdf' +# Read file contents +with open(path1, 'r') as f: + content1 = f.read() +with open(path2, 'r') as f: + content2 = f.read() +ligands = [ + {'name': 'ligand1.sdf', + 'content': content1 }, + {'name': 'ligand2.sdf', + 'content': content2} +] + +def submit_autodock_multiple_ligands(): + url = f"{BASE_URL}/api/autodock_api/autodock_docking" + + data = { + "job_name": "AutoDock_Multiple_Ligands_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "ligands": ligands, + # "ligands": ['https://www.ligand1.sdf', 'https://www.ligand2.sdf'], # URL link list + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } + + response = requests.post(url, headers=HEADERS, json=data) + + if response.status_code == 200: + result = response.json() + print(f"Batch task submitted successfully, Task ID: {result.get('task_id')}") + return result + else: + print(f"Request failed: {response.status_code}, {response.text}") + return None +``` + +#### Example 1.3: SMILES String Docking + +**Python** +```python +# Local smiles.txt file reading +path = '/path/to/file/smiles.txt' +with open(path, 'r') as f: + content = f.read() +smiles = { + 'content': content +} + +def submit_autodock_smiles(): + url = f"{BASE_URL}/api/autodock_api/autodock_docking" + + data = { + "job_name": "AutoDock_SMILES_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": smiles, # Local smiles file + # "smiles": "CC(=O)CC(c1ccccc1)c1c(O)c2ccccc2oc1=O", # Can also be a molecular smiles string + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } + + response = requests.post(url, headers=HEADERS, json=data) + + if response.status_code == 200: + result = response.json() + print(f"SMILES task submitted successfully, Task ID: {result.get('task_id')}") + return result + else: + print(f"Request failed: {response.status_code}, {response.text}") + return None +``` + + --- ### 2. DiffDock Molecular Docking @@ -171,18 +332,6 @@ Performs molecular docking using the AI-based DiffDock algorithm. #### Example: Protein Sequence and SMILES -**cURL** -```bash -curl -X POST "https://api.quregenai.com/api/diffdock_api/diffdock_docking" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer " \ - -d '{ - "job_name": "DiffDock_Sequence_Test", - "protein": "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN", - "smiles": "CCO" - }' -``` - **Python** ```python import requests @@ -196,20 +345,30 @@ HEADERS = { 'Authorization': f'Bearer {API_KEY}' } +# Local file +with open('/path/to/file/receptor.pdb', 'r') as f: + content = f.read() +protein = { + 'content': content, + 'name': 'protein.pdb' +} + +# Can also be a URL +# protein = 'https://files.rcsb.org/download/7RT3.pdb' + def submit_diffdock_sequence_to_smiles(): url = f"{BASE_URL}/api/diffdock_api/diffdock_docking" - protein_sequence = "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN" data = { "job_name": "DiffDock_Sequence_Test", - "protein": protein_sequence, + "protein": protein, "smiles": "CCO", # Ethanol } response = requests.post(url, headers=HEADERS, json=data) if response.status_code == 200: - print("Job submitted successfully:", response.json()) + print("Task submitted successfully:", response.json()) return response.json() else: print(f"Error: {response.status_code}", response.text) @@ -218,6 +377,8 @@ def submit_diffdock_sequence_to_smiles(): # submit_diffdock_sequence_to_smiles() ``` + + --- ### 3. Protenix Protein Structure Prediction @@ -332,7 +493,129 @@ Due to the long computation times for these models, all API calls are **asynchro ``` 3. **Monitor Task Status**: You can monitor the status of your job using the `task_id` through the platform's web interface. Log in to the web portal, navigate to the appropriate model section (e.g., AutoDock), and find your task in the history list to view its status and retrieve results. -**Note**: A dedicated API endpoint for programmatically checking task status is planned for a future release. +## Task Query +```python +import requests +# Known task ID +task_id = '1-688c4948-15b5223d-770c7c8b5656' +BASE_URL = 'http://api.quregenai.com' +url = f"{BASE_URL}/api/tasks/{task_id}" + +API_KEY = 'sk-xxxx' +HEADERS = { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {API_KEY}' +} + +response = requests.get(url, headers=HEADERS) +response.json() +``` +**Completed Task Response** + +Note that the `status` field value is `completed` +```python +{'success': True, + 'message': 'Task completed', + 'result': {'task_id': '1-688c4948-15b5223d-770c7c8b5656', + 'user_id': 'XXXX', + 'task_type': 'protenix', + 'job_name': 'Validation Test', + 'status': 'completed', + 'created_at': '2025-08-01 12:57:44', + 'completed_at': '2025-08-01 13:01:15', + 'parameters': {'complex_count': 1, + 'complex_0_name': 'Validation Test', + 'complex_0_sequence_count': 2, + 'seeds': 42, + 'n_sample': 5, + 'n_step': 150, + 'n_cycle': 5, + 'complex_0_sequence_0_type': 'dnaSequence', + 'complex_0_sequence_0_sequence': 'ATGCGTACGGGGTTTTAAAACCCCGGATCCTTAGGCCTAAGGATCCTTAG', + 'complex_0_sequence_0_count': 1, + 'complex_0_sequence_1_type': 'rnaSequence', + 'complex_0_sequence_1_sequence': 'AUGCGUACGGGGUUUUAAAACCCCGGAUCCUUAGGCCUAAGGAUCCUUAG', + 'complex_0_sequence_1_count': 1}, + 'result': 'Result file count: 10'}} +``` +**Incomplete Task Response** + +Note that the `status` field value is `pending`, indicating that the task is still running and needs to wait a few minutes +```python +{'success': True, + 'message': 'Task is still running, not completed', + 'result': {'task_id': '1-688c7950-1562fcd4-d1bd26f61a59', + 'user_id': 'XXXX', + 'task_type': 'protenix', + 'job_name': 'protenix_Sequence_Test', + 'status': 'pending', + 'parameters': {'complex_count': 1, + 'complex_0_name': 'protenix_Sequence_Test', + 'complex_0_sequence_count': 2, + 'seeds': 42, + 'n_sample': 5, + 'n_step': 150, + 'n_cycle': 5, + 'complex_0_sequence_0_type': 'proteinChain', + 'complex_0_sequence_0_sequence': 'MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN', + 'complex_0_sequence_0_count': 1, + 'complex_0_sequence_1_type': 'ligand', + 'complex_0_sequence_1_ligand': 'CC(=O)Oc1ccccc(=C)c1C(=O)O', + 'complex_0_sequence_1_count': 1}}} +``` + +## Result File Download +The download interface will package all files into a `.zip` archive +> AutoDock results in the compressed package are sorted by best docking score, with file name prefixes `rank_0`, `rank_1` + +```python +import os +import requests + +# Known completed task ID +task_id = '1-688c4948-15b5223d-770c7c8b5656' +BASE_URL = 'http://api.quregenai.com' +url = f"{BASE_URL}/api/tasks/{task_id}/results_download" +response = requests.get(url, headers=HEADERS) + + +def download(response, local_path='./tmp/results/protenix_results.zip'): + """ + response: HTTP response object + local_path: Local path where you want to save the results + """ + if response.status_code == 200: + # Ensure directory exists + os.makedirs(os.path.dirname(local_path), exist_ok=True) + + # Write response content to local file + with open(local_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + + # Verify file creation + if os.path.exists(local_path): + file_size = os.path.getsize(local_path) + print(f"✅ File downloaded successfully: {local_path}") + print(f"📊 File size: {file_size} bytes") + else: + print("❌ File creation failed") + else: + try: + error_info = response.json() + print(f"❌ Download failed: {error_info}") + except: + print(f"❌ Download failed: {response.text}") + +# Execute download +download(response) +``` +Download success message: +```python +✅ File downloaded successfully: /tmp/results/protenix_results.zip +📊 File size: 295983 bytes +``` ## Error Handling @@ -344,6 +627,138 @@ The API uses standard HTTP status codes to indicate the success or failure of a | `401 Unauthorized` | The API key is missing, invalid, or the account has insufficient funds. | `{"message":"Invalid or missing Authorization header","success":false}` | | `500 Internal Server Error` | An unexpected error occurred on the server. | Varies. | +## Common Failure Examples + +### a. Insufficient Balance +```bash +Request failed: 401, {"message":"Insufficient QAU balance, current balance: 0, at least 5 QAU required to submit task, please top up first","success":false} +``` + +### b. API Key Authentication Error +```bash +Request failed: 401, {"message":"Missing Authorization header, please provide API key","success":false} +``` + + +### c. Missing Required Parameters +```python + # Missing center_y and center_z parameters for pocket center coordinates + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCO", + "center_x": '-3.52', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +Request failed: 400, { + "success": false, + "message": "Missing required parameter: center_y (docking box parameter)" +} +``` + +### d. Redundant Parameters +```python + # Both smiles and ligand parameters are provided, + # but only one should be provided + with open('/path/to/file/ligand.sdf', 'r') as f: + content = f.read() + ligand = { + 'content': content, + 'name': 'ligand.sdf' + } + + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCO", # redundant + "ligand": ligand, # redundant + "center_x": '-3.52', + 'center_y': '5.57', + 'center_z': '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +Request failed: 400, { + "success": false, + "message": "Only one of ligand file(ligand/ligands) or SMILES string can be provided" +} +``` + +### e. Incorrect Ligand File - Protein PDB Instead of Small Molecule +```python + # Here ligand parameter is given a protein PDB local file instead of a small molecule + # 1uw6.pdb is a protein file + with open('/path/to/file/1uw6.pdb', 'r') as f + content = f.read() + + ligand = { + 'content': content, + 'name': '1uw6.pdb' + } + + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + 'ligand': ligand, # incorrect file + "center_x": '-3.52', + 'center_y': '5.57', + 'center_z': '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +Request failed: 400, { + "success": false, + "message": "Detected ligand file '1uw6.pdb' contains multiple amino acid residues (TYR, MET, THR, HIS, ARG...), this appears to be a protein file. This platform only supports protein-small molecule docking, not protein-protein docking. Please check your ligand file content." +} +``` + +### f. Ligand Structure Error - Unable to Convert to PDBQT Successfully +```python + # Here an incorrect SMILES structure is provided + # Need to strictly check the structural correctness of ligands and receptor proteins + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCCCCcccccccccc", + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +Request failed: 400, { + "success": false, + "message": "Failed to convert ligand structure to PDBQT format. Please verify the SMILES string is chemically valid and properly formatted." +} +``` + +### g. Query with Incorrect Task ID +```python +{'success': False, + 'message': 'Task does not exist, check if task ID is correct: xx-xxxx'} +``` + ## Best Practices - **Sequence Lengths**: diff --git a/README_zh.md b/README_zh.md index 06bdeae..dc9e72a 100644 --- a/README_zh.md +++ b/README_zh.md @@ -77,67 +77,230 @@ Authorization: Bearer your_api_key_here | `receptor` | string | 是 | 指向受体文件(例如 PDB 格式)的 URL 或服务器可访问路径。 | | `center_x`, `center_y`, `center_z` | number/string | 是 | 对接盒子中心的坐标。 | | `size_x`, `size_y`, `size_z` | number | 否 | 对接盒子的尺寸。每个轴默认为 15。 | -| `ligand` | string | 是 (三选一) | 单个配体文件(SDF, PDB)的路径。 | -| `ligands` | array of strings | 是 (三选一) | 多个配体文件路径的列表。 | -| `smiles` | string | 是 (三选一) | SMILES 字符串(多个分子使用 `\n` 分隔),或指向包含 SMILES 字符串(每行一个)的 `.txt` 文件的路径。 | +| `ligand` | string | 是 (三选一) | 单个配体文件(SDF, PDB, URL),文件大小不超过`10MB`| +| `ligands` | array of strings | 是 (三选一) | 多个配体文件的列表。 | +| `smiles` | string | 是 (三选一) | SMILES 字符串(多个分子使用 `\n` 分隔),或指向包含 SMILES 字符串(每行一个)的 `.txt` 文件。 | | `thread` | integer | 否 | 线程数。默认为 1200,最小为 1000。 | **注意**: 您必须提供 `ligand`、`ligands` 或 `smiles` 中的一种。 -#### 示例: 单个配体文件 +#### 示例:必须参数 +- `receptor`: 受体本地文件/URL + - 本地文件 + ```python + # 本地文件路径 + path = '/path/to/file/receptor.pdb' + with open(path, 'r') as f: + content = f.read() + receptor = { + 'content': content, + 'name': 'receptor.pdb' + } + ``` + - url + ```python + receptor = 'http://www.receptor.pdb' + ``` + +- `center_x`, `center_y`, `center_z`: 对接盒子中心坐标(可以利用web应用的分子结构查看器选择) +- `size_x`, `size_y`, `size_z`: 对接盒子尺寸(默认都为15) +- 配体输入(三选一): + 1. `ligand`: 单个配体,如果是本地文件则为键值(字典)对象,必须包含`content`字段,`name`字段可选,方便后续查看结果;如果是url可以直为字符串,(SDF格式文件,PDB格式文件,url链接地址)文件大小不超过`10MB` + - 本地文件: + ```python + # 本地磁盘路径 + path = '/path/to/file/ligand.sdf' + # 读取文件内容 + with open(path, 'r') as f: + content = f.read() + ligand = { + 'content': content, + 'name': 'ligand.sdf' + } + ``` + - url: + ```python + ligand = 'http://www.ligand.sdf' + ``` + + 2. `ligands`: 多个配体 (多个文件,SDF格式,PDB格式, url链接地址), 列表对象,其中每个文件大小不超过`10MB` + - 本地文件 + ```python + # 本地磁盘多个配体文件路径 + path1 = '/path/to/file/ligand1.sdf' + path2 = '/path/to/file/ligand2.sdf' + # 读取文件内容 + with open(path1, 'r') as f: + content1 = f.read() + with open(path2, 'r') as f: + content2 = f.read() + ligands = [ + {'name': 'ligand1.sdf', + 'content': content1 }, + {'name': 'ligand2.sdf', + 'content': content2} + ] + ``` + - url + ```python + ligands = ['http://www.ligand1.sdf', + 'http://www.ligand2.sdf'] + ``` + + 3. `smiles`: SMILES模式 + - SMILES字符串,换行符`\n`分割多个分子 + ```python + smiles = 'CCO\ncccccc' + ``` + - 文件路径,本身是`txt`文件,包含多个分子smiles字符串,一个分子smiles一行) + ```python + # 本地文件 + path = '/path/to/file/smiles.txt' + with open(path, 'r') as f: + content = f.read() + smiles = { + 'content': content + } + # url + smiles = 'http://www.smiles.txt' + + ``` + -**cURL** -```bash -curl -X POST "https://api.quregenai.com/api/autodock_api/autodock_docking" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer " \ - -d '{ - "job_name": "AutoDock_Single_Ligand_Test", - "receptor": "https://files.rcsb.org/download/7RT3.pdb", - "ligand": "/path/to/your/ligand.sdf", - "center_x": -3.52, - "center_y": 5.57, - "center_z": -26.55, - "size_x": 15, - "size_y": 15, - "size_z": 15 - }' -``` + +#### 示例1.1: 单个配体文件 **Python** ```python import requests -import os -BASE_URL = "https://api.quregenai.com" -API_KEY = os.environ.get("QUREGENAI_API_KEY", "") +# 读取本地配体文件内容,文件大小不超过10MB +with open('ligand.sdf', 'r') as f: + ligand_content = f.read() -HEADERS = { - 'Content-Type': 'application/json', - 'Authorization': f'Bearer {API_KEY}' +# 构造ligand文件对象 +ligand = { + 'content': ligand_content, + 'name': 'ligand.sdf' } def submit_autodock_single_ligand(): url = f"{BASE_URL}/api/autodock_api/autodock_docking" + data = { "job_name": "AutoDock_Single_Ligand_Test", "receptor": "https://files.rcsb.org/download/7RT3.pdb", - "ligand": "/path/to/your/ligand.sdf", - "center_x": -3.52, - "center_y": 5.57, - "center_z": -26.55 + "ligand": ligand, # 使用文件对象格式 + # "ligand": "https://www.ligand.sdf" # 或者使用URL链接 + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 } response = requests.post(url, headers=HEADERS, json=data) if response.status_code == 200: - print("任务提交成功:", response.json()) - return response.json() + result = response.json() + print(f"任务提交成功,任务ID: {result.get('task_id')}") + return result else: - print(f"错误: {response.status_code}", response.text) + print(f"请求失败: {response.status_code}, {response.text}") + return None + +# 调用示例 +result = submit_autodock_single_ligand() +``` + +#### 示例1.2: 批量配体对接 + +**Python** +```python + # 本地磁盘多个配体文件路径 + path1 = '/path/to/file/ligand1.sdf' + path2 = '/path/to/file/ligand2.sdf' + # 读取文件内容 + with open(path1, 'r') as f: + content1 = f.read() + with open(path2, 'r') as f: + content2 = f.read() + ligands = [ + {'name': 'ligand1.sdf', + 'content': content1 }, + {'name': 'ligand2.sdf', + 'content': content2} + ] + +def submit_autodock_multiple_ligands(): + url = f"{BASE_URL}/api/autodock_api/autodock_docking" + + data = { + "job_name": "AutoDock_Multiple_Ligands_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "ligands": ligands, + # "ligands": ['https://www.ligand1.sdf', 'https://www.ligand2.sdf'], # url链接列表 + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } + + response = requests.post(url, headers=HEADERS, json=data) + + if response.status_code == 200: + result = response.json() + print(f"批量任务提交成功,任务ID: {result.get('task_id')}") + return result + else: + print(f"请求失败: {response.status_code}, {response.text}") return None +``` + -# submit_autodock_single_ligand() +#### 示例1.3: SMILES字符串对接 +**Python** +```python + +# 本地 smiles.txt 文本读取 +path = '/path/to/file/smiles.txt' +with open(path, 'r') as f: + content = f.read() +smiles = { + 'content': content +} + +def submit_autodock_smiles(): + url = f"{BASE_URL}/api/autodock_api/autodock_docking" + + data = { + "job_name": "AutoDock_SMILES_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": smiles, # 本地smiles文件 + # "smiles": "CC(=O)CC(c1ccccc1)c1c(O)c2ccccc2oc1=O", # 也可以是分子的smiles字符串 + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } + + response = requests.post(url, headers=HEADERS, json=data) + + if response.status_code == 200: + result = response.json() + print(f"SMILES任务提交成功,任务ID: {result.get('task_id')}") + return result + else: + print(f"请求失败: {response.status_code}, {response.text}") + return None ``` --- @@ -164,18 +327,6 @@ def submit_autodock_single_ligand(): #### 示例: 蛋白质序列和 SMILES -**cURL** -```bash -curl -X POST "https://api.quregenai.com/api/diffdock_api/diffdock_docking" \ - -H "Content-Type: application/json" \ - -H "Authorization: Bearer " \ - -d '{ - "job_name": "DiffDock_Sequence_Test", - "protein": "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN", - "smiles": "CCO" - }' -``` - **Python** ```python import requests @@ -189,13 +340,23 @@ HEADERS = { 'Authorization': f'Bearer {API_KEY}' } +# 本地文件 +with open('/path/to/file/receptor.pdb', 'r') as f: + content = f.read() +protein = { + 'content': content, + 'name': 'protein.pdb' +} + +# 也可以是 url +# protein = 'https://files.rcsb.org/download/7RT3.pdb' + def submit_diffdock_sequence_to_smiles(): url = f"{BASE_URL}/api/diffdock_api/diffdock_docking" - protein_sequence = "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN" data = { "job_name": "DiffDock_Sequence_Test", - "protein": protein_sequence, + "protein": protein, "smiles": "CCO", # 乙醇 } @@ -325,7 +486,131 @@ def submit_protenix_protein_ligand(): ``` 3. **监控任务状态**: 您可以使用 `task_id` 通过平台的 Web 界面监控任务的状态。登录 Web 门户,导航到相应的模型部分(例如 AutoDock),然后在历史记录列表中找到您的任务以查看其状态并检索结果。 -**注意**: 用于以编程方式检查任务状态的专用 API 端点计划在未来版本中发布。 +## 任务查询 +```python +import requests +# 已知任务id +task_id = '1-688c4948-15b5223d-770c7c8b5656' +BASE_URL = 'http://api.quregenai.com' +url = f"{BASE_URL}/api/tasks/{task_id}" + +API_KEY = 'sk-xxxx' +HEADERS = { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {API_KEY}' +} + +response = requests.get(url, headers=HEADERS) +response.json() +``` +**已完成任务返回结果** + +注意`status`字段值为`completed` +```python +{'success': True, + 'message': '任务已完成', + 'result': {'task_id': '1-688c4948-15b5223d-770c7c8b5656', + 'user_id': 'XXXX', + 'task_type': 'protenix', + 'job_name': '确保通过验证的测试', + 'status': 'completed', + 'created_at': '2025-08-01 12:57:44', + 'completed_at': '2025-08-01 13:01:15', + 'parameters': {'complex_count': 1, + 'complex_0_name': '确保通过验证的测试', + 'complex_0_sequence_count': 2, + 'seeds': 42, + 'n_sample': 5, + 'n_step': 150, + 'n_cycle': 5, + 'complex_0_sequence_0_type': 'dnaSequence', + 'complex_0_sequence_0_sequence': 'ATGCGTACGGGGTTTTAAAACCCCGGATCCTTAGGCCTAAGGATCCTTAG', + 'complex_0_sequence_0_count': 1, + 'complex_0_sequence_1_type': 'rnaSequence', + 'complex_0_sequence_1_sequence': 'AUGCGUACGGGGUUUUAAAACCCCGGAUCCUUAGGCCUAAGGAUCCUUAG', + 'complex_0_sequence_1_count': 1}, + 'result': '结果文件数量: 10'}} +``` +**未完成任务返回结果** + +注意`status`字段的值为`pending`,表示任务仍然在运行计算中,需要等待几分钟 +```python +{'success': True, + 'message': '任务仍在运行,未完成', + 'result': {'task_id': '1-688c7950-1562fcd4-d1bd26f61a59', + 'user_id': 'XXXX', + 'task_type': 'protenix', + 'job_name': 'protenix_Sequence_Test', + 'status': 'pending', + 'parameters': {'complex_count': 1, + 'complex_0_name': 'protenix_Sequence_Test', + 'complex_0_sequence_count': 2, + 'seeds': 42, + 'n_sample': 5, + 'n_step': 150, + 'n_cycle': 5, + 'complex_0_sequence_0_type': 'proteinChain', + 'complex_0_sequence_0_sequence': 'MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKREQTGQGWVPSNYITPVN', + 'complex_0_sequence_0_count': 1, + 'complex_0_sequence_1_type': 'ligand', + 'complex_0_sequence_1_ligand': 'CC(=O)Oc1ccccc(=C)c1C(=O)O', + 'complex_0_sequence_1_count': 1}}} +``` + +## 结果文件下载 +下载接口会将所有文件打包为`.zip`压缩包 +> autodock 压缩包内部的结果文件会根据最佳对接得分进行排序, 以`rank_0`, `rand_1`为文件名前缀 + +```python +import os +import requests + +# 已知已完成任务的task_id +task_id = '1-688c4948-15b5223d-770c7c8b5656' +BASE_URL = 'http://api.quregenai.com' +url = f"{BASE_URL}/api/tasks/{task_id}/results_download" +response = requests.get(url, headers=HEADERS) + + +def download(response, local_path='./tmp/results/protenix_results.zip'): + """" + response: + local_path: 本地希望保存结果的文件路径 + """" + if response.status_code == 200: + # 确保目录存在 + os.makedirs(os.path.dirname(local_path), exist_ok=True) + + # 将响应内容写入本地文件 + with open(local_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=8192): + if chunk: + f.write(chunk) + + # 验证文件是否创建成功 + if os.path.exists(local_path): + file_size = os.path.getsize(local_path) + print(f"✅ 文件下载成功: {local_path}") + print(f"📊 文件大小: {file_size} bytes") + else: + print("❌ 文件未创建成功") + else: + try: + error_info = response.json() + print(f"❌ 下载失败: {error_info}") + except: + print(f"❌ 下载失败: {response.text}") + +# 执行下载 +download() + +``` +提示下载成功 +```python +✅ 文件下载成功: /tmps/results/protenix_results.zip +📊 文件大小: 295983 bytes +``` + ## 错误处理 @@ -337,6 +622,127 @@ API 使用标准的 HTTP 状态码来指示请求的成功或失败。 | `401 Unauthorized` | API 密钥缺失、无效或账户余额不足。 | `{"message":"缺少或无效的 Authorization 头部","success":false}` | | `500 Internal Server Error` | 服务器上发生意外错误。 | 多种多样。 | + +## 常见运行失败样例 +### a. API 验证错误 +```bash +# 传递了错误的API_KEY +{'message': '无效的API密钥', 'success': False} +``` + +### b. 余额不足 +```bash +请求失败: 401, {"message":"QAU余额不足,当前余额: 0,至少需要5 QAU才能提交任务,请先充值","success":false} +``` + +### c. 缺少必要的参数 +```python + # 这里缺少了口袋中心坐标center_y 以及 center_z两个参数 + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCO", + "center_x": '-3.52', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +请求失败: 400, { + "success": false, + "message": "缺少必需参数: center_y(对接盒子参数)" +} +``` + +### d. 参数冗余 +```python + + # 这里不但提供了smiles参数而且还有ligand参数, + # 但只能提供其中的一项 + with open('/path/to/file/ligand.sdf', 'r') as f: + content = f.read() + + ligand = { + 'content': content, + 'name': 'ligand.sdf' + } + + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCO", + "ligand": ligand, + "center_x": '-3.52', + 'center_y': '5.57', + 'center_z': '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +请求失败: 400, { + "success": false, + "message": "只能提供配体文件(ligand/ligands)或SMILES字符串中的一种" +} +``` + +### e. 配体文件错误上传成蛋白质pdb文件,而不是小分子 +```python + # 这里ligand参数给了一个蛋白质pdb本地文件而不是小分子 + + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + 'smiles': "CCO", + "center_x": '-3.52', + 'center_y': '5.57', + 'center_z': '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` + +```bash +请求失败: 400, { + "success": false, + "message": "检测到配体文件 '1uw6.pdb' 包含多个氨基酸残基 (TYR, MET, THR, HIS, ARG...),这似乎是一个蛋白质文件。本平台只支持蛋白质与小分子对接,不支持蛋白质与蛋白质对接。请检查您的配体文件内容。" +} +``` + +### f. 配体结构错误导致无法转换PDBQT成功 +```python + # 这里给了一个结构错误的smiles + # 需要严格检查配体和受体蛋白的结构正确性 + data = { + "job_name": "AutoDock_Single_Ligand_Test", + "receptor": "https://files.rcsb.org/download/7RT3.pdb", + "smiles": "CCCCCcccccccccc", + "center_x": '-3.52', + "center_y": '5.57', + "center_z": '-26.55', + "size_x": 15, + "size_y": 15, + "size_z": 15, + "thread": 1200 + } +``` +### g. 查询到错误的task_id +```python +{'success': False, + 'message': '任务不存在, 检查任务id 是否正确: xx-xxxx'} +``` + + + + ## 最佳实践 - **序列长度**: