flaxflow 1.0.0__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.
- flaxflow-1.0.0/.gitignore +6 -0
- flaxflow-1.0.0/PKG-INFO +158 -0
- flaxflow-1.0.0/README.md +132 -0
- flaxflow-1.0.0/pyproject.toml +44 -0
- flaxflow-1.0.0/scripts/configure-pypi.sh +154 -0
- flaxflow-1.0.0/scripts/generate.sh +28 -0
- flaxflow-1.0.0/scripts/setup-github-repo.sh +98 -0
- flaxflow-1.0.0/src/flaxflow/__init__.py +43 -0
- flaxflow-1.0.0/src/flaxflow/_files.py +78 -0
- flaxflow-1.0.0/src/flaxflow/_generated/__init__.py +5 -0
- flaxflow-1.0.0/src/flaxflow/_generated/models.py +1863 -0
- flaxflow-1.0.0/src/flaxflow/_http.py +146 -0
- flaxflow-1.0.0/src/flaxflow/client.py +74 -0
- flaxflow-1.0.0/src/flaxflow/errors.py +84 -0
- flaxflow-1.0.0/src/flaxflow/py.typed +0 -0
- flaxflow-1.0.0/src/flaxflow/resources/__init__.py +17 -0
- flaxflow-1.0.0/src/flaxflow/resources/_base.py +10 -0
- flaxflow-1.0.0/src/flaxflow/resources/api_keys.py +35 -0
- flaxflow-1.0.0/src/flaxflow/resources/classifiers.py +47 -0
- flaxflow-1.0.0/src/flaxflow/resources/documents.py +107 -0
- flaxflow-1.0.0/src/flaxflow/resources/jobs.py +54 -0
- flaxflow-1.0.0/src/flaxflow/resources/processing.py +98 -0
- flaxflow-1.0.0/src/flaxflow/resources/webhooks.py +58 -0
- flaxflow-1.0.0/tests/test_client.py +153 -0
flaxflow-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flaxflow
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the FlaxFlow Engine API — AI document processing.
|
|
5
|
+
Project-URL: Homepage, https://www.flaxia.com.br
|
|
6
|
+
Project-URL: Documentation, https://www.flaxia.com.br/engine-api
|
|
7
|
+
Project-URL: Source, https://github.com/flaxflow/FlaxFlow.PortalAI.Backend
|
|
8
|
+
Author: FlaxFlow
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: ai,document,extraction,flaxflow,ocr,sdk
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx<1,>=0.27
|
|
20
|
+
Requires-Dist: pydantic<3,>=2
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: datamodel-code-generator>=0.25; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
24
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# flaxflow — Python SDK
|
|
28
|
+
|
|
29
|
+
Official Python SDK for the **FlaxFlow Engine API** — AI-powered document processing
|
|
30
|
+
(extraction, classification, webhooks).
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install flaxflow
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Authentication
|
|
37
|
+
|
|
38
|
+
The SDK authenticates with an **API key** (`sk_...`). Create one in the FlaxFlow app under
|
|
39
|
+
**Settings → API keys**, then pass it to the client or set `FLAXFLOW_API_KEY`.
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from flaxflow import FlaxFlow
|
|
43
|
+
|
|
44
|
+
fx = FlaxFlow(api_key="sk_...") # or FlaxFlow() reading FLAXFLOW_API_KEY
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from flaxflow import FlaxFlow
|
|
51
|
+
|
|
52
|
+
fx = FlaxFlow(api_key="sk_...")
|
|
53
|
+
|
|
54
|
+
# 1. Create a document class from a sample — the AI infers the fields to extract
|
|
55
|
+
doc = fx.documents.create_from_sample("invoice-sample.pdf")
|
|
56
|
+
|
|
57
|
+
# 2. Process a real document against that class
|
|
58
|
+
job = fx.processing.process_document("invoice-001.pdf", document_id=str(doc.document_id))
|
|
59
|
+
print(job.result) # -> {"invoice_number": "123", "total_amount": "99.90", ...}
|
|
60
|
+
|
|
61
|
+
# 3. Or extract with a free-form prompt, no document class needed
|
|
62
|
+
job = fx.processing.process_with_prompt(
|
|
63
|
+
"invoice-001.pdf",
|
|
64
|
+
prompt="Extract invoice number, issue date and total amount",
|
|
65
|
+
)
|
|
66
|
+
print(job.result)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The file argument accepts a **path**, raw **bytes**, or any file-like object. For paths the
|
|
70
|
+
`documentType` is inferred from the extension; otherwise pass `document_type=`.
|
|
71
|
+
|
|
72
|
+
## Resources
|
|
73
|
+
|
|
74
|
+
| Resource | Highlights |
|
|
75
|
+
|----------|------------|
|
|
76
|
+
| `fx.documents` | `create_from_sample`, `create_manual`, `update`, `list`, `delete` |
|
|
77
|
+
| `fx.processing` | `process_document`, `process_with_prompt`, `process_many` |
|
|
78
|
+
| `fx.jobs` | `list`, `get`, `get_batch`, `analytics`, `download_document` |
|
|
79
|
+
| `fx.classifiers` | `create`, `list`, `get`, `update`, `set_models`, `delete` |
|
|
80
|
+
| `fx.webhooks` | `create`, `list`, `update`, `delete`, `delivery_logs` |
|
|
81
|
+
| `fx.api_keys` | `create`, `list`, `delete` |
|
|
82
|
+
|
|
83
|
+
### Batch processing
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
batch = fx.processing.process_many(
|
|
87
|
+
["a.pdf", "b.pdf", "c.pdf"],
|
|
88
|
+
classifier_id="<classifier_id>", # let the classifier pick the right class
|
|
89
|
+
)
|
|
90
|
+
print(batch.batch_id, len(batch.jobs))
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Webhooks
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
hook = fx.webhooks.create("https://example.com/hooks/flaxflow",
|
|
97
|
+
event_types=["job.completed", "job.failed"])
|
|
98
|
+
print(hook.secret) # HMAC-SHA256 signing secret — shown only once
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Error handling
|
|
102
|
+
|
|
103
|
+
Every failure raises a subclass of `FlaxFlowError`:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from flaxflow import FlaxFlow, AuthenticationError, NotFoundError, RateLimitError
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
fx.jobs.get("does-not-exist")
|
|
110
|
+
except NotFoundError:
|
|
111
|
+
...
|
|
112
|
+
except RateLimitError as e:
|
|
113
|
+
print("slow down", e.status_code)
|
|
114
|
+
except AuthenticationError:
|
|
115
|
+
print("check your API key")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
| Option | Default | Env var |
|
|
121
|
+
|--------|---------|---------|
|
|
122
|
+
| `api_key` | – (required) | `FLAXFLOW_API_KEY` |
|
|
123
|
+
| `base_url` | `https://api.flaxia.com.br` | `FLAXFLOW_BASE_URL` |
|
|
124
|
+
| `timeout` | `60` seconds | – |
|
|
125
|
+
|
|
126
|
+
`FlaxFlow` is a context manager — use `with FlaxFlow(...) as fx:` to close the HTTP client
|
|
127
|
+
automatically.
|
|
128
|
+
|
|
129
|
+
## Types
|
|
130
|
+
|
|
131
|
+
Response objects are [pydantic](https://docs.pydantic.dev) models generated from the API's
|
|
132
|
+
OpenAPI spec, so you get full editor autocompletion and validation. Field names are
|
|
133
|
+
`snake_case` in Python (the wire format stays `camelCase`).
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
python -m venv .venv && source .venv/bin/activate
|
|
139
|
+
pip install -e ".[dev]"
|
|
140
|
+
bash scripts/generate.sh # regenerate models from ../openapi.json
|
|
141
|
+
pytest
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Publishing (maintainers)
|
|
145
|
+
|
|
146
|
+
Configure o token PyPI no GitHub (uma vez):
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
bash scripts/configure-pypi.sh # cole o token pypi-...
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Push em `main` com mudanças nesta pasta publica automaticamente a versão em
|
|
153
|
+
`pyproject.toml`. Antes de cada release, aumente `version` (ex.: `1.0.1`).
|
|
154
|
+
|
|
155
|
+
The generated models live in `src/flaxflow/_generated/` and are produced from
|
|
156
|
+
`sdks/openapi.json` (exported from the backend via `cargo run --bin export_openapi`).
|
|
157
|
+
|
|
158
|
+
> Async support (`AsyncFlaxFlow`) is planned. The sync client is fully featured today.
|
flaxflow-1.0.0/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# flaxflow — Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the **FlaxFlow Engine API** — AI-powered document processing
|
|
4
|
+
(extraction, classification, webhooks).
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install flaxflow
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Authentication
|
|
11
|
+
|
|
12
|
+
The SDK authenticates with an **API key** (`sk_...`). Create one in the FlaxFlow app under
|
|
13
|
+
**Settings → API keys**, then pass it to the client or set `FLAXFLOW_API_KEY`.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from flaxflow import FlaxFlow
|
|
17
|
+
|
|
18
|
+
fx = FlaxFlow(api_key="sk_...") # or FlaxFlow() reading FLAXFLOW_API_KEY
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from flaxflow import FlaxFlow
|
|
25
|
+
|
|
26
|
+
fx = FlaxFlow(api_key="sk_...")
|
|
27
|
+
|
|
28
|
+
# 1. Create a document class from a sample — the AI infers the fields to extract
|
|
29
|
+
doc = fx.documents.create_from_sample("invoice-sample.pdf")
|
|
30
|
+
|
|
31
|
+
# 2. Process a real document against that class
|
|
32
|
+
job = fx.processing.process_document("invoice-001.pdf", document_id=str(doc.document_id))
|
|
33
|
+
print(job.result) # -> {"invoice_number": "123", "total_amount": "99.90", ...}
|
|
34
|
+
|
|
35
|
+
# 3. Or extract with a free-form prompt, no document class needed
|
|
36
|
+
job = fx.processing.process_with_prompt(
|
|
37
|
+
"invoice-001.pdf",
|
|
38
|
+
prompt="Extract invoice number, issue date and total amount",
|
|
39
|
+
)
|
|
40
|
+
print(job.result)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The file argument accepts a **path**, raw **bytes**, or any file-like object. For paths the
|
|
44
|
+
`documentType` is inferred from the extension; otherwise pass `document_type=`.
|
|
45
|
+
|
|
46
|
+
## Resources
|
|
47
|
+
|
|
48
|
+
| Resource | Highlights |
|
|
49
|
+
|----------|------------|
|
|
50
|
+
| `fx.documents` | `create_from_sample`, `create_manual`, `update`, `list`, `delete` |
|
|
51
|
+
| `fx.processing` | `process_document`, `process_with_prompt`, `process_many` |
|
|
52
|
+
| `fx.jobs` | `list`, `get`, `get_batch`, `analytics`, `download_document` |
|
|
53
|
+
| `fx.classifiers` | `create`, `list`, `get`, `update`, `set_models`, `delete` |
|
|
54
|
+
| `fx.webhooks` | `create`, `list`, `update`, `delete`, `delivery_logs` |
|
|
55
|
+
| `fx.api_keys` | `create`, `list`, `delete` |
|
|
56
|
+
|
|
57
|
+
### Batch processing
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
batch = fx.processing.process_many(
|
|
61
|
+
["a.pdf", "b.pdf", "c.pdf"],
|
|
62
|
+
classifier_id="<classifier_id>", # let the classifier pick the right class
|
|
63
|
+
)
|
|
64
|
+
print(batch.batch_id, len(batch.jobs))
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Webhooks
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
hook = fx.webhooks.create("https://example.com/hooks/flaxflow",
|
|
71
|
+
event_types=["job.completed", "job.failed"])
|
|
72
|
+
print(hook.secret) # HMAC-SHA256 signing secret — shown only once
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Error handling
|
|
76
|
+
|
|
77
|
+
Every failure raises a subclass of `FlaxFlowError`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from flaxflow import FlaxFlow, AuthenticationError, NotFoundError, RateLimitError
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
fx.jobs.get("does-not-exist")
|
|
84
|
+
except NotFoundError:
|
|
85
|
+
...
|
|
86
|
+
except RateLimitError as e:
|
|
87
|
+
print("slow down", e.status_code)
|
|
88
|
+
except AuthenticationError:
|
|
89
|
+
print("check your API key")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Configuration
|
|
93
|
+
|
|
94
|
+
| Option | Default | Env var |
|
|
95
|
+
|--------|---------|---------|
|
|
96
|
+
| `api_key` | – (required) | `FLAXFLOW_API_KEY` |
|
|
97
|
+
| `base_url` | `https://api.flaxia.com.br` | `FLAXFLOW_BASE_URL` |
|
|
98
|
+
| `timeout` | `60` seconds | – |
|
|
99
|
+
|
|
100
|
+
`FlaxFlow` is a context manager — use `with FlaxFlow(...) as fx:` to close the HTTP client
|
|
101
|
+
automatically.
|
|
102
|
+
|
|
103
|
+
## Types
|
|
104
|
+
|
|
105
|
+
Response objects are [pydantic](https://docs.pydantic.dev) models generated from the API's
|
|
106
|
+
OpenAPI spec, so you get full editor autocompletion and validation. Field names are
|
|
107
|
+
`snake_case` in Python (the wire format stays `camelCase`).
|
|
108
|
+
|
|
109
|
+
## Development
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
python -m venv .venv && source .venv/bin/activate
|
|
113
|
+
pip install -e ".[dev]"
|
|
114
|
+
bash scripts/generate.sh # regenerate models from ../openapi.json
|
|
115
|
+
pytest
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Publishing (maintainers)
|
|
119
|
+
|
|
120
|
+
Configure o token PyPI no GitHub (uma vez):
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
bash scripts/configure-pypi.sh # cole o token pypi-...
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Push em `main` com mudanças nesta pasta publica automaticamente a versão em
|
|
127
|
+
`pyproject.toml`. Antes de cada release, aumente `version` (ex.: `1.0.1`).
|
|
128
|
+
|
|
129
|
+
The generated models live in `src/flaxflow/_generated/` and are produced from
|
|
130
|
+
`sdks/openapi.json` (exported from the backend via `cargo run --bin export_openapi`).
|
|
131
|
+
|
|
132
|
+
> Async support (`AsyncFlaxFlow`) is planned. The sync client is fully featured today.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "flaxflow"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Official Python SDK for the FlaxFlow Engine API — AI document processing."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "FlaxFlow" }]
|
|
13
|
+
keywords = ["flaxflow", "document", "ai", "ocr", "extraction", "sdk"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.10",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"httpx>=0.27,<1",
|
|
25
|
+
"pydantic>=2,<3",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest>=8",
|
|
31
|
+
"respx>=0.21",
|
|
32
|
+
"datamodel-code-generator>=0.25",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://www.flaxia.com.br"
|
|
37
|
+
Documentation = "https://www.flaxia.com.br/engine-api"
|
|
38
|
+
Source = "https://github.com/flaxflow/FlaxFlow.PortalAI.Backend"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/flaxflow"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Configura o secret PYPI_API_TOKEN no GitHub para publicação automática do SDK.
|
|
3
|
+
#
|
|
4
|
+
# Repo: flaxflow/FlaxFlow.PortalAI.Backend
|
|
5
|
+
#
|
|
6
|
+
# Uso:
|
|
7
|
+
# bash scripts/configure-pypi.sh # interativo
|
|
8
|
+
# bash scripts/configure-pypi.sh pypi-xxx # token como argumento
|
|
9
|
+
# bash scripts/configure-pypi.sh pypi-xxx --repo owner/repo
|
|
10
|
+
# FLAXFLOW_GITHUB_REPO=owner/repo bash scripts/configure-pypi.sh
|
|
11
|
+
#
|
|
12
|
+
# Pré-requisitos: GitHub CLI (gh) autenticado — brew install gh && gh auth login
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
+
SDK_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
|
+
DEFAULT_REPO="flaxflow/FlaxFlow.PortalAI.Backend"
|
|
18
|
+
|
|
19
|
+
usage() {
|
|
20
|
+
sed -n '3,11p' "$0" | sed 's/^# \{0,1\}//'
|
|
21
|
+
exit "${1:-0}"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
25
|
+
usage 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
if ! command -v gh &>/dev/null; then
|
|
29
|
+
echo "Erro: GitHub CLI (gh) não encontrado."
|
|
30
|
+
echo "Instale com: brew install gh"
|
|
31
|
+
echo "Depois autentique: gh auth login"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if ! gh auth status &>/dev/null; then
|
|
36
|
+
echo "Erro: gh não está autenticado. Rode: gh auth login"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
TOKEN=""
|
|
41
|
+
REPO="${FLAXFLOW_GITHUB_REPO:-}"
|
|
42
|
+
|
|
43
|
+
while [[ $# -gt 0 ]]; do
|
|
44
|
+
case "$1" in
|
|
45
|
+
--repo)
|
|
46
|
+
REPO="${2:?informe owner/repo após --repo}"
|
|
47
|
+
shift 2
|
|
48
|
+
;;
|
|
49
|
+
-h|--help)
|
|
50
|
+
usage 0
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
if [[ -z "$TOKEN" ]]; then
|
|
54
|
+
TOKEN="$1"
|
|
55
|
+
else
|
|
56
|
+
echo "Argumento desconhecido: $1"
|
|
57
|
+
usage 1
|
|
58
|
+
fi
|
|
59
|
+
shift
|
|
60
|
+
;;
|
|
61
|
+
esac
|
|
62
|
+
done
|
|
63
|
+
|
|
64
|
+
if [[ -z "$TOKEN" ]]; then
|
|
65
|
+
echo "Cole o token PyPI (começa com pypi-) e pressione Enter:"
|
|
66
|
+
read -rs TOKEN
|
|
67
|
+
echo
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
TOKEN="${TOKEN//$'\r'/}"
|
|
71
|
+
TOKEN="${TOKEN//$'\n'/}"
|
|
72
|
+
TOKEN="$(echo -n "$TOKEN" | xargs)"
|
|
73
|
+
|
|
74
|
+
if [[ -z "$TOKEN" ]]; then
|
|
75
|
+
echo "Erro: token vazio."
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if [[ ! "$TOKEN" =~ ^pypi- ]]; then
|
|
80
|
+
echo "Erro: token inválido — deve começar com pypi-"
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
repo_from_git_dir() {
|
|
85
|
+
local git_dir="$1"
|
|
86
|
+
if [[ ! -d "$git_dir" ]]; then
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
(
|
|
90
|
+
cd "$git_dir"
|
|
91
|
+
gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null \
|
|
92
|
+
|| git remote get-url origin 2>/dev/null | sed -E 's#.*github\.com[:/](.+)(\.git)?$#\1#' \
|
|
93
|
+
| sed -E 's#^git@[^:]+:##'
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
find_git_repo() {
|
|
98
|
+
local dir="$PWD"
|
|
99
|
+
while [[ "$dir" != "/" ]]; do
|
|
100
|
+
if [[ -d "$dir/.git" ]]; then
|
|
101
|
+
repo_from_git_dir "$dir"
|
|
102
|
+
return 0
|
|
103
|
+
fi
|
|
104
|
+
dir="$(dirname "$dir")"
|
|
105
|
+
done
|
|
106
|
+
|
|
107
|
+
# sdks dentro do Backend (FlaxFlow.PortalAI.Backend/sdks/python)
|
|
108
|
+
local inside_backend
|
|
109
|
+
inside_backend="$(cd "$SDK_ROOT/../.." && pwd)"
|
|
110
|
+
if repo_from_git_dir "$inside_backend" &>/dev/null; then
|
|
111
|
+
repo_from_git_dir "$inside_backend"
|
|
112
|
+
return 0
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# layout monorepo local: plataforma/sdks ao lado de FlaxFlow.PortalAI.Backend
|
|
116
|
+
local sibling_backend="$SDK_ROOT/../FlaxFlow.PortalAI.Backend"
|
|
117
|
+
if repo_from_git_dir "$sibling_backend" &>/dev/null; then
|
|
118
|
+
repo_from_git_dir "$sibling_backend"
|
|
119
|
+
return 0
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
return 1
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if [[ -z "$REPO" ]]; then
|
|
126
|
+
REPO="$(find_git_repo 2>/dev/null || true)"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
if [[ -z "$REPO" ]]; then
|
|
130
|
+
REPO="$DEFAULT_REPO"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
if ! gh repo view "$REPO" &>/dev/null; then
|
|
134
|
+
echo "Erro: repositório não encontrado ou sem acesso: $REPO"
|
|
135
|
+
echo "Informe manualmente: bash scripts/configure-pypi.sh --repo owner/repo"
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
echo "Configurando PYPI_API_TOKEN em $REPO ..."
|
|
140
|
+
gh secret set PYPI_API_TOKEN --repo "$REPO" --body "$TOKEN"
|
|
141
|
+
|
|
142
|
+
VERSION="$(grep '^version' "$SDK_ROOT/pyproject.toml" | head -1 | sed 's/.*"\(.*\)".*/\1/')"
|
|
143
|
+
|
|
144
|
+
echo ""
|
|
145
|
+
echo "Pronto. Secret PYPI_API_TOKEN configurado em $REPO."
|
|
146
|
+
echo ""
|
|
147
|
+
echo "Publicação automática (após push em main):"
|
|
148
|
+
echo " • Alterações em sdks/python/** disparam sdk-python-release.yml"
|
|
149
|
+
echo " • Versão atual do pacote: $VERSION"
|
|
150
|
+
echo ""
|
|
151
|
+
echo "Disparar manualmente:"
|
|
152
|
+
echo " gh workflow run sdk-python-release.yml --repo $REPO"
|
|
153
|
+
echo ""
|
|
154
|
+
echo "Antes de cada nova release, aumente version em sdks/python/pyproject.toml"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Regenera os modelos pydantic a partir da spec OpenAPI (fonte de verdade).
|
|
4
|
+
# A spec é exportada do backend com: cargo run --bin export_openapi
|
|
5
|
+
#
|
|
6
|
+
# Uso: bash scripts/generate.sh
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
10
|
+
SPEC="${1:-$HERE/../openapi.json}"
|
|
11
|
+
OUT="$HERE/src/flaxflow/_generated/models.py"
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$SPEC" ]; then
|
|
14
|
+
echo "OpenAPI spec not found at $SPEC" >&2
|
|
15
|
+
echo "Generate it first: cargo run --bin export_openapi && cp openapi.json sdks/openapi.json" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
datamodel-codegen \
|
|
20
|
+
--input "$SPEC" --input-file-type openapi \
|
|
21
|
+
--output "$OUT" \
|
|
22
|
+
--output-model-type pydantic_v2.BaseModel \
|
|
23
|
+
--use-standard-collections \
|
|
24
|
+
--target-python-version 3.10 \
|
|
25
|
+
--snake-case-field --use-field-description \
|
|
26
|
+
--collapse-root-models
|
|
27
|
+
|
|
28
|
+
echo "Generated $OUT"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Cria o repositório GitHub para os SDKs (primeira vez) e prepara o push em main.
|
|
3
|
+
#
|
|
4
|
+
# Uso:
|
|
5
|
+
# bash scripts/setup-github-repo.sh
|
|
6
|
+
# bash scripts/setup-github-repo.sh --repo flaxflow/plataforma
|
|
7
|
+
# bash scripts/setup-github-repo.sh --repo roberto-fernandino/flaxflow-sdks
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
11
|
+
SDK_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
|
+
MONOREPO_ROOT="$(cd "$SDK_ROOT/../.." && pwd)"
|
|
13
|
+
DEFAULT_REPO="flaxflow/plataforma"
|
|
14
|
+
|
|
15
|
+
REPO="${FLAXFLOW_GITHUB_REPO:-$DEFAULT_REPO}"
|
|
16
|
+
PRIVATE="--private"
|
|
17
|
+
|
|
18
|
+
while [[ $# -gt 0 ]]; do
|
|
19
|
+
case "$1" in
|
|
20
|
+
--repo)
|
|
21
|
+
REPO="${2:?informe owner/repo após --repo}"
|
|
22
|
+
shift 2
|
|
23
|
+
;;
|
|
24
|
+
--public)
|
|
25
|
+
PRIVATE="--public"
|
|
26
|
+
shift
|
|
27
|
+
;;
|
|
28
|
+
*)
|
|
29
|
+
echo "Uso: $0 [--repo owner/repo] [--public]"
|
|
30
|
+
exit 1
|
|
31
|
+
;;
|
|
32
|
+
esac
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
if ! command -v gh &>/dev/null || ! gh auth status &>/dev/null; then
|
|
36
|
+
echo "Erro: instale e autentique o gh — brew install gh && gh auth login"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
cd "$MONOREPO_ROOT"
|
|
41
|
+
|
|
42
|
+
if [[ ! -f .gitignore ]]; then
|
|
43
|
+
cat > .gitignore <<'EOF'
|
|
44
|
+
.DS_Store
|
|
45
|
+
.cursor/
|
|
46
|
+
.claude/
|
|
47
|
+
.playwright-mcp/
|
|
48
|
+
*.json
|
|
49
|
+
|
|
50
|
+
# Apps com repositórios Git próprios (não fazem parte deste repo de SDKs)
|
|
51
|
+
FlaxFlow.PortalAI.Backend/
|
|
52
|
+
FlaxFlow.PortalAI.Frontend/
|
|
53
|
+
videos/
|
|
54
|
+
|
|
55
|
+
# Python / Node artefatos locais
|
|
56
|
+
sdks/python/.venv/
|
|
57
|
+
sdks/python/dist/
|
|
58
|
+
sdks/python/build/
|
|
59
|
+
sdks/python/.pytest_cache/
|
|
60
|
+
sdks/typescript/node_modules/
|
|
61
|
+
EOF
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [[ ! -d .git ]]; then
|
|
65
|
+
echo "Inicializando git em $MONOREPO_ROOT ..."
|
|
66
|
+
git init -b main
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
git add .gitignore sdks/ .github/ AGENTS.md CLAUDE.md 2>/dev/null || true
|
|
70
|
+
git add -A sdks/ .github/ 2>/dev/null || true
|
|
71
|
+
|
|
72
|
+
if git diff --cached --quiet; then
|
|
73
|
+
echo "Nada novo para commitar (já está tudo staged/commitado?)."
|
|
74
|
+
else
|
|
75
|
+
git commit -m "$(cat <<'EOF'
|
|
76
|
+
chore(sdks): preparar monorepo de SDKs com release automático no PyPI
|
|
77
|
+
|
|
78
|
+
EOF
|
|
79
|
+
)"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if gh repo view "$REPO" &>/dev/null; then
|
|
83
|
+
echo "Repositório $REPO já existe."
|
|
84
|
+
if ! git remote get-url origin &>/dev/null; then
|
|
85
|
+
git remote add origin "https://github.com/$REPO.git"
|
|
86
|
+
fi
|
|
87
|
+
echo "Fazendo push para main ..."
|
|
88
|
+
git push -u origin main
|
|
89
|
+
else
|
|
90
|
+
echo "Criando $REPO no GitHub e fazendo push ..."
|
|
91
|
+
gh repo create "$REPO" $PRIVATE --source=. --remote=origin --push
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
echo ""
|
|
95
|
+
echo "Repositório pronto: https://github.com/$REPO"
|
|
96
|
+
echo ""
|
|
97
|
+
echo "Próximo passo — configurar o token PyPI:"
|
|
98
|
+
echo " cd sdks/python && bash scripts/configure-pypi.sh"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""SDK oficial em Python para a FlaxFlow Engine API (processamento de documentos com IA).
|
|
2
|
+
|
|
3
|
+
Quickstart:
|
|
4
|
+
>>> from flaxflow import FlaxFlow
|
|
5
|
+
>>> fx = FlaxFlow(api_key="sk_...")
|
|
6
|
+
>>> job = fx.processing.process_document("invoice.pdf", document_id="<doc_id>")
|
|
7
|
+
>>> print(job.result)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from ._files import SUPPORTED_DOCUMENT_TYPES
|
|
13
|
+
from .client import FlaxFlow
|
|
14
|
+
from .errors import (
|
|
15
|
+
APIConnectionError,
|
|
16
|
+
APIStatusError,
|
|
17
|
+
AuthenticationError,
|
|
18
|
+
ConflictError,
|
|
19
|
+
FlaxFlowError,
|
|
20
|
+
NotFoundError,
|
|
21
|
+
PermissionDeniedError,
|
|
22
|
+
RateLimitError,
|
|
23
|
+
ServerError,
|
|
24
|
+
UnprocessableEntityError,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__version__ = "0.1.0"
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"FlaxFlow",
|
|
31
|
+
"FlaxFlowError",
|
|
32
|
+
"APIConnectionError",
|
|
33
|
+
"APIStatusError",
|
|
34
|
+
"AuthenticationError",
|
|
35
|
+
"PermissionDeniedError",
|
|
36
|
+
"NotFoundError",
|
|
37
|
+
"ConflictError",
|
|
38
|
+
"UnprocessableEntityError",
|
|
39
|
+
"RateLimitError",
|
|
40
|
+
"ServerError",
|
|
41
|
+
"SUPPORTED_DOCUMENT_TYPES",
|
|
42
|
+
"__version__",
|
|
43
|
+
]
|