From 9b53df73f0a876c97d79260c50e899d0c0fb33c3 Mon Sep 17 00:00:00 2001 From: alphaflows Date: Fri, 3 May 2024 15:33:22 -0400 Subject: [PATCH] refactor and prepare for release --- README.md | 2 +- examples/example-demo-v0.0.2.ipynb | 733 ++++++++++++++++++ examples/example-demo.ipynb | 709 ----------------- ...=> example-deploy-v0.0.1-deprecated.ipynb} | 48 +- examples/example-deploy-v2.ipynb | 560 ------------- swan/api/swan_api.py | 5 +- swan/object/__init__.py | 3 +- swan/object/source_uri.py | 369 --------- test/conftest.py | 0 test/dev_test.ipynb | 557 ------------- test/github_test.ipynb | 96 --- test/mcs_test.ipynb | 352 --------- test/nsfw_test.py | 10 - test/source.json | 1 - 14 files changed, 750 insertions(+), 2695 deletions(-) create mode 100644 examples/example-demo-v0.0.2.ipynb delete mode 100644 examples/example-demo.ipynb rename examples/{example-deploy-v1.ipynb => example-deploy-v0.0.1-deprecated.ipynb} (69%) delete mode 100644 examples/example-deploy-v2.ipynb delete mode 100644 swan/object/source_uri.py delete mode 100644 test/conftest.py delete mode 100644 test/dev_test.ipynb delete mode 100644 test/github_test.ipynb delete mode 100644 test/mcs_test.ipynb delete mode 100644 test/nsfw_test.py delete mode 100644 test/source.json diff --git a/README.md b/README.md index 02aa2da1..8f6998bd 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ swan_api = SwanAPI(api_key='your_api_key_here') hardwares = swan_api.get_hardware_config() price_list = [(hardware.name, hardware.price) for hardware in hardwares] -# Deploy a task +# Create a task result = swan_api.deploy_task(cfg_name='config1', region='US', start_in=123, duration=123, job_source_uri='uri', paid=123, tx_hash='tx_hash_here', wallet_address='wallet_address_here') print("Deployment Result:", result) diff --git a/examples/example-demo-v0.0.2.ipynb b/examples/example-demo-v0.0.2.ipynb new file mode 100644 index 00000000..21b0af53 --- /dev/null +++ b/examples/example-demo-v0.0.2.ipynb @@ -0,0 +1,733 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Demo for SDK (latest)\n", + "\n", + "This example shows how to use SDK to deploy a task. The demo notebook includes the following steps:\n", + "- [initialization](#initialization)\n", + "- [show available hardware info list](#show-available-hardware-information)\n", + "- [choose hardware config](#choose-hardware-config)\n", + "- [get `job_source_uri`](#get-job_source_uri)\n", + "- [estimate payment amount](#estimate-payment-amount)\n", + "- [create task to get `task_uuid`](#create-task)\n", + "- [submit payment](#submit-payment)\n", + "- [validate payment](#validate-payment-to-deploy-task)\n", + "- [follow up task status](#follow-up-task-status-optional)\n", + "- [show result](#show-result)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Initialization\n", + "\n", + "#### get an `API_KEY`\n", + "\n", + "- For test version, get `API_KEY` in dashboard page: https://orchestrator-test.swanchain.io\n", + "- For prod version, get `API_KEY` in dashboard page: https://orchestrator.swanchain.io\n", + "\n", + "If use this repository to test on your local machine, add `sys.path.insert(0, '..')` at the beginning, and run code in the root directory of this repository.\n", + "\n", + "You need to add environment file `.env` in your local directory, including the following parameters (`PK` is private key):\n", + "\n", + "```\n", + "API_KEY=\n", + "WALLET=\n", + "PK=\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.insert(0, '..') \n", + "\n", + "import os\n", + "import time\n", + "import dotenv\n", + "import json\n", + "dotenv.load_dotenv()\n", + "from swan import SwanAPI\n", + "\n", + "# dev_url = \"https://swanhub-cali.swanchain.io\"\n", + "# dev_url = \"http://127.0.0.1:5008\"\n", + "\n", + "# Initialize the Swan Service\n", + "# dev\n", + "# swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"), environment=dev_url)\n", + "# prod\n", + "swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"))\n", + "\n", + "from swan.contract.swan_contract import SwanContract\n", + "\n", + "contract = SwanContract(os.getenv('PK'), swan_api.contract_info)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"client_contract_address\": \"0x20a67c6Bea000fAf0BE862BB254F092abF0E5b98\",\n", + " \"payment_contract_address\": \"0x5094A609Af5184d076Be2DF741820732126b4Fd2\",\n", + " \"rpc_url\": \"https://rpc-atom-internal.swanchain.io\",\n", + " \"swan_token_contract_address\": \"0x91B25A65b295F0405552A4bbB77879ab5e38166c\"\n", + "}\n" + ] + } + ], + "source": [ + "r = swan_api.contract_info\n", + "print(json.dumps(r, indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Show available hardware information" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': 0,\n", + " 'name': 'C1ae.small',\n", + " 'description': 'CPU only · 2 vCPU · 2 GiB',\n", + " 'type': 'CPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'Bashkortostan Republic-RU',\n", + " 'Kyiv City-UA',\n", + " 'Kowloon City-HK',\n", + " 'Tokyo-JP',\n", + " 'California-US',\n", + " 'Central and Western District-HK',\n", + " 'Quebec-CA',\n", + " 'North West-SG',\n", + " 'Kwai Tsing-HK',\n", + " 'Bavaria-DE',\n", + " 'Saxony-DE',\n", + " 'Guangdong-CN',\n", + " 'Kowloon-HK',\n", + " 'North Rhine-Westphalia-DE'],\n", + " 'price': '0.0',\n", + " 'status': 'available'},\n", + " {'id': 1,\n", + " 'name': 'C1ae.medium',\n", + " 'description': 'CPU only · 4 vCPU · 4 GiB',\n", + " 'type': 'CPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'Bashkortostan Republic-RU',\n", + " 'Kyiv City-UA',\n", + " 'Kowloon City-HK',\n", + " 'Tokyo-JP',\n", + " 'California-US',\n", + " 'Central and Western District-HK',\n", + " 'Quebec-CA',\n", + " 'North West-SG',\n", + " 'Kwai Tsing-HK',\n", + " 'Bavaria-DE',\n", + " 'Guangdong-CN',\n", + " 'Kowloon-HK',\n", + " 'North Rhine-Westphalia-DE'],\n", + " 'price': '1.0',\n", + " 'status': 'available'},\n", + " {'id': 4,\n", + " 'name': 'M1ae.large',\n", + " 'description': 'Nvidia 3060 · 8 vCPU · 8 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['Kyiv City-UA'],\n", + " 'price': '4.0',\n", + " 'status': 'available'},\n", + " {'id': 6,\n", + " 'name': 'M1ae.2xlarge',\n", + " 'description': 'Nvidia 2080 Ti · 4 vCPU · 8 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '6.0',\n", + " 'status': 'available'},\n", + " {'id': 7,\n", + " 'name': 'M1ae.3xlarge',\n", + " 'description': 'Nvidia 2080 Ti · 8 vCPU · 16 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '6.5',\n", + " 'status': 'available'},\n", + " {'id': 12,\n", + " 'name': 'G1ae.small',\n", + " 'description': 'Nvidia 3080 · 4 vCPU · 8 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'Kowloon City-HK',\n", + " 'Tokyo-JP',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Kwai Tsing-HK'],\n", + " 'price': '10.0',\n", + " 'status': 'available'},\n", + " {'id': 13,\n", + " 'name': 'G1ae.medium',\n", + " 'description': 'Nvidia 3080 · 8 vCPU · 16 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'Kowloon City-HK',\n", + " 'Tokyo-JP',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Kwai Tsing-HK'],\n", + " 'price': '11.0',\n", + " 'status': 'available'},\n", + " {'id': 20,\n", + " 'name': 'Hpc1ae.small',\n", + " 'description': 'Nvidia 3090 · 4 vCPU · 8 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Guangdong-CN',\n", + " 'Kowloon-HK'],\n", + " 'price': '14.0',\n", + " 'status': 'available'},\n", + " {'id': 21,\n", + " 'name': 'Hpc1ae.medium',\n", + " 'description': 'Nvidia 3090 · 8 vCPU · 16 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Guangdong-CN',\n", + " 'Kowloon-HK'],\n", + " 'price': '16.0',\n", + " 'status': 'available'},\n", + " {'id': 24,\n", + " 'name': 'Hpc1ae.2xlarge',\n", + " 'description': 'NVIDIA A4000 · 4 vCPU · 8 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['North Carolina-US', 'North Rhine-Westphalia-DE'],\n", + " 'price': '21.0',\n", + " 'status': 'available'},\n", + " {'id': 25,\n", + " 'name': 'Hpc1ae.3xlarge',\n", + " 'description': 'NVIDIA A4000 · 8 vCPU · 16 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['North Carolina-US', 'North Rhine-Westphalia-DE'],\n", + " 'price': '21.0',\n", + " 'status': 'available'},\n", + " {'id': 27,\n", + " 'name': 'T1ae.medium',\n", + " 'description': 'Nvidia 2080 Ti · 12 vCPU · 64 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '36.0',\n", + " 'status': 'available'},\n", + " {'id': 32,\n", + " 'name': 'Hpc2ae.small',\n", + " 'description': 'Nvidia 4090 · 4 vCPU · 8 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['Bavaria-DE', 'Tokyo-JP', 'Bashkortostan Republic-RU'],\n", + " 'price': '22.0',\n", + " 'status': 'available'},\n", + " {'id': 33,\n", + " 'name': 'Hpc2ae.medium',\n", + " 'description': 'Nvidia 4090 · 8 vCPU · 16 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['Bavaria-DE', 'Tokyo-JP', 'Bashkortostan Republic-RU'],\n", + " 'price': '24.0',\n", + " 'status': 'available'},\n", + " {'id': 42,\n", + " 'name': 'T1az.2xlarge',\n", + " 'description': 'Nvidia 4090 · 8 vCPU · 64 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['Bavaria-DE', 'Tokyo-JP', 'Bashkortostan Republic-RU'],\n", + " 'price': '60.0',\n", + " 'status': 'available'},\n", + " {'id': 44,\n", + " 'name': 'T1az.4xlarge',\n", + " 'description': 'Nvidia A4000 · 8 vCPU · 64 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '65.0',\n", + " 'status': 'available'},\n", + " {'id': 53,\n", + " 'name': 'T2az.2xlarge',\n", + " 'description': 'Nvidia 4090 · 12 vCPU · 128 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['Bavaria-DE', 'Tokyo-JP'],\n", + " 'price': '70.0',\n", + " 'status': 'available'},\n", + " {'id': 55,\n", + " 'name': 'T2az.4xlarge',\n", + " 'description': 'Nvidia A4000 · 12 vCPU · 128 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '75.0',\n", + " 'status': 'available'},\n", + " {'id': 72,\n", + " 'name': 'R1ae.small',\n", + " 'description': 'Nvidia 2080 TI · 8 vCPU · 32 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '12.0',\n", + " 'status': 'available'},\n", + " {'id': 73,\n", + " 'name': 'R1ae.medium',\n", + " 'description': 'Nvidia 3080 · 8 vCPU · 32 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'Kowloon City-HK',\n", + " 'Tokyo-JP',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Kwai Tsing-HK'],\n", + " 'price': '22.0',\n", + " 'status': 'available'},\n", + " {'id': 74,\n", + " 'name': 'R1ae.large',\n", + " 'description': 'Nvidia 3090 · 8 vCPU · 32 GiB',\n", + " 'type': 'GPU',\n", + " 'reigion': ['North Carolina-US',\n", + " 'California-US',\n", + " 'Quebec-CA',\n", + " 'Guangdong-CN',\n", + " 'Kowloon-HK'],\n", + " 'price': '30.0',\n", + " 'status': 'available'},\n", + " {'id': 77,\n", + " 'name': 'R2ae.large',\n", + " 'description': 'Nvidia 4090 · 8 vCPU · 32 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['Bavaria-DE', 'Tokyo-JP', 'Bashkortostan Republic-RU'],\n", + " 'price': '50.0',\n", + " 'status': 'available'},\n", + " {'id': 78,\n", + " 'name': 'R2ae.xlarge',\n", + " 'description': 'Nvidia A4000 · 8 vCPU · 32 GiB',\n", + " 'type': 'AI GPU',\n", + " 'reigion': ['North Carolina-US'],\n", + " 'price': '52.0',\n", + " 'status': 'available'}]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hardwares = swan_api.get_hardware_config()\n", + "hardwares_info = [hardware.to_dict() for hardware in hardwares if hardware.status == \"available\"] \n", + "hardwares_info" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Choose hardware config\n", + "\n", + "choose the hardware with its config name or hardware id\n", + "\n", + "in hardware config, `cfg_name` and `hardware_id` will be used in the steps to deploy task (create task and submit payment)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hardware.name='C1ae.medium', hardware.id=1, ['North Carolina-US', 'Bashkortostan Republic-RU', 'Kyiv City-UA', 'Kowloon City-HK', 'Tokyo-JP', 'California-US', 'Central and Western District-HK', 'Quebec-CA', 'North West-SG', 'Kwai Tsing-HK', 'Bavaria-DE', 'Guangdong-CN', 'Kowloon-HK', 'North Rhine-Westphalia-DE']\n", + "The chosen hardware_id=1\n" + ] + } + ], + "source": [ + "cfg_name = 'C1ae.medium' #\"G1ae.medium\"\n", + "hardware = [hardware for hardware in hardwares if hardware.name == cfg_name][0]\n", + "print(f\"{hardware.name=}, {hardware.id=}, {hardware.region}\")\n", + "\n", + "hardware_id = hardware.id\n", + "print(f\"The chosen {hardware_id=}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hardware_id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get `job_source_uri`\n", + "\n", + "We can use the `get_source_uri` interface to get a `job_source_uri` for creating task." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "job_source_uri = swan_api.get_source_uri(\n", + " repo_uri='https://github.com/alphaflows/tetris-docker-image.git',\n", + " hardware_id=hardware_id,\n", + " wallet_address=os.getenv('WALLET')\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "if job_source_uri and job_source_uri.get('data'):\n", + " job_source_uri = job_source_uri['data']['job_source_uri']" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'https://data.mcs.lagrangedao.org/ipfs/QmRGyt2gSvUkM8UePz5aeTW2tmw2MQrS4oXPVWLwHufqyN'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "job_source_uri" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Estimate Payment amount" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1000000000000000000\n" + ] + } + ], + "source": [ + "duration_hour = 1 # hour\n", + "amount = contract.estimate_payment(hardware_id, duration_hour)\n", + "print(amount)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Create task\n", + "\n", + "This step uses above information to create task, and get `task_uuid`, which is useful in submit payment step." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"data\": {\n", + " \"task\": {\n", + " \"created_at\": \"1714763824\",\n", + " \"end_at\": \"1714767416\",\n", + " \"leading_job_id\": null,\n", + " \"refund_amount\": null,\n", + " \"status\": \"initialized\",\n", + " \"task_detail_cid\": \"https://data.mcs.lagrangedao.org/ipfs/QmWkquL27Tss4GWGs5nzPnijV1gZmF5FSxA8znTQmvmn3B\",\n", + " \"tx_hash\": null,\n", + " \"updated_at\": \"1714763824\",\n", + " \"uuid\": \"8d19975e-cbfc-4423-a580-2bd1ba7aac1e\"\n", + " }\n", + " },\n", + " \"message\": \"Task_uuid initialized.\",\n", + " \"status\": \"success\"\n", + "}\n" + ] + } + ], + "source": [ + "duration=3600*duration_hour\n", + "\n", + "result = swan_api.create_task(\n", + " cfg_name=cfg_name, \n", + " region='North Carolina-US', \n", + " start_in=300, \n", + " duration=duration, \n", + " job_source_uri=job_source_uri,#repo.source_uri, \n", + " paid=contract._wei_to_swan(amount),\n", + " wallet_address=os.getenv('WALLET'),\n", + ")\n", + "print(json.dumps(result, indent=2))\n", + "task_uuid = result['data']['task']['uuid']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Submit Payment\n", + "\n", + "This step is using `task_uuid`, `hardware_id` and `duration` to submit payment via **ClientPayment** contract." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0x27205cc0eeb4a2283af518c9aa5e05f436b829b0dc51ec40d08652168651b9d7\n" + ] + } + ], + "source": [ + "tx_hash = contract.submit_payment(task_uuid, hardware_id, duration)\n", + "print(tx_hash)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Validate Payment to deploy task\n", + "\n", + "This step will validate the payment and then make task eligible for assigning if validation successful" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'tx_hash': '0x27205cc0eeb4a2283af518c9aa5e05f436b829b0dc51ec40d08652168651b9d7', 'task_uuid': '8d19975e-cbfc-4423-a580-2bd1ba7aac1e'}\n", + "{\n", + " \"data\": {\n", + " \"task\": {\n", + " \"created_at\": \"1714763824\",\n", + " \"end_at\": \"1714767416\",\n", + " \"leading_job_id\": null,\n", + " \"refund_amount\": null,\n", + " \"status\": \"created\",\n", + " \"task_detail_cid\": \"https://data.mcs.lagrangedao.org/ipfs/QmWkquL27Tss4GWGs5nzPnijV1gZmF5FSxA8znTQmvmn3B\",\n", + " \"tx_hash\": null,\n", + " \"updated_at\": \"1714763841\",\n", + " \"uuid\": \"8d19975e-cbfc-4423-a580-2bd1ba7aac1e\"\n", + " }\n", + " },\n", + " \"message\": \"Task payment validated successfully.\",\n", + " \"status\": \"success\"\n", + "}\n" + ] + } + ], + "source": [ + "if result_validation := swan_api.validate_payment(\n", + " tx_hash=tx_hash,\n", + " task_uuid=task_uuid\n", + "):\n", + " print(json.dumps(result_validation, indent=2))\n", + "else:\n", + " print('validation failed')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### follow up task status (optional)\n", + "The following step is optional, shows information when waiting for task being deployed." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"data\": {\n", + " \"computing_providers\": [],\n", + " \"jobs\": [],\n", + " \"task\": {\n", + " \"created_at\": \"1714763824\",\n", + " \"end_at\": \"1714767416\",\n", + " \"leading_job_id\": null,\n", + " \"refund_amount\": null,\n", + " \"status\": \"accepting_bids\",\n", + " \"task_detail_cid\": \"https://data.mcs.lagrangedao.org/ipfs/QmWkquL27Tss4GWGs5nzPnijV1gZmF5FSxA8znTQmvmn3B\",\n", + " \"tx_hash\": null,\n", + " \"updated_at\": \"1714763861\",\n", + " \"uuid\": \"8d19975e-cbfc-4423-a580-2bd1ba7aac1e\"\n", + " }\n", + " },\n", + " \"message\": \"fetch task info for task_uuid='8d19975e-cbfc-4423-a580-2bd1ba7aac1e' successfully\",\n", + " \"status\": \"success\"\n", + "}\n" + ] + } + ], + "source": [ + "# Check task info\n", + "info = swan_api.get_deployment_info(task_uuid=task_uuid)\n", + "print(json.dumps(info, indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Show result\n", + "\n", + "`job_real_uri` is for show the result of application you deployed. \n", + "You can put it into the web browser to view application." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['https://077dupt8wa.cp.filezoo.com.cn']\n" + ] + } + ], + "source": [ + "r = swan_api.get_real_url(task_uuid)\n", + "print(r)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "list index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[52], line 8\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[1;32m 4\u001b[0m headers \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 5\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mContent-Type\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mapplication/json\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 6\u001b[0m }\n\u001b[0;32m----> 8\u001b[0m response \u001b[38;5;241m=\u001b[39m requests\u001b[38;5;241m.\u001b[39mget(\u001b[43mr\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m, headers\u001b[38;5;241m=\u001b[39mheaders)\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(json\u001b[38;5;241m.\u001b[39mdumps(response\u001b[38;5;241m.\u001b[39mjson(), indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m))\n", + "\u001b[0;31mIndexError\u001b[0m: list index out of range" + ] + } + ], + "source": [ + "import requests\n", + "import json\n", + "\n", + "headers = {\n", + " 'Content-Type': 'application/json',\n", + "}\n", + "\n", + "response = requests.get(r[0], headers=headers)\n", + "\n", + "try:\n", + " print(json.dumps(response.json(), indent=4))\n", + "except Exception as e:\n", + " print(e)\n", + " print(response)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "swanchain", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/example-demo.ipynb b/examples/example-demo.ipynb deleted file mode 100644 index 8bb4529e..00000000 --- a/examples/example-demo.ipynb +++ /dev/null @@ -1,709 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Demo for SDK (latest)\n", - "\n", - "This example shows how to use SDK to deploy a task. The demo notebook includes the following steps:\n", - "- [initialization](#initialization)\n", - "- [show available hardware info list](#show-available-hardware-information)\n", - "- [choose hardware config](#choose-hardware-config)\n", - "- [get `job_source_uri`](#get-job_source_uri)\n", - "- [estimate payment amount](#estimate-payment-amount)\n", - "- [create task to get `task_uuid`](#create-task)\n", - "- [submit payment](#submit-payment)\n", - "- [validate payment](#validate-payment-to-deploy-task)\n", - "- [follow up task status](#follow-up-task-status-optional)\n", - "- [show result](#show-result)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### Initialization\n", - "\n", - "#### get an `API_KEY`\n", - "\n", - "- For test version, get `API_KEY` in dashboard page: https://orchestrator-test.swanchain.io\n", - "- For prod version, get `API_KEY` in dashboard page: https://orchestrator.swanchain.io" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "import time\n", - "import dotenv\n", - "dotenv.load_dotenv()\n", - "from swan import SwanAPI\n", - "\n", - "# dev_url = \"https://swanhub-cali.swanchain.io\"\n", - "# dev_url = \"http://127.0.0.1:5008\"\n", - "\n", - "# Initialize the Swan Service\n", - "# dev\n", - "# swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"), environment=dev_url)\n", - "# prod\n", - "swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"))\n", - "\n", - "from swan.contract.swan_contract import SwanContract\n", - "\n", - "contract = SwanContract(os.getenv('PK'), swan_api.contract_info)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'client_contract_address': '0x20a67c6Bea000fAf0BE862BB254F092abF0E5b98', 'payment_contract_address': '0x5094A609Af5184d076Be2DF741820732126b4Fd2', 'rpc_url': 'https://rpc-atom-internal.swanchain.io', 'swan_token_contract_address': '0x91B25A65b295F0405552A4bbB77879ab5e38166c'}\n" - ] - } - ], - "source": [ - "r = swan_api.contract_info\n", - "print(r)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Show available hardware information" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'id': 0,\n", - " 'name': 'C1ae.small',\n", - " 'description': 'CPU only · 2 vCPU · 2 GiB',\n", - " 'type': 'CPU',\n", - " 'reigion': ['Ivano-Frankivsk Oblast-UA',\n", - " 'North Rhine-Westphalia-DE',\n", - " 'Henan-CN',\n", - " 'Kowloon City-HK',\n", - " 'Guangdong-CN',\n", - " 'Kowloon-HK',\n", - " 'Saxony-DE',\n", - " 'Central and Western District-HK',\n", - " 'North Carolina-US',\n", - " 'California-US',\n", - " 'Bashkortostan Republic-RU',\n", - " 'Jiangsu-CN',\n", - " 'North West-SG',\n", - " 'Kyiv City-UA',\n", - " 'Illinois-US',\n", - " 'Bavaria-DE',\n", - " 'North Holland-NL',\n", - " 'Quebec-CA'],\n", - " 'price': '0.0',\n", - " 'status': 'available'},\n", - " {'id': 1,\n", - " 'name': 'C1ae.medium',\n", - " 'description': 'CPU only · 4 vCPU · 4 GiB',\n", - " 'type': 'CPU',\n", - " 'reigion': ['Ivano-Frankivsk Oblast-UA',\n", - " 'North Rhine-Westphalia-DE',\n", - " 'Henan-CN',\n", - " 'Kowloon City-HK',\n", - " 'Guangdong-CN',\n", - " 'Kowloon-HK',\n", - " 'Central and Western District-HK',\n", - " 'North Carolina-US',\n", - " 'California-US',\n", - " 'Bashkortostan Republic-RU',\n", - " 'Jiangsu-CN',\n", - " 'North West-SG',\n", - " 'Kyiv City-UA',\n", - " 'Illinois-US',\n", - " 'Bavaria-DE',\n", - " 'North Holland-NL',\n", - " 'Quebec-CA'],\n", - " 'price': '1.0',\n", - " 'status': 'available'},\n", - " {'id': 4,\n", - " 'name': 'M1ae.large',\n", - " 'description': 'Nvidia 3060 · 8 vCPU · 8 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['Kyiv City-UA'],\n", - " 'price': '4.0',\n", - " 'status': 'available'},\n", - " {'id': 6,\n", - " 'name': 'M1ae.2xlarge',\n", - " 'description': 'Nvidia 2080 Ti · 4 vCPU · 8 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '6.0',\n", - " 'status': 'available'},\n", - " {'id': 7,\n", - " 'name': 'M1ae.3xlarge',\n", - " 'description': 'Nvidia 2080 Ti · 8 vCPU · 16 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '6.5',\n", - " 'status': 'available'},\n", - " {'id': 12,\n", - " 'name': 'G1ae.small',\n", - " 'description': 'Nvidia 3080 · 4 vCPU · 8 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['Kowloon City-HK',\n", - " 'Kowloon-HK',\n", - " 'North Carolina-US',\n", - " 'California-US',\n", - " 'Quebec-CA'],\n", - " 'price': '10.0',\n", - " 'status': 'available'},\n", - " {'id': 13,\n", - " 'name': 'G1ae.medium',\n", - " 'description': 'Nvidia 3080 · 8 vCPU · 16 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['Kowloon City-HK',\n", - " 'Kowloon-HK',\n", - " 'North Carolina-US',\n", - " 'California-US',\n", - " 'Quebec-CA'],\n", - " 'price': '11.0',\n", - " 'status': 'available'},\n", - " {'id': 20,\n", - " 'name': 'Hpc1ae.small',\n", - " 'description': 'Nvidia 3090 · 4 vCPU · 8 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Rhine-Westphalia-DE',\n", - " 'Guangdong-CN',\n", - " 'Kowloon-HK',\n", - " 'California-US',\n", - " 'North Carolina-US',\n", - " 'Quebec-CA'],\n", - " 'price': '14.0',\n", - " 'status': 'available'},\n", - " {'id': 21,\n", - " 'name': 'Hpc1ae.medium',\n", - " 'description': 'Nvidia 3090 · 8 vCPU · 16 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Rhine-Westphalia-DE',\n", - " 'Guangdong-CN',\n", - " 'Kowloon-HK',\n", - " 'California-US',\n", - " 'North Carolina-US',\n", - " 'Quebec-CA'],\n", - " 'price': '16.0',\n", - " 'status': 'available'},\n", - " {'id': 24,\n", - " 'name': 'Hpc1ae.2xlarge',\n", - " 'description': 'NVIDIA A4000 · 4 vCPU · 8 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '21.0',\n", - " 'status': 'available'},\n", - " {'id': 25,\n", - " 'name': 'Hpc1ae.3xlarge',\n", - " 'description': 'NVIDIA A4000 · 8 vCPU · 16 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '21.0',\n", - " 'status': 'available'},\n", - " {'id': 27,\n", - " 'name': 'T1ae.medium',\n", - " 'description': 'Nvidia 2080 Ti · 12 vCPU · 64 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '36.0',\n", - " 'status': 'available'},\n", - " {'id': 32,\n", - " 'name': 'Hpc2ae.small',\n", - " 'description': 'Nvidia 4090 · 4 vCPU · 8 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['Bavaria-DE', 'Henan-CN', 'Bashkortostan Republic-RU'],\n", - " 'price': '22.0',\n", - " 'status': 'available'},\n", - " {'id': 33,\n", - " 'name': 'Hpc2ae.medium',\n", - " 'description': 'Nvidia 4090 · 8 vCPU · 16 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['Bavaria-DE', 'Henan-CN', 'Bashkortostan Republic-RU'],\n", - " 'price': '24.0',\n", - " 'status': 'available'},\n", - " {'id': 42,\n", - " 'name': 'T1az.2xlarge',\n", - " 'description': 'Nvidia 4090 · 8 vCPU · 64 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['Bavaria-DE', 'Henan-CN', 'Bashkortostan Republic-RU'],\n", - " 'price': '60.0',\n", - " 'status': 'available'},\n", - " {'id': 44,\n", - " 'name': 'T1az.4xlarge',\n", - " 'description': 'Nvidia A4000 · 8 vCPU · 64 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '65.0',\n", - " 'status': 'available'},\n", - " {'id': 53,\n", - " 'name': 'T2az.2xlarge',\n", - " 'description': 'Nvidia 4090 · 12 vCPU · 128 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['Bavaria-DE'],\n", - " 'price': '70.0',\n", - " 'status': 'available'},\n", - " {'id': 55,\n", - " 'name': 'T2az.4xlarge',\n", - " 'description': 'Nvidia A4000 · 12 vCPU · 128 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '75.0',\n", - " 'status': 'available'},\n", - " {'id': 72,\n", - " 'name': 'R1ae.small',\n", - " 'description': 'Nvidia 2080 TI · 8 vCPU · 32 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '12.0',\n", - " 'status': 'available'},\n", - " {'id': 73,\n", - " 'name': 'R1ae.medium',\n", - " 'description': 'Nvidia 3080 · 8 vCPU · 32 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Carolina-US',\n", - " 'California-US',\n", - " 'Kowloon City-HK',\n", - " 'Quebec-CA'],\n", - " 'price': '22.0',\n", - " 'status': 'available'},\n", - " {'id': 74,\n", - " 'name': 'R1ae.large',\n", - " 'description': 'Nvidia 3090 · 8 vCPU · 32 GiB',\n", - " 'type': 'GPU',\n", - " 'reigion': ['North Rhine-Westphalia-DE',\n", - " 'Guangdong-CN',\n", - " 'Kowloon-HK',\n", - " 'California-US',\n", - " 'North Carolina-US',\n", - " 'Quebec-CA'],\n", - " 'price': '30.0',\n", - " 'status': 'available'},\n", - " {'id': 77,\n", - " 'name': 'R2ae.large',\n", - " 'description': 'Nvidia 4090 · 8 vCPU · 32 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['Bavaria-DE', 'Henan-CN', 'Bashkortostan Republic-RU'],\n", - " 'price': '50.0',\n", - " 'status': 'available'},\n", - " {'id': 78,\n", - " 'name': 'R2ae.xlarge',\n", - " 'description': 'Nvidia A4000 · 8 vCPU · 32 GiB',\n", - " 'type': 'AI GPU',\n", - " 'reigion': ['North Carolina-US'],\n", - " 'price': '52.0',\n", - " 'status': 'available'}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hardwares = swan_api.get_hardware_config()\n", - "hardwares_info = [hardware.to_dict() for hardware in hardwares if hardware.status == \"available\"] \n", - "hardwares_info" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Choose hardware config\n", - "\n", - "choose the hardware with its config name or hardware id\n", - "\n", - "in hardware config, `cfg_name` and `hardware_id` will be used in the steps to deploy task (create task and submit payment)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hardware.name='C1ae.medium', hardware.id=1, ['Ivano-Frankivsk Oblast-UA', 'North Rhine-Westphalia-DE', 'Henan-CN', 'Kowloon City-HK', 'Guangdong-CN', 'Kowloon-HK', 'Central and Western District-HK', 'North Carolina-US', 'California-US', 'Bashkortostan Republic-RU', 'Jiangsu-CN', 'North West-SG', 'Kyiv City-UA', 'Illinois-US', 'Bavaria-DE', 'North Holland-NL', 'Quebec-CA']\n", - "The chosen hardware_id=1\n" - ] - } - ], - "source": [ - "cfg_name = 'C1ae.medium' #\"G1ae.medium\"\n", - "hardware = [hardware for hardware in hardwares if hardware.name == cfg_name][0]\n", - "print(f\"{hardware.name=}, {hardware.id=}, {hardware.region}\")\n", - "\n", - "hardware_id = hardware.id\n", - "print(f\"The chosen {hardware_id=}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hardware_id" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Get `job_source_uri`\n", - "\n", - "We can use the `get_source_uri` interface to get a `job_source_uri` for creating task." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "job_source_uri = swan_api.get_source_uri(\n", - " repo_uri='https://github.com/alphaflows/tetris-docker-image.git',\n", - " hardware_id=hardware_id,\n", - " wallet_address=os.getenv('WALLET')\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "if job_source_uri and job_source_uri.get('data'):\n", - " job_source_uri = job_source_uri['data']['job_source_uri']" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "job_source_uri" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Estimate Payment amount" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1000000000000000000\n" - ] - } - ], - "source": [ - "duration_hour = 1 # hour\n", - "amount = contract.estimate_payment(hardware_id, duration_hour)\n", - "print(amount)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Create task\n", - "\n", - "This step uses above information to create task, and get `task_uuid`, which is useful in submit payment step." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "ename": "KeyboardInterrupt", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[10], line 5\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[1;32m 3\u001b[0m duration\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m3600\u001b[39m\u001b[38;5;241m*\u001b[39mduration_hour\n\u001b[0;32m----> 5\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mswan_api\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_task\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 6\u001b[0m \u001b[43m \u001b[49m\u001b[43mcfg_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcfg_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[43m \u001b[49m\u001b[43mregion\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mNorth Carolina-US\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_in\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m300\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mduration\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mduration\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 10\u001b[0m \u001b[43m \u001b[49m\u001b[43mjob_source_uri\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjob_source_uri\u001b[49m\u001b[43m,\u001b[49m\u001b[38;5;66;43;03m#repo.source_uri, \u001b[39;49;00m\n\u001b[1;32m 11\u001b[0m \u001b[43m \u001b[49m\u001b[43mpaid\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcontract\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_wei_to_swan\u001b[49m\u001b[43m(\u001b[49m\u001b[43mamount\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 12\u001b[0m \u001b[43m \u001b[49m\u001b[43mwallet_address\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mos\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgetenv\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mWALLET\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 13\u001b[0m \u001b[43m)\u001b[49m\n\u001b[1;32m 14\u001b[0m \u001b[38;5;28mprint\u001b[39m(json\u001b[38;5;241m.\u001b[39mdumps(result, indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m))\n\u001b[1;32m 15\u001b[0m task_uuid \u001b[38;5;241m=\u001b[39m result[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdata\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtask\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muuid\u001b[39m\u001b[38;5;124m'\u001b[39m]\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/examples/../swan/api/swan_api.py:193\u001b[0m, in \u001b[0;36mSwanAPI.create_task\u001b[0;34m(self, cfg_name, region, start_in, duration, job_source_uri, wallet_address, paid)\u001b[0m\n\u001b[1;32m 183\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verify_hardware_region(cfg_name, region):\n\u001b[1;32m 184\u001b[0m params \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 185\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpaid\u001b[39m\u001b[38;5;124m\"\u001b[39m: paid,\n\u001b[1;32m 186\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mduration\u001b[39m\u001b[38;5;124m\"\u001b[39m: duration,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mjob_source_uri\u001b[39m\u001b[38;5;124m\"\u001b[39m: job_source_uri\n\u001b[1;32m 192\u001b[0m }\n\u001b[0;32m--> 193\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_request_with_params\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 194\u001b[0m \u001b[43m \u001b[49m\u001b[43mPOST\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 195\u001b[0m \u001b[43m \u001b[49m\u001b[43mCREATE_TASK\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 196\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mswan_url\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 197\u001b[0m \u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 198\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtoken\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m 199\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\n\u001b[1;32m 200\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 201\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n\u001b[1;32m 202\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/examples/../swan/api_client.py:113\u001b[0m, in \u001b[0;36mAPIClient._request_with_params\u001b[0;34m(self, method, request_path, swan_api, params, token, files, json_body)\u001b[0m\n\u001b[1;32m 112\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_request_with_params\u001b[39m(\u001b[38;5;28mself\u001b[39m, method, request_path, swan_api, params, token, files, json_body\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[0;32m--> 113\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrequest_path\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mswan_api\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtoken\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfiles\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mjson_body\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjson_body\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/examples/../swan/api_client.py:39\u001b[0m, in \u001b[0;36mAPIClient._request\u001b[0;34m(self, method, request_path, swan_api, params, token, files, json_body)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 38\u001b[0m body \u001b[38;5;241m=\u001b[39m params\n\u001b[0;32m---> 39\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpost\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheader\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 40\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m method \u001b[38;5;241m==\u001b[39m DELETE:\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m params:\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/requests/api.py:115\u001b[0m, in \u001b[0;36mpost\u001b[0;34m(url, data, json, **kwargs)\u001b[0m\n\u001b[1;32m 103\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpost\u001b[39m(url, data\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, json\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m 104\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Sends a POST request.\u001b[39;00m\n\u001b[1;32m 105\u001b[0m \n\u001b[1;32m 106\u001b[0m \u001b[38;5;124;03m :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 112\u001b[0m \u001b[38;5;124;03m :rtype: requests.Response\u001b[39;00m\n\u001b[1;32m 113\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 115\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mpost\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mjson\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mjson\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/requests/api.py:59\u001b[0m, in \u001b[0;36mrequest\u001b[0;34m(method, url, **kwargs)\u001b[0m\n\u001b[1;32m 55\u001b[0m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[1;32m 56\u001b[0m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[1;32m 57\u001b[0m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[1;32m 58\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m sessions\u001b[38;5;241m.\u001b[39mSession() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[0;32m---> 59\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43msession\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/requests/sessions.py:587\u001b[0m, in \u001b[0;36mSession.request\u001b[0;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[1;32m 582\u001b[0m send_kwargs \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 583\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeout\u001b[39m\u001b[38;5;124m\"\u001b[39m: timeout,\n\u001b[1;32m 584\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mallow_redirects\u001b[39m\u001b[38;5;124m\"\u001b[39m: allow_redirects,\n\u001b[1;32m 585\u001b[0m }\n\u001b[1;32m 586\u001b[0m send_kwargs\u001b[38;5;241m.\u001b[39mupdate(settings)\n\u001b[0;32m--> 587\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43msend_kwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 589\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/requests/sessions.py:701\u001b[0m, in \u001b[0;36mSession.send\u001b[0;34m(self, request, **kwargs)\u001b[0m\n\u001b[1;32m 698\u001b[0m start \u001b[38;5;241m=\u001b[39m preferred_clock()\n\u001b[1;32m 700\u001b[0m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[0;32m--> 701\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43madapter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 703\u001b[0m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[1;32m 704\u001b[0m elapsed \u001b[38;5;241m=\u001b[39m preferred_clock() \u001b[38;5;241m-\u001b[39m start\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/requests/adapters.py:489\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[0;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[1;32m 487\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 488\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m chunked:\n\u001b[0;32m--> 489\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 490\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 491\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 492\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 493\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 494\u001b[0m \u001b[43m \u001b[49m\u001b[43mredirect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 495\u001b[0m \u001b[43m \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 496\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 497\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m 498\u001b[0m \u001b[43m \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 499\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 500\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 502\u001b[0m \u001b[38;5;66;03m# Send the request.\u001b[39;00m\n\u001b[1;32m 503\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 504\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(conn, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mproxy_pool\u001b[39m\u001b[38;5;124m\"\u001b[39m):\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:715\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[0;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)\u001b[0m\n\u001b[1;32m 712\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_prepare_proxy(conn)\n\u001b[1;32m 714\u001b[0m \u001b[38;5;66;03m# Make the request on the httplib connection object.\u001b[39;00m\n\u001b[0;32m--> 715\u001b[0m httplib_response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_make_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 716\u001b[0m \u001b[43m \u001b[49m\u001b[43mconn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 717\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 718\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 719\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout_obj\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 720\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 721\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 722\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 723\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 725\u001b[0m \u001b[38;5;66;03m# If we're going to release the connection in ``finally:``, then\u001b[39;00m\n\u001b[1;32m 726\u001b[0m \u001b[38;5;66;03m# the response doesn't need to know about the connection. Otherwise\u001b[39;00m\n\u001b[1;32m 727\u001b[0m \u001b[38;5;66;03m# it will also try to release it and we'll have a double-release\u001b[39;00m\n\u001b[1;32m 728\u001b[0m \u001b[38;5;66;03m# mess.\u001b[39;00m\n\u001b[1;32m 729\u001b[0m response_conn \u001b[38;5;241m=\u001b[39m conn \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m release_conn \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:467\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001b[0m\n\u001b[1;32m 462\u001b[0m httplib_response \u001b[38;5;241m=\u001b[39m conn\u001b[38;5;241m.\u001b[39mgetresponse()\n\u001b[1;32m 463\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# Remove the TypeError from the exception chain in\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;66;03m# Python 3 (including for exceptions like SystemExit).\u001b[39;00m\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# Otherwise it looks like a bug in the code.\u001b[39;00m\n\u001b[0;32m--> 467\u001b[0m \u001b[43msix\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraise_from\u001b[49m\u001b[43m(\u001b[49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 468\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (SocketTimeout, BaseSSLError, SocketError) \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 469\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_raise_timeout(err\u001b[38;5;241m=\u001b[39me, url\u001b[38;5;241m=\u001b[39murl, timeout_value\u001b[38;5;241m=\u001b[39mread_timeout)\n", - "File \u001b[0;32m:3\u001b[0m, in \u001b[0;36mraise_from\u001b[0;34m(value, from_value)\u001b[0m\n", - "File \u001b[0;32m~/Documents/work_repos/orchestrator-sdk/venv/lib/python3.10/site-packages/urllib3/connectionpool.py:462\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[0;34m(self, conn, method, url, timeout, chunked, **httplib_request_kw)\u001b[0m\n\u001b[1;32m 459\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[1;32m 460\u001b[0m \u001b[38;5;66;03m# Python 3\u001b[39;00m\n\u001b[1;32m 461\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 462\u001b[0m httplib_response \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgetresponse\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 463\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 464\u001b[0m \u001b[38;5;66;03m# Remove the TypeError from the exception chain in\u001b[39;00m\n\u001b[1;32m 465\u001b[0m \u001b[38;5;66;03m# Python 3 (including for exceptions like SystemExit).\u001b[39;00m\n\u001b[1;32m 466\u001b[0m \u001b[38;5;66;03m# Otherwise it looks like a bug in the code.\u001b[39;00m\n\u001b[1;32m 467\u001b[0m six\u001b[38;5;241m.\u001b[39mraise_from(e, \u001b[38;5;28;01mNone\u001b[39;00m)\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/http/client.py:1375\u001b[0m, in \u001b[0;36mHTTPConnection.getresponse\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1373\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1374\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1375\u001b[0m \u001b[43mresponse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbegin\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1376\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m:\n\u001b[1;32m 1377\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mclose()\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/http/client.py:318\u001b[0m, in \u001b[0;36mHTTPResponse.begin\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 316\u001b[0m \u001b[38;5;66;03m# read until we get a non-100 response\u001b[39;00m\n\u001b[1;32m 317\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[0;32m--> 318\u001b[0m version, status, reason \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_read_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 319\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m status \u001b[38;5;241m!=\u001b[39m CONTINUE:\n\u001b[1;32m 320\u001b[0m \u001b[38;5;28;01mbreak\u001b[39;00m\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/http/client.py:279\u001b[0m, in \u001b[0;36mHTTPResponse._read_status\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 278\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_read_status\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[0;32m--> 279\u001b[0m line \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mstr\u001b[39m(\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mreadline\u001b[49m\u001b[43m(\u001b[49m\u001b[43m_MAXLINE\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124miso-8859-1\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 280\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(line) \u001b[38;5;241m>\u001b[39m _MAXLINE:\n\u001b[1;32m 281\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m LineTooLong(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstatus line\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/socket.py:705\u001b[0m, in \u001b[0;36mSocketIO.readinto\u001b[0;34m(self, b)\u001b[0m\n\u001b[1;32m 703\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[1;32m 704\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 705\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrecv_into\u001b[49m\u001b[43m(\u001b[49m\u001b[43mb\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 706\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m timeout:\n\u001b[1;32m 707\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_timeout_occurred \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ssl.py:1307\u001b[0m, in \u001b[0;36mSSLSocket.recv_into\u001b[0;34m(self, buffer, nbytes, flags)\u001b[0m\n\u001b[1;32m 1303\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m flags \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 1304\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 1305\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnon-zero flags not allowed in calls to recv_into() on \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m%\u001b[39m\n\u001b[1;32m 1306\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m)\n\u001b[0;32m-> 1307\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnbytes\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbuffer\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1308\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1309\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28msuper\u001b[39m()\u001b[38;5;241m.\u001b[39mrecv_into(buffer, nbytes, flags)\n", - "File \u001b[0;32m/opt/homebrew/Cellar/python@3.10/3.10.14/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ssl.py:1163\u001b[0m, in \u001b[0;36mSSLSocket.read\u001b[0;34m(self, len, buffer)\u001b[0m\n\u001b[1;32m 1161\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1162\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m buffer \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m-> 1163\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_sslobj\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mlen\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbuffer\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1164\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1165\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sslobj\u001b[38;5;241m.\u001b[39mread(\u001b[38;5;28mlen\u001b[39m)\n", - "\u001b[0;31mKeyboardInterrupt\u001b[0m: " - ] - } - ], - "source": [ - "import json\n", - "\n", - "duration=3600*duration_hour\n", - "\n", - "result = swan_api.create_task(\n", - " cfg_name=cfg_name, \n", - " region='North Carolina-US', \n", - " start_in=300, \n", - " duration=duration, \n", - " job_source_uri=job_source_uri,#repo.source_uri, \n", - " paid=contract._wei_to_swan(amount),\n", - " wallet_address=os.getenv('WALLET'),\n", - ")\n", - "print(json.dumps(result, indent=2))\n", - "task_uuid = result['data']['task']['uuid']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Submit Payment\n", - "\n", - "This step is using `task_uuid`, `hardware_id` and `duration` to submit payment via **ClientPayment** contract." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0xca3e3a2cf9eaf8718516d0fae9e45cd693e9fe3ac31955433a55ae77bd86fad7\n" - ] - } - ], - "source": [ - "tx_hash = contract.submit_payment(task_uuid, hardware_id, duration)\n", - "print(tx_hash)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Validate Payment to deploy task\n", - "\n", - "This step will validate the payment and then make task eligible for assigning if validation successful" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'tx_hash': '0xca3e3a2cf9eaf8718516d0fae9e45cd693e9fe3ac31955433a55ae77bd86fad7', 'task_uuid': 'c5da85dd-7c45-4725-ab23-68948698aa7d'}\n", - "{\n", - " \"data\": {\n", - " \"error_code\": 1131\n", - " },\n", - " \"message\": \"payment validation failed: payment receipt contract address is not correct\",\n", - " \"status\": \"failed\"\n", - "}\n" - ] - } - ], - "source": [ - "if result_validation := swan_api.validate_payment(\n", - " tx_hash=tx_hash,\n", - " task_uuid=task_uuid\n", - "):\n", - " print(json.dumps(result_validation, indent=2))\n", - "else:\n", - " print('validation failed')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### follow up task status (optional)\n", - "The following step is optional, shows information when waiting for task being deployed." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"data\": {\n", - " \"computing_providers\": [],\n", - " \"jobs\": [],\n", - " \"task\": {\n", - " \"created_at\": \"1714249086\",\n", - " \"end_at\": \"1714252680\",\n", - " \"leading_job_id\": null,\n", - " \"refund_amount\": null,\n", - " \"status\": \"created\",\n", - " \"task_detail_cid\": \"https://plutotest.acl.swanipfs.com/ipfs/QmRhBxuNFxMmWreEQfsB1WKXjpoK9SP5yKAK4DiqE4ihKx\",\n", - " \"tx_hash\": null,\n", - " \"updated_at\": \"1714249094\",\n", - " \"uuid\": \"ec5d4242-0ebe-48b4-a4a1-96f5080ba064\"\n", - " }\n", - " },\n", - " \"message\": \"fetch task info for task_uuid='ec5d4242-0ebe-48b4-a4a1-96f5080ba064' successfully\",\n", - " \"status\": \"success\"\n", - "}\n" - ] - } - ], - "source": [ - "# Check task info\n", - "info = swan_api.get_deployment_info(task_uuid=task_uuid)\n", - "print(json.dumps(info, indent=2))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Show result\n", - "\n", - "`job_real_uri` is for show the result of application you deployed. \n", - "You can put it into the web browser to view application." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['https://077dupt8wa.cp.filezoo.com.cn']\n" - ] - } - ], - "source": [ - "r = swan_api.get_real_url(task_uuid)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "ename": "IndexError", - "evalue": "list index out of range", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[52], line 8\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[1;32m 4\u001b[0m headers \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 5\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mContent-Type\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mapplication/json\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 6\u001b[0m }\n\u001b[0;32m----> 8\u001b[0m response \u001b[38;5;241m=\u001b[39m requests\u001b[38;5;241m.\u001b[39mget(\u001b[43mr\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m, headers\u001b[38;5;241m=\u001b[39mheaders)\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(json\u001b[38;5;241m.\u001b[39mdumps(response\u001b[38;5;241m.\u001b[39mjson(), indent\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m))\n", - "\u001b[0;31mIndexError\u001b[0m: list index out of range" - ] - } - ], - "source": [ - "import requests\n", - "import json\n", - "\n", - "headers = {\n", - " 'Content-Type': 'application/json',\n", - "}\n", - "\n", - "response = requests.get(r[0], headers=headers)\n", - "\n", - "try:\n", - " print(json.dumps(response.json(), indent=4))\n", - "except Exception as e:\n", - " print(e)\n", - " print(response)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "swanchain", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.14" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/example-deploy-v1.ipynb b/examples/example-deploy-v0.0.1-deprecated.ipynb similarity index 69% rename from examples/example-deploy-v1.ipynb rename to examples/example-deploy-v0.0.1-deprecated.ipynb index 6fe2c4c3..7cfcdcd7 100644 --- a/examples/example-deploy-v1.ipynb +++ b/examples/example-deploy-v0.0.1-deprecated.ipynb @@ -6,7 +6,7 @@ "source": [ "## Example for SDK\n", "\n", - "This example shows how to use SDK to deploy a task (V1)\n", + "This example shows how to use SDK to deploy a task (deprecated version)\n", "\n", "### Initialization" ] @@ -33,8 +33,8 @@ "# get user api_key in dashboard page: https://orchestrator-test.swanchain.io/provider-status\n", "swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"), environment=dev_url)\n", "\n", - "api_key = os.getenv(\"MCS_API_KEY\")\n", - "mcs_api = MCSAPI(api_key)" + "# api_key = os.getenv(\"MCS_API_KEY\")\n", + "# mcs_api = MCSAPI(api_key)" ] }, { @@ -72,7 +72,7 @@ "output_type": "stream", "text": [ "1\n", - "('C1ae.medium', 1, ['-', 'North Carolina-US'])\n" + "('C1ae.medium', 1, ['Quebec-CA', 'North Carolina-US'])\n" ] } ], @@ -142,8 +142,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "0xf2bb683e0b3f933bf4d1582a3ca4ea158904dab2c26c7d6d78cc6aded2cefd04\n", - "0xc391e15ec0ac1f80078b965778b6b87cb8a2582be1805a98553142e6b24e92dd\n" + "0x800bbde44740faa1d44b1cf9c3b1a3b629b43742c427fdd743a0ec8e571ad703\n", + "0x0682f87926cd8db6ce3465772bb36f3ae09696443d9a065f5403e0c3e2fe7ce1\n" ] } ], @@ -173,29 +173,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "ERROR:root:SwanAPIRequestException: No C1ae.medium machine in Quebec-CA.Traceback (most recent call last):\n", - " File \"/Users/zihangchen/Documents/work_repos/orchestrator-sdk/examples/../swan/api/swan_api.py\", line 151, in deploy_task\n", - " raise SwanAPIException(f\"No {cfg_name} machine in {region}.\")\n", - "swan.common.exception.SwanAPIException: SwanAPIRequestException: No C1ae.medium machine in Quebec-CA.\n", - "\n" + "/var/folders/f1/12wnv55x7vz6rr1ts9l6lytm0000gn/T/ipykernel_38565/44368673.py:2: DeprecationWarning: Call to deprecated method deploy_task. (This API will be removed in the future version.) -- Deprecated since version 0.0.2.\n", + " result = swan_api.deploy_task(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "None\n" - ] - }, - { - "ename": "TypeError", - "evalue": "'NoneType' object is not subscriptable", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 12\u001b[0m\n\u001b[1;32m 2\u001b[0m result \u001b[38;5;241m=\u001b[39m swan_api\u001b[38;5;241m.\u001b[39mdeploy_task(\n\u001b[1;32m 3\u001b[0m cfg_name\u001b[38;5;241m=\u001b[39mdevice, \n\u001b[1;32m 4\u001b[0m region\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mQuebec-CA\u001b[39m\u001b[38;5;124m'\u001b[39m, \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 9\u001b[0m wallet_address\u001b[38;5;241m=\u001b[39mos\u001b[38;5;241m.\u001b[39mgetenv(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mWALLET\u001b[39m\u001b[38;5;124m'\u001b[39m),\n\u001b[1;32m 10\u001b[0m )\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(result)\n\u001b[0;32m---> 12\u001b[0m task_uuid \u001b[38;5;241m=\u001b[39m \u001b[43mresult\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mdata\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtask\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124muuid\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 13\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTask UUID:\u001b[39m\u001b[38;5;124m\"\u001b[39m, task_uuid)\n", - "\u001b[0;31mTypeError\u001b[0m: 'NoneType' object is not subscriptable" + "{'data': {'task': {'created_at': '1714764579', 'end_at': '1714768172', 'leading_job_id': None, 'refund_amount': None, 'status': 'created', 'task_detail_cid': 'https://plutotest.acl.swanipfs.com/ipfs/QmcSoSW6MvSyNQesEMTJLSPWEpngCVwyXfbnN12bmbtN2p', 'tx_hash': None, 'updated_at': '1714764579', 'uuid': '226ea8b5-8d91-4470-8002-68fbd89232a2'}}, 'message': 'Task_uuid created.', 'status': 'success'}\n", + "Task UUID: 226ea8b5-8d91-4470-8002-68fbd89232a2\n" ] } ], @@ -226,20 +213,7 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "buildImage\n", - "Job Result URL: https://42f6d9f62851.acl.swanipfs.com/ipfs/QmQEW9Dyi9aEQYtVdMxA7qkr7gdiiNE9MJxNtjt9uSyUKc\n", - "Job Real URL: https://cf24tc2oot.dev2.crosschain.computer\n", - "deployToK8s\n", - "Job Result URL: https://42f6d9f62851.acl.swanipfs.com/ipfs/QmQEW9Dyi9aEQYtVdMxA7qkr7gdiiNE9MJxNtjt9uSyUKc\n", - "Job Real URL: https://cf24tc2oot.dev2.crosschain.computer\n" - ] - } - ], + "outputs": [], "source": [ "# Check task info\n", "while True:\n", diff --git a/examples/example-deploy-v2.ipynb b/examples/example-deploy-v2.ipynb deleted file mode 100644 index 786d67e8..00000000 --- a/examples/example-deploy-v2.ipynb +++ /dev/null @@ -1,560 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example for SDK\n", - "\n", - "This example shows how to use SDK to deploy a task (V2)\n", - "\n", - "### Initialization\n", - "\n", - "For test version, get a user `API_KEY` in dashboard page: https://orchestrator-test.swanchain.io/provider-status" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import time\n", - "import dotenv\n", - "dotenv.load_dotenv(\"../.env\")\n", - "from swan import SwanAPI , MCSAPI\n", - "\n", - "# Initialize the Swan Service\n", - "swan_api = SwanAPI(api_key=os.getenv(\"API_KEY\"), environment=\"https://swanhub-cali.swanchain.io\")\n", - "\n", - "api_key = os.getenv(\"MCS_API_KEY\")\n", - "mcs_api = MCSAPI(api_key)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Available hardware information" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "hardwares = swan_api.get_hardware_config()\n", - "hardwares_info = [hardware.to_dict() for hardware in hardwares if hardware.status == \"available\"] \n", - "# hardwares_info" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "choose hardware config" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "('C1ae.medium', 1, ['North Carolina-US', 'Quebec-CA'])\n" - ] - } - ], - "source": [ - "device = 'C1ae.medium' #\"G1ae.medium\"\n", - "obj = [hardware for hardware in hardwares if hardware.name == device][0]\n", - "print(obj.id)\n", - "print([(hardware.name, hardware.id, hardware.region) for hardware in hardwares if hardware.name == device][0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "to simplify the process, here we use a existing `job_source_uri` which is a hello world application, used to create task." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "job_source_uri = 'https://test-api.lagrangedao.org/spaces/5117e998-c623-4837-8af9-2b7b0ce2de7f'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define task deploy v2" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Deploy task\n", - "\n", - "# before v2 integrated into SDK, use customed function instead\n", - "import logging\n", - "import traceback\n", - "import json\n", - "from swan.common.constant import *\n", - "from swan.common.exception import SwanAPIException\n", - "\n", - "def deploy_task_v2(\n", - " cfg_name: str, \n", - " region: str, \n", - " start_in: int, \n", - " duration: int, \n", - " job_source_uri: str, \n", - " wallet_address: str, \n", - " paid: float = 0.0\n", - " ):\n", - " \"\"\"Sent deploy task request via orchestrator.\n", - "\n", - " Args:\n", - " cfg_name: name of cp/hardware configuration set.\n", - " region: region of hardware.\n", - " start_in: unix timestamp of starting time.\n", - " duration: duration of service runtime in unix time.\n", - " job_source_uri: source uri for space.\n", - " wallet_address: user wallet address.\n", - " paid: paid amount in Eth.\n", - "\n", - " Returns:\n", - " JSON response from backend server including 'task_uuid'.\n", - " \"\"\"\n", - " try:\n", - " if swan_api._verify_hardware_region(cfg_name, region):\n", - " params = {\n", - " \"paid\": paid,\n", - " \"duration\": duration,\n", - " \"cfg_name\": cfg_name,\n", - " \"region\": region,\n", - " \"start_in\": start_in,\n", - " \"wallet\": wallet_address,\n", - " \"job_source_uri\": job_source_uri\n", - " }\n", - " result = swan_api._request_with_params(\n", - " POST, \n", - " '/v2/task_deployment', \n", - " swan_api.swan_url, \n", - " params, \n", - " swan_api.token, \n", - " None\n", - " )\n", - " return result\n", - " else:\n", - " raise SwanAPIException(f\"No {cfg_name} machine in {region}.\")\n", - " except Exception as e:\n", - " logging.error(str(e) + traceback.format_exc())\n", - " return None\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define contract util class v2" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# ./swan/contract/swan_contract_ex.py\n", - "\n", - "\n", - "from swan.common.constant import *\n", - "from swan.common.utils import get_contract_abi\n", - "\n", - "from swan.contract.swan_contract import SwanContract\n", - "\n", - "\n", - "CLIENT_CONTRACT_ADDRESS=\"0xe356a758fA1748dfBE71E989c876959665a66ddA\"\n", - "_CLIENT_CONTRACT_ABI = \"../swan/contract/abi/ClientPayment.json\"\n", - "\n", - "class SwanContractEx(SwanContract):\n", - "\n", - " def __init__(self, private_key: str, rpc_url: str):\n", - " \"\"\" Initialize swan contract API connection.\n", - "\n", - " Args:\n", - " private_key: private key for wallet.\n", - " rpc_url: rpc url of swan chain for connection.\n", - " \"\"\"\n", - "\n", - " # with open(_CLIENT_CONTRACT_ABI, 'r') as abi_file:\n", - " # abi_data = json.load(abi_file)\n", - " # client_abi = json.dumps(abi_data)\n", - " \n", - " \n", - " super().__init__(private_key=private_key, rpc_url=rpc_url)\n", - " self.client_contract = self.w3.eth.contract(\n", - " address=CLIENT_CONTRACT_ADDRESS, \n", - " abi=json.load(open(_CLIENT_CONTRACT_ABI))\n", - " )\n", - "\n", - " def submit_payment(self, task_id: str, hardware_id: int, duration: int):\n", - " nonce = self.w3.eth.get_transaction_count(self.account.address)\n", - " base_fee = self.w3.eth.get_block('latest')['baseFeePerGas']\n", - " max_priority_fee_per_gas = self.w3.to_wei(2, 'gwei')\n", - " max_fee_per_gas = base_fee + max_priority_fee_per_gas\n", - " if max_fee_per_gas < max_priority_fee_per_gas:\n", - " max_fee_per_gas = max_priority_fee_per_gas + base_fee\n", - " tx = self.client_contract.functions.submitPayment(task_id, hardware_id, duration).build_transaction({\n", - " 'from': self.account.address,\n", - " 'nonce': nonce,\n", - " \"maxFeePerGas\": max_fee_per_gas,\n", - " \"maxPriorityFeePerGas\": max_priority_fee_per_gas,\n", - " })\n", - " signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key)\n", - " tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)\n", - " self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIMEOUT)\n", - " return self.w3.to_hex(tx_hash)\n", - " \n", - " def _approve_swan_token(self, amount):\n", - " nonce = self.w3.eth.get_transaction_count(self.account.address)\n", - " base_fee = self.w3.eth.get_block('latest')['baseFeePerGas']\n", - " max_priority_fee_per_gas = self.w3.to_wei(2, 'gwei')\n", - " max_fee_per_gas = base_fee + max_priority_fee_per_gas\n", - " if max_fee_per_gas < max_priority_fee_per_gas:\n", - " max_fee_per_gas = max_priority_fee_per_gas + base_fee\n", - " tx = self.token_contract.functions.approve(self.client_contract.address, amount).build_transaction({\n", - " 'from': self.account.address,\n", - " 'nonce': nonce,\n", - " \"maxFeePerGas\": max_fee_per_gas,\n", - " \"maxPriorityFeePerGas\": max_priority_fee_per_gas,\n", - " })\n", - " signed_tx = self.w3.eth.account.sign_transaction(tx, self.account._private_key)\n", - " tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)\n", - " self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=CONTRACT_TIMEOUT)\n", - " return self.w3.to_hex(tx_hash)\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Contract and Payment Estimation\n", - "\n", - "- Firstly, use contract function to estimate the amount to pay. \n", - "- Secondly, by `task_uuid` gotten from v2 API `/v2/task_deployment`, **pay** with `task_uuid` and `hardware_id`\n", - "- Thirdly, do payment validation via v2 API `/v2/task_payment_validate`, which will enable task eligible for assigning" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1000000000000000000\n" - ] - } - ], - "source": [ - "pk = os.getenv('PK')\n", - "rpc = os.getenv('RPC')\n", - "\n", - "c2 = SwanContractEx(pk, rpc)\n", - "duration_hour = 1 # hour\n", - "amount = c2.estimate_payment(obj.id, duration_hour)\n", - "print(amount)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Deploy task\n", - "\n", - "This step shows how to use SDK's interface for deploying task, which calls Orchestrator's task deployment API (V2), to get `task_uuid`, which will be used in payment." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': {'task': {'created_at': '1713377715', 'end_at': '1713381312', 'leading_job_id': None, 'refund_amount': None, 'status': 'initialized', 'task_detail_cid': 'https://plutotest.acl.swanipfs.com/ipfs/QmUvHQNGETErt6MP7PMx6525ZgKKoe19zyt6oBkVR9kvzU', 'tx_hash': None, 'updated_at': '1713377715', 'uuid': '0242bdf6-45bb-4743-b081-f86d4f702bc0'}}, 'message': 'Task_uuid initialized.', 'status': 'success'}\n", - "Task UUID: 0242bdf6-45bb-4743-b081-f86d4f702bc0\n" - ] - } - ], - "source": [ - "duration=3600*duration_hour\n", - "\n", - "result = deploy_task_v2(\n", - " cfg_name=device, \n", - " region='Quebec-CA', \n", - " start_in=5, \n", - " duration=duration, \n", - " job_source_uri=job_source_uri, \n", - " paid=c2._wei_to_swan(amount),\n", - " wallet_address=os.getenv('WALLET'),\n", - " )\n", - "print(result)\n", - "task_uuid = result['data']['task']['uuid']\n", - "print(\"Task UUID:\", task_uuid)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Submit Payment\n", - "\n", - "This step is using `task_uuid`, `hardware_id` and `duration` to submit payment via **ClientPayment** contract." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0x30b0bce0f724fc7fc56e89c2e79c520cc68b5376246212d64b8427b25de6138e\n", - "0x4fcabb68f20381cc8f10fe5873e7c544ec0500fb4b84542230e21db803fd1336\n" - ] - } - ], - "source": [ - "r = c2._approve_swan_token(amount)\n", - "print(r)\n", - " \n", - "tx_hash = c2.submit_payment(task_uuid, obj.id, duration)\n", - "print(tx_hash)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Validate Payment via API\n", - "\n", - "This step will validate the payment and then make task eligible for assigning if validation successful" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0x70d958a1bb0d43b88215674789dbdf142b9d3bb512c1a5345dd8e09dcb6c09ce\n", - "b35d5ce8-2dcb-4e67-88de-f48d89487418\n", - "{'tx_hash': '0x70d958a1bb0d43b88215674789dbdf142b9d3bb512c1a5345dd8e09dcb6c09ce', 'task_uuid': 'b35d5ce8-2dcb-4e67-88de-f48d89487418'}\n", - "{'data': {'error_code': 1131}, 'message': 'payment validation failed: payment receipt contract address is not correct', 'status': 'failed'}\n" - ] - } - ], - "source": [ - "\n", - "def validate_payment(\n", - " tx_hash,\n", - " task_uuid\n", - " ):\n", - " \n", - " print(tx_hash)\n", - " print(task_uuid)\n", - "\n", - " try:\n", - " if tx_hash and task_uuid:\n", - " params = {\n", - " \"tx_hash\": tx_hash,\n", - " \"task_uuid\": task_uuid\n", - " }\n", - " print(params)\n", - " result = swan_api._request_with_params(\n", - " POST, \n", - " '/v2/task_payment_validate', \n", - " swan_api.swan_url, \n", - " params, \n", - " os.getenv(\"API_KEY\"), #swan_api.token, \n", - " None\n", - " )\n", - " return result\n", - " else:\n", - " raise SwanAPIException(f\"{tx_hash=} or {task_uuid=} invalid\")\n", - " except Exception as e:\n", - " logging.error(str(e) + traceback.format_exc())\n", - " return None\n", - "\n", - "result_validation = validate_payment(\n", - " tx_hash=tx_hash,\n", - " task_uuid=task_uuid\n", - ")\n", - "print(result_validation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following step is optional, shows information when waiting for task being deployed." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "buildImage\n", - "Job Result URL: https://42f6d9f62851.acl.swanipfs.com/ipfs/QmQEW9Dyi9aEQYtVdMxA7qkr7gdiiNE9MJxNtjt9uSyUKc\n", - "Job Real URL: https://cf24tc2oot.dev2.crosschain.computer\n", - "deployToK8s\n", - "Job Result URL: https://42f6d9f62851.acl.swanipfs.com/ipfs/QmQEW9Dyi9aEQYtVdMxA7qkr7gdiiNE9MJxNtjt9uSyUKc\n", - "Job Real URL: https://cf24tc2oot.dev2.crosschain.computer\n" - ] - } - ], - "source": [ - "# Check task info\n", - "while True:\n", - " info = swan_api.get_deployment_info(task_uuid=task_uuid)\n", - " if len(info['data']['jobs']) > 0:\n", - " \n", - " status = info['data']['jobs'][0]['status']\n", - " print(status)\n", - " \n", - " job_res_uri = info['data']['jobs'][0]['job_result_uri']\n", - " job_real_uri = info['data']['jobs'][0]['job_real_uri']\n", - " print(\"Job Result URL: \", job_res_uri)\n", - " print(\"Job Real URL: \", job_real_uri)\n", - " \n", - " # break\n", - " if status == 'deployToK8s' or status == \"Cancelled\" or status == \"Failed\":\n", - " break\n", - " \n", - " time.sleep(30)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Show result\n", - "\n", - "`job_real_uri` is for show the result of application you deployed." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "ERROR:root:'NoneType' object is not subscriptableTraceback (most recent call last):\n", - " File \"/Users/aaronli/miniconda3/envs/test-sdk2/lib/python3.10/site-packages/swan/api/swan_api.py\", line 184, in get_real_url\n", - " jobs = deployment_info['data']['jobs']\n", - "TypeError: 'NoneType' object is not subscriptable\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "None\n" - ] - } - ], - "source": [ - "r = swan_api.get_real_url(task_uuid)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"Hello\": \"World! Today - 06.21\"\n", - "}\n" - ] - } - ], - "source": [ - "import requests\n", - "import json\n", - "\n", - "headers = {\n", - " 'Content-Type': 'application/json',\n", - "}\n", - "\n", - "response = requests.get(r[0], headers=headers)\n", - "\n", - "try:\n", - " print(json.dumps(response.json(), indent=4))\n", - "except Exception as e:\n", - " print(e)\n", - " print(response)\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "swanchain", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.14" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/swan/api/swan_api.py b/swan/api/swan_api.py index bb12eae0..a4d030d3 100644 --- a/swan/api/swan_api.py +++ b/swan/api/swan_api.py @@ -7,8 +7,10 @@ from swan.api_client import APIClient from swan.common.constant import * -from swan.object import HardwareConfig, LagrangeSpace +from swan.object import HardwareConfig from swan.common.exception import SwanAPIException +from deprecated import deprecated + class SwanAPI(APIClient): @@ -117,6 +119,7 @@ def get_hardware_config(self): logging.error("Failed to fetch hardware configurations.") return None + @deprecated(version='0.0.2', reason='This API will be removed in the future version.') def deploy_task(self, cfg_name: str, region: str, start_in: int, duration: int, job_source_uri: str, wallet_address: str, tx_hash: str, paid: float = 0.0): """Sent deploy task request via orchestrator. diff --git a/swan/object/__init__.py b/swan/object/__init__.py index b5890086..b9befca9 100644 --- a/swan/object/__init__.py +++ b/swan/object/__init__.py @@ -1,5 +1,4 @@ # ./swan/object/__init__.py from swan.object.cp_config import HardwareConfig -from swan.object.task import Task -from swan.object.source_uri import SourceFilesInfo, Repository, LagrangeSpace \ No newline at end of file +from swan.object.task import Task \ No newline at end of file diff --git a/swan/object/source_uri.py b/swan/object/source_uri.py deleted file mode 100644 index b6e46669..00000000 --- a/swan/object/source_uri.py +++ /dev/null @@ -1,369 +0,0 @@ -import json -import requests -import uuid -from swan.api.mcs_api import MCSAPI, File -from swan.common.utils import datetime_to_unixtime -from swan.object.cp_config import HardwareConfig - - -class SourceFilesInfo(): - - def __init__(self): - self.file_list = [] - self.mcs_client = None - - def mcs_connection(self, mcs_client: MCSAPI): - """Add mcs connection. - - Args: - mcs_client: mcs API object. - """ - self.mcs_client = mcs_client - - def add_folder(self, bucket_name: str, object_name: str): - """Add a folder/repo to the source file info. - - Args: - bucket_name: bucket name of bucket locating the folder. - object_name: folder object_name (directory) - """ - folder_file = self.mcs_client._get_full_file_list(bucket_name, object_name) - self.file_list += self.get_folder_files(bucket_name, folder_file) - - - def add_file(self, bucket_name: str, object_name: str): - """Add single file to source file info. - - Args: - bucket_name: bucket name of bucket locating the folder. - object_name: file object_name (directory + file name) - """ - file = self.mcs_client.get_file(bucket_name, object_name) - list.append(file) - - def _file_to_dict(self, file: File): - return { - "cid": file.payloadCid, - "created_at": datetime_to_unixtime(file.created_at), - "name": f'0x000000/spaces/{str(file.name)}', - "updated_at": datetime_to_unixtime(file.updated_at), - "url": file.ipfs_url - } - - def get_folder_files(self, bucket_name: str, file_list: list): - """Retrieve all files under folders. - - Args: - bucket_name: bucket name of bucket locating the folder. - file_llist: list of directories (cotain folders). - - Returns: - Updated file_list without folder and all files under given directories. - """ - folder_list = [] - exist_folder = False - for file in file_list: - if file.is_folder: - exist_folder = True - folder_list.append(file) - file_list.remove(file) - for folder in folder_list: - new_file_list = self.mcs_client.list_files(bucket_name, folder.object_name) - file_list += new_file_list - if exist_folder: - file_list = self.get_folder_files(bucket_name, file_list) - return file_list - - def to_dict(self): - return { - "data": { - "files": [ - self._file_to_dict(file) for file in self.file_list - ] - } - } - - def to_json(self): - return json.dumps(self, default=lambda o: o.__dict__, - sort_keys=True, indent=4) - - -class Repository(): - - def __init__(self): - """Initialize repository for swan task. - """ - self.folder_dir = None - self.bucket = None - self.path = None - self.source_uri = None - - def update_bucket_info(self, bucket_name: str, object_name: str): - """Update the current mcs bucket info on MCS. - - Args: - bucket_name: name of bucket. - object_name: directory + file_name. - """ - self.bucket = bucket_name - self.path = object_name - - def add_local_dir(self, folder_dir: str): - """Initialize repository for swan task. - - Args: - folder_dir: Directory of folder to upload to mcs. - """ - self.folder_dir = folder_dir - - def mcs_connection(self, mcs_client: MCSAPI): - """Add mcs connection. - - Args: - mcs_client: mcs API object. - """ - self.mcs_client = mcs_client - - def upload_local_to_mcs(self, bucket_name: str, obj_name: str, mcs_client: MCSAPI = None): - """Upload repository to MCS to create remote source. - - Args: - bucket_name: bucket to upload repository. - obj_name: dir + file_name for repository. - mcs_client: mcs API object. - - Returns: - API response from uploading folder to MCS. Contain info of list of files uploaded. - """ - if self.folder_dir: - if mcs_client: - self.mcs_connection(mcs_client) - self.bucket = bucket_name - self.path = obj_name - upload = mcs_client.upload_folder(bucket_name, obj_name, self.folder_dir) - return upload - return None - - def generate_source_uri(self, bucket_name: str, obj_name: str, file_path: str, mcs_client: MCSAPI = None, replace: bool = True): - """Generate source uri for task using MCS service. - - Args: - bucket_name: bucket name to store source uri. - obj_name: object name (dir + file name) to store source uri. - file_path: local file path to store source uri JSON file. - replace: replace existing file or not. - mcs_client: mcs API object. - - Returns: - API response from MCS after uploading. Contains file information. - - """ - if self.bucket and self.path: - if mcs_client: - self.mcs_connection(mcs_client) - local_source = SourceFilesInfo() - local_source.mcs_connection(mcs_client) - local_source.add_folder(self.bucket, self.path) - with open(file_path, "w") as file: - json.dump(local_source.to_dict(), file) - res = mcs_client.upload_file(bucket_name, obj_name, file_path, replace) - self.source_uri = res.ipfs_url - return res - - def to_dict(self): - return { - "folder_dir": self.folder_dir, - "bucket_name": self.bucket, - "folder_path": self.path, - "source_uri": self.source_uri - } - - def to_json(self): - return json.dumps(self, default=lambda o: o.__dict__, - sort_keys=True, indent=4) - - -class LagrangeSpace(): - - def __init__(self, space_owner: str, space_name: str, wallet_address: str, hardware_config: HardwareConfig): - - self.wallet_address = wallet_address - self.space_name = space_name - self.space_owner = space_owner - self.hardware_config = hardware_config - self.space_uuid = None - self.source_uri = None - self.file_list = [] - - def get_space_info(self): - space_file_uri = f'https://api.lagrangedao.org/spaces/{self.space_owner}/{self.space_name}/files' - space_detail_uri = f'https://api.lagrangedao.org/spaces/{self.space_owner}/{self.space_name}' - space_files = requests.get(space_file_uri).json() - space_detail = requests.get(space_detail_uri).json() - - for file in space_files["data"]: - self.file_list.append(file) - - self.space_uuid = space_detail["data"]["space"]["uuid"] - - - def mcs_connection(self, mcs_client: MCSAPI): - """Add mcs connection. - - Args: - mcs_client: mcs API object. - """ - self.mcs_client = mcs_client - - def to_dict(self): - hardware_info = self.hardware_config.description - hardware_info = hardware_info.split(" · ") - - return { - "data": { - "files": self.file_list, - "owner": { - "public_address": self.wallet_address, - }, - "space": { - "activeOrder": { - "config": { - "description": self.hardware_config.description, - "hardware": hardware_info[0], - "hardware_id": int(self.hardware_config.id), - "hardware_type": self.hardware_config.type, - "memory": [int(s) for s in hardware_info[2].split() if s.isdigit()][0], - "name": self.hardware_config.name, - "price_per_hour": float(self.hardware_config.price), - "vcpu": [int(s) for s in hardware_info[1].split() if s.isdigit()][0], - }, - }, - "name": self.space_name, - "uuid": self.space_uuid, - } - } - } - - def to_json(self): - return json.dumps(self, default=lambda o: o.__dict__, - sort_keys=True, indent=4) - - def generate_source_uri(self, bucket_name: str, obj_name: str, file_path: str, mcs_client: MCSAPI = None, replace: bool = True): - """Generate source uri for task using MCS service. - - Args: - bucket_name: bucket name to store source uri. - obj_name: object name (dir + file name) to store source uri. - file_path: local file path to store source uri JSON file. - replace: replace existing file or not. - mcs_client: mcs API object. - - Returns: - API response from MCS after uploading. Contains file information. - - """ - if mcs_client: - self.mcs_connection(mcs_client) - with open(file_path, "w") as file: - json.dump(self.to_dict(), file) - res = mcs_client.upload_file(bucket_name, obj_name, file_path, replace) - self.source_uri = res.ipfs_url - return res - -class GithubRepo(): - - def __init__(self, repo_owner: str, repo_name: str, repo_branch: str, wallet_address: str, hardware_config: HardwareConfig, repo_uri: str = None): - - if repo_uri and not (repo_owner or repo_name): - # TO DO: Add retrieve repo owner, name and branch from URI - pass - - self.repo_owner = repo_owner - self.repo_name = repo_name - self.repo_branch = repo_branch - self.wallet_address = wallet_address - self.hardware_config = hardware_config - self.repo_uuid = str(uuid.uuid4()) - self.mcs_client = None - self.source_uri = None - self.file_list = [] - - def mcs_connection(self, mcs_client: MCSAPI): - """Add mcs connection. - - Args: - mcs_client: mcs API object. - """ - self.mcs_client = mcs_client - - def get_github_tree(self): - github_tree_uri = f"https://api.github.com/repos/{self.repo_owner}/{self.repo_name}/git/trees/{self.repo_branch}?recursive=1" - - github_repo_files = requests.get(github_tree_uri).json() - - for file in github_repo_files["tree"]: - if file["type"] == "blob": - self.file_list.append( - { - "cid": file["sha"], - "created_at": None, - "name": f"{self.repo_owner}/{self.repo_name}/{self.repo_branch}/{file['path']}", - "updated_at": None, - "url": f"https://raw.githubusercontent.com/{self.repo_owner}/{self.repo_name}/{self.repo_branch}/{file['path']}" - } - ) - - def to_dict(self): - hardware_info = self.hardware_config.description - hardware_info = hardware_info.split(" · ") - - return { - "data": { - "files": self.file_list, - "owner": { - "public_address": self.wallet_address, - }, - "space": { - "activeOrder": { - "config": { - "description": self.hardware_config.description, - "hardware": hardware_info[0], - "hardware_id": int(self.hardware_config.id), - "hardware_type": self.hardware_config.type, - "memory": [int(s) for s in hardware_info[2].split() if s.isdigit()][0], - "name": self.hardware_config.name, - "price_per_hour": float(self.hardware_config.price), - "vcpu": [int(s) for s in hardware_info[1].split() if s.isdigit()][0], - }, - }, - "name": self.repo_name, - "uuid": self.repo_uuid, - } - } - } - - def to_json(self): - return json.dumps(self, default=lambda o: o.__dict__, - sort_keys=True, indent=4) - - def generate_source_uri(self, bucket_name: str, obj_name: str, file_path: str, mcs_client: MCSAPI = None, replace: bool = True): - """Generate source uri for task using MCS service. - - Args: - bucket_name: bucket name to store source uri. - obj_name: object name (dir + file name) to store source uri. - file_path: local file path to store source uri JSON file. - replace: replace existing file or not. - mcs_client: mcs API object. - - Returns: - API response from MCS after uploading. Contains file information. - - """ - if mcs_client: - self.mcs_connection(mcs_client) - with open(file_path, "w") as file: - json.dump(self.to_dict(), file) - res = mcs_client.upload_file(bucket_name, obj_name, file_path, replace) - self.source_uri = res.ipfs_url - return res \ No newline at end of file diff --git a/test/conftest.py b/test/conftest.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/dev_test.ipynb b/test/dev_test.ipynb deleted file mode 100644 index 13394a40..00000000 --- a/test/dev_test.ipynb +++ /dev/null @@ -1,557 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "gmP5D6yRr8\n", - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxMzU2MDY2NiwianRpIjoiOThiOWIzYzktNjFlYy00OGE0LWE0OTYtYmVjNWI4YTU2NjBkIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IjB4NjFjM2UwM2RiZWQ1NWY1REUyMTM3MzJlODE2RjhBOEZkNkU5YmZGMCIsIm5iZiI6MTcxMzU2MDY2NiwiY3NyZiI6IjdkMWQ2NmViLTdmNTMtNGVmYy05ODRiLWY1NzY0OGNmNWU1NiIsImV4cCI6MTcxNjE1MjY2Nn0.uFFizTbsq6jSHK_sgl38_ZL1eqj8HLBrNqDc46hckzg\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "\n", - "api_key = os.getenv('API_KEY')\n", - "print(api_key)\n", - "\n", - "# Test login \n", - "from swan import SwanAPI\n", - "\n", - "client = SwanAPI(api_key)\n", - "print(client.token)\n", - "\n", - "# r = [hardware for hardware in client.get_hardware_config()]\n", - "# print(r[1].region)\n", - "\n", - "# r = client._verify_hardware_region('Hpc1ae.2xlarge', 'North Carolina-US')\n", - "# print(r)\n", - "\n", - "# # Deploy Space\n", - "n = os.getenv('NAME')\n", - "r = os.getenv('REGION')\n", - "s = os.getenv('START')\n", - "d = os.getenv('DURATION')\n", - "u = os.getenv('SOURCE')\n", - "w = os.getenv('WALLET')\n", - "t = os.getenv('TX')\n", - "r = client.deploy_task(n, r, s, d, u, w, t, 11)\n", - "# print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': {'computing_providers': [], 'jobs': [], 'task': {'created_at': '1713560675', 'end_at': '1713597866', 'leading_job_id': None, 'refund_amount': None, 'status': 'failed', 'task_detail_cid': 'https://data.mcs.lagrangedao.org/ipfs/QmS5m628bpDsozhYgYVVk41FmrhdPDY138nk1EyN1CPGPA', 'tx_hash': None, 'updated_at': '1713560683', 'uuid': '197d8e39-518c-49f1-a757-9b0d14175566'}}, 'message': \"fetch task info for task_uuid='197d8e39-518c-49f1-a757-9b0d14175566' successfully\", 'status': 'success'}\n" - ] - } - ], - "source": [ - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': {'computing_providers': [], 'jobs': [], 'task': {'created_at': '1713560675', 'end_at': '1713597866', 'leading_job_id': None, 'refund_amount': None, 'status': 'failed', 'task_detail_cid': 'https://data.mcs.lagrangedao.org/ipfs/QmS5m628bpDsozhYgYVVk41FmrhdPDY138nk1EyN1CPGPA', 'tx_hash': None, 'updated_at': '1713560683', 'uuid': '197d8e39-518c-49f1-a757-9b0d14175566'}}, 'message': \"fetch task info for task_uuid='197d8e39-518c-49f1-a757-9b0d14175566' successfully\", 'status': 'success'}\n" - ] - } - ], - "source": [ - "r = client.get_deployment_info(\"\")\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[]\n" - ] - } - ], - "source": [ - "r = client.get_real_url(\"\")\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hpc1ae.2xlarge\n", - "['California-US', 'North Carolina-US']\n" - ] - } - ], - "source": [ - "# r = [hardware if hardware.status == 'available' else None for hardware in client.get_hardware_config()]\n", - "# for i in range(len(r)):\n", - "# print(f'{i} {r[i].name if r[i] else None}')\n", - "# print(r[24].name)\n", - "# print(r[24].region)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "('M1ae.3xlarge', ['Guangdong-CN'])\n" - ] - } - ], - "source": [ - "hardwares = client.get_hardware_config()\n", - "hl = [(hardware.name, hardware.region) for hardware in hardwares]\n", - "\n", - "for h in hl:\n", - " if h[0] == \"M1ae.3xlarge\":\n", - " print(h)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "None\n" - ] - } - ], - "source": [ - "print(client.token)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "gmP5D6yRr8\n", - "{'data': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxMDI3NTQ0NCwianRpIjoiNjYxYmI0M2QtMTgzYi00OTVhLTk5MzYtYWMxMjY0ODUzOTdmIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IjB4NjFjM2UwM2RiZWQ1NWY1REUyMTM3MzJlODE2RjhBOEZkNkU5YmZGMCIsIm5iZiI6MTcxMDI3NTQ0NCwiY3NyZiI6ImVkYjM0YzliLTM1Y2EtNDZlMi04NDViLTg0MjlmNWExYWJhYSIsImV4cCI6MTcxMjg2NzQ0NH0.6Bii2HVeyav1DvL4K6t_2yFgyZIiZBiXFvTyfD1EDQY', 'message': 'Token created', 'status': 'success'}\n", - "{'data': {'computing_providers': [], 'jobs': [], 'task': None}, 'message': \"No task found with given task_uuid='84220a02-e963-489c-90e1-794754042253'\", 'status': 'failed'}\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "\n", - "api_key = os.getenv('API_KEY')\n", - "print(api_key)\n", - "\n", - "from swan import SwanAPI\n", - "client = SwanAPI(api_key)\n", - "\n", - "# Get deployment info\n", - "print(client.get_deployment_info('84220a02-e963-489c-90e1-794754042253'))" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1100000000000000000000\n", - "0x12981484b991e0547804b0d5c571e3584f4202a0a2eb45d9ad526b95aa53eece\n", - "0xb08eb18de9d6b95c61b02afa02f033be46bd54843b91c46a3360c118ee838f4d\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "\n", - "from swan import SwanContract\n", - "\n", - "pk = os.getenv('KEY')\n", - "rpc = os.getenv('RPC')\n", - "\n", - "c = SwanContract(pk, rpc)\n", - "\n", - "# Test esimate lock revenue\n", - "r = c.estimate_payment(13, 100)\n", - "print(r)\n", - "\n", - "# # Test get hardware info\n", - "# r = c.hardware_info(1)\n", - "# print(r)\n", - "\n", - "# # Test get swan token balance\n", - "# r = c._get_swan_balance()\n", - "# print(r * 1e-18)\n", - "\n", - "# # Test get gas\n", - "# r = c._get_swan_gas()\n", - "# print(r* 1e-18)\n", - "\n", - "r = c._approve_swan_token(2100000000000000000000)\n", - "print(r)\n", - "\n", - "# gas_estimate = c.payment_contract.functions.lockRevenue('1', 1, 1).estimate_gas()\n", - "# print(gas_estimate)\n", - "\n", - "# r = c.w3.eth.get_block('latest')['baseFeePerGas']\n", - "# print(r)\n", - "\n", - "r = c.lock_revenue('1', 13, 1)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZGRyZXNzIjoiMHhDOTE4MDYxNkIyYjc5NzM4NUFkNjRkMDlCRjg3MzBENzRFM2I1YTQxIiwiZXhwIjoyMDI1NjM1NDUxfQ.gQx1X7nxWWSixUO99YxZO6ry-bhxSnGrL_pm0slxBJM'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "\n", - "from swan import SwanAPI\n", - "\n", - "api_key = os.getenv('API_KEY')\n", - "swan_api = SwanAPI(api_key)\n", - "\n", - "hardwares = swan_api.get_hardware_config()\n", - "price_list = [(hardware.name, hardware.price) for hardware in hardwares]\n", - "print(price_list)\n", - "\n", - "from swan import MCSAPI\n", - "\n", - "api_key = os.getenv('MCS_API_KEY')\n", - "mcs_api = MCSAPI(api_key)\n", - "mcs_api.token\n", - "\n", - "from swan.object import Repository\n", - "\n", - "repo = Repository()\n", - "\n", - "# Add local directory\n", - "repo.add_local_dir('./api')\n", - "\n", - "# Upload Directory to MCS\n", - "repo.upload_local_to_mcs('swan_test', 'mar8t2', mcs_api)\n", - "\n", - "response = repo.generate_source_uri('swan_test', 'mar8s1', './source.json', mcs_client = mcs_api)\n", - "\n", - "repo.source_uri" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'Repository' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[1;32mIn[1], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m source \u001b[38;5;241m=\u001b[39m \u001b[43mRepository\u001b[49m()\n\u001b[0;32m 2\u001b[0m source\u001b[38;5;241m.\u001b[39mmcs_connection(mcs_api)\n\u001b[0;32m 4\u001b[0m \u001b[38;5;66;03m# Add MCS folder\u001b[39;00m\n", - "\u001b[1;31mNameError\u001b[0m: name 'Repository' is not defined" - ] - } - ], - "source": [ - "source = Repository()\n", - "source.mcs_connection(mcs_api)\n", - "\n", - "# Add MCS folder\n", - "source.update_bucket_info('swan_test', 'march4t4')\n", - "\n", - "# Get source URI\n", - "response = source.generate_source_uri('swan_test', 'mar1s2', './source.json', mcs_client=mcs_api)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "gmP5D6yRr8\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxMTU5NjYzOSwianRpIjoiMDY0NGI3MmEtM2I5OC00ZWEyLTk2NTgtNDYzMTM3ZTI1M2Q5IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IjB4NjFjM2UwM2RiZWQ1NWY1REUyMTM3MzJlODE2RjhBOEZkNkU5YmZGMCIsIm5iZiI6MTcxMTU5NjYzOSwiY3NyZiI6Ijk0MzJmOGUzLWQxYzEtNDgwZS05ZmFiLWIyZTAzNmFhN2M5NyIsImV4cCI6MTcxNDE4ODYzOX0.ja7LPcp6uulYsRCt_BQL4ahvpayMP8PFtt3boNWF2A4\n", - "{'data': {'task': {'created_at': '1711596643', 'end_at': '1711633839', 'leading_job_id': None, 'status': 'created', 'task_detail_cid': 'https://data.mcs.lagrangedao.org/ipfs/QmaPqdVdmRJX7sos7whFhK7Da3XxzKt98UNYdata7o6zUo', 'updated_at': '1711596643', 'uuid': 'bf0093da-4489-412d-82df-b418cce5dba5'}}, 'message': 'Task_uuid created.', 'status': 'success'}\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "\n", - "api_key = os.getenv('API_KEY')\n", - "print(api_key)\n", - "\n", - "# Test login \n", - "from swan import SwanAPI\n", - "\n", - "client = SwanAPI(api_key)\n", - "print(client.token)\n", - "\n", - "n = os.getenv('NAME')\n", - "r = os.getenv('REGION')\n", - "s = os.getenv('START')\n", - "d = os.getenv('DURATION')\n", - "u = os.getenv('SOURCE')\n", - "w = os.getenv('WALLET')\n", - "t = os.getenv('TX')\n", - "r = client.deploy_task(n, r, s, d, u, w, t, 10)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': {'computing_providers': [{'allowed_nodes': None, 'autobid': 1, 'city': 'Richmond', 'country': None, 'created_at': '1706081835', 'deleted_at': None, 'last_active_at': None, 'lat': 37.5147, 'lon': -77.5034, 'multi_address': '/ip4/207.254.208.84/tcp/8085', 'name': 'meta.crosschain.computer', 'node_id': '049669a235dc8c2d9532903d9683ac44c02a6d2a4185efde76305f768b7cea32726f4c9b241bfc9ed6c62d4edb3694311c41ecc906c50062891d323553f0fc73f4', 'online': True, 'public_address': '0xFbc1d38a2127D81BFe3EA347bec7310a1cfa2373', 'region': 'North Carolina-US', 'score': 100, 'status': 'Active', 'updated_at': '1712154366'}, {'allowed_nodes': None, 'autobid': 1, 'city': 'Richmond', 'country': None, 'created_at': '1706081577', 'deleted_at': None, 'last_active_at': None, 'lat': 37.5147, 'lon': -77.5034, 'multi_address': '/ip4/207.254.208.84/tcp/8088', 'name': 'computing.nebulablock.com', 'node_id': '0431d0a54e995fc8bb45fdb082b7a60cf84137b67e3939942d8b3b2ef04ea407531bc9fe41d157d1251d46fa8f95eab34c3cf48e110fdac50aae352a1634a9ad40', 'online': True, 'public_address': '0xFbc1d38a2127D81BFe3EA347bec7310a1cfa2373', 'region': 'North Carolina-US', 'score': 100, 'status': 'Active', 'updated_at': '1712154359'}, {'allowed_nodes': None, 'autobid': 1, 'city': 'Richmond', 'country': None, 'created_at': '1706081318', 'deleted_at': None, 'last_active_at': None, 'lat': 37.5147, 'lon': -77.5034, 'multi_address': '/ip4/207.254.208.84/tcp/8092', 'name': 'computing.fogmeta.com', 'node_id': '0485e73d7293125d58ac2b6106c4949d6e447d128d24b5ef6fad64247f901b02b505b095b076753a85d276bce133dbf1da4c43f405ff44e9b70004d5f98df0b6c8', 'online': True, 'public_address': '0xFbc1d38a2127D81BFe3EA347bec7310a1cfa2373', 'region': 'North Carolina-US', 'score': 100, 'status': 'Active', 'updated_at': '1712154354'}], 'jobs': [{'bidder_id': '049669a235dc8c2d9532903d9683ac44c02a6d2a4185efde76305f768b7cea32726f4c9b241bfc9ed6c62d4edb3694311c41ecc906c50062891d323553f0fc73f4', 'build_log': 'wss://log.meta.crosschain.computer:8085/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=build', 'container_log': 'wss://log.meta.crosschain.computer:8085/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=container', 'created_at': '1711596659', 'duration': 36000, 'ended_at': '1711633839', 'hardware': 'C1ae.small', 'job_real_uri': 'https://6nba9kx8o3.meta.crosschain.computer', 'job_result_uri': 'https://42f6d9f62851.acl.swanipfs.com/ipfs/QmPmkxK32gsuLryKH7vXix54SaLkf6cKF3RuLdUoApdoCf', 'job_source_uri': 'https://plutotest.acl.swanipfs.com/ipfs/QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw', 'name': 'Job-823a6b79-9ea3-4276-9119-8423d9de26ad', 'start_at': '1711597839', 'status': 'Cancelled', 'storage_source': 'lagrange', 'task_uuid': 'bf0093da-4489-412d-82df-b418cce5dba5', 'updated_at': '1711633902', 'uuid': '823a6b79-9ea3-4276-9119-8423d9de26ad'}, {'bidder_id': '0431d0a54e995fc8bb45fdb082b7a60cf84137b67e3939942d8b3b2ef04ea407531bc9fe41d157d1251d46fa8f95eab34c3cf48e110fdac50aae352a1634a9ad40', 'build_log': 'wss://log.computing.nebulablock.com:8088/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=build', 'container_log': 'wss://log.computing.nebulablock.com:8088/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=container', 'created_at': '1711596666', 'duration': 36000, 'ended_at': '1711633839', 'hardware': 'C1ae.small', 'job_real_uri': 'https://xgl2yunbz4.computing.nebulablock.com', 'job_result_uri': 'https://42f6d9f62851.acl.swanipfs.com/ipfs/QmQ2yumTasxNjk5WWzeZzDQLYpzcsK1o7iUvZ1kn6mtgRP', 'job_source_uri': 'https://plutotest.acl.swanipfs.com/ipfs/QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw', 'name': 'Job-45a01e47-a047-4d33-8e5a-e27b4f967dc7', 'start_at': '1711597839', 'status': 'Cancelled', 'storage_source': 'lagrange', 'task_uuid': 'bf0093da-4489-412d-82df-b418cce5dba5', 'updated_at': '1711633906', 'uuid': '45a01e47-a047-4d33-8e5a-e27b4f967dc7'}, {'bidder_id': '0485e73d7293125d58ac2b6106c4949d6e447d128d24b5ef6fad64247f901b02b505b095b076753a85d276bce133dbf1da4c43f405ff44e9b70004d5f98df0b6c8', 'build_log': 'wss://log.computing.fogmeta.com:8092/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=build', 'container_log': 'wss://log.computing.fogmeta.com:8092/api/v1/computing/lagrange/spaces/log?space_id=QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw&type=container', 'created_at': '1711596672', 'duration': 36000, 'ended_at': '1711633839', 'hardware': 'C1ae.small', 'job_real_uri': 'https://3zy5fntwyh.computing.fogmeta.com', 'job_result_uri': 'https://42f6d9f62851.acl.swanipfs.com/ipfs/QmajtnUeNZgdhpn1yZkbteaJibF3eNQQUcX23aqcNAzYeR', 'job_source_uri': 'https://plutotest.acl.swanipfs.com/ipfs/QmPsBv8jYgosyq6x8EWkcK3659b66QvXhhEUVP5ar6mhJw', 'name': 'Job-b9224b4e-be85-4230-ac49-338fd1fdcdf7', 'start_at': '1711597839', 'status': 'Cancelled', 'storage_source': 'lagrange', 'task_uuid': 'bf0093da-4489-412d-82df-b418cce5dba5', 'updated_at': '1711597890', 'uuid': 'b9224b4e-be85-4230-ac49-338fd1fdcdf7'}], 'task': {'created_at': '1711596643', 'end_at': '1711633839', 'leading_job_id': '823a6b79-9ea3-4276-9119-8423d9de26ad', 'status': 'finished', 'task_detail_cid': 'https://data.mcs.lagrangedao.org/ipfs/QmaPqdVdmRJX7sos7whFhK7Da3XxzKt98UNYdata7o6zUo', 'updated_at': '1711633906', 'uuid': 'bf0093da-4489-412d-82df-b418cce5dba5'}}, 'message': \"fetch task info for task_uuid='bf0093da-4489-412d-82df-b418cce5dba5' successfully\", 'status': 'success'}\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "api_key = os.getenv('API_KEY')\n", - "# Test login \n", - "from swan import SwanAPI\n", - "client = SwanAPI(api_key)\n", - "\n", - "id = os.getenv('TASK')\n", - "r = client.get_deployment_info(id)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n" - ] - } - ], - "source": [ - "r = client.get_deployment_info_json(id, './result.json')\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['https://6nba9kx8o3.meta.crosschain.computer', 'https://xgl2yunbz4.computing.nebulablock.com', 'https://3zy5fntwyh.computing.fogmeta.com']\n" - ] - } - ], - "source": [ - "r = client.get_real_url(id)\n", - "print(r)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "https://plutotest.acl.swanipfs.com/ipfs/QmdVrZFDRUkmAk8DuRGcfNc6WrK2kYeojVVo745Z5QSNGA\n" - ] - } - ], - "source": [ - "print(source.source_uri)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('C1ae.small', '0.0'), ('C1ae.medium', '1.0'), ('M1ae.small', '2.0'), ('M1ae.medium', '3.0'), ('M1ae.large', '4.0'), ('M1ae.xlarge', '5.0'), ('M1ae.2xlarge', '6.0'), ('M1ae.3xlarge', '6.5'), ('M2ae.small', '7.0'), ('M2ae.medium', '8.0'), ('M2ae.large', '8.5'), ('M2ae.xlarge', '9.0'), ('G1ae.small', '10.0'), ('G1ae.medium', '11.0'), ('G1ae.large', '12.0'), ('G1ae.xlarge', '13.0'), ('G2ae.small', '9.0'), ('G2ae.medium', '10.0'), ('G2ae.large', '11.0'), ('G2ae.lxarge', '12.0'), ('Hpc1ae.small', '14.0'), ('Hpc1ae.medium', '16.0'), ('Hpc1ae.large', '18.0'), ('Hpc1ae.xlarge', '20.0'), ('Hpc1ae.2xlarge', '21.0'), ('Hpc1ae.3xlarge', '21.0'), ('T1ae.small', '32.0'), ('T1ae.medium', '36.0'), ('T1ae.large', '40.0'), ('T1ae.xlarge', '42.0'), ('T1ae.2xlarge', '48.0'), ('T1ae.3xlarge', '50.0'), ('Hpc2ae.small', '22.0'), ('Hpc2ae.medium', '24.0'), ('Hpc2ae.large', '26.0'), ('Hpc2ae.xlarge', '28.0'), ('P1ae.small', '30.0'), ('P1ae.medium', '32.0'), ('P1ae.large', '40.0'), ('P1ae.xlarge', '45.0'), ('T1az.large', '52.0'), ('T1az.xlarge', '55.0'), ('T1az.2xlarge', '60.0'), ('T1az.3xlarge', '62.0'), ('T1az.4xlarge', '65.0'), ('T1az.5xlarge', '68.0'), ('T1az.6xlarge', '70.0'), ('T1az.7xlarge', '72.0'), ('T1az.8xlarge', '75.0'), ('T1az.9xlarge', '90.0'), ('T1az.10xlarge', '80.0'), ('T2az.large', '62.0'), ('T2az.xlarge', '65.0'), ('T2az.2xlarge', '70.0'), ('T2az.3xlarge', '72.0'), ('T2az.4xlarge', '75.0'), ('T2az.5xlarge', '78.0'), ('T2az.6xlarge', '80.0'), ('T2az.7xlarge', '82.0'), ('T2az.8xlarge', '85.0'), ('T2az.9xlarge', '100.0'), ('T2az.10xlarge', '90.0'), ('Hpc2ad.small', '16.0'), ('Hpc2ad.medium', '18.0'), ('Hpc2ad.large', '20.0'), ('Hpc2ad.xlarge', '21.0'), ('Hpc2ad.1xlarge', '22.0'), ('Hpc2az.small', '21.0'), ('Hpc2az.medium', '23.0'), ('Hpc2az.large', '25.0'), ('Hpc2az.xlarge', '26.0'), ('Hpc2az.1xlarge', '27.0'), ('R1ae.small', '12.0'), ('R1ae.medium', '22.0'), ('R1ae.large', '30.0'), ('R2ae.small', '35.0'), ('R2ae.medium', '38.0'), ('R2ae.large', '50.0'), ('R2ae.xlarge', '52.0'), ('R2ae.1xlarge', '54.0'), ('R2ae.2xlarge', '56.0'), ('R2ae.3xlarge', '58.0')]\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "mar8s2: 0%| | 0.00/994 [00:00" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "client.upload_file('swan_test', 'mar4test/dev_test.ipynb', 'dev_test.ipynb')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': {'files': []}}\n" - ] - } - ], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "from swan.common.utils import datetime_to_unixtime, object_to_filename\n", - "from swan.object.source_uri import SourceFilesInfo\n", - "\n", - "# r = datetime_to_unixtime('2024-03-01T22:13:23Z')\n", - "# print(r)\n", - "\n", - "# r1, r2 = object_to_filename('mine\\\\file\\\\whatever')\n", - "# print(f'dir: {r1}, file: {r2}')\n", - "\n", - "s = SourceFilesInfo()\n", - "s.mcs_connection(client)\n", - "\n", - "s.add_folder(\"swan_test\", \"\")\n", - "\n", - "print(s.to_dict())" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "mcs_ak = os.getenv('MCS_API_KEY')\n", - "\n", - "from swan import MCSAPI\n", - "client = MCSAPI(mcs_ak)\n", - "\n", - "from swan.object.source_uri import Repository\n", - "\n", - "repo = Repository()\n", - "repo.add_local_dir('./api')" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "res = repo.upload_local_to_mcs(\"swan_test\", \"march4t4\", client)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "swan_test\n", - "march4t4\n" - ] - } - ], - "source": [ - "print(repo.bucket)\n", - "print(repo.path)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "init.py: 270B [00:05, 49.4B/s] \n" - ] - } - ], - "source": [ - "# print(f'{repo.bucket}, {repo.path}')\n", - "# client.upload_file(\"swan_test\", \"march4t4/init.py\", \"./__init__.py\")\n", - "res = repo.generate_source_uri(\"swan_test\", \"mar1s2\", \"test.json\", mcs_client=client)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "https://plutotest.acl.swanipfs.com/ipfs/QmdVrZFDRUkmAk8DuRGcfNc6WrK2kYeojVVo745Z5QSNGA\n" - ] - } - ], - "source": [ - "print(repo.source_uri)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['mar1s2', 'march4t2\\\\test_swan_api.py', 'march4t2', 'march4t1\\\\test_swan_api.py', 'march4t1']\n", - "['https://plutotest.acl.swanipfs.com/ipfs/QmY5fFEFdPkfA2wmNgxPLhsZkMAmLrWQvijYZdCuUHAytf', 'https://plutotest.acl.swanipfs.com/ipfs/QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', 'https://plutotest.acl.swanipfs.com/ipfs/', 'https://plutotest.acl.swanipfs.com/ipfs/QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', 'https://plutotest.acl.swanipfs.com/ipfs/']\n", - "['2024-03-04T21:35:18Z', '2024-03-04T21:30:31Z', '2024-03-04T21:30:30Z', '2024-03-04T21:27:47Z', '2024-03-04T21:27:46Z']\n", - "['QmY5fFEFdPkfA2wmNgxPLhsZkMAmLrWQvijYZdCuUHAytf', 'QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', '', 'QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', '']\n", - "[False, False, True, False, True]\n", - "{'data': {'files': [{'cid': 'QmY5fFEFdPkfA2wmNgxPLhsZkMAmLrWQvijYZdCuUHAytf', 'created_at': 1709606118.0, 'name': 'mar1s2', 'updated_at': 1709606118.0, 'url': 'https://plutotest.acl.swanipfs.com/ipfs/QmY5fFEFdPkfA2wmNgxPLhsZkMAmLrWQvijYZdCuUHAytf'}, {'cid': 'QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', 'created_at': 1709605831.0, 'name': 'march4t2\\\\test_swan_api.py', 'updated_at': 1709605831.0, 'url': 'https://plutotest.acl.swanipfs.com/ipfs/QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD'}, {'cid': 'QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD', 'created_at': 1709605667.0, 'name': 'march4t1\\\\test_swan_api.py', 'updated_at': 1709605667.0, 'url': 'https://plutotest.acl.swanipfs.com/ipfs/QmcwvuhugPXeiTxD6L9RGs9pC5DqN8SZ36TZasdGE2vqeD'}]}}\n" - ] - } - ], - "source": [ - "files = client._get_full_file_list(bucket_name=repo.bucket, prefix=repo.path)\n", - "print([file.object_name for file in files])\n", - "print([file.ipfs_url for file in files])\n", - "print([file.created_at for file in files])\n", - "print([file.payloadCid for file in files])\n", - "print([file.is_folder for file in files])\n", - "\n", - "from swan.object.source_uri import SourceFilesInfo\n", - "\n", - "s = SourceFilesInfo()\n", - "s.mcs_connection(client)\n", - "s.add_folder(\"swan_test\", \"\")\n", - "print(s.to_dict())" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/test/nsfw_test.py b/test/nsfw_test.py deleted file mode 100644 index d6ba3ee6..00000000 --- a/test/nsfw_test.py +++ /dev/null @@ -1,10 +0,0 @@ -import sys -sys.path.insert(0, '..') - -import os -from dotenv import load_dotenv -load_dotenv() - -api_key = os.getenv('API_KEY') - - diff --git a/test/source.json b/test/source.json deleted file mode 100644 index 11993453..00000000 --- a/test/source.json +++ /dev/null @@ -1 +0,0 @@ -{"data": {"files": [{"cid": "68bc17f9ff2104a9d7b6777058bb4c343ca72609", "created_at": null, "name": "ZihangChenNBAI/hello/main/.gitignore", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/.gitignore"}, {"cid": "6631425230a9a1db084374f990d0640aec1f9952", "created_at": null, "name": "ZihangChenNBAI/hello/main/Dockerfile", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/Dockerfile"}, {"cid": "f4d71977a9fdc266f84d94b74aa391a04880bbd8", "created_at": null, "name": "ZihangChenNBAI/hello/main/LICENSE", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/LICENSE"}, {"cid": "2de669ef819ed4c3f5c696080d67d6603f987aaa", "created_at": null, "name": "ZihangChenNBAI/hello/main/README.md", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/README.md"}, {"cid": "0e13864fe8c5476f1acf5a37323ae9360361f500", "created_at": null, "name": "ZihangChenNBAI/hello/main/app.py", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/app.py"}, {"cid": "72f88c115dbb0d27fd4ee3063f4032336ced7301", "created_at": null, "name": "ZihangChenNBAI/hello/main/requirements.txt", "updated_at": null, "url": "https://raw.githubusercontent.com/ZihangChenNBAI/hello/main/requirements.txt"}], "owner": {"public_address": "0x61c3e03dbed55f5DE213732e816F8A8Fd6E9bfF0"}, "space": {"activeOrder": {"config": {"description": "CPU only \u00b7 2 vCPU \u00b7 2 GiB", "hardware": "CPU only", "hardware_id": 0, "hardware_type": "CPU", "memory": 2, "name": "C1ae.small", "price_per_hour": 0.0, "vcpu": 2}}, "name": "hello", "uuid": "4ce1ebea-2474-45ab-a7d9-21a912d75061"}}} \ No newline at end of file