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.
- fastai_stack-0.1.0/LICENSE +21 -0
- fastai_stack-0.1.0/PKG-INFO +80 -0
- fastai_stack-0.1.0/README.md +53 -0
- fastai_stack-0.1.0/fastforge/__init__.py +4 -0
- fastai_stack-0.1.0/fastforge/__main__.py +3 -0
- fastai_stack-0.1.0/fastforge/cli.py +95 -0
- fastai_stack-0.1.0/fastforge/generator.py +153 -0
- fastai_stack-0.1.0/fastforge/models.py +116 -0
- fastai_stack-0.1.0/pyproject.toml +48 -0
|
@@ -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,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"
|