fastai-stack 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FastForge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,80 @@
1
+ Metadata-Version: 2.1
2
+ Name: fastai-stack
3
+ Version: 0.1.0
4
+ Summary: Interactive CLI generator for production-ready FastAPI AI stacks
5
+ Home-page: https://github.com/HarshG1308/fastai-stack
6
+ License: MIT
7
+ Keywords: fastapi,cli,scaffold,ai,ml,generator
8
+ Author: Harsh Gautam
9
+ Author-email: hgqeir@gmai.com
10
+ Requires-Python: >=3.10,<4.0
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Code Generators
21
+ Requires-Dist: jinja2 (>=3.1.4)
22
+ Requires-Dist: rich (>=13.7.0)
23
+ Requires-Dist: typer (>=0.12.0)
24
+ Project-URL: Repository, https://github.com/HarshG1308/fastai-stack
25
+ Description-Content-Type: text/markdown
26
+
27
+ # fastai-stack
28
+
29
+ fastai-stack is an interactive CLI for generating production-ready FastAPI backends tailored to AI/ML workflows.
30
+
31
+ ## Vision
32
+
33
+ Build the best FastAPI scaffolding experience for AI developers by 2026: async-first, type-safe, and deployment-ready.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install fastai-stack
39
+ ```
40
+
41
+ ## Quickstart
42
+
43
+ ```bash
44
+ fastai-stack create myapp --interactive
45
+ ```
46
+
47
+ Generate without prompts:
48
+
49
+ ```bash
50
+ fastai-stack create myapp --non-interactive --db sqlite --auth none --ai openai --vector-db pgvector
51
+ ```
52
+
53
+ ## What Gets Generated
54
+
55
+ - FastAPI app skeleton with modular package layout
56
+ - Pydantic v2 settings + async-ready API router
57
+ - Optional auth, tasks, AI, vector DB, and monitoring integrations
58
+ - Dockerfile + docker-compose (CPU/GPU-aware)
59
+ - Poetry-managed app dependencies
60
+ - Tests and CI workflow scaffolding
61
+
62
+ ## Development
63
+
64
+ ```bash
65
+ poetry install
66
+ poetry run pytest
67
+ poetry run fastai-stack --help
68
+ ```
69
+
70
+ ## Publish
71
+
72
+ ```bash
73
+ poetry build
74
+ poetry publish
75
+ ```
76
+
77
+ ## License
78
+
79
+ MIT
80
+
@@ -0,0 +1,53 @@
1
+ # fastai-stack
2
+
3
+ fastai-stack is an interactive CLI for generating production-ready FastAPI backends tailored to AI/ML workflows.
4
+
5
+ ## Vision
6
+
7
+ Build the best FastAPI scaffolding experience for AI developers by 2026: async-first, type-safe, and deployment-ready.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install fastai-stack
13
+ ```
14
+
15
+ ## Quickstart
16
+
17
+ ```bash
18
+ fastai-stack create myapp --interactive
19
+ ```
20
+
21
+ Generate without prompts:
22
+
23
+ ```bash
24
+ fastai-stack create myapp --non-interactive --db sqlite --auth none --ai openai --vector-db pgvector
25
+ ```
26
+
27
+ ## What Gets Generated
28
+
29
+ - FastAPI app skeleton with modular package layout
30
+ - Pydantic v2 settings + async-ready API router
31
+ - Optional auth, tasks, AI, vector DB, and monitoring integrations
32
+ - Dockerfile + docker-compose (CPU/GPU-aware)
33
+ - Poetry-managed app dependencies
34
+ - Tests and CI workflow scaffolding
35
+
36
+ ## Development
37
+
38
+ ```bash
39
+ poetry install
40
+ poetry run pytest
41
+ poetry run fastai-stack --help
42
+ ```
43
+
44
+ ## Publish
45
+
46
+ ```bash
47
+ poetry build
48
+ poetry publish
49
+ ```
50
+
51
+ ## License
52
+
53
+ MIT
@@ -0,0 +1,4 @@
1
+ """FastForge package."""
2
+
3
+ __all__ = ["__version__"]
4
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from .cli import app
2
+
3
+ app()
@@ -0,0 +1,95 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from pathlib import Path
5
+
6
+ import typer
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+
10
+ from .generator import render_project
11
+ from .models import (AIChoice, AuthChoice, DatabaseChoice, DockerChoice,
12
+ FrontendChoice, MonitoringChoice, ProjectConfig,
13
+ TaskChoice, VectorDBChoice)
14
+
15
+ app = typer.Typer(help="fastai-stack: Generate production-ready FastAPI stacks for AI developers.")
16
+ console = Console()
17
+
18
+
19
+ def _slugify(value: str) -> str:
20
+ slug = re.sub(r"[^a-zA-Z0-9]+", "-", value.strip().lower()).strip("-")
21
+ return slug or "fastforge-app"
22
+
23
+
24
+ def _prompt_enum(label: str, enum_type: type, default: str) -> str:
25
+ choices = ", ".join(item.value for item in enum_type)
26
+ return typer.prompt(f"{label} [{choices}]", default=default)
27
+
28
+
29
+ @app.command()
30
+ def create(
31
+ project_name: str = typer.Argument(..., help="Project name or slug."),
32
+ interactive: bool = typer.Option(True, "--interactive/--non-interactive", help="Prompt for stack options."),
33
+ db: DatabaseChoice = typer.Option(DatabaseChoice.postgres, help="Database backend."),
34
+ auth: AuthChoice = typer.Option(AuthChoice.none, help="Authentication mode."),
35
+ tasks: TaskChoice = typer.Option(TaskChoice.none, help="Background tasks setup."),
36
+ ai: AIChoice = typer.Option(AIChoice.none, help="AI integration provider."),
37
+ vector_db: VectorDBChoice = typer.Option(VectorDBChoice.none, "--vector-db", help="Vector database option."),
38
+ docker: DockerChoice = typer.Option(DockerChoice.cpu, help="Docker runtime profile."),
39
+ monitoring: MonitoringChoice = typer.Option(MonitoringChoice.none, help="Monitoring integration."),
40
+ frontend: FrontendChoice = typer.Option(FrontendChoice.none, help="Frontend starter option."),
41
+ output_dir: Path = typer.Option(Path("."), "--output-dir", help="Directory where the project will be generated."),
42
+ ) -> None:
43
+ """Create a new FastAPI AI stack project."""
44
+ final_project_name = project_name
45
+ final_project_slug = _slugify(project_name)
46
+
47
+ if interactive:
48
+ console.print(Panel("fastai-stack interactive setup", style="bold cyan"))
49
+ final_project_name = typer.prompt("Project name", default=project_name)
50
+ final_project_slug = typer.prompt("Project slug", default=_slugify(final_project_name))
51
+
52
+ db = DatabaseChoice(_prompt_enum("DB", DatabaseChoice, db.value))
53
+ auth = AuthChoice(_prompt_enum("Auth", AuthChoice, auth.value))
54
+ tasks = TaskChoice(_prompt_enum("Tasks", TaskChoice, tasks.value))
55
+ ai = AIChoice(_prompt_enum("AI", AIChoice, ai.value))
56
+ vector_db = VectorDBChoice(_prompt_enum("Vector DB", VectorDBChoice, vector_db.value))
57
+ docker = DockerChoice(_prompt_enum("Docker", DockerChoice, docker.value))
58
+ monitoring = MonitoringChoice(_prompt_enum("Monitoring", MonitoringChoice, monitoring.value))
59
+ frontend = FrontendChoice(_prompt_enum("Frontend", FrontendChoice, frontend.value))
60
+
61
+ config = ProjectConfig(
62
+ project_name=final_project_name,
63
+ project_slug=final_project_slug,
64
+ db=db,
65
+ auth=auth,
66
+ tasks=tasks,
67
+ ai=ai,
68
+ vector_db=vector_db,
69
+ docker=docker,
70
+ monitoring=monitoring,
71
+ frontend=frontend,
72
+ )
73
+
74
+ try:
75
+ project_dir = render_project(config=config, destination=output_dir.resolve())
76
+ except FileExistsError as exc:
77
+ console.print(f"[bold red]Error:[/bold red] {exc}")
78
+ raise typer.Exit(code=1)
79
+
80
+ console.print("\n[bold green]Project created successfully![/bold green]")
81
+ console.print(f"Location: [cyan]{project_dir}[/cyan]")
82
+ console.print("\nNext steps:")
83
+ console.print(f" cd {config.project_slug}")
84
+ console.print(" poetry install")
85
+ console.print(" poetry run uvicorn app.main:app --reload")
86
+
87
+
88
+ @app.command()
89
+ def version() -> None:
90
+ """Show CLI version."""
91
+ console.print("fastai-stack 0.1.0")
92
+
93
+
94
+ if __name__ == "__main__":
95
+ app()
@@ -0,0 +1,153 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from jinja2 import Environment, FileSystemLoader, StrictUndefined
7
+
8
+ from .models import ProjectConfig
9
+
10
+ TEMPLATE_ROOT = Path(__file__).resolve().parent.parent / "templates" / "project"
11
+
12
+
13
+ def _base_dependencies(config: ProjectConfig) -> list[str]:
14
+ deps = [
15
+ "fastapi>=0.115.0",
16
+ "uvicorn>=0.30.0",
17
+ "pydantic>=2.7.0",
18
+ "pydantic-settings>=2.3.0",
19
+ "python-dotenv>=1.0.1",
20
+ ]
21
+
22
+ if config.use_postgres:
23
+ deps += ["sqlalchemy>=2.0.30", "asyncpg>=0.29.0", "alembic>=1.13.1"]
24
+ elif config.use_sqlite:
25
+ deps += ["sqlalchemy>=2.0.30", "aiosqlite>=0.20.0"]
26
+ elif config.use_mongodb:
27
+ deps += ["motor>=3.5.1", "beanie>=1.26.0"]
28
+
29
+ if config.use_jwt or config.use_oauth2:
30
+ deps.append("fastapi-users>=13.0.0")
31
+
32
+ if config.use_ai:
33
+ deps += ["httpx>=0.27.0", "sse-starlette>=2.1.0"]
34
+ if config.ai.value == "openai":
35
+ deps.append("openai>=1.35.0")
36
+ if config.ai.value == "langchain":
37
+ deps += ["langchain>=0.2.6", "langchain-openai>=0.1.14"]
38
+ if config.ai.value == "huggingface":
39
+ deps += ["transformers>=4.42.0", "accelerate>=0.32.0"]
40
+
41
+ if config.use_celery:
42
+ deps += ["celery>=5.4.0", "redis>=5.0.7", "flower>=2.0.1"]
43
+
44
+ if config.use_pgvector:
45
+ deps.append("pgvector>=0.2.5")
46
+ if config.use_weaviate:
47
+ deps.append("weaviate-client>=4.6.7")
48
+
49
+ if config.use_sentry:
50
+ deps.append("sentry-sdk>=2.7.1")
51
+ if config.use_prometheus:
52
+ deps.append("prometheus-fastapi-instrumentator>=7.0.0")
53
+
54
+ if config.use_frontend:
55
+ deps.append("jinja2>=3.1.4")
56
+
57
+ return deps
58
+
59
+
60
+ def _dev_dependencies() -> list[str]:
61
+ return [
62
+ "pytest>=8.2.0",
63
+ "pytest-asyncio>=0.23.8",
64
+ "httpx>=0.27.0",
65
+ "factory-boy>=3.3.0",
66
+ "black>=24.4.2",
67
+ "ruff>=0.5.0",
68
+ "mypy>=1.10.0",
69
+ "pre-commit>=3.7.1",
70
+ "commitizen>=3.27.0",
71
+ ]
72
+
73
+
74
+ def _template_map(config: ProjectConfig) -> list[tuple[str, str]]:
75
+ mapping = [
76
+ ("README.md.j2", "README.md"),
77
+ ("pyproject.toml.j2", "pyproject.toml"),
78
+ (".env.example.j2", ".env.example"),
79
+ ("Dockerfile.j2", "Dockerfile"),
80
+ ("docker-compose.yml.j2", "docker-compose.yml"),
81
+ ("app/__init__.py.j2", "app/__init__.py"),
82
+ ("app/main.py.j2", "app/main.py"),
83
+ ("app/core/config.py.j2", "app/core/config.py"),
84
+ ("app/core/deps.py.j2", "app/core/deps.py"),
85
+ ("app/core/security.py.j2", "app/core/security.py"),
86
+ ("app/api/__init__.py.j2", "app/api/__init__.py"),
87
+ ("app/api/v1/__init__.py.j2", "app/api/v1/__init__.py"),
88
+ ("app/api/v1/deps.py.j2", "app/api/v1/deps.py"),
89
+ ("app/api/v1/endpoints/__init__.py.j2", "app/api/v1/endpoints/__init__.py"),
90
+ ("app/api/v1/endpoints/health.py.j2", "app/api/v1/endpoints/health.py"),
91
+ ("app/models/__init__.py.j2", "app/models/__init__.py"),
92
+ ("app/schemas/__init__.py.j2", "app/schemas/__init__.py"),
93
+ ("app/crud/__init__.py.j2", "app/crud/__init__.py"),
94
+ ("tests/conftest.py.j2", "tests/conftest.py"),
95
+ ("tests/test_api/test_health.py.j2", "tests/test_api/test_health.py"),
96
+ (".github/workflows/ci.yml.j2", ".github/workflows/ci.yml"),
97
+ (".gitignore.j2", ".gitignore"),
98
+ ]
99
+
100
+ if config.use_postgres:
101
+ mapping.append(("migrations/.gitkeep.j2", "migrations/.gitkeep"))
102
+
103
+ if config.use_ai:
104
+ mapping += [
105
+ ("app/api/v1/endpoints/ai/__init__.py.j2", "app/api/v1/endpoints/ai/__init__.py"),
106
+ ("app/api/v1/endpoints/ai/chat.py.j2", "app/api/v1/endpoints/ai/chat.py"),
107
+ ("app/api/v1/endpoints/ai/embeddings.py.j2", "app/api/v1/endpoints/ai/embeddings.py"),
108
+ ]
109
+
110
+ if config.use_celery:
111
+ mapping.append(("app/tasks.py.j2", "app/tasks.py"))
112
+
113
+ if config.use_frontend:
114
+ mapping += [
115
+ ("frontend/package.json.j2", "frontend/package.json"),
116
+ ("frontend/index.html.j2", "frontend/index.html"),
117
+ ("frontend/src/main.js.j2", "frontend/src/main.js"),
118
+ ]
119
+
120
+ return mapping
121
+
122
+
123
+ def render_project(config: ProjectConfig, destination: Path) -> Path:
124
+ project_dir = destination / config.project_slug
125
+ if project_dir.exists():
126
+ raise FileExistsError(f"Directory already exists: {project_dir}")
127
+
128
+ project_dir.mkdir(parents=True, exist_ok=False)
129
+
130
+ env = Environment(
131
+ loader=FileSystemLoader(str(TEMPLATE_ROOT)),
132
+ autoescape=False,
133
+ trim_blocks=True,
134
+ lstrip_blocks=True,
135
+ undefined=StrictUndefined,
136
+ )
137
+
138
+ context: dict[str, Any] = {
139
+ "config": config,
140
+ "project_name": config.project_name,
141
+ "project_slug": config.project_slug,
142
+ "dependencies": _base_dependencies(config),
143
+ "dev_dependencies": _dev_dependencies(),
144
+ }
145
+
146
+ for source_name, target_name in _template_map(config):
147
+ template = env.get_template(source_name)
148
+ rendered = template.render(**context)
149
+ target = project_dir / target_name
150
+ target.parent.mkdir(parents=True, exist_ok=True)
151
+ target.write_text(rendered.rstrip() + "\n", encoding="utf-8")
152
+
153
+ return project_dir
@@ -0,0 +1,116 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+
6
+
7
+ class DatabaseChoice(str, Enum):
8
+ postgres = "postgres"
9
+ mongodb = "mongodb"
10
+ sqlite = "sqlite"
11
+
12
+
13
+ class AuthChoice(str, Enum):
14
+ none = "none"
15
+ jwt = "jwt"
16
+ oauth2 = "oauth2"
17
+
18
+
19
+ class TaskChoice(str, Enum):
20
+ none = "none"
21
+ celery_redis = "celery+redis"
22
+
23
+
24
+ class AIChoice(str, Enum):
25
+ none = "none"
26
+ openai = "openai"
27
+ langchain = "langchain"
28
+ huggingface = "huggingface"
29
+
30
+
31
+ class VectorDBChoice(str, Enum):
32
+ none = "none"
33
+ pgvector = "pgvector"
34
+ weaviate = "weaviate"
35
+
36
+
37
+ class DockerChoice(str, Enum):
38
+ cpu = "cpu"
39
+ gpu = "gpu"
40
+
41
+
42
+ class MonitoringChoice(str, Enum):
43
+ none = "none"
44
+ sentry = "sentry"
45
+ prometheus = "prometheus"
46
+
47
+
48
+ class FrontendChoice(str, Enum):
49
+ none = "none"
50
+ htmx_vite = "htmx+vite"
51
+
52
+
53
+ @dataclass
54
+ class ProjectConfig:
55
+ project_name: str
56
+ project_slug: str
57
+ db: DatabaseChoice
58
+ auth: AuthChoice
59
+ tasks: TaskChoice
60
+ ai: AIChoice
61
+ vector_db: VectorDBChoice
62
+ docker: DockerChoice
63
+ monitoring: MonitoringChoice
64
+ frontend: FrontendChoice
65
+
66
+ @property
67
+ def use_ai(self) -> bool:
68
+ return self.ai != AIChoice.none
69
+
70
+ @property
71
+ def use_postgres(self) -> bool:
72
+ return self.db == DatabaseChoice.postgres
73
+
74
+ @property
75
+ def use_mongodb(self) -> bool:
76
+ return self.db == DatabaseChoice.mongodb
77
+
78
+ @property
79
+ def use_sqlite(self) -> bool:
80
+ return self.db == DatabaseChoice.sqlite
81
+
82
+ @property
83
+ def use_jwt(self) -> bool:
84
+ return self.auth == AuthChoice.jwt
85
+
86
+ @property
87
+ def use_oauth2(self) -> bool:
88
+ return self.auth == AuthChoice.oauth2
89
+
90
+ @property
91
+ def use_celery(self) -> bool:
92
+ return self.tasks == TaskChoice.celery_redis
93
+
94
+ @property
95
+ def use_pgvector(self) -> bool:
96
+ return self.vector_db == VectorDBChoice.pgvector
97
+
98
+ @property
99
+ def use_weaviate(self) -> bool:
100
+ return self.vector_db == VectorDBChoice.weaviate
101
+
102
+ @property
103
+ def use_gpu(self) -> bool:
104
+ return self.docker == DockerChoice.gpu
105
+
106
+ @property
107
+ def use_sentry(self) -> bool:
108
+ return self.monitoring == MonitoringChoice.sentry
109
+
110
+ @property
111
+ def use_prometheus(self) -> bool:
112
+ return self.monitoring == MonitoringChoice.prometheus
113
+
114
+ @property
115
+ def use_frontend(self) -> bool:
116
+ return self.frontend == FrontendChoice.htmx_vite
@@ -0,0 +1,48 @@
1
+ [tool.poetry]
2
+ name = "fastai-stack"
3
+ version = "0.1.0"
4
+ description = "Interactive CLI generator for production-ready FastAPI AI stacks"
5
+ authors = ["Harsh Gautam <hgqeir@gmai.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ packages = [{ include = "fastforge" }]
9
+ homepage = "https://github.com/HarshG1308/fastai-stack"
10
+ repository = "https://github.com/HarshG1308/fastai-stack"
11
+ keywords = ["fastapi", "cli", "scaffold", "ai", "ml", "generator"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: Software Development :: Code Generators"
22
+ ]
23
+
24
+ [tool.poetry.dependencies]
25
+ python = ">=3.10,<4.0"
26
+ typer = ">=0.12.0"
27
+ rich = ">=13.7.0"
28
+ jinja2 = ">=3.1.4"
29
+
30
+ [tool.poetry.group.dev.dependencies]
31
+ pytest = ">=8.2.0"
32
+ ruff = ">=0.5.0"
33
+ mypy = ">=1.10.0"
34
+
35
+ [tool.poetry.scripts]
36
+ fastai-stack = "fastforge.cli:app"
37
+
38
+ [tool.ruff]
39
+ line-length = 100
40
+ target-version = "py310"
41
+
42
+ [tool.pytest.ini_options]
43
+ addopts = "-q"
44
+ testpaths = ["tests"]
45
+
46
+ [build-system]
47
+ requires = ["poetry-core>=1.9.0"]
48
+ build-backend = "poetry.core.masonry.api"