Spaces:
Sleeping
Sleeping
marintosti12 commited on
Commit ·
3b97d72
1
Parent(s): ef040c3
feat (api/orm) : first version api with orm
Browse files- .github/workflows/deploy.yaml +21 -0
- .gitignore +3 -1
- alembic.ini +147 -0
- alembic/README +1 -0
- alembic/env.py +56 -0
- alembic/script.py.mako +28 -0
- alembic/versions/99e339b56253_initial_schema.py +35 -0
- alembic/versions/ecd589af543e_ml_inputs.py +74 -0
- docker-compose.yml +19 -0
- notebook/1_Analyse.ipynb +0 -0
- notebook/2_Nettoyage_Standardisation.ipynb +0 -0
- notebook/3_Feature_Engineering.ipynb +0 -0
- notebook/4_Modelisation.ipynb +0 -0
- poetry.lock +420 -2
- pyproject.toml +6 -1
- space.yaml +0 -8
- src/config/db.py +15 -0
- src/controllers/home_controller.py +28 -0
- src/controllers/predict_controller.py +72 -0
- src/features.py +38 -0
- src/main.py +19 -72
- src/model_loader.py +18 -0
- src/models/base.py +3 -0
- src/models/ml.py +23 -0
- src/models/ml_inputs.py +54 -0
- src/{shema → schemas}/ModelFeatures.py +0 -0
- src/schemas/PredictItemResult.py +7 -0
- src/schemas/PredictRequest.py +8 -0
- src/schemas/PredictResponse.py +9 -0
- src/{shema → schemas}/__init__.py +0 -0
- src/seeds/ml_models_seed.py +40 -0
- utils/__pycache__/scoring.cpython-312.pyc +0 -0
.github/workflows/deploy.yaml
CHANGED
|
@@ -21,6 +21,8 @@ jobs:
|
|
| 21 |
HF_SPACE_URL: ${{ secrets.HF_SPACE_URL }}
|
| 22 |
HF_GIT_EMAIL: ${{ secrets.HF_GIT_EMAIL || 'actions@github.com' }}
|
| 23 |
HF_GIT_NAME: ${{ secrets.HF_GIT_NAME || 'github-actions' }}
|
|
|
|
|
|
|
| 24 |
|
| 25 |
steps:
|
| 26 |
- name: Checkout
|
|
@@ -55,6 +57,25 @@ jobs:
|
|
| 55 |
|
| 56 |
git lfs status || true
|
| 57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
- name: Push to Space
|
| 60 |
run: |
|
|
|
|
| 21 |
HF_SPACE_URL: ${{ secrets.HF_SPACE_URL }}
|
| 22 |
HF_GIT_EMAIL: ${{ secrets.HF_GIT_EMAIL || 'actions@github.com' }}
|
| 23 |
HF_GIT_NAME: ${{ secrets.HF_GIT_NAME || 'github-actions' }}
|
| 24 |
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
| 25 |
+
|
| 26 |
|
| 27 |
steps:
|
| 28 |
- name: Checkout
|
|
|
|
| 57 |
|
| 58 |
git lfs status || true
|
| 59 |
|
| 60 |
+
- name: Setup Python
|
| 61 |
+
uses: actions/setup-python@v5
|
| 62 |
+
with:
|
| 63 |
+
python-version: "3.12"
|
| 64 |
+
|
| 65 |
+
- name: Install Poetry
|
| 66 |
+
uses: abatilo/actions-poetry@v3
|
| 67 |
+
with:
|
| 68 |
+
poetry-version: "1.8.3"
|
| 69 |
+
|
| 70 |
+
- name: Install deps (with dev)
|
| 71 |
+
run: poetry install --no-interaction --no-root
|
| 72 |
+
|
| 73 |
+
- name: Run Alembic migrations
|
| 74 |
+
env:
|
| 75 |
+
DATABASE_URL: ${{ env.DATABASE_URL }}
|
| 76 |
+
run: |
|
| 77 |
+
echo "Migrating DB: $DATABASE_URL"
|
| 78 |
+
PYTHONPATH=./src poetry run alembic upgrade head
|
| 79 |
|
| 80 |
- name: Push to Space
|
| 81 |
run: |
|
.gitignore
CHANGED
|
@@ -219,4 +219,6 @@ __marimo__/
|
|
| 219 |
*.joblib
|
| 220 |
*.pkl
|
| 221 |
*.pt
|
| 222 |
-
*.onnx
|
|
|
|
|
|
|
|
|
| 219 |
*.joblib
|
| 220 |
*.pkl
|
| 221 |
*.pt
|
| 222 |
+
*.onnx
|
| 223 |
+
|
| 224 |
+
/artifacts
|
alembic.ini
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# A generic, single database configuration.
|
| 2 |
+
|
| 3 |
+
[alembic]
|
| 4 |
+
# path to migration scripts.
|
| 5 |
+
# this is typically a path given in POSIX (e.g. forward slashes)
|
| 6 |
+
# format, relative to the token %(here)s which refers to the location of this
|
| 7 |
+
# ini file
|
| 8 |
+
script_location = %(here)s/alembic
|
| 9 |
+
|
| 10 |
+
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
|
| 11 |
+
# Uncomment the line below if you want the files to be prepended with date and time
|
| 12 |
+
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
|
| 13 |
+
# for all available tokens
|
| 14 |
+
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
| 15 |
+
|
| 16 |
+
# sys.path path, will be prepended to sys.path if present.
|
| 17 |
+
# defaults to the current working directory. for multiple paths, the path separator
|
| 18 |
+
# is defined by "path_separator" below.
|
| 19 |
+
prepend_sys_path = .
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
# timezone to use when rendering the date within the migration file
|
| 23 |
+
# as well as the filename.
|
| 24 |
+
# If specified, requires the python>=3.9 or backports.zoneinfo library and tzdata library.
|
| 25 |
+
# Any required deps can installed by adding `alembic[tz]` to the pip requirements
|
| 26 |
+
# string value is passed to ZoneInfo()
|
| 27 |
+
# leave blank for localtime
|
| 28 |
+
# timezone =
|
| 29 |
+
|
| 30 |
+
# max length of characters to apply to the "slug" field
|
| 31 |
+
# truncate_slug_length = 40
|
| 32 |
+
|
| 33 |
+
# set to 'true' to run the environment during
|
| 34 |
+
# the 'revision' command, regardless of autogenerate
|
| 35 |
+
# revision_environment = false
|
| 36 |
+
|
| 37 |
+
# set to 'true' to allow .pyc and .pyo files without
|
| 38 |
+
# a source .py file to be detected as revisions in the
|
| 39 |
+
# versions/ directory
|
| 40 |
+
# sourceless = false
|
| 41 |
+
|
| 42 |
+
# version location specification; This defaults
|
| 43 |
+
# to <script_location>/versions. When using multiple version
|
| 44 |
+
# directories, initial revisions must be specified with --version-path.
|
| 45 |
+
# The path separator used here should be the separator specified by "path_separator"
|
| 46 |
+
# below.
|
| 47 |
+
# version_locations = %(here)s/bar:%(here)s/bat:%(here)s/alembic/versions
|
| 48 |
+
|
| 49 |
+
# path_separator; This indicates what character is used to split lists of file
|
| 50 |
+
# paths, including version_locations and prepend_sys_path within configparser
|
| 51 |
+
# files such as alembic.ini.
|
| 52 |
+
# The default rendered in new alembic.ini files is "os", which uses os.pathsep
|
| 53 |
+
# to provide os-dependent path splitting.
|
| 54 |
+
#
|
| 55 |
+
# Note that in order to support legacy alembic.ini files, this default does NOT
|
| 56 |
+
# take place if path_separator is not present in alembic.ini. If this
|
| 57 |
+
# option is omitted entirely, fallback logic is as follows:
|
| 58 |
+
#
|
| 59 |
+
# 1. Parsing of the version_locations option falls back to using the legacy
|
| 60 |
+
# "version_path_separator" key, which if absent then falls back to the legacy
|
| 61 |
+
# behavior of splitting on spaces and/or commas.
|
| 62 |
+
# 2. Parsing of the prepend_sys_path option falls back to the legacy
|
| 63 |
+
# behavior of splitting on spaces, commas, or colons.
|
| 64 |
+
#
|
| 65 |
+
# Valid values for path_separator are:
|
| 66 |
+
#
|
| 67 |
+
# path_separator = :
|
| 68 |
+
# path_separator = ;
|
| 69 |
+
# path_separator = space
|
| 70 |
+
# path_separator = newline
|
| 71 |
+
#
|
| 72 |
+
# Use os.pathsep. Default configuration used for new projects.
|
| 73 |
+
path_separator = os
|
| 74 |
+
|
| 75 |
+
# set to 'true' to search source files recursively
|
| 76 |
+
# in each "version_locations" directory
|
| 77 |
+
# new in Alembic version 1.10
|
| 78 |
+
# recursive_version_locations = false
|
| 79 |
+
|
| 80 |
+
# the output encoding used when revision files
|
| 81 |
+
# are written from script.py.mako
|
| 82 |
+
# output_encoding = utf-8
|
| 83 |
+
|
| 84 |
+
# database URL. This is consumed by the user-maintained env.py script only.
|
| 85 |
+
# other means of configuring database URLs may be customized within the env.py
|
| 86 |
+
# file.
|
| 87 |
+
sqlalchemy.url = driver://user:pass@localhost/dbname
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
[post_write_hooks]
|
| 91 |
+
# post_write_hooks defines scripts or Python functions that are run
|
| 92 |
+
# on newly generated revision scripts. See the documentation for further
|
| 93 |
+
# detail and examples
|
| 94 |
+
|
| 95 |
+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
| 96 |
+
# hooks = black
|
| 97 |
+
# black.type = console_scripts
|
| 98 |
+
# black.entrypoint = black
|
| 99 |
+
# black.options = -l 79 REVISION_SCRIPT_FILENAME
|
| 100 |
+
|
| 101 |
+
# lint with attempts to fix using "ruff" - use the module runner, against the "ruff" module
|
| 102 |
+
# hooks = ruff
|
| 103 |
+
# ruff.type = module
|
| 104 |
+
# ruff.module = ruff
|
| 105 |
+
# ruff.options = check --fix REVISION_SCRIPT_FILENAME
|
| 106 |
+
|
| 107 |
+
# Alternatively, use the exec runner to execute a binary found on your PATH
|
| 108 |
+
# hooks = ruff
|
| 109 |
+
# ruff.type = exec
|
| 110 |
+
# ruff.executable = ruff
|
| 111 |
+
# ruff.options = check --fix REVISION_SCRIPT_FILENAME
|
| 112 |
+
|
| 113 |
+
# Logging configuration. This is also consumed by the user-maintained
|
| 114 |
+
# env.py script only.
|
| 115 |
+
[loggers]
|
| 116 |
+
keys = root,sqlalchemy,alembic
|
| 117 |
+
|
| 118 |
+
[handlers]
|
| 119 |
+
keys = console
|
| 120 |
+
|
| 121 |
+
[formatters]
|
| 122 |
+
keys = generic
|
| 123 |
+
|
| 124 |
+
[logger_root]
|
| 125 |
+
level = WARNING
|
| 126 |
+
handlers = console
|
| 127 |
+
qualname =
|
| 128 |
+
|
| 129 |
+
[logger_sqlalchemy]
|
| 130 |
+
level = WARNING
|
| 131 |
+
handlers =
|
| 132 |
+
qualname = sqlalchemy.engine
|
| 133 |
+
|
| 134 |
+
[logger_alembic]
|
| 135 |
+
level = INFO
|
| 136 |
+
handlers =
|
| 137 |
+
qualname = alembic
|
| 138 |
+
|
| 139 |
+
[handler_console]
|
| 140 |
+
class = StreamHandler
|
| 141 |
+
args = (sys.stderr,)
|
| 142 |
+
level = NOTSET
|
| 143 |
+
formatter = generic
|
| 144 |
+
|
| 145 |
+
[formatter_generic]
|
| 146 |
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
| 147 |
+
datefmt = %H:%M:%S
|
alembic/README
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Generic single-database configuration.
|
alembic/env.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
from logging.config import fileConfig
|
| 3 |
+
|
| 4 |
+
from alembic import context
|
| 5 |
+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine
|
| 6 |
+
from sqlalchemy import pool
|
| 7 |
+
|
| 8 |
+
from src.config.db import Base, settings
|
| 9 |
+
|
| 10 |
+
# Alembic Config
|
| 11 |
+
config = context.config
|
| 12 |
+
if config.config_file_name is not None:
|
| 13 |
+
fileConfig(config.config_file_name)
|
| 14 |
+
|
| 15 |
+
target_metadata = Base.metadata
|
| 16 |
+
|
| 17 |
+
def get_url() -> str:
|
| 18 |
+
return settings.DATABASE_URL
|
| 19 |
+
|
| 20 |
+
def run_migrations_offline() -> None:
|
| 21 |
+
"""Mode offline : pas d'engine, juste l'URL."""
|
| 22 |
+
context.configure(
|
| 23 |
+
url=get_url(),
|
| 24 |
+
target_metadata=target_metadata,
|
| 25 |
+
literal_binds=True,
|
| 26 |
+
compare_type=True,
|
| 27 |
+
dialect_opts={"paramstyle": "named"},
|
| 28 |
+
)
|
| 29 |
+
with context.begin_transaction():
|
| 30 |
+
context.run_migrations()
|
| 31 |
+
|
| 32 |
+
def do_run_migrations(connection) -> None:
|
| 33 |
+
"""Configuration commune (online) une fois connecté."""
|
| 34 |
+
context.configure(
|
| 35 |
+
connection=connection,
|
| 36 |
+
target_metadata=target_metadata,
|
| 37 |
+
compare_type=True,
|
| 38 |
+
)
|
| 39 |
+
with context.begin_transaction():
|
| 40 |
+
context.run_migrations()
|
| 41 |
+
|
| 42 |
+
async def run_migrations_online() -> None:
|
| 43 |
+
"""Mode online : engine async."""
|
| 44 |
+
connectable: AsyncEngine = create_async_engine(
|
| 45 |
+
get_url(),
|
| 46 |
+
poolclass=pool.NullPool,
|
| 47 |
+
)
|
| 48 |
+
async with connectable.connect() as connection:
|
| 49 |
+
await connection.run_sync(do_run_migrations)
|
| 50 |
+
await connectable.dispose()
|
| 51 |
+
|
| 52 |
+
if context.is_offline_mode():
|
| 53 |
+
run_migrations_offline()
|
| 54 |
+
else:
|
| 55 |
+
import asyncio
|
| 56 |
+
asyncio.run(run_migrations_online())
|
alembic/script.py.mako
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""${message}
|
| 2 |
+
|
| 3 |
+
Revision ID: ${up_revision}
|
| 4 |
+
Revises: ${down_revision | comma,n}
|
| 5 |
+
Create Date: ${create_date}
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
${imports if imports else ""}
|
| 13 |
+
|
| 14 |
+
# revision identifiers, used by Alembic.
|
| 15 |
+
revision: str = ${repr(up_revision)}
|
| 16 |
+
down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
|
| 17 |
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
| 18 |
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def upgrade() -> None:
|
| 22 |
+
"""Upgrade schema."""
|
| 23 |
+
${upgrades if upgrades else "pass"}
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def downgrade() -> None:
|
| 27 |
+
"""Downgrade schema."""
|
| 28 |
+
${downgrades if downgrades else "pass"}
|
alembic/versions/99e339b56253_initial_schema.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""initial schema
|
| 2 |
+
|
| 3 |
+
Revision ID: 99e339b56253
|
| 4 |
+
Revises:
|
| 5 |
+
Create Date: 2025-09-15 12:01:54.205742
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
from sqlalchemy.dialects import postgresql
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
# revision identifiers, used by Alembic.
|
| 16 |
+
revision: str = '99e339b56253'
|
| 17 |
+
down_revision: Union[str, Sequence[str], None] = None
|
| 18 |
+
branch_labels: Union[str, Sequence[str], None] = None
|
| 19 |
+
depends_on: Union[str, Sequence[str], None] = None
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def upgrade() -> None:
|
| 23 |
+
op.create_table(
|
| 24 |
+
"ml_models",
|
| 25 |
+
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, nullable=False),
|
| 26 |
+
sa.Column("name", sa.String(length=100), nullable=False, unique=True),
|
| 27 |
+
sa.Column("description", sa.Text(), nullable=True),
|
| 28 |
+
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("NOW()"), nullable=False),
|
| 29 |
+
sa.Column("is_active", sa.Boolean(), server_default=sa.text("TRUE"), nullable=False),
|
| 30 |
+
)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def downgrade() -> None:
|
| 34 |
+
op.drop_table("ml_models")
|
| 35 |
+
|
alembic/versions/ecd589af543e_ml_inputs.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ml inputs
|
| 2 |
+
|
| 3 |
+
Revision ID: ecd589af543e
|
| 4 |
+
Revises: 99e339b56253
|
| 5 |
+
Create Date: 2025-09-15 13:47:50.220857
|
| 6 |
+
|
| 7 |
+
"""
|
| 8 |
+
from typing import Sequence, Union
|
| 9 |
+
|
| 10 |
+
from alembic import op
|
| 11 |
+
import sqlalchemy as sa
|
| 12 |
+
from sqlalchemy.dialects import postgresql
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
# revision identifiers, used by Alembic.
|
| 16 |
+
revision: str = 'ecd589af543e'
|
| 17 |
+
down_revision: Union[str, Sequence[str], None] = '99e339b56253'
|
| 18 |
+
branch_labels: Union[str, Sequence[str], None] = None
|
| 19 |
+
depends_on: Union[str, Sequence[str], None] = None
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def upgrade() -> None:
|
| 23 |
+
op.create_table(
|
| 24 |
+
"ml_inputs",
|
| 25 |
+
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, nullable=False),
|
| 26 |
+
sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.text("NOW()"), nullable=False),
|
| 27 |
+
|
| 28 |
+
sa.Column("id_employee", sa.Integer(), nullable=False),
|
| 29 |
+
sa.Column("age", sa.Integer(), nullable=False),
|
| 30 |
+
|
| 31 |
+
sa.Column("genre", sa.String(length=20), nullable=False),
|
| 32 |
+
sa.Column("revenu_mensuel", sa.Integer(), nullable=False),
|
| 33 |
+
sa.Column("statut_marital", sa.String(length=50), nullable=False),
|
| 34 |
+
sa.Column("departement", sa.String(length=100), nullable=False),
|
| 35 |
+
sa.Column("poste", sa.String(length=100), nullable=False),
|
| 36 |
+
|
| 37 |
+
sa.Column("nombre_experiences_precedentes", sa.Integer(), nullable=False),
|
| 38 |
+
sa.Column("nombre_heures_travailless", sa.Integer(), nullable=False),
|
| 39 |
+
sa.Column("annee_experience_totale", sa.Integer(), nullable=False),
|
| 40 |
+
sa.Column("annees_dans_l_entreprise", sa.Integer(), nullable=False),
|
| 41 |
+
sa.Column("annees_dans_le_poste_actuel", sa.Integer(), nullable=False),
|
| 42 |
+
|
| 43 |
+
sa.Column("nombre_participation_pee", sa.Integer(), nullable=False),
|
| 44 |
+
sa.Column("nb_formations_suivies", sa.Integer(), nullable=False),
|
| 45 |
+
sa.Column("nombre_employee_sous_responsabilite", sa.Integer(), nullable=False),
|
| 46 |
+
|
| 47 |
+
sa.Column("code_sondage", sa.Integer(), nullable=False),
|
| 48 |
+
sa.Column("distance_domicile_travail", sa.Integer(), nullable=False),
|
| 49 |
+
sa.Column("niveau_education", sa.Integer(), nullable=False),
|
| 50 |
+
sa.Column("domaine_etude", sa.String(length=100), nullable=False),
|
| 51 |
+
|
| 52 |
+
sa.Column("ayant_enfants", sa.String(length=10), nullable=False),
|
| 53 |
+
sa.Column("frequence_deplacement", sa.String(length=50), nullable=False),
|
| 54 |
+
|
| 55 |
+
sa.Column("annees_depuis_la_derniere_promotion", sa.Integer(), nullable=False),
|
| 56 |
+
sa.Column("annes_sous_responsable_actuel", sa.Integer(), nullable=False),
|
| 57 |
+
|
| 58 |
+
sa.Column("satisfaction_employee_environnement", sa.Integer(), nullable=False),
|
| 59 |
+
sa.Column("note_evaluation_precedente", sa.Integer(), nullable=False),
|
| 60 |
+
sa.Column("niveau_hierarchique_poste", sa.Integer(), nullable=False),
|
| 61 |
+
sa.Column("satisfaction_employee_nature_travail", sa.Integer(), nullable=False),
|
| 62 |
+
sa.Column("satisfaction_employee_equipe", sa.Integer(), nullable=False),
|
| 63 |
+
sa.Column("satisfaction_employee_equilibre_pro_perso", sa.Integer(), nullable=False),
|
| 64 |
+
|
| 65 |
+
sa.Column("eval_number", sa.String(length=50), nullable=False),
|
| 66 |
+
sa.Column("note_evaluation_actuelle", sa.Integer(), nullable=False),
|
| 67 |
+
sa.Column("heure_supplementaires", sa.String(length=10), nullable=False),
|
| 68 |
+
sa.Column("augementation_salaire_precedente", sa.Integer(), nullable=False),
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def downgrade() -> None:
|
| 73 |
+
op.drop_table("ml_inputs")
|
| 74 |
+
|
docker-compose.yml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
services:
|
| 2 |
+
db:
|
| 3 |
+
image: postgres:16
|
| 4 |
+
container_name: futurisys-db
|
| 5 |
+
environment:
|
| 6 |
+
POSTGRES_USER: futu
|
| 7 |
+
POSTGRES_PASSWORD: futu_pass
|
| 8 |
+
POSTGRES_DB: futurisys
|
| 9 |
+
ports:
|
| 10 |
+
- "5432:5432"
|
| 11 |
+
volumes:
|
| 12 |
+
- pgdata:/var/lib/postgresql/data
|
| 13 |
+
healthcheck:
|
| 14 |
+
test: ["CMD-SHELL", "pg_isready -U futu -d futurisys"]
|
| 15 |
+
interval: 5s
|
| 16 |
+
timeout: 5s
|
| 17 |
+
retries: 10
|
| 18 |
+
volumes:
|
| 19 |
+
pgdata:
|
notebook/1_Analyse.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebook/2_Nettoyage_Standardisation.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebook/3_Feature_Engineering.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebook/4_Modelisation.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
poetry.lock
CHANGED
|
@@ -1,5 +1,24 @@
|
|
| 1 |
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
[[package]]
|
| 4 |
name = "annotated-types"
|
| 5 |
version = "0.7.0"
|
|
@@ -30,6 +49,69 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
|
|
| 30 |
[package.extras]
|
| 31 |
trio = ["trio (>=0.26.1)"]
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
[[package]]
|
| 34 |
name = "certifi"
|
| 35 |
version = "2025.8.3"
|
|
@@ -41,6 +123,94 @@ files = [
|
|
| 41 |
{file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"},
|
| 42 |
]
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
[[package]]
|
| 45 |
name = "click"
|
| 46 |
version = "8.2.1"
|
|
@@ -289,6 +459,17 @@ uvicorn = {version = ">=0.15.0", extras = ["standard"]}
|
|
| 289 |
[package.extras]
|
| 290 |
standard = ["uvicorn[standard] (>=0.15.0)"]
|
| 291 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
[[package]]
|
| 293 |
name = "fonttools"
|
| 294 |
version = "4.59.2"
|
|
@@ -369,6 +550,45 @@ type1 = ["xattr"]
|
|
| 369 |
unicode = ["unicodedata2 (>=15.1.0)"]
|
| 370 |
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
| 371 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
[[package]]
|
| 373 |
name = "greenlet"
|
| 374 |
version = "3.2.4"
|
|
@@ -447,6 +667,26 @@ files = [
|
|
| 447 |
{file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
|
| 448 |
]
|
| 449 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 450 |
[[package]]
|
| 451 |
name = "httpcore"
|
| 452 |
version = "1.0.9"
|
|
@@ -547,6 +787,44 @@ http2 = ["h2 (>=3,<5)"]
|
|
| 547 |
socks = ["socksio (==1.*)"]
|
| 548 |
zstd = ["zstandard (>=0.18.0)"]
|
| 549 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 550 |
[[package]]
|
| 551 |
name = "idna"
|
| 552 |
version = "3.10"
|
|
@@ -767,6 +1045,25 @@ files = [
|
|
| 767 |
{file = "llvmlite-0.45.0rc1.tar.gz", hash = "sha256:bec0a4c729848a4e7f6355fdbd98f2ee9471189d0a5aeb03a3cd19f672327fef"},
|
| 768 |
]
|
| 769 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 770 |
[[package]]
|
| 771 |
name = "markdown-it-py"
|
| 772 |
version = "4.0.0"
|
|
@@ -1290,6 +1587,83 @@ files = [
|
|
| 1290 |
dev = ["pre-commit", "tox"]
|
| 1291 |
testing = ["coverage", "pytest", "pytest-benchmark"]
|
| 1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1293 |
[[package]]
|
| 1294 |
name = "pydantic"
|
| 1295 |
version = "2.11.7"
|
|
@@ -1423,6 +1797,29 @@ files = [
|
|
| 1423 |
[package.dependencies]
|
| 1424 |
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
| 1425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1426 |
[[package]]
|
| 1427 |
name = "pygments"
|
| 1428 |
version = "2.19.2"
|
|
@@ -1584,6 +1981,27 @@ files = [
|
|
| 1584 |
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
| 1585 |
]
|
| 1586 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1587 |
[[package]]
|
| 1588 |
name = "rich"
|
| 1589 |
version = "14.1.0"
|
|
@@ -2154,7 +2572,7 @@ files = [
|
|
| 2154 |
]
|
| 2155 |
|
| 2156 |
[package.dependencies]
|
| 2157 |
-
greenlet = {version = ">=1", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
| 2158 |
typing-extensions = ">=4.6.0"
|
| 2159 |
|
| 2160 |
[package.extras]
|
|
@@ -2577,4 +2995,4 @@ files = [
|
|
| 2577 |
[metadata]
|
| 2578 |
lock-version = "2.0"
|
| 2579 |
python-versions = "^3.12"
|
| 2580 |
-
content-hash = "
|
|
|
|
| 1 |
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
| 2 |
|
| 3 |
+
[[package]]
|
| 4 |
+
name = "alembic"
|
| 5 |
+
version = "1.16.5"
|
| 6 |
+
description = "A database migration tool for SQLAlchemy."
|
| 7 |
+
optional = false
|
| 8 |
+
python-versions = ">=3.9"
|
| 9 |
+
files = [
|
| 10 |
+
{file = "alembic-1.16.5-py3-none-any.whl", hash = "sha256:e845dfe090c5ffa7b92593ae6687c5cb1a101e91fa53868497dbd79847f9dbe3"},
|
| 11 |
+
{file = "alembic-1.16.5.tar.gz", hash = "sha256:a88bb7f6e513bd4301ecf4c7f2206fe93f9913f9b48dac3b78babde2d6fe765e"},
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[package.dependencies]
|
| 15 |
+
Mako = "*"
|
| 16 |
+
SQLAlchemy = ">=1.4.0"
|
| 17 |
+
typing-extensions = ">=4.12"
|
| 18 |
+
|
| 19 |
+
[package.extras]
|
| 20 |
+
tz = ["tzdata"]
|
| 21 |
+
|
| 22 |
[[package]]
|
| 23 |
name = "annotated-types"
|
| 24 |
version = "0.7.0"
|
|
|
|
| 49 |
[package.extras]
|
| 50 |
trio = ["trio (>=0.26.1)"]
|
| 51 |
|
| 52 |
+
[[package]]
|
| 53 |
+
name = "asyncpg"
|
| 54 |
+
version = "0.30.0"
|
| 55 |
+
description = "An asyncio PostgreSQL driver"
|
| 56 |
+
optional = false
|
| 57 |
+
python-versions = ">=3.8.0"
|
| 58 |
+
files = [
|
| 59 |
+
{file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"},
|
| 60 |
+
{file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"},
|
| 61 |
+
{file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3152fef2e265c9c24eec4ee3d22b4f4d2703d30614b0b6753e9ed4115c8a146f"},
|
| 62 |
+
{file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7255812ac85099a0e1ffb81b10dc477b9973345793776b128a23e60148dd1af"},
|
| 63 |
+
{file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:578445f09f45d1ad7abddbff2a3c7f7c291738fdae0abffbeb737d3fc3ab8b75"},
|
| 64 |
+
{file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c42f6bb65a277ce4d93f3fba46b91a265631c8df7250592dd4f11f8b0152150f"},
|
| 65 |
+
{file = "asyncpg-0.30.0-cp310-cp310-win32.whl", hash = "sha256:aa403147d3e07a267ada2ae34dfc9324e67ccc4cdca35261c8c22792ba2b10cf"},
|
| 66 |
+
{file = "asyncpg-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb622c94db4e13137c4c7f98834185049cc50ee01d8f657ef898b6407c7b9c50"},
|
| 67 |
+
{file = "asyncpg-0.30.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5e0511ad3dec5f6b4f7a9e063591d407eee66b88c14e2ea636f187da1dcfff6a"},
|
| 68 |
+
{file = "asyncpg-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:915aeb9f79316b43c3207363af12d0e6fd10776641a7de8a01212afd95bdf0ed"},
|
| 69 |
+
{file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c198a00cce9506fcd0bf219a799f38ac7a237745e1d27f0e1f66d3707c84a5a"},
|
| 70 |
+
{file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3326e6d7381799e9735ca2ec9fd7be4d5fef5dcbc3cb555d8a463d8460607956"},
|
| 71 |
+
{file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51da377487e249e35bd0859661f6ee2b81db11ad1f4fc036194bc9cb2ead5056"},
|
| 72 |
+
{file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc6d84136f9c4d24d358f3b02be4b6ba358abd09f80737d1ac7c444f36108454"},
|
| 73 |
+
{file = "asyncpg-0.30.0-cp311-cp311-win32.whl", hash = "sha256:574156480df14f64c2d76450a3f3aaaf26105869cad3865041156b38459e935d"},
|
| 74 |
+
{file = "asyncpg-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:3356637f0bd830407b5597317b3cb3571387ae52ddc3bca6233682be88bbbc1f"},
|
| 75 |
+
{file = "asyncpg-0.30.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c902a60b52e506d38d7e80e0dd5399f657220f24635fee368117b8b5fce1142e"},
|
| 76 |
+
{file = "asyncpg-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aca1548e43bbb9f0f627a04666fedaca23db0a31a84136ad1f868cb15deb6e3a"},
|
| 77 |
+
{file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2a2ef565400234a633da0eafdce27e843836256d40705d83ab7ec42074efb3"},
|
| 78 |
+
{file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1292b84ee06ac8a2ad8e51c7475aa309245874b61333d97411aab835c4a2f737"},
|
| 79 |
+
{file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f5712350388d0cd0615caec629ad53c81e506b1abaaf8d14c93f54b35e3595a"},
|
| 80 |
+
{file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af"},
|
| 81 |
+
{file = "asyncpg-0.30.0-cp312-cp312-win32.whl", hash = "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e"},
|
| 82 |
+
{file = "asyncpg-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305"},
|
| 83 |
+
{file = "asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70"},
|
| 84 |
+
{file = "asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3"},
|
| 85 |
+
{file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33"},
|
| 86 |
+
{file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4"},
|
| 87 |
+
{file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4"},
|
| 88 |
+
{file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba"},
|
| 89 |
+
{file = "asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590"},
|
| 90 |
+
{file = "asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e"},
|
| 91 |
+
{file = "asyncpg-0.30.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ff1fc8b5bf724273782ff8b4f57b0f8220a1b2324184846b39d1ab4122031d"},
|
| 92 |
+
{file = "asyncpg-0.30.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64e899bce0600871b55368b8483e5e3e7f1860c9482e7f12e0a771e747988168"},
|
| 93 |
+
{file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b290f4726a887f75dcd1b3006f484252db37602313f806e9ffc4e5996cfe5cb"},
|
| 94 |
+
{file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86b0e2cd3f1249d6fe6fd6cfe0cd4538ba994e2d8249c0491925629b9104d0f"},
|
| 95 |
+
{file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:393af4e3214c8fa4c7b86da6364384c0d1b3298d45803375572f415b6f673f38"},
|
| 96 |
+
{file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fd4406d09208d5b4a14db9a9dbb311b6d7aeeab57bded7ed2f8ea41aeef39b34"},
|
| 97 |
+
{file = "asyncpg-0.30.0-cp38-cp38-win32.whl", hash = "sha256:0b448f0150e1c3b96cb0438a0d0aa4871f1472e58de14a3ec320dbb2798fb0d4"},
|
| 98 |
+
{file = "asyncpg-0.30.0-cp38-cp38-win_amd64.whl", hash = "sha256:f23b836dd90bea21104f69547923a02b167d999ce053f3d502081acea2fba15b"},
|
| 99 |
+
{file = "asyncpg-0.30.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f4e83f067b35ab5e6371f8a4c93296e0439857b4569850b178a01385e82e9ad"},
|
| 100 |
+
{file = "asyncpg-0.30.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5df69d55add4efcd25ea2a3b02025b669a285b767bfbf06e356d68dbce4234ff"},
|
| 101 |
+
{file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3479a0d9a852c7c84e822c073622baca862d1217b10a02dd57ee4a7a081f708"},
|
| 102 |
+
{file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26683d3b9a62836fad771a18ecf4659a30f348a561279d6227dab96182f46144"},
|
| 103 |
+
{file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1b982daf2441a0ed314bd10817f1606f1c28b1136abd9e4f11335358c2c631cb"},
|
| 104 |
+
{file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1c06a3a50d014b303e5f6fc1e5f95eb28d2cee89cf58384b700da621e5d5e547"},
|
| 105 |
+
{file = "asyncpg-0.30.0-cp39-cp39-win32.whl", hash = "sha256:1b11a555a198b08f5c4baa8f8231c74a366d190755aa4f99aacec5970afe929a"},
|
| 106 |
+
{file = "asyncpg-0.30.0-cp39-cp39-win_amd64.whl", hash = "sha256:8b684a3c858a83cd876f05958823b68e8d14ec01bb0c0d14a6704c5bf9711773"},
|
| 107 |
+
{file = "asyncpg-0.30.0.tar.gz", hash = "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851"},
|
| 108 |
+
]
|
| 109 |
+
|
| 110 |
+
[package.extras]
|
| 111 |
+
docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"]
|
| 112 |
+
gssauth = ["gssapi", "sspilib"]
|
| 113 |
+
test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"]
|
| 114 |
+
|
| 115 |
[[package]]
|
| 116 |
name = "certifi"
|
| 117 |
version = "2025.8.3"
|
|
|
|
| 123 |
{file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"},
|
| 124 |
]
|
| 125 |
|
| 126 |
+
[[package]]
|
| 127 |
+
name = "charset-normalizer"
|
| 128 |
+
version = "3.4.3"
|
| 129 |
+
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
| 130 |
+
optional = false
|
| 131 |
+
python-versions = ">=3.7"
|
| 132 |
+
files = [
|
| 133 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"},
|
| 134 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"},
|
| 135 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"},
|
| 136 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"},
|
| 137 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"},
|
| 138 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"},
|
| 139 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"},
|
| 140 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"},
|
| 141 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"},
|
| 142 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"},
|
| 143 |
+
{file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"},
|
| 144 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"},
|
| 145 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"},
|
| 146 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"},
|
| 147 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"},
|
| 148 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"},
|
| 149 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"},
|
| 150 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"},
|
| 151 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"},
|
| 152 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"},
|
| 153 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"},
|
| 154 |
+
{file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"},
|
| 155 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"},
|
| 156 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"},
|
| 157 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"},
|
| 158 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"},
|
| 159 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"},
|
| 160 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"},
|
| 161 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"},
|
| 162 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"},
|
| 163 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"},
|
| 164 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"},
|
| 165 |
+
{file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"},
|
| 166 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"},
|
| 167 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"},
|
| 168 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"},
|
| 169 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"},
|
| 170 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"},
|
| 171 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"},
|
| 172 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"},
|
| 173 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"},
|
| 174 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"},
|
| 175 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"},
|
| 176 |
+
{file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"},
|
| 177 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"},
|
| 178 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"},
|
| 179 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"},
|
| 180 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"},
|
| 181 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"},
|
| 182 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"},
|
| 183 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"},
|
| 184 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"},
|
| 185 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"},
|
| 186 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"},
|
| 187 |
+
{file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"},
|
| 188 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"},
|
| 189 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"},
|
| 190 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"},
|
| 191 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"},
|
| 192 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"},
|
| 193 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"},
|
| 194 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"},
|
| 195 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"},
|
| 196 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"},
|
| 197 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"},
|
| 198 |
+
{file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"},
|
| 199 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"},
|
| 200 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"},
|
| 201 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"},
|
| 202 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"},
|
| 203 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"},
|
| 204 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"},
|
| 205 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"},
|
| 206 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"},
|
| 207 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"},
|
| 208 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"},
|
| 209 |
+
{file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"},
|
| 210 |
+
{file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"},
|
| 211 |
+
{file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"},
|
| 212 |
+
]
|
| 213 |
+
|
| 214 |
[[package]]
|
| 215 |
name = "click"
|
| 216 |
version = "8.2.1"
|
|
|
|
| 459 |
[package.extras]
|
| 460 |
standard = ["uvicorn[standard] (>=0.15.0)"]
|
| 461 |
|
| 462 |
+
[[package]]
|
| 463 |
+
name = "filelock"
|
| 464 |
+
version = "3.19.1"
|
| 465 |
+
description = "A platform independent file lock."
|
| 466 |
+
optional = false
|
| 467 |
+
python-versions = ">=3.9"
|
| 468 |
+
files = [
|
| 469 |
+
{file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"},
|
| 470 |
+
{file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"},
|
| 471 |
+
]
|
| 472 |
+
|
| 473 |
[[package]]
|
| 474 |
name = "fonttools"
|
| 475 |
version = "4.59.2"
|
|
|
|
| 550 |
unicode = ["unicodedata2 (>=15.1.0)"]
|
| 551 |
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
| 552 |
|
| 553 |
+
[[package]]
|
| 554 |
+
name = "fsspec"
|
| 555 |
+
version = "2025.9.0"
|
| 556 |
+
description = "File-system specification"
|
| 557 |
+
optional = false
|
| 558 |
+
python-versions = ">=3.9"
|
| 559 |
+
files = [
|
| 560 |
+
{file = "fsspec-2025.9.0-py3-none-any.whl", hash = "sha256:530dc2a2af60a414a832059574df4a6e10cce927f6f4a78209390fe38955cfb7"},
|
| 561 |
+
{file = "fsspec-2025.9.0.tar.gz", hash = "sha256:19fd429483d25d28b65ec68f9f4adc16c17ea2c7c7bf54ec61360d478fb19c19"},
|
| 562 |
+
]
|
| 563 |
+
|
| 564 |
+
[package.extras]
|
| 565 |
+
abfs = ["adlfs"]
|
| 566 |
+
adl = ["adlfs"]
|
| 567 |
+
arrow = ["pyarrow (>=1)"]
|
| 568 |
+
dask = ["dask", "distributed"]
|
| 569 |
+
dev = ["pre-commit", "ruff (>=0.5)"]
|
| 570 |
+
doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"]
|
| 571 |
+
dropbox = ["dropbox", "dropboxdrivefs", "requests"]
|
| 572 |
+
full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
|
| 573 |
+
fuse = ["fusepy"]
|
| 574 |
+
gcs = ["gcsfs"]
|
| 575 |
+
git = ["pygit2"]
|
| 576 |
+
github = ["requests"]
|
| 577 |
+
gs = ["gcsfs"]
|
| 578 |
+
gui = ["panel"]
|
| 579 |
+
hdfs = ["pyarrow (>=1)"]
|
| 580 |
+
http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"]
|
| 581 |
+
libarchive = ["libarchive-c"]
|
| 582 |
+
oci = ["ocifs"]
|
| 583 |
+
s3 = ["s3fs"]
|
| 584 |
+
sftp = ["paramiko"]
|
| 585 |
+
smb = ["smbprotocol"]
|
| 586 |
+
ssh = ["paramiko"]
|
| 587 |
+
test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"]
|
| 588 |
+
test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"]
|
| 589 |
+
test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"]
|
| 590 |
+
tqdm = ["tqdm"]
|
| 591 |
+
|
| 592 |
[[package]]
|
| 593 |
name = "greenlet"
|
| 594 |
version = "3.2.4"
|
|
|
|
| 667 |
{file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
|
| 668 |
]
|
| 669 |
|
| 670 |
+
[[package]]
|
| 671 |
+
name = "hf-xet"
|
| 672 |
+
version = "1.1.9"
|
| 673 |
+
description = "Fast transfer of large files with the Hugging Face Hub."
|
| 674 |
+
optional = false
|
| 675 |
+
python-versions = ">=3.8"
|
| 676 |
+
files = [
|
| 677 |
+
{file = "hf_xet-1.1.9-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a3b6215f88638dd7a6ff82cb4e738dcbf3d863bf667997c093a3c990337d1160"},
|
| 678 |
+
{file = "hf_xet-1.1.9-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9b486de7a64a66f9a172f4b3e0dfe79c9f0a93257c501296a2521a13495a698a"},
|
| 679 |
+
{file = "hf_xet-1.1.9-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c5a840c2c4e6ec875ed13703a60e3523bc7f48031dfd750923b2a4d1a5fc3c"},
|
| 680 |
+
{file = "hf_xet-1.1.9-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:96a6139c9e44dad1c52c52520db0fffe948f6bce487cfb9d69c125f254bb3790"},
|
| 681 |
+
{file = "hf_xet-1.1.9-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ad1022e9a998e784c97b2173965d07fe33ee26e4594770b7785a8cc8f922cd95"},
|
| 682 |
+
{file = "hf_xet-1.1.9-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86754c2d6d5afb11b0a435e6e18911a4199262fe77553f8c50d75e21242193ea"},
|
| 683 |
+
{file = "hf_xet-1.1.9-cp37-abi3-win_amd64.whl", hash = "sha256:5aad3933de6b725d61d51034e04174ed1dce7a57c63d530df0014dea15a40127"},
|
| 684 |
+
{file = "hf_xet-1.1.9.tar.gz", hash = "sha256:c99073ce404462e909f1d5839b2d14a3827b8fe75ed8aed551ba6609c026c803"},
|
| 685 |
+
]
|
| 686 |
+
|
| 687 |
+
[package.extras]
|
| 688 |
+
tests = ["pytest"]
|
| 689 |
+
|
| 690 |
[[package]]
|
| 691 |
name = "httpcore"
|
| 692 |
version = "1.0.9"
|
|
|
|
| 787 |
socks = ["socksio (==1.*)"]
|
| 788 |
zstd = ["zstandard (>=0.18.0)"]
|
| 789 |
|
| 790 |
+
[[package]]
|
| 791 |
+
name = "huggingface-hub"
|
| 792 |
+
version = "0.34.4"
|
| 793 |
+
description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
|
| 794 |
+
optional = false
|
| 795 |
+
python-versions = ">=3.8.0"
|
| 796 |
+
files = [
|
| 797 |
+
{file = "huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a"},
|
| 798 |
+
{file = "huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c"},
|
| 799 |
+
]
|
| 800 |
+
|
| 801 |
+
[package.dependencies]
|
| 802 |
+
filelock = "*"
|
| 803 |
+
fsspec = ">=2023.5.0"
|
| 804 |
+
hf-xet = {version = ">=1.1.3,<2.0.0", markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""}
|
| 805 |
+
packaging = ">=20.9"
|
| 806 |
+
pyyaml = ">=5.1"
|
| 807 |
+
requests = "*"
|
| 808 |
+
tqdm = ">=4.42.1"
|
| 809 |
+
typing-extensions = ">=3.7.4.3"
|
| 810 |
+
|
| 811 |
+
[package.extras]
|
| 812 |
+
all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0)", "mypy (>=1.14.1,<1.15.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
|
| 813 |
+
cli = ["InquirerPy (==0.3.4)"]
|
| 814 |
+
dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0)", "mypy (>=1.14.1,<1.15.0)", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
|
| 815 |
+
fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
|
| 816 |
+
hf-transfer = ["hf-transfer (>=0.1.4)"]
|
| 817 |
+
hf-xet = ["hf-xet (>=1.1.2,<2.0.0)"]
|
| 818 |
+
inference = ["aiohttp"]
|
| 819 |
+
mcp = ["aiohttp", "mcp (>=1.8.0)", "typer"]
|
| 820 |
+
oauth = ["authlib (>=1.3.2)", "fastapi", "httpx", "itsdangerous"]
|
| 821 |
+
quality = ["libcst (>=1.4.0)", "mypy (==1.15.0)", "mypy (>=1.14.1,<1.15.0)", "ruff (>=0.9.0)"]
|
| 822 |
+
tensorflow = ["graphviz", "pydot", "tensorflow"]
|
| 823 |
+
tensorflow-testing = ["keras (<3.0)", "tensorflow"]
|
| 824 |
+
testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
|
| 825 |
+
torch = ["safetensors[torch]", "torch"]
|
| 826 |
+
typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
|
| 827 |
+
|
| 828 |
[[package]]
|
| 829 |
name = "idna"
|
| 830 |
version = "3.10"
|
|
|
|
| 1045 |
{file = "llvmlite-0.45.0rc1.tar.gz", hash = "sha256:bec0a4c729848a4e7f6355fdbd98f2ee9471189d0a5aeb03a3cd19f672327fef"},
|
| 1046 |
]
|
| 1047 |
|
| 1048 |
+
[[package]]
|
| 1049 |
+
name = "mako"
|
| 1050 |
+
version = "1.3.10"
|
| 1051 |
+
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
| 1052 |
+
optional = false
|
| 1053 |
+
python-versions = ">=3.8"
|
| 1054 |
+
files = [
|
| 1055 |
+
{file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"},
|
| 1056 |
+
{file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"},
|
| 1057 |
+
]
|
| 1058 |
+
|
| 1059 |
+
[package.dependencies]
|
| 1060 |
+
MarkupSafe = ">=0.9.2"
|
| 1061 |
+
|
| 1062 |
+
[package.extras]
|
| 1063 |
+
babel = ["Babel"]
|
| 1064 |
+
lingua = ["lingua"]
|
| 1065 |
+
testing = ["pytest"]
|
| 1066 |
+
|
| 1067 |
[[package]]
|
| 1068 |
name = "markdown-it-py"
|
| 1069 |
version = "4.0.0"
|
|
|
|
| 1587 |
dev = ["pre-commit", "tox"]
|
| 1588 |
testing = ["coverage", "pytest", "pytest-benchmark"]
|
| 1589 |
|
| 1590 |
+
[[package]]
|
| 1591 |
+
name = "psycopg2-binary"
|
| 1592 |
+
version = "2.9.10"
|
| 1593 |
+
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
| 1594 |
+
optional = false
|
| 1595 |
+
python-versions = ">=3.8"
|
| 1596 |
+
files = [
|
| 1597 |
+
{file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"},
|
| 1598 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"},
|
| 1599 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906"},
|
| 1600 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92"},
|
| 1601 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007"},
|
| 1602 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0"},
|
| 1603 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4"},
|
| 1604 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1"},
|
| 1605 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5"},
|
| 1606 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5"},
|
| 1607 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53"},
|
| 1608 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-win32.whl", hash = "sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b"},
|
| 1609 |
+
{file = "psycopg2_binary-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1"},
|
| 1610 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff"},
|
| 1611 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c"},
|
| 1612 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c"},
|
| 1613 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb"},
|
| 1614 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341"},
|
| 1615 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a"},
|
| 1616 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b"},
|
| 1617 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7"},
|
| 1618 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e"},
|
| 1619 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68"},
|
| 1620 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392"},
|
| 1621 |
+
{file = "psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4"},
|
| 1622 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0"},
|
| 1623 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a"},
|
| 1624 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539"},
|
| 1625 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526"},
|
| 1626 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1"},
|
| 1627 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e"},
|
| 1628 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f"},
|
| 1629 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00"},
|
| 1630 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5"},
|
| 1631 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47"},
|
| 1632 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64"},
|
| 1633 |
+
{file = "psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0"},
|
| 1634 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d"},
|
| 1635 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb"},
|
| 1636 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7"},
|
| 1637 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d"},
|
| 1638 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73"},
|
| 1639 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673"},
|
| 1640 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f"},
|
| 1641 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"},
|
| 1642 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"},
|
| 1643 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"},
|
| 1644 |
+
{file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"},
|
| 1645 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"},
|
| 1646 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"},
|
| 1647 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"},
|
| 1648 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:056470c3dc57904bbf63d6f534988bafc4e970ffd50f6271fc4ee7daad9498a5"},
|
| 1649 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aa0e31fa4bb82578f3a6c74a73c273367727de397a7a0f07bd83cbea696baa"},
|
| 1650 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8de718c0e1c4b982a54b41779667242bc630b2197948405b7bd8ce16bcecac92"},
|
| 1651 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5c370b1e4975df846b0277b4deba86419ca77dbc25047f535b0bb03d1a544d44"},
|
| 1652 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ffe8ed017e4ed70f68b7b371d84b7d4a790368db9203dfc2d222febd3a9c8863"},
|
| 1653 |
+
{file = "psycopg2_binary-2.9.10-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8aecc5e80c63f7459a1a2ab2c64df952051df196294d9f739933a9f6687e86b3"},
|
| 1654 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:7a813c8bdbaaaab1f078014b9b0b13f5de757e2b5d9be6403639b298a04d218b"},
|
| 1655 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00924255d7fc916ef66e4bf22f354a940c67179ad3fd7067d7a0a9c84d2fbfc"},
|
| 1656 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7559bce4b505762d737172556a4e6ea8a9998ecac1e39b5233465093e8cee697"},
|
| 1657 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8b58f0a96e7a1e341fc894f62c1177a7c83febebb5ff9123b579418fdc8a481"},
|
| 1658 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b269105e59ac96aba877c1707c600ae55711d9dcd3fc4b5012e4af68e30c648"},
|
| 1659 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:79625966e176dc97ddabc142351e0409e28acf4660b88d1cf6adb876d20c490d"},
|
| 1660 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8aabf1c1a04584c168984ac678a668094d831f152859d06e055288fa515e4d30"},
|
| 1661 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:19721ac03892001ee8fdd11507e6a2e01f4e37014def96379411ca99d78aeb2c"},
|
| 1662 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7f5d859928e635fa3ce3477704acee0f667b3a3d3e4bb109f2b18d4005f38287"},
|
| 1663 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-win32.whl", hash = "sha256:3216ccf953b3f267691c90c6fe742e45d890d8272326b4a8b20850a03d05b7b8"},
|
| 1664 |
+
{file = "psycopg2_binary-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:30e34c4e97964805f715206c7b789d54a78b70f3ff19fbe590104b71c45600e5"},
|
| 1665 |
+
]
|
| 1666 |
+
|
| 1667 |
[[package]]
|
| 1668 |
name = "pydantic"
|
| 1669 |
version = "2.11.7"
|
|
|
|
| 1797 |
[package.dependencies]
|
| 1798 |
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
| 1799 |
|
| 1800 |
+
[[package]]
|
| 1801 |
+
name = "pydantic-settings"
|
| 1802 |
+
version = "2.10.1"
|
| 1803 |
+
description = "Settings management using Pydantic"
|
| 1804 |
+
optional = false
|
| 1805 |
+
python-versions = ">=3.9"
|
| 1806 |
+
files = [
|
| 1807 |
+
{file = "pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796"},
|
| 1808 |
+
{file = "pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee"},
|
| 1809 |
+
]
|
| 1810 |
+
|
| 1811 |
+
[package.dependencies]
|
| 1812 |
+
pydantic = ">=2.7.0"
|
| 1813 |
+
python-dotenv = ">=0.21.0"
|
| 1814 |
+
typing-inspection = ">=0.4.0"
|
| 1815 |
+
|
| 1816 |
+
[package.extras]
|
| 1817 |
+
aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"]
|
| 1818 |
+
azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
|
| 1819 |
+
gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"]
|
| 1820 |
+
toml = ["tomli (>=2.0.1)"]
|
| 1821 |
+
yaml = ["pyyaml (>=6.0.1)"]
|
| 1822 |
+
|
| 1823 |
[[package]]
|
| 1824 |
name = "pygments"
|
| 1825 |
version = "2.19.2"
|
|
|
|
| 1981 |
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
| 1982 |
]
|
| 1983 |
|
| 1984 |
+
[[package]]
|
| 1985 |
+
name = "requests"
|
| 1986 |
+
version = "2.32.5"
|
| 1987 |
+
description = "Python HTTP for Humans."
|
| 1988 |
+
optional = false
|
| 1989 |
+
python-versions = ">=3.9"
|
| 1990 |
+
files = [
|
| 1991 |
+
{file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"},
|
| 1992 |
+
{file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"},
|
| 1993 |
+
]
|
| 1994 |
+
|
| 1995 |
+
[package.dependencies]
|
| 1996 |
+
certifi = ">=2017.4.17"
|
| 1997 |
+
charset_normalizer = ">=2,<4"
|
| 1998 |
+
idna = ">=2.5,<4"
|
| 1999 |
+
urllib3 = ">=1.21.1,<3"
|
| 2000 |
+
|
| 2001 |
+
[package.extras]
|
| 2002 |
+
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
| 2003 |
+
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
| 2004 |
+
|
| 2005 |
[[package]]
|
| 2006 |
name = "rich"
|
| 2007 |
version = "14.1.0"
|
|
|
|
| 2572 |
]
|
| 2573 |
|
| 2574 |
[package.dependencies]
|
| 2575 |
+
greenlet = {version = ">=1", optional = true, markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\") or extra == \"asyncio\""}
|
| 2576 |
typing-extensions = ">=4.6.0"
|
| 2577 |
|
| 2578 |
[package.extras]
|
|
|
|
| 2995 |
[metadata]
|
| 2996 |
lock-version = "2.0"
|
| 2997 |
python-versions = "^3.12"
|
| 2998 |
+
content-hash = "ae6861740d43c577f92198e978bd401f46311b2faddb8841e5d26b8163e1a78c"
|
pyproject.toml
CHANGED
|
@@ -17,7 +17,12 @@ scipy = "^1.16.1"
|
|
| 17 |
scikit-learn = "^1.7.2"
|
| 18 |
imbalanced-learn = "^0.14.0"
|
| 19 |
shap = "^0.48.0"
|
| 20 |
-
sqlalchemy = "^2.0.43"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
|
| 23 |
[tool.poetry.group.dev.dependencies]
|
|
|
|
| 17 |
scikit-learn = "^1.7.2"
|
| 18 |
imbalanced-learn = "^0.14.0"
|
| 19 |
shap = "^0.48.0"
|
| 20 |
+
sqlalchemy = {extras = ["asyncio"], version = "^2.0.43"}
|
| 21 |
+
huggingface-hub = "^0.34.4"
|
| 22 |
+
alembic = "^1.16.5"
|
| 23 |
+
asyncpg = "^0.30.0"
|
| 24 |
+
psycopg2-binary = "^2.9.10"
|
| 25 |
+
pydantic-settings = "^2.10.1"
|
| 26 |
|
| 27 |
|
| 28 |
[tool.poetry.group.dev.dependencies]
|
space.yaml
DELETED
|
@@ -1,8 +0,0 @@
|
|
| 1 |
-
# space.yaml
|
| 2 |
-
title: "Deploy ML API"
|
| 3 |
-
emoji: "🚀"
|
| 4 |
-
colorFrom: "blue"
|
| 5 |
-
colorTo: "green"
|
| 6 |
-
sdk: "docker"
|
| 7 |
-
pinned: false
|
| 8 |
-
license: "apache-2.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/config/db.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy import create_engine
|
| 2 |
+
from sqlalchemy.orm import sessionmaker, DeclarativeBase
|
| 3 |
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
| 4 |
+
|
| 5 |
+
class Settings(BaseSettings):
|
| 6 |
+
DATABASE_URL: str
|
| 7 |
+
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore",)
|
| 8 |
+
|
| 9 |
+
settings = Settings()
|
| 10 |
+
|
| 11 |
+
class Base(DeclarativeBase):
|
| 12 |
+
pass
|
| 13 |
+
|
| 14 |
+
engine = create_engine(settings.DATABASE_URL, echo=True, future=True)
|
| 15 |
+
SessionLocal = sessionmaker(bind=engine, autocommit=False, autoflush=False)
|
src/controllers/home_controller.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException
|
| 2 |
+
from sqlalchemy.orm import Session
|
| 3 |
+
from config.db import SessionLocal
|
| 4 |
+
from models.ml import MLModel
|
| 5 |
+
|
| 6 |
+
router = APIRouter()
|
| 7 |
+
|
| 8 |
+
@router.get("/", tags=["models"])
|
| 9 |
+
def list_ml_models():
|
| 10 |
+
try:
|
| 11 |
+
with SessionLocal() as s:
|
| 12 |
+
rows = (
|
| 13 |
+
s.query(MLModel)
|
| 14 |
+
.order_by(MLModel.created_at.desc())
|
| 15 |
+
.all()
|
| 16 |
+
)
|
| 17 |
+
return [
|
| 18 |
+
{
|
| 19 |
+
"id": str(r.id),
|
| 20 |
+
"name": r.name,
|
| 21 |
+
"description": r.description,
|
| 22 |
+
"created_at": r.created_at.isoformat() if r.created_at else None,
|
| 23 |
+
"is_active": r.is_active,
|
| 24 |
+
}
|
| 25 |
+
for r in rows
|
| 26 |
+
]
|
| 27 |
+
except Exception as e:
|
| 28 |
+
raise HTTPException(status_code=500, detail=str(e))
|
src/controllers/predict_controller.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# src/controllers/predict_controller.py
|
| 2 |
+
from fastapi import APIRouter, HTTPException
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
from typing import Optional, List
|
| 5 |
+
|
| 6 |
+
from sqlalchemy.orm import Session
|
| 7 |
+
from config.db import SessionLocal
|
| 8 |
+
from models.ml import MLModel
|
| 9 |
+
|
| 10 |
+
# Schemas
|
| 11 |
+
from models.ml_inputs import MLInput
|
| 12 |
+
from schemas.ModelFeatures import ModelFeatures
|
| 13 |
+
|
| 14 |
+
import pandas as pd
|
| 15 |
+
from model_loader import load_model
|
| 16 |
+
from features import compute_features
|
| 17 |
+
from schemas.PredictItemResult import PredictItemResult
|
| 18 |
+
from schemas.PredictResponse import PredictResponse
|
| 19 |
+
from schemas.PredictRequest import PredictRequest
|
| 20 |
+
|
| 21 |
+
router = APIRouter(prefix="/predict", tags=["inference"])
|
| 22 |
+
|
| 23 |
+
# (optionnel) mapping lisible des classes
|
| 24 |
+
LABELS = {
|
| 25 |
+
"0": "reste_dans_l_entreprise",
|
| 26 |
+
"1": "parti_de_l_entreprise",
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
# --------- Route ----------
|
| 30 |
+
@router.post("/", response_model=PredictResponse)
|
| 31 |
+
def batch_predict(payload: PredictRequest):
|
| 32 |
+
with SessionLocal() as s:
|
| 33 |
+
row = (
|
| 34 |
+
s.query(MLModel)
|
| 35 |
+
.filter(MLModel.name == payload.model_name)
|
| 36 |
+
.first()
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
objs = [MLInput(**x.model_dump()) for x in payload.inputs]
|
| 40 |
+
s.add_all(objs)
|
| 41 |
+
s.commit()
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
if not row or getattr(row, "is_active", True) is False:
|
| 45 |
+
raise HTTPException(status_code=404, detail="Modèle introuvable ou inactif")
|
| 46 |
+
|
| 47 |
+
try:
|
| 48 |
+
m = load_model(payload.model_name)
|
| 49 |
+
except Exception as e:
|
| 50 |
+
raise HTTPException(status_code=500, detail=f"Chargement du modèle '{payload.model_name}' impossible: {e}")
|
| 51 |
+
|
| 52 |
+
try:
|
| 53 |
+
df = pd.DataFrame([x.model_dump() for x in payload.inputs])
|
| 54 |
+
X = compute_features(df)
|
| 55 |
+
|
| 56 |
+
results: list[PredictItemResult] = []
|
| 57 |
+
|
| 58 |
+
probas = m.predict_proba(X)
|
| 59 |
+
classes = getattr(m, "classes_", None)
|
| 60 |
+
for p in probas:
|
| 61 |
+
i = int(p.argmax())
|
| 62 |
+
key = str(classes[i]) if classes is not None else str(i)
|
| 63 |
+
label = LABELS.get(key, key)
|
| 64 |
+
results.append(PredictItemResult(label=label, proba=float(p[i])))
|
| 65 |
+
|
| 66 |
+
except Exception as e:
|
| 67 |
+
raise HTTPException(status_code=400, detail=f"Erreur pendant la prédiction: {e}")
|
| 68 |
+
|
| 69 |
+
return PredictResponse(
|
| 70 |
+
model_name=payload.model_name,
|
| 71 |
+
results=results,
|
| 72 |
+
)
|
src/features.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import pandas as pd
|
| 3 |
+
|
| 4 |
+
def _safe_div(a, b):
|
| 5 |
+
a = pd.to_numeric(a, errors="coerce")
|
| 6 |
+
b = pd.to_numeric(b, errors="coerce").replace(0, np.nan)
|
| 7 |
+
return (a / b).fillna(0.0)
|
| 8 |
+
|
| 9 |
+
def compute_features(df: pd.DataFrame) -> pd.DataFrame:
|
| 10 |
+
SAT_COLS = [
|
| 11 |
+
"satisfaction_employee_environnement",
|
| 12 |
+
"satisfaction_employee_nature_travail",
|
| 13 |
+
"satisfaction_employee_equipe",
|
| 14 |
+
"satisfaction_employee_equilibre_pro_perso",
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
X = df.copy()
|
| 18 |
+
X["sat_mean"] = X[SAT_COLS].astype(float).mean(axis=1)
|
| 19 |
+
X["sat_std"] = X[SAT_COLS].astype(float).std(axis=1, ddof=0)
|
| 20 |
+
X["delta_eval"] = (
|
| 21 |
+
X["note_evaluation_actuelle"].astype(float)
|
| 22 |
+
- X["note_evaluation_precedente"].astype(float)
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
X["ratio_post_stab"] = _safe_div(X["annes_sous_responsable_actuel"], X["annees_dans_le_poste_actuel"])
|
| 26 |
+
X["revenu_par_niveau"] = _safe_div(X["revenu_mensuel"], X["niveau_hierarchique_poste"])
|
| 27 |
+
|
| 28 |
+
age_bins = [-np.inf, 25, 35, 45, 60, np.inf]
|
| 29 |
+
dist_bins = [-np.inf, 5, 10, 20, np.inf]
|
| 30 |
+
revenu_bins = [-np.inf, 2500, 4000, 6000, np.inf]
|
| 31 |
+
sat_mean_bins = [-np.inf, 2.0, 3.0, 4.0, np.inf]
|
| 32 |
+
|
| 33 |
+
X["tranche_age"] = pd.cut(X["age"].astype(float), age_bins, labels=["<=25","26-35","36-45","46-60","60+"])
|
| 34 |
+
X["tranche_distance"] = pd.cut(X["distance_domicile_travail"].astype(float), dist_bins, labels=["<=5","6-10","11-20",">20"])
|
| 35 |
+
X["tranche_revenu"] = pd.cut(X["revenu_mensuel"].astype(float), revenu_bins, labels=["<=2.5k","2.5-4k","4-6k",">6k"])
|
| 36 |
+
X["tranche_sat_mean"] = pd.cut(X["sat_mean"], sat_mean_bins, labels=["basse","moyenne","bonne","excellente"])
|
| 37 |
+
|
| 38 |
+
return X
|
src/main.py
CHANGED
|
@@ -1,81 +1,28 @@
|
|
| 1 |
|
| 2 |
-
from
|
| 3 |
-
from fastapi import FastAPI, HTTPException
|
| 4 |
-
import joblib
|
| 5 |
-
import numpy as np
|
| 6 |
import pandas as pd
|
|
|
|
| 7 |
|
| 8 |
-
from
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
-
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
LABELS = {
|
| 15 |
-
"0": "reste_dans_l_entreprise",
|
| 16 |
-
"1": "parti_de_l_entreprise",
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def load_model():
|
| 21 |
-
global _model
|
| 22 |
-
if _model is None:
|
| 23 |
-
_model = joblib.load('./artifacts/best_model.joblib')
|
| 24 |
-
return _model
|
| 25 |
-
|
| 26 |
-
def _safe_div(a, b):
|
| 27 |
-
a = pd.to_numeric(a, errors="coerce")
|
| 28 |
-
b = pd.to_numeric(b, errors="coerce").replace(0, np.nan)
|
| 29 |
-
return (a / b).fillna(0.0)
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
def compute_features(df: pd.DataFrame) -> pd.DataFrame:
|
| 33 |
-
SAT_COLS = [
|
| 34 |
-
"satisfaction_employee_environnement",
|
| 35 |
-
"satisfaction_employee_nature_travail",
|
| 36 |
-
"satisfaction_employee_equipe",
|
| 37 |
-
"satisfaction_employee_equilibre_pro_perso",
|
| 38 |
-
]
|
| 39 |
-
|
| 40 |
-
X = df.copy()
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
age_bins = [-np.inf, 25, 35, 45, 60, np.inf]
|
| 51 |
-
dist_bins = [-np.inf, 5, 10, 20, np.inf]
|
| 52 |
-
revenu_bins = [-np.inf, 2500, 4000, 6000, np.inf]
|
| 53 |
-
sat_mean_bins = [-np.inf, 2.0, 3.0, 4.0, np.inf]
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
X["tranche_age"] = pd.cut(X["age"].astype(float), age_bins, labels=["<=25","26-35","36-45","46-60","60+"])
|
| 57 |
-
X["tranche_distance"] = pd.cut(X["distance_domicile_travail"].astype(float), dist_bins, labels=["<=5","6-10","11-20",">20"])
|
| 58 |
-
X["tranche_revenu"] = pd.cut(X["revenu_mensuel"].astype(float), revenu_bins, labels=["<=2.5k","2.5-4k","4-6k",">6k"])
|
| 59 |
-
X["tranche_sat_mean"] = pd.cut(X["sat_mean"], sat_mean_bins, labels=["basse","moyenne","bonne","excellente"])
|
| 60 |
-
|
| 61 |
-
return X
|
| 62 |
|
| 63 |
-
|
| 64 |
-
def read_root():
|
| 65 |
-
return {"Hello": "World"}
|
| 66 |
|
| 67 |
-
|
| 68 |
-
def predict(body: ModelFeatures):
|
| 69 |
-
try:
|
| 70 |
-
m = load_model()
|
| 71 |
-
raw = pd.DataFrame([body.model_dump()])
|
| 72 |
|
| 73 |
-
|
| 74 |
-
proba = m.predict_proba(X)[0]
|
| 75 |
-
i = int(proba.argmax())
|
| 76 |
-
classes = getattr(m, "classes_", None)
|
| 77 |
-
pred = str(classes[i]) if classes is not None else str(i)
|
| 78 |
-
label = LABELS.get(pred, str(pred))
|
| 79 |
-
return {"label": label, "proba": float(proba[i])}
|
| 80 |
-
except Exception as e:
|
| 81 |
-
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
| 1 |
|
| 2 |
+
from fastapi import FastAPI, Depends, HTTPException
|
|
|
|
|
|
|
|
|
|
| 3 |
import pandas as pd
|
| 4 |
+
from contextlib import asynccontextmanager
|
| 5 |
|
| 6 |
+
from config.db import SessionLocal
|
| 7 |
+
from schemas.ModelFeatures import ModelFeatures
|
| 8 |
+
from model_loader import load_model
|
| 9 |
+
from features import compute_features
|
| 10 |
|
| 11 |
+
from sqlalchemy.orm import Session
|
| 12 |
|
| 13 |
+
from controllers.home_controller import router as ml_home_router
|
| 14 |
+
from controllers.predict_controller import router as predict_router
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
+
def get_db():
|
| 17 |
+
db = SessionLocal()
|
| 18 |
+
try:
|
| 19 |
+
yield db
|
| 20 |
+
finally:
|
| 21 |
+
db.close()
|
| 22 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
+
app = FastAPI()
|
|
|
|
|
|
|
| 25 |
|
| 26 |
+
app.include_router(ml_home_router)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
app.include_router(predict_router)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/model_loader.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from functools import lru_cache
|
| 3 |
+
from typing import Any
|
| 4 |
+
from huggingface_hub import hf_hub_download
|
| 5 |
+
import joblib
|
| 6 |
+
|
| 7 |
+
HF_REPO_ID = os.getenv("HF_REPO_ID", "Marintosti/attrition")
|
| 8 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 9 |
+
|
| 10 |
+
@lru_cache(maxsize=1)
|
| 11 |
+
def load_model(name) -> Any:
|
| 12 |
+
local_path = hf_hub_download(
|
| 13 |
+
repo_id=HF_REPO_ID,
|
| 14 |
+
filename=f"{name}.joblib",
|
| 15 |
+
token=HF_TOKEN,
|
| 16 |
+
local_files_only=False,
|
| 17 |
+
)
|
| 18 |
+
return joblib.load(local_path)
|
src/models/base.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sqlalchemy.orm import declarative_base
|
| 2 |
+
|
| 3 |
+
Base = declarative_base()
|
src/models/ml.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from sqlalchemy import Column, String, Text, DateTime, Boolean
|
| 4 |
+
from sqlalchemy.dialects.postgresql import UUID
|
| 5 |
+
from sqlalchemy.orm import Mapped, mapped_column
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
from .base import Base
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class MLModel(Base):
|
| 12 |
+
__tablename__ = "ml_models"
|
| 13 |
+
|
| 14 |
+
id: Mapped[uuid.UUID] = mapped_column(
|
| 15 |
+
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
|
| 16 |
+
)
|
| 17 |
+
name: Mapped[str] = mapped_column(String(100), nullable=False, unique=True)
|
| 18 |
+
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| 19 |
+
created_at: Mapped[datetime] = mapped_column(
|
| 20 |
+
DateTime(timezone=True), default=datetime.utcnow, nullable=False
|
| 21 |
+
)
|
| 22 |
+
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
| 23 |
+
|
src/models/ml_inputs.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
from datetime import datetime, timezone
|
| 3 |
+
from sqlalchemy.orm import Mapped, mapped_column
|
| 4 |
+
from sqlalchemy import String, Integer, Boolean, DateTime
|
| 5 |
+
from sqlalchemy.dialects.postgresql import UUID
|
| 6 |
+
from .base import Base
|
| 7 |
+
|
| 8 |
+
class MLInput(Base):
|
| 9 |
+
__tablename__ = "ml_inputs"
|
| 10 |
+
|
| 11 |
+
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
| 12 |
+
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True),
|
| 13 |
+
default=lambda: datetime.now(timezone.utc), nullable=False)
|
| 14 |
+
|
| 15 |
+
id_employee: Mapped[int] = mapped_column(Integer, index=True)
|
| 16 |
+
age: Mapped[int] = mapped_column(Integer)
|
| 17 |
+
|
| 18 |
+
genre: Mapped[str] = mapped_column(String(20))
|
| 19 |
+
revenu_mensuel: Mapped[int] = mapped_column(Integer)
|
| 20 |
+
statut_marital: Mapped[str] = mapped_column(String(50))
|
| 21 |
+
departement: Mapped[str] = mapped_column(String(100), index=True)
|
| 22 |
+
poste: Mapped[str] = mapped_column(String(100))
|
| 23 |
+
|
| 24 |
+
nombre_experiences_precedentes: Mapped[int] = mapped_column(Integer)
|
| 25 |
+
nombre_heures_travailless: Mapped[int] = mapped_column(Integer)
|
| 26 |
+
annee_experience_totale: Mapped[int] = mapped_column(Integer)
|
| 27 |
+
annees_dans_l_entreprise: Mapped[int] = mapped_column(Integer)
|
| 28 |
+
annees_dans_le_poste_actuel: Mapped[int] = mapped_column(Integer)
|
| 29 |
+
|
| 30 |
+
nombre_participation_pee: Mapped[int] = mapped_column(Integer)
|
| 31 |
+
nb_formations_suivies: Mapped[int] = mapped_column(Integer)
|
| 32 |
+
nombre_employee_sous_responsabilite: Mapped[int] = mapped_column(Integer)
|
| 33 |
+
|
| 34 |
+
code_sondage: Mapped[int] = mapped_column(Integer)
|
| 35 |
+
distance_domicile_travail: Mapped[int] = mapped_column(Integer)
|
| 36 |
+
niveau_education: Mapped[int] = mapped_column(Integer)
|
| 37 |
+
domaine_etude: Mapped[str] = mapped_column(String(100))
|
| 38 |
+
|
| 39 |
+
ayant_enfants: Mapped[str] = mapped_column(String(10))
|
| 40 |
+
frequence_deplacement: Mapped[str] = mapped_column(String(50))
|
| 41 |
+
|
| 42 |
+
annees_depuis_la_derniere_promotion: Mapped[int] = mapped_column(Integer)
|
| 43 |
+
annes_sous_responsable_actuel: Mapped[int] = mapped_column(Integer)
|
| 44 |
+
satisfaction_employee_environnement: Mapped[int] = mapped_column(Integer)
|
| 45 |
+
note_evaluation_precedente: Mapped[int] = mapped_column(Integer)
|
| 46 |
+
niveau_hierarchique_poste: Mapped[int] = mapped_column(Integer)
|
| 47 |
+
satisfaction_employee_nature_travail: Mapped[int] = mapped_column(Integer)
|
| 48 |
+
satisfaction_employee_equipe: Mapped[int] = mapped_column(Integer)
|
| 49 |
+
satisfaction_employee_equilibre_pro_perso: Mapped[int] = mapped_column(Integer)
|
| 50 |
+
|
| 51 |
+
eval_number: Mapped[str] = mapped_column(String(50))
|
| 52 |
+
note_evaluation_actuelle: Mapped[int] = mapped_column(Integer)
|
| 53 |
+
heure_supplementaires: Mapped[str] = mapped_column(String(10))
|
| 54 |
+
augementation_salaire_precedente: Mapped[int] = mapped_column(Integer)
|
src/{shema → schemas}/ModelFeatures.py
RENAMED
|
File without changes
|
src/schemas/PredictItemResult.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class PredictItemResult(BaseModel):
|
| 6 |
+
label: str
|
| 7 |
+
proba: Optional[float] = None
|
src/schemas/PredictRequest.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
|
| 4 |
+
from schemas.ModelFeatures import ModelFeatures
|
| 5 |
+
|
| 6 |
+
class PredictRequest(BaseModel):
|
| 7 |
+
model_name: str
|
| 8 |
+
inputs: List[ModelFeatures]
|
src/schemas/PredictResponse.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
|
| 4 |
+
from schemas.PredictItemResult import PredictItemResult
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class PredictResponse(BaseModel):
|
| 8 |
+
model_name: str
|
| 9 |
+
results: List[PredictItemResult]
|
src/{shema → schemas}/__init__.py
RENAMED
|
File without changes
|
src/seeds/ml_models_seed.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# src/seeds/ml_models_seed.py
|
| 2 |
+
import os
|
| 3 |
+
from datetime import datetime, timezone
|
| 4 |
+
from sqlalchemy import create_engine, text
|
| 5 |
+
from sqlalchemy.orm import Session
|
| 6 |
+
|
| 7 |
+
# (optionnel) charge .env automatiquement
|
| 8 |
+
try:
|
| 9 |
+
from dotenv import load_dotenv
|
| 10 |
+
load_dotenv()
|
| 11 |
+
except Exception:
|
| 12 |
+
pass
|
| 13 |
+
|
| 14 |
+
DATABASE_URL = os.environ["DATABASE_URL"] # ex: postgresql+psycopg2://...
|
| 15 |
+
engine = create_engine(DATABASE_URL, future=True)
|
| 16 |
+
|
| 17 |
+
UPSERT = text("""
|
| 18 |
+
INSERT INTO ml_models (id, name, description, created_at, is_active)
|
| 19 |
+
VALUES (:id, :name, :description, :created_at, :is_active)
|
| 20 |
+
ON CONFLICT (name) DO UPDATE
|
| 21 |
+
SET description = EXCLUDED.description,
|
| 22 |
+
is_active = EXCLUDED.is_active
|
| 23 |
+
""")
|
| 24 |
+
|
| 25 |
+
def seed_ml_models(session: Session):
|
| 26 |
+
rows = [
|
| 27 |
+
{"id": "5b1c7b3a-0000-4000-8000-000000000001", "name": "baseline", "description": "Baseline model", "is_active": True},
|
| 28 |
+
{"id": "5b1c7b3a-0000-4000-8000-000000000002", "name": "xgboost_v1", "description": "XGB v1", "is_active": False},
|
| 29 |
+
]
|
| 30 |
+
now = datetime.now(timezone.utc)
|
| 31 |
+
for r in rows:
|
| 32 |
+
session.execute(UPSERT, {**r, "created_at": now})
|
| 33 |
+
|
| 34 |
+
def main():
|
| 35 |
+
with Session(engine) as s:
|
| 36 |
+
seed_ml_models(s)
|
| 37 |
+
s.commit()
|
| 38 |
+
|
| 39 |
+
if __name__ == "__main__":
|
| 40 |
+
main()
|
utils/__pycache__/scoring.cpython-312.pyc
CHANGED
|
Binary files a/utils/__pycache__/scoring.cpython-312.pyc and b/utils/__pycache__/scoring.cpython-312.pyc differ
|
|
|