fal 1.7.5__tar.gz → 1.7.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fal might be problematic. Click here for more details.
- {fal-1.7.5/fal.egg-info → fal-1.7.7}/PKG-INFO +4 -2
- {fal-1.7.5 → fal-1.7.7}/README.md +3 -1
- {fal-1.7.5 → fal-1.7.7/fal.egg-info}/PKG-INFO +4 -2
- {fal-1.7.5 → fal-1.7.7}/src/fal/_fal_version.py +2 -2
- {fal-1.7.5 → fal-1.7.7}/src/fal/app.py +5 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/providers/fal.py +326 -10
- {fal-1.7.5 → fal-1.7.7}/.gitignore +0 -0
- {fal-1.7.5 → fal-1.7.7}/Makefile +0 -0
- {fal-1.7.5 → fal-1.7.7}/docs/conf.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/docs/index.rst +0 -0
- {fal-1.7.5 → fal-1.7.7}/fal.egg-info/SOURCES.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/fal.egg-info/dependency_links.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/fal.egg-info/entry_points.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/fal.egg-info/requires.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/fal.egg-info/top_level.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/README.md +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/applications/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/applications/app_metadata.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/billing/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/billing/get_user_details.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/create_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/delete_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/get_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/list_user_workflows.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/comfy/update_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/files/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/files/check_dir_hash.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/files/upload_local_file.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/users/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/users/get_current_user.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/create_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/delete_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/get_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/update_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/client.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/errors.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/app_metadata_response_app_metadata.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/body_upload_local_file.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_detail.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_item.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs_dev_info.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/current_user.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/customer_details.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/hash_check.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/http_validation_error.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/lock_reason.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/page_workflow_item.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/team_role.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/typed_workflow_update.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/user_member.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/validation_error.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_nodes.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_item.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_node.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_node_type.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_input.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_schema_output.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/py.typed +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/types.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/pyproject.toml +0 -0
- {fal-1.7.5 → fal-1.7.7}/openapi_rest.config.yaml +0 -0
- {fal-1.7.5 → fal-1.7.7}/pyproject.toml +0 -0
- {fal-1.7.5 → fal-1.7.7}/setup.cfg +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/__main__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/_serialization.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/_version.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/api.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/apps.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/auth/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/auth/auth0.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/auth/local.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/_utils.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/apps.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/auth.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/create.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/debug.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/deploy.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/doctor.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/keys.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/main.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/parser.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/run.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/runners.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/cli/secrets.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/config.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/console/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/console/icons.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/console/ux.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/container.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/exceptions/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/exceptions/_base.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/exceptions/_cuda.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/exceptions/auth.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/files.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/flags.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/logging/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/logging/isolate.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/logging/style.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/logging/trace.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/logging/user.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/py.typed +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/rest_client.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/sdk.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/sync.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/exceptions.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/file.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/providers/gcp.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/providers/r2.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/providers/s3.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/file/types.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/image.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/nsfw_filter/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/nsfw_filter/env.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/nsfw_filter/inference.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/nsfw_filter/model.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/nsfw_filter/requirements.txt +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/image/safety_checker.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/optimize.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/types.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/utils/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/utils/download_utils.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/toolkit/utils/retry.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/utils.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/src/fal/workflows.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/assets/cat.png +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_apps.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_auth.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_deploy.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_keys.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_run.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/cli/test_secrets.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/conftest.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/integration_test.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/mainify_package/__init__.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/mainify_package/impl.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/mainify_package/utils.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/mainify_target.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/test_apps.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/test_stability.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/toolkit/file_test.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/toolkit/image_test.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/toolkit/test_types.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tests/toolkit/utils/retry.py +0 -0
- {fal-1.7.5 → fal-1.7.7}/tools/demo_script.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.7
|
|
4
4
|
Summary: fal is an easy-to-use Serverless Python Framework
|
|
5
5
|
Author: Features & Labels <support@fal.ai>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -64,11 +64,13 @@ With fal, you can build pipelines, serve ML models and scale them up to many use
|
|
|
64
64
|
## Quickstart
|
|
65
65
|
|
|
66
66
|
First, you need to install the `fal` package. You can do so using pip:
|
|
67
|
+
|
|
67
68
|
```shell
|
|
68
69
|
pip install fal
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
Then you need to authenticate:
|
|
73
|
+
|
|
72
74
|
```shell
|
|
73
75
|
fal auth login
|
|
74
76
|
```
|
|
@@ -117,7 +119,7 @@ pytest
|
|
|
117
119
|
|
|
118
120
|
### Pre-commit
|
|
119
121
|
|
|
120
|
-
```
|
|
122
|
+
```bash
|
|
121
123
|
cd projects/fal
|
|
122
124
|
pre-commit install
|
|
123
125
|
```
|
|
@@ -10,11 +10,13 @@ With fal, you can build pipelines, serve ML models and scale them up to many use
|
|
|
10
10
|
## Quickstart
|
|
11
11
|
|
|
12
12
|
First, you need to install the `fal` package. You can do so using pip:
|
|
13
|
+
|
|
13
14
|
```shell
|
|
14
15
|
pip install fal
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
Then you need to authenticate:
|
|
19
|
+
|
|
18
20
|
```shell
|
|
19
21
|
fal auth login
|
|
20
22
|
```
|
|
@@ -63,7 +65,7 @@ pytest
|
|
|
63
65
|
|
|
64
66
|
### Pre-commit
|
|
65
67
|
|
|
66
|
-
```
|
|
68
|
+
```bash
|
|
67
69
|
cd projects/fal
|
|
68
70
|
pre-commit install
|
|
69
71
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fal
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.7
|
|
4
4
|
Summary: fal is an easy-to-use Serverless Python Framework
|
|
5
5
|
Author: Features & Labels <support@fal.ai>
|
|
6
6
|
Requires-Python: >=3.8
|
|
@@ -64,11 +64,13 @@ With fal, you can build pipelines, serve ML models and scale them up to many use
|
|
|
64
64
|
## Quickstart
|
|
65
65
|
|
|
66
66
|
First, you need to install the `fal` package. You can do so using pip:
|
|
67
|
+
|
|
67
68
|
```shell
|
|
68
69
|
pip install fal
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
Then you need to authenticate:
|
|
73
|
+
|
|
72
74
|
```shell
|
|
73
75
|
fal auth login
|
|
74
76
|
```
|
|
@@ -117,7 +119,7 @@ pytest
|
|
|
117
119
|
|
|
118
120
|
### Pre-commit
|
|
119
121
|
|
|
120
|
-
```
|
|
122
|
+
```bash
|
|
121
123
|
cd projects/fal
|
|
122
124
|
pre-commit install
|
|
123
125
|
```
|
|
@@ -374,6 +374,11 @@ class App(fal.api.BaseServable):
|
|
|
374
374
|
@app.middleware("http")
|
|
375
375
|
async def set_request_id(request, call_next):
|
|
376
376
|
# NOTE: Setting request_id is not supported for websocket/realtime endpoints
|
|
377
|
+
if not os.getenv("IS_ISOLATE_AGENT") or not os.environ.get(
|
|
378
|
+
"NOMAD_ALLOC_PORT_grpc"
|
|
379
|
+
):
|
|
380
|
+
# If not running in the expected environment, skip setting request_id
|
|
381
|
+
return await call_next(request)
|
|
377
382
|
|
|
378
383
|
if self.isolate_channel is None:
|
|
379
384
|
grpc_port = os.environ.get("NOMAD_ALLOC_PORT_grpc")
|
|
@@ -190,14 +190,6 @@ class FalFileRepository(FalFileRepositoryBase):
|
|
|
190
190
|
return self._save(file, "gcs")
|
|
191
191
|
|
|
192
192
|
|
|
193
|
-
@dataclass
|
|
194
|
-
class FalFileRepositoryV3(FalFileRepositoryBase):
|
|
195
|
-
def save(
|
|
196
|
-
self, file: FileData, object_lifecycle_preference: dict[str, str] | None = None
|
|
197
|
-
) -> str:
|
|
198
|
-
return self._save(file, "fal-cdn-v3")
|
|
199
|
-
|
|
200
|
-
|
|
201
193
|
class MultipartUpload:
|
|
202
194
|
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
203
195
|
MULTIPART_CHUNK_SIZE = 100 * 1024 * 1024
|
|
@@ -366,6 +358,212 @@ class MultipartUpload:
|
|
|
366
358
|
return multipart.complete()
|
|
367
359
|
|
|
368
360
|
|
|
361
|
+
class MultipartUploadV3:
|
|
362
|
+
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
363
|
+
MULTIPART_CHUNK_SIZE = 10 * 1024 * 1024
|
|
364
|
+
MULTIPART_MAX_CONCURRENCY = 10
|
|
365
|
+
|
|
366
|
+
def __init__(
|
|
367
|
+
self,
|
|
368
|
+
file_name: str,
|
|
369
|
+
chunk_size: int | None = None,
|
|
370
|
+
content_type: str | None = None,
|
|
371
|
+
max_concurrency: int | None = None,
|
|
372
|
+
) -> None:
|
|
373
|
+
self.file_name = file_name
|
|
374
|
+
self.chunk_size = chunk_size or self.MULTIPART_CHUNK_SIZE
|
|
375
|
+
self.content_type = content_type or "application/octet-stream"
|
|
376
|
+
self.max_concurrency = max_concurrency or self.MULTIPART_MAX_CONCURRENCY
|
|
377
|
+
|
|
378
|
+
self._access_url: str | None = None
|
|
379
|
+
self._upload_url: str | None = None
|
|
380
|
+
|
|
381
|
+
self._parts: list[dict] = []
|
|
382
|
+
|
|
383
|
+
@property
|
|
384
|
+
def access_url(self) -> str:
|
|
385
|
+
if not self._access_url:
|
|
386
|
+
raise FileUploadException("Upload not initiated")
|
|
387
|
+
return self._access_url
|
|
388
|
+
|
|
389
|
+
@property
|
|
390
|
+
def upload_url(self) -> str:
|
|
391
|
+
if not self._upload_url:
|
|
392
|
+
raise FileUploadException("Upload not initiated")
|
|
393
|
+
return self._upload_url
|
|
394
|
+
|
|
395
|
+
@property
|
|
396
|
+
def auth_headers(self) -> dict[str, str]:
|
|
397
|
+
fal_key = key_credentials()
|
|
398
|
+
if not fal_key:
|
|
399
|
+
raise FileUploadException("FAL_KEY must be set")
|
|
400
|
+
|
|
401
|
+
key_id, key_secret = fal_key
|
|
402
|
+
return {
|
|
403
|
+
"Authorization": f"Key {key_id}:{key_secret}",
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
def create(self):
|
|
407
|
+
grpc_host = os.environ.get("FAL_HOST", "api.alpha.fal.ai")
|
|
408
|
+
rest_host = grpc_host.replace("api", "rest", 1)
|
|
409
|
+
url = f"https://{rest_host}/storage/upload/initiate-multipart?storage_type=fal-cdn-v3"
|
|
410
|
+
|
|
411
|
+
try:
|
|
412
|
+
req = Request(
|
|
413
|
+
url,
|
|
414
|
+
method="POST",
|
|
415
|
+
headers={
|
|
416
|
+
**self.auth_headers,
|
|
417
|
+
"Accept": "application/json",
|
|
418
|
+
},
|
|
419
|
+
data=json.dumps(
|
|
420
|
+
{
|
|
421
|
+
"file_name": self.file_name,
|
|
422
|
+
"content_type": self.content_type,
|
|
423
|
+
}
|
|
424
|
+
).encode(),
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
with urlopen(req) as response:
|
|
428
|
+
result = json.load(response)
|
|
429
|
+
self._access_url = result["file_url"]
|
|
430
|
+
self._upload_url = result["upload_url"]
|
|
431
|
+
|
|
432
|
+
except HTTPError as exc:
|
|
433
|
+
raise FileUploadException(
|
|
434
|
+
f"Error initiating upload. Status {exc.status}: {exc.reason}"
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
@retry(max_retries=5, base_delay=1, backoff_type="exponential", jitter=True)
|
|
438
|
+
def upload_part(self, part_number: int, data: bytes) -> None:
|
|
439
|
+
parsed = urlparse(self.upload_url)
|
|
440
|
+
part_path = parsed.path + f"/{part_number}"
|
|
441
|
+
url = urlunparse(parsed._replace(path=part_path))
|
|
442
|
+
|
|
443
|
+
req = Request(
|
|
444
|
+
url,
|
|
445
|
+
method="PUT",
|
|
446
|
+
headers={
|
|
447
|
+
"Content-Type": self.content_type,
|
|
448
|
+
},
|
|
449
|
+
data=data,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
with urlopen(req) as resp:
|
|
454
|
+
self._parts.append(
|
|
455
|
+
{
|
|
456
|
+
"partNumber": part_number,
|
|
457
|
+
"etag": resp.headers["ETag"],
|
|
458
|
+
}
|
|
459
|
+
)
|
|
460
|
+
except HTTPError as exc:
|
|
461
|
+
raise FileUploadException(
|
|
462
|
+
f"Error uploading part {part_number} to {url}. "
|
|
463
|
+
f"Status {exc.status}: {exc.reason}"
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
def complete(self) -> str:
|
|
467
|
+
parsed = urlparse(self.upload_url)
|
|
468
|
+
complete_path = parsed.path + "/complete"
|
|
469
|
+
url = urlunparse(parsed._replace(path=complete_path))
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
req = Request(
|
|
473
|
+
url,
|
|
474
|
+
method="POST",
|
|
475
|
+
headers={
|
|
476
|
+
"Accept": "application/json",
|
|
477
|
+
"Content-Type": "application/json",
|
|
478
|
+
},
|
|
479
|
+
data=json.dumps({"parts": self._parts}).encode(),
|
|
480
|
+
)
|
|
481
|
+
with urlopen(req):
|
|
482
|
+
pass
|
|
483
|
+
except HTTPError as e:
|
|
484
|
+
raise FileUploadException(
|
|
485
|
+
f"Error completing upload {url}. Status {e.status}: {e.reason}"
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
return self.access_url
|
|
489
|
+
|
|
490
|
+
@classmethod
|
|
491
|
+
def save(
|
|
492
|
+
cls,
|
|
493
|
+
file: FileData,
|
|
494
|
+
chunk_size: int | None = None,
|
|
495
|
+
max_concurrency: int | None = None,
|
|
496
|
+
):
|
|
497
|
+
import concurrent.futures
|
|
498
|
+
|
|
499
|
+
multipart = cls(
|
|
500
|
+
file.file_name,
|
|
501
|
+
chunk_size=chunk_size,
|
|
502
|
+
content_type=file.content_type,
|
|
503
|
+
max_concurrency=max_concurrency,
|
|
504
|
+
)
|
|
505
|
+
multipart.create()
|
|
506
|
+
|
|
507
|
+
parts = math.ceil(len(file.data) / multipart.chunk_size)
|
|
508
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
509
|
+
max_workers=multipart.max_concurrency
|
|
510
|
+
) as executor:
|
|
511
|
+
futures = []
|
|
512
|
+
for part_number in range(1, parts + 1):
|
|
513
|
+
start = (part_number - 1) * multipart.chunk_size
|
|
514
|
+
data = file.data[start : start + multipart.chunk_size]
|
|
515
|
+
futures.append(
|
|
516
|
+
executor.submit(multipart.upload_part, part_number, data)
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
for future in concurrent.futures.as_completed(futures):
|
|
520
|
+
future.result()
|
|
521
|
+
|
|
522
|
+
return multipart.complete()
|
|
523
|
+
|
|
524
|
+
@classmethod
|
|
525
|
+
def save_file(
|
|
526
|
+
cls,
|
|
527
|
+
file_path: str | Path,
|
|
528
|
+
chunk_size: int | None = None,
|
|
529
|
+
content_type: str | None = None,
|
|
530
|
+
max_concurrency: int | None = None,
|
|
531
|
+
) -> str:
|
|
532
|
+
import concurrent.futures
|
|
533
|
+
|
|
534
|
+
file_name = os.path.basename(file_path)
|
|
535
|
+
size = os.path.getsize(file_path)
|
|
536
|
+
|
|
537
|
+
multipart = cls(
|
|
538
|
+
file_name,
|
|
539
|
+
chunk_size=chunk_size,
|
|
540
|
+
content_type=content_type,
|
|
541
|
+
max_concurrency=max_concurrency,
|
|
542
|
+
)
|
|
543
|
+
multipart.create()
|
|
544
|
+
|
|
545
|
+
parts = math.ceil(size / multipart.chunk_size)
|
|
546
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
547
|
+
max_workers=multipart.max_concurrency
|
|
548
|
+
) as executor:
|
|
549
|
+
futures = []
|
|
550
|
+
for part_number in range(1, parts + 1):
|
|
551
|
+
|
|
552
|
+
def _upload_part(pn: int) -> None:
|
|
553
|
+
with open(file_path, "rb") as f:
|
|
554
|
+
start = (pn - 1) * multipart.chunk_size
|
|
555
|
+
f.seek(start)
|
|
556
|
+
data = f.read(multipart.chunk_size)
|
|
557
|
+
multipart.upload_part(pn, data)
|
|
558
|
+
|
|
559
|
+
futures.append(executor.submit(_upload_part, part_number))
|
|
560
|
+
|
|
561
|
+
for future in concurrent.futures.as_completed(futures):
|
|
562
|
+
future.result()
|
|
563
|
+
|
|
564
|
+
return multipart.complete()
|
|
565
|
+
|
|
566
|
+
|
|
369
567
|
class InternalMultipartUploadV3:
|
|
370
568
|
MULTIPART_THRESHOLD = 100 * 1024 * 1024
|
|
371
569
|
MULTIPART_CHUNK_SIZE = 10 * 1024 * 1024
|
|
@@ -703,6 +901,122 @@ class FalCDNFileRepository(FileRepository):
|
|
|
703
901
|
}
|
|
704
902
|
|
|
705
903
|
|
|
904
|
+
@dataclass
|
|
905
|
+
class FalFileRepositoryV3(FileRepository):
|
|
906
|
+
@property
|
|
907
|
+
def auth_headers(self) -> dict[str, str]:
|
|
908
|
+
fal_key = key_credentials()
|
|
909
|
+
if not fal_key:
|
|
910
|
+
raise FileUploadException("FAL_KEY must be set")
|
|
911
|
+
|
|
912
|
+
key_id, key_secret = fal_key
|
|
913
|
+
return {
|
|
914
|
+
"Authorization": f"Key {key_id}:{key_secret}",
|
|
915
|
+
"User-Agent": "fal/0.1.0",
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
@retry(max_retries=3, base_delay=1, backoff_type="exponential", jitter=True)
|
|
919
|
+
def save(
|
|
920
|
+
self,
|
|
921
|
+
file: FileData,
|
|
922
|
+
multipart: bool | None = None,
|
|
923
|
+
multipart_threshold: int | None = None,
|
|
924
|
+
multipart_chunk_size: int | None = None,
|
|
925
|
+
multipart_max_concurrency: int | None = None,
|
|
926
|
+
object_lifecycle_preference: dict[str, str] | None = None,
|
|
927
|
+
) -> str:
|
|
928
|
+
if multipart is None:
|
|
929
|
+
threshold = multipart_threshold or MultipartUploadV3.MULTIPART_THRESHOLD
|
|
930
|
+
multipart = len(file.data) > threshold
|
|
931
|
+
|
|
932
|
+
if multipart:
|
|
933
|
+
return MultipartUploadV3.save(
|
|
934
|
+
file,
|
|
935
|
+
chunk_size=multipart_chunk_size,
|
|
936
|
+
max_concurrency=multipart_max_concurrency,
|
|
937
|
+
)
|
|
938
|
+
|
|
939
|
+
headers = {
|
|
940
|
+
**self.auth_headers,
|
|
941
|
+
"Accept": "application/json",
|
|
942
|
+
"Content-Type": "application/json",
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
grpc_host = os.environ.get("FAL_HOST", "api.alpha.fal.ai")
|
|
946
|
+
rest_host = grpc_host.replace("api", "rest", 1)
|
|
947
|
+
url = f"https://{rest_host}/storage/upload/initiate?storage_type=fal-cdn-v3"
|
|
948
|
+
|
|
949
|
+
request = Request(
|
|
950
|
+
url,
|
|
951
|
+
headers=headers,
|
|
952
|
+
method="POST",
|
|
953
|
+
data=json.dumps(
|
|
954
|
+
{
|
|
955
|
+
"file_name": file.file_name,
|
|
956
|
+
"content_type": file.content_type,
|
|
957
|
+
}
|
|
958
|
+
).encode(),
|
|
959
|
+
)
|
|
960
|
+
try:
|
|
961
|
+
with urlopen(request) as response:
|
|
962
|
+
result = json.load(response)
|
|
963
|
+
file_url = result["file_url"]
|
|
964
|
+
upload_url = result["upload_url"]
|
|
965
|
+
except HTTPError as e:
|
|
966
|
+
raise FileUploadException(
|
|
967
|
+
f"Error initiating upload. Status {e.status}: {e.reason}"
|
|
968
|
+
)
|
|
969
|
+
|
|
970
|
+
request = Request(
|
|
971
|
+
upload_url,
|
|
972
|
+
headers={"Content-Type": file.content_type},
|
|
973
|
+
method="PUT",
|
|
974
|
+
data=file.data,
|
|
975
|
+
)
|
|
976
|
+
try:
|
|
977
|
+
with urlopen(request):
|
|
978
|
+
pass
|
|
979
|
+
except HTTPError as e:
|
|
980
|
+
raise FileUploadException(
|
|
981
|
+
f"Error uploading file. Status {e.status}: {e.reason}"
|
|
982
|
+
)
|
|
983
|
+
|
|
984
|
+
return file_url
|
|
985
|
+
|
|
986
|
+
def save_file(
|
|
987
|
+
self,
|
|
988
|
+
file_path: str | Path,
|
|
989
|
+
content_type: str,
|
|
990
|
+
multipart: bool | None = None,
|
|
991
|
+
multipart_threshold: int | None = None,
|
|
992
|
+
multipart_chunk_size: int | None = None,
|
|
993
|
+
multipart_max_concurrency: int | None = None,
|
|
994
|
+
object_lifecycle_preference: dict[str, str] | None = None,
|
|
995
|
+
) -> tuple[str, FileData | None]:
|
|
996
|
+
if multipart is None:
|
|
997
|
+
threshold = multipart_threshold or MultipartUploadV3.MULTIPART_THRESHOLD
|
|
998
|
+
multipart = os.path.getsize(file_path) > threshold
|
|
999
|
+
|
|
1000
|
+
if multipart:
|
|
1001
|
+
url = MultipartUploadV3.save_file(
|
|
1002
|
+
file_path,
|
|
1003
|
+
chunk_size=multipart_chunk_size,
|
|
1004
|
+
content_type=content_type,
|
|
1005
|
+
max_concurrency=multipart_max_concurrency,
|
|
1006
|
+
)
|
|
1007
|
+
data = None
|
|
1008
|
+
else:
|
|
1009
|
+
with open(file_path, "rb") as f:
|
|
1010
|
+
data = FileData(
|
|
1011
|
+
f.read(),
|
|
1012
|
+
content_type=content_type,
|
|
1013
|
+
file_name=os.path.basename(file_path),
|
|
1014
|
+
)
|
|
1015
|
+
url = self.save(data, object_lifecycle_preference)
|
|
1016
|
+
|
|
1017
|
+
return url, data
|
|
1018
|
+
|
|
1019
|
+
|
|
706
1020
|
# This is only available for internal users to have long-lived access tokens
|
|
707
1021
|
@dataclass
|
|
708
1022
|
class InternalFalFileRepositoryV3(FileRepository):
|
|
@@ -784,11 +1098,13 @@ class InternalFalFileRepositoryV3(FileRepository):
|
|
|
784
1098
|
object_lifecycle_preference: dict[str, str] | None = None,
|
|
785
1099
|
) -> tuple[str, FileData | None]:
|
|
786
1100
|
if multipart is None:
|
|
787
|
-
threshold =
|
|
1101
|
+
threshold = (
|
|
1102
|
+
multipart_threshold or InternalMultipartUploadV3.MULTIPART_THRESHOLD
|
|
1103
|
+
)
|
|
788
1104
|
multipart = os.path.getsize(file_path) > threshold
|
|
789
1105
|
|
|
790
1106
|
if multipart:
|
|
791
|
-
url =
|
|
1107
|
+
url = InternalMultipartUploadV3.save_file(
|
|
792
1108
|
file_path,
|
|
793
1109
|
chunk_size=multipart_chunk_size,
|
|
794
1110
|
content_type=content_type,
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/Makefile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/api/workflows/list_user_workflows.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_extra_data.py
RENAMED
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_fal_inputs.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/comfy_workflow_schema_prompt.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/page_comfy_workflow_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/typed_comfy_workflow_update.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_contents_output.py
RENAMED
|
File without changes
|
|
File without changes
|
{fal-1.7.5 → fal-1.7.7}/openapi-fal-rest/openapi_fal_rest/models/workflow_detail_contents.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|