python-infrakit-dev 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl
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.
- infrakit/__init__.py +74 -0
- infrakit/cli/__init__.py +5 -1
- infrakit/cli/commands/__init__.py +19 -1
- infrakit/core/__init__.py +46 -0
- infrakit/core/config/__init__.py +71 -0
- infrakit/llm/__init__.py +2 -1
- infrakit/llm/client.py +140 -20
- infrakit/llm/key_manager.py +57 -6
- infrakit/llm/models.py +1 -0
- infrakit/llm/providers/__init__.py +2 -1
- infrakit/llm/providers/groq.py +167 -0
- infrakit/scaffolder/ai.py +19 -6
- infrakit/scaffolder/backend.py +27 -9
- infrakit/scaffolder/cli_tool.py +20 -10
- infrakit/scaffolder/generator.py +62 -2
- infrakit/scaffolder/pipeline.py +17 -8
- {python_infrakit_dev-0.1.4.dist-info → python_infrakit_dev-0.1.6.dist-info}/METADATA +114 -8
- {python_infrakit_dev-0.1.4.dist-info → python_infrakit_dev-0.1.6.dist-info}/RECORD +20 -19
- {python_infrakit_dev-0.1.4.dist-info → python_infrakit_dev-0.1.6.dist-info}/WHEEL +1 -1
- {python_infrakit_dev-0.1.4.dist-info → python_infrakit_dev-0.1.6.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""
|
|
2
|
+
infrakit.llm.providers.groq
|
|
3
|
+
-----------------------------
|
|
4
|
+
Groq provider — wraps the groq Python SDK.
|
|
5
|
+
|
|
6
|
+
Install dependency::
|
|
7
|
+
|
|
8
|
+
pip install groq
|
|
9
|
+
|
|
10
|
+
Supported models (default): llama-3.3-70b-versatile
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import time
|
|
16
|
+
from typing import Any, Optional, Type
|
|
17
|
+
|
|
18
|
+
from pydantic import BaseModel
|
|
19
|
+
|
|
20
|
+
from ..models import LLMResponse, Prompt
|
|
21
|
+
from .base import BaseProvider
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GroqProvider(BaseProvider):
|
|
25
|
+
"""
|
|
26
|
+
Provider for Groq's Chat Completions API.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
model Model string to use. Defaults to ``llama-3.3-70b-versatile``.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
DEFAULT_MODEL = "llama-3.3-70b-versatile"
|
|
34
|
+
PROVIDER_NAME = "groq"
|
|
35
|
+
|
|
36
|
+
def __init__(self, model: Optional[str] = None) -> None:
|
|
37
|
+
super().__init__(model)
|
|
38
|
+
self._check_sdk()
|
|
39
|
+
|
|
40
|
+
# ── public interface ───────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
async def async_generate(
|
|
43
|
+
self,
|
|
44
|
+
prompt: Prompt,
|
|
45
|
+
api_key: str,
|
|
46
|
+
response_model: Optional[Type[BaseModel]] = None,
|
|
47
|
+
schema_retries: int = 2,
|
|
48
|
+
**kwargs: Any,
|
|
49
|
+
) -> LLMResponse:
|
|
50
|
+
"""Async generate using groq.AsyncGroq."""
|
|
51
|
+
from groq import AsyncGroq
|
|
52
|
+
|
|
53
|
+
client = AsyncGroq(api_key=api_key)
|
|
54
|
+
messages = self._build_messages(prompt)
|
|
55
|
+
t0 = time.perf_counter()
|
|
56
|
+
|
|
57
|
+
response = await client.chat.completions.create(
|
|
58
|
+
model=self.model,
|
|
59
|
+
messages=messages,
|
|
60
|
+
**kwargs,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
latency_ms = (time.perf_counter() - t0) * 1000
|
|
64
|
+
return self._build_response(response, latency_ms, response_model, schema_retries, api_key)
|
|
65
|
+
|
|
66
|
+
def sync_generate(
|
|
67
|
+
self,
|
|
68
|
+
prompt: Prompt,
|
|
69
|
+
api_key: str,
|
|
70
|
+
response_model: Optional[Type[BaseModel]] = None,
|
|
71
|
+
schema_retries: int = 2,
|
|
72
|
+
**kwargs: Any,
|
|
73
|
+
) -> LLMResponse:
|
|
74
|
+
"""Sync generate using groq.Groq (the blocking SDK client)."""
|
|
75
|
+
from groq import Groq
|
|
76
|
+
|
|
77
|
+
client = Groq(api_key=api_key)
|
|
78
|
+
messages = self._build_messages(prompt)
|
|
79
|
+
t0 = time.perf_counter()
|
|
80
|
+
|
|
81
|
+
response = client.chat.completions.create(
|
|
82
|
+
model=self.model,
|
|
83
|
+
messages=messages,
|
|
84
|
+
**kwargs,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
latency_ms = (time.perf_counter() - t0) * 1000
|
|
88
|
+
return self._build_response(response, latency_ms, response_model, schema_retries, api_key)
|
|
89
|
+
|
|
90
|
+
# ── internal helpers ───────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def _build_messages(prompt: Prompt) -> list[dict]:
|
|
94
|
+
messages = []
|
|
95
|
+
if prompt.system:
|
|
96
|
+
messages.append({"role": "system", "content": prompt.system})
|
|
97
|
+
messages.append({"role": "user", "content": prompt.user})
|
|
98
|
+
return messages
|
|
99
|
+
|
|
100
|
+
def _build_response(
|
|
101
|
+
self,
|
|
102
|
+
response: Any,
|
|
103
|
+
latency_ms: float,
|
|
104
|
+
response_model: Optional[Type[BaseModel]],
|
|
105
|
+
schema_retries: int,
|
|
106
|
+
api_key: str,
|
|
107
|
+
) -> LLMResponse:
|
|
108
|
+
choice = response.choices[0]
|
|
109
|
+
content = choice.message.content or ""
|
|
110
|
+
|
|
111
|
+
usage = response.usage
|
|
112
|
+
input_tokens = usage.prompt_tokens if usage else 0
|
|
113
|
+
output_tokens = usage.completion_tokens if usage else 0
|
|
114
|
+
total_tokens = usage.total_tokens if usage else 0
|
|
115
|
+
|
|
116
|
+
parsed = None
|
|
117
|
+
schema_matched = False
|
|
118
|
+
|
|
119
|
+
if response_model is not None:
|
|
120
|
+
parsed, schema_matched = self._validate_schema(
|
|
121
|
+
content, response_model, schema_retries
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return LLMResponse(
|
|
125
|
+
content=content,
|
|
126
|
+
parsed=parsed,
|
|
127
|
+
schema_matched=schema_matched,
|
|
128
|
+
provider=self.PROVIDER_NAME,
|
|
129
|
+
model=self.model,
|
|
130
|
+
key_id=api_key[:8],
|
|
131
|
+
input_tokens=input_tokens,
|
|
132
|
+
output_tokens=output_tokens,
|
|
133
|
+
total_tokens=total_tokens,
|
|
134
|
+
latency_ms=latency_ms,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def _check_sdk() -> None:
|
|
139
|
+
try:
|
|
140
|
+
import groq # noqa: F401
|
|
141
|
+
except ImportError as exc:
|
|
142
|
+
raise ImportError(
|
|
143
|
+
"groq package is required for GroqProvider. "
|
|
144
|
+
"Install it with: pip install groq"
|
|
145
|
+
) from exc
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def _is_quota_error(exc: Exception) -> bool:
|
|
149
|
+
"""
|
|
150
|
+
Groq-specific quota/auth HTTP status codes.
|
|
151
|
+
|
|
152
|
+
429 with "rate_limit_exceeded" is *transient* (burst limit) and should
|
|
153
|
+
be retried with backoff — NOT treated as a permanent quota exhaustion.
|
|
154
|
+
Only 401/402 and 429 with "quota" or "billing" in the message warrant
|
|
155
|
+
immediate model deactivation.
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
from groq import APIStatusError
|
|
159
|
+
if isinstance(exc, APIStatusError):
|
|
160
|
+
if exc.status_code in (401, 402):
|
|
161
|
+
return True
|
|
162
|
+
if exc.status_code == 429:
|
|
163
|
+
msg = str(exc).lower()
|
|
164
|
+
return "quota" in msg or "billing" in msg
|
|
165
|
+
except ImportError:
|
|
166
|
+
pass
|
|
167
|
+
return BaseProvider._is_quota_error(exc)
|
infrakit/scaffolder/ai.py
CHANGED
|
@@ -40,6 +40,8 @@ from infrakit.scaffolder.generator import (
|
|
|
40
40
|
_write,
|
|
41
41
|
_config_content,
|
|
42
42
|
_gitignore,
|
|
43
|
+
_infrakit_dep,
|
|
44
|
+
_pkg_dep,
|
|
43
45
|
_logger_util,
|
|
44
46
|
_src_init,
|
|
45
47
|
_tests_init,
|
|
@@ -124,9 +126,11 @@ def _load_keys() -> dict:
|
|
|
124
126
|
# fall back to keys declared in the config file
|
|
125
127
|
openai_key = _cfg.get("OPENAI_API_KEY", "")
|
|
126
128
|
gemini_key = _cfg.get("GEMINI_API_KEY", "")
|
|
129
|
+
groq_key = _cfg.get("GROQ_API_KEY", "")
|
|
127
130
|
return {{
|
|
128
131
|
"openai_keys": [openai_key] if openai_key else [],
|
|
129
132
|
"gemini_keys": [gemini_key] if gemini_key else [],
|
|
133
|
+
"groq_keys": [groq_key] if groq_key else [],
|
|
130
134
|
}}
|
|
131
135
|
|
|
132
136
|
|
|
@@ -142,6 +146,7 @@ llm: LLMClient = LLMClient(
|
|
|
142
146
|
max_concurrent=int(_cfg.get("LLM_CONCURRENCY", 3)),
|
|
143
147
|
openai_model=_cfg.get("OPENAI_MODEL") or None,
|
|
144
148
|
gemini_model=_cfg.get("GEMINI_MODEL") or None,
|
|
149
|
+
groq_model=_cfg.get("GROQ_MODEL") or None,
|
|
145
150
|
)
|
|
146
151
|
|
|
147
152
|
__all__ = ["llm", "Prompt"]
|
|
@@ -316,7 +321,8 @@ def _keys_json_template() -> str:
|
|
|
316
321
|
{
|
|
317
322
|
"_comment": "Fill in your API keys. Never commit this file — it is in .gitignore.",
|
|
318
323
|
"openai_keys": [],
|
|
319
|
-
"gemini_keys":
|
|
324
|
+
"gemini_keys": [],
|
|
325
|
+
"groq_keys": []
|
|
320
326
|
}
|
|
321
327
|
"""
|
|
322
328
|
|
|
@@ -401,6 +407,12 @@ pytest
|
|
|
401
407
|
|
|
402
408
|
def _ai_pyproject(project_name: str, version: str, description: str, author: str) -> str:
|
|
403
409
|
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
410
|
+
infrakit_dep = _infrakit_dep()
|
|
411
|
+
openai_dep = _pkg_dep("openai")
|
|
412
|
+
genai_dep = _pkg_dep("google-genai")
|
|
413
|
+
groq_dep = _pkg_dep("groq")
|
|
414
|
+
pydantic_dep = _pkg_dep("pydantic")
|
|
415
|
+
tqdm_dep = _pkg_dep("tqdm")
|
|
404
416
|
return f"""\
|
|
405
417
|
[project]
|
|
406
418
|
name = "{project_name}"
|
|
@@ -413,11 +425,12 @@ authors = [
|
|
|
413
425
|
]
|
|
414
426
|
|
|
415
427
|
dependencies = [
|
|
416
|
-
|
|
417
|
-
"
|
|
418
|
-
"
|
|
419
|
-
"
|
|
420
|
-
"
|
|
428
|
+
{infrakit_dep},
|
|
429
|
+
"{openai_dep}",
|
|
430
|
+
"{genai_dep}",
|
|
431
|
+
"{groq_dep}",
|
|
432
|
+
"{pydantic_dep}",
|
|
433
|
+
"{tqdm_dep}",
|
|
421
434
|
]
|
|
422
435
|
|
|
423
436
|
[project.optional-dependencies]
|
infrakit/scaffolder/backend.py
CHANGED
|
@@ -48,6 +48,8 @@ from infrakit.scaffolder.generator import (
|
|
|
48
48
|
_mkdir,
|
|
49
49
|
_write,
|
|
50
50
|
_gitignore,
|
|
51
|
+
_infrakit_dep,
|
|
52
|
+
_pkg_dep,
|
|
51
53
|
_logger_util,
|
|
52
54
|
_src_init,
|
|
53
55
|
_tests_init,
|
|
@@ -64,10 +66,12 @@ def _backend_env_config(project_name: str, include_llm: bool) -> str:
|
|
|
64
66
|
LLM_KEYS_FILE=keys.json
|
|
65
67
|
OPENAI_API_KEY=
|
|
66
68
|
GEMINI_API_KEY=
|
|
69
|
+
GROQ_API_KEY=
|
|
67
70
|
LLM_MODE=async
|
|
68
71
|
LLM_CONCURRENCY=3
|
|
69
72
|
# OPENAI_MODEL=gpt-4o
|
|
70
73
|
# GEMINI_MODEL=gemini-2.0-flash
|
|
74
|
+
# GROQ_MODEL=llama-3.3-70b-versatile
|
|
71
75
|
""" if include_llm else ""
|
|
72
76
|
return f"""\
|
|
73
77
|
# Application
|
|
@@ -96,10 +100,12 @@ def _backend_yaml_config(project_name: str, include_llm: bool) -> str:
|
|
|
96
100
|
LLM_KEYS_FILE: keys.json
|
|
97
101
|
OPENAI_API_KEY: ""
|
|
98
102
|
GEMINI_API_KEY: ""
|
|
103
|
+
GROQ_API_KEY: ""
|
|
99
104
|
LLM_MODE: async
|
|
100
105
|
LLM_CONCURRENCY: 3
|
|
101
106
|
# OPENAI_MODEL: gpt-4o
|
|
102
107
|
# GEMINI_MODEL: gemini-2.0-flash
|
|
108
|
+
# GROQ_MODEL: llama-3.3-70b-versatile
|
|
103
109
|
""" if include_llm else ""
|
|
104
110
|
return f"""\
|
|
105
111
|
# Application configuration
|
|
@@ -127,6 +133,7 @@ def _backend_json_config(project_name: str, include_llm: bool) -> str:
|
|
|
127
133
|
"LLM_KEYS_FILE": "keys.json",
|
|
128
134
|
"OPENAI_API_KEY": "",
|
|
129
135
|
"GEMINI_API_KEY": "",
|
|
136
|
+
"GROQ_API_KEY": "",
|
|
130
137
|
"LLM_MODE": "async",
|
|
131
138
|
"LLM_CONCURRENCY": 3""" if include_llm else ""
|
|
132
139
|
return f"""\
|
|
@@ -195,6 +202,7 @@ class Settings(BaseSettings):
|
|
|
195
202
|
# optional: LLM keys (override ~/.infrakit/llm/ defaults)
|
|
196
203
|
openai_api_key: str = ""
|
|
197
204
|
gemini_api_key: str = ""
|
|
205
|
+
groq_api_key: str = ""
|
|
198
206
|
llm_mode: str = "async"
|
|
199
207
|
llm_concurrency: int = 3
|
|
200
208
|
|
|
@@ -448,7 +456,16 @@ services:
|
|
|
448
456
|
def _backend_pyproject(
|
|
449
457
|
project_name: str, version: str, description: str, author: str
|
|
450
458
|
) -> str:
|
|
451
|
-
author_line
|
|
459
|
+
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
460
|
+
infrakit_dep = _infrakit_dep()
|
|
461
|
+
fastapi_dep = _pkg_dep("fastapi")
|
|
462
|
+
uvicorn_dep = _pkg_dep("uvicorn")
|
|
463
|
+
pydantic_dep = _pkg_dep("pydantic")
|
|
464
|
+
pydset_dep = _pkg_dep("pydantic-settings")
|
|
465
|
+
openai_dep = _pkg_dep("openai")
|
|
466
|
+
genai_dep = _pkg_dep("google-genai")
|
|
467
|
+
groq_dep = _pkg_dep("groq")
|
|
468
|
+
tqdm_dep = _pkg_dep("tqdm")
|
|
452
469
|
return f"""\
|
|
453
470
|
[project]
|
|
454
471
|
name = "{project_name}"
|
|
@@ -461,14 +478,15 @@ authors = [
|
|
|
461
478
|
]
|
|
462
479
|
|
|
463
480
|
dependencies = [
|
|
464
|
-
|
|
465
|
-
"
|
|
466
|
-
"
|
|
467
|
-
"
|
|
468
|
-
"
|
|
469
|
-
"
|
|
470
|
-
"
|
|
471
|
-
"
|
|
481
|
+
{infrakit_dep},
|
|
482
|
+
"{fastapi_dep}",
|
|
483
|
+
"{uvicorn_dep}[standard]",
|
|
484
|
+
"{pydantic_dep}",
|
|
485
|
+
"{pydset_dep}",
|
|
486
|
+
"{openai_dep}",
|
|
487
|
+
"{genai_dep}",
|
|
488
|
+
"{groq_dep}",
|
|
489
|
+
"{tqdm_dep}",
|
|
472
490
|
]
|
|
473
491
|
|
|
474
492
|
[project.optional-dependencies]
|
infrakit/scaffolder/cli_tool.py
CHANGED
|
@@ -40,6 +40,8 @@ from infrakit.scaffolder.generator import (
|
|
|
40
40
|
_write,
|
|
41
41
|
_config_content,
|
|
42
42
|
_gitignore,
|
|
43
|
+
_infrakit_dep,
|
|
44
|
+
_pkg_dep,
|
|
43
45
|
_logger_util,
|
|
44
46
|
_src_init,
|
|
45
47
|
_tests_init,
|
|
@@ -199,13 +201,21 @@ def test_hello_name():
|
|
|
199
201
|
def _cli_pyproject(
|
|
200
202
|
project_name: str, version: str, description: str, author: str, include_llm: bool
|
|
201
203
|
) -> str:
|
|
202
|
-
author_line
|
|
203
|
-
cmd
|
|
204
|
-
|
|
205
|
-
"
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
|
|
204
|
+
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
205
|
+
cmd = project_name.replace("_", "-")
|
|
206
|
+
infrakit_dep = _infrakit_dep()
|
|
207
|
+
typer_dep = _pkg_dep("typer")
|
|
208
|
+
pydantic_dep = _pkg_dep("pydantic")
|
|
209
|
+
openai_dep = _pkg_dep("openai")
|
|
210
|
+
genai_dep = _pkg_dep("google-genai")
|
|
211
|
+
groq_dep = _pkg_dep("groq")
|
|
212
|
+
tqdm_dep = _pkg_dep("tqdm")
|
|
213
|
+
llm_deps = f'''\
|
|
214
|
+
"{openai_dep}",
|
|
215
|
+
"{genai_dep}",
|
|
216
|
+
"{groq_dep}",
|
|
217
|
+
"{tqdm_dep}",
|
|
218
|
+
''' if include_llm else ""
|
|
209
219
|
return f"""\
|
|
210
220
|
[project]
|
|
211
221
|
name = "{project_name}"
|
|
@@ -218,9 +228,9 @@ authors = [
|
|
|
218
228
|
]
|
|
219
229
|
|
|
220
230
|
dependencies = [
|
|
221
|
-
|
|
222
|
-
"
|
|
223
|
-
"
|
|
231
|
+
{infrakit_dep},
|
|
232
|
+
"{typer_dep}[all]",
|
|
233
|
+
"{pydantic_dep}",
|
|
224
234
|
{llm_deps}]
|
|
225
235
|
|
|
226
236
|
[project.optional-dependencies]
|
infrakit/scaffolder/generator.py
CHANGED
|
@@ -63,6 +63,58 @@ def _mkdir(result: ScaffoldResult, path: Path) -> None:
|
|
|
63
63
|
result.entries.append(ScaffoldEntry(path=path, status="created", kind="dir"))
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
# ── helpers ───────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
_version_cache: dict[str, str] = {}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _get_package_version(pkg_name: str) -> str:
|
|
72
|
+
"""
|
|
73
|
+
Return the installed or latest-PyPI version of *pkg_name*.
|
|
74
|
+
|
|
75
|
+
Tries ``importlib.metadata`` first (fast, no network), then falls back
|
|
76
|
+
to a PyPI API call. Results are cached in-process.
|
|
77
|
+
"""
|
|
78
|
+
if pkg_name in _version_cache:
|
|
79
|
+
return _version_cache[pkg_name]
|
|
80
|
+
|
|
81
|
+
ver = ""
|
|
82
|
+
try:
|
|
83
|
+
from importlib.metadata import version
|
|
84
|
+
ver = version(pkg_name)
|
|
85
|
+
except Exception:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
if not ver:
|
|
89
|
+
try:
|
|
90
|
+
import json
|
|
91
|
+
import urllib.request
|
|
92
|
+
url = f"https://pypi.org/pypi/{pkg_name}/json"
|
|
93
|
+
with urllib.request.urlopen(url, timeout=5) as resp: # noqa: S310
|
|
94
|
+
ver = json.loads(resp.read())["info"]["version"]
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
_version_cache[pkg_name] = ver
|
|
99
|
+
return ver
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _get_infrakit_version() -> str:
|
|
103
|
+
return _get_package_version("python-infrakit-dev")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _infrakit_dep() -> str:
|
|
107
|
+
"""Return the versioned dependency string for python-infrakit-dev."""
|
|
108
|
+
ver = _get_infrakit_version()
|
|
109
|
+
return f'"python-infrakit-dev>={ver}"' if ver else '"python-infrakit-dev"'
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _pkg_dep(pkg_name: str) -> str:
|
|
113
|
+
"""Return a versioned dep string like ``openai>=1.2.3`` or just ``openai``."""
|
|
114
|
+
ver = _get_package_version(pkg_name)
|
|
115
|
+
return f"{pkg_name}>={ver}" if ver else pkg_name
|
|
116
|
+
|
|
117
|
+
|
|
66
118
|
# ── template content ──────────────────────────────────────────────────────────
|
|
67
119
|
|
|
68
120
|
def _pyproject_toml(
|
|
@@ -72,6 +124,7 @@ def _pyproject_toml(
|
|
|
72
124
|
author: str,
|
|
73
125
|
) -> str:
|
|
74
126
|
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
127
|
+
infrakit_dep = _infrakit_dep()
|
|
75
128
|
return f"""\
|
|
76
129
|
[project]
|
|
77
130
|
name = "{project_name}"
|
|
@@ -84,7 +137,7 @@ authors = [
|
|
|
84
137
|
]
|
|
85
138
|
|
|
86
139
|
dependencies = [
|
|
87
|
-
|
|
140
|
+
{infrakit_dep},
|
|
88
141
|
]
|
|
89
142
|
|
|
90
143
|
[project.optional-dependencies]
|
|
@@ -96,10 +149,12 @@ dev = [
|
|
|
96
149
|
|
|
97
150
|
|
|
98
151
|
def _requirements_txt(project_name: str) -> str:
|
|
152
|
+
ver = _get_infrakit_version()
|
|
153
|
+
dep = f"python-infrakit-dev>={ver}" if ver else "python-infrakit-dev"
|
|
99
154
|
return f"""\
|
|
100
155
|
# requirements.txt — {project_name}
|
|
101
156
|
# Add your dependencies below.
|
|
102
|
-
|
|
157
|
+
{dep}
|
|
103
158
|
"""
|
|
104
159
|
|
|
105
160
|
|
|
@@ -110,10 +165,12 @@ def _env_config(include_llm: bool = False) -> str:
|
|
|
110
165
|
LLM_KEYS_FILE=keys.json
|
|
111
166
|
OPENAI_API_KEY=
|
|
112
167
|
GEMINI_API_KEY=
|
|
168
|
+
GROQ_API_KEY=
|
|
113
169
|
LLM_MODE=async
|
|
114
170
|
LLM_CONCURRENCY=3
|
|
115
171
|
# OPENAI_MODEL=gpt-4o
|
|
116
172
|
# GEMINI_MODEL=gemini-2.0-flash
|
|
173
|
+
# GROQ_MODEL=llama-3.3-70b-versatile
|
|
117
174
|
# LLM_STATE_DIR=
|
|
118
175
|
# LLM_QUOTA_FILE=
|
|
119
176
|
""" if include_llm else ""
|
|
@@ -139,10 +196,12 @@ def _yaml_config(include_llm: bool = False) -> str:
|
|
|
139
196
|
LLM_KEYS_FILE: keys.json
|
|
140
197
|
OPENAI_API_KEY: ""
|
|
141
198
|
GEMINI_API_KEY: ""
|
|
199
|
+
GROQ_API_KEY: ""
|
|
142
200
|
LLM_MODE: async
|
|
143
201
|
LLM_CONCURRENCY: 3
|
|
144
202
|
# OPENAI_MODEL: gpt-4o
|
|
145
203
|
# GEMINI_MODEL: gemini-2.0-flash
|
|
204
|
+
# GROQ_MODEL: llama-3.3-70b-versatile
|
|
146
205
|
# LLM_STATE_DIR: ""
|
|
147
206
|
# LLM_QUOTA_FILE: ""
|
|
148
207
|
""" if include_llm else ""
|
|
@@ -167,6 +226,7 @@ def _json_config(include_llm: bool = False) -> str:
|
|
|
167
226
|
"LLM_KEYS_FILE": "keys.json",
|
|
168
227
|
"OPENAI_API_KEY": "",
|
|
169
228
|
"GEMINI_API_KEY": "",
|
|
229
|
+
"GROQ_API_KEY": "",
|
|
170
230
|
"LLM_MODE": "async",
|
|
171
231
|
"LLM_CONCURRENCY": 3""" if include_llm else ""
|
|
172
232
|
return f"""\
|
infrakit/scaffolder/pipeline.py
CHANGED
|
@@ -49,6 +49,8 @@ from infrakit.scaffolder.generator import (
|
|
|
49
49
|
_write,
|
|
50
50
|
_config_content,
|
|
51
51
|
_gitignore,
|
|
52
|
+
_infrakit_dep,
|
|
53
|
+
_pkg_dep,
|
|
52
54
|
_logger_util,
|
|
53
55
|
_src_init,
|
|
54
56
|
_tests_init,
|
|
@@ -374,12 +376,19 @@ def test_runner_returns_all_stages():
|
|
|
374
376
|
def _pipeline_pyproject(
|
|
375
377
|
project_name: str, version: str, description: str, author: str, include_llm: bool
|
|
376
378
|
) -> str:
|
|
377
|
-
author_line
|
|
378
|
-
|
|
379
|
-
"
|
|
380
|
-
"
|
|
381
|
-
"
|
|
382
|
-
|
|
379
|
+
author_line = f' "{author}",' if author else ' # "Your Name <you@example.com>",'
|
|
380
|
+
infrakit_dep = _infrakit_dep()
|
|
381
|
+
pydantic_dep = _pkg_dep("pydantic")
|
|
382
|
+
openai_dep = _pkg_dep("openai")
|
|
383
|
+
genai_dep = _pkg_dep("google-genai")
|
|
384
|
+
groq_dep = _pkg_dep("groq")
|
|
385
|
+
tqdm_dep = _pkg_dep("tqdm")
|
|
386
|
+
llm_deps = f'''\
|
|
387
|
+
"{openai_dep}",
|
|
388
|
+
"{genai_dep}",
|
|
389
|
+
"{groq_dep}",
|
|
390
|
+
"{tqdm_dep}",
|
|
391
|
+
''' if include_llm else ""
|
|
383
392
|
return f"""\
|
|
384
393
|
[project]
|
|
385
394
|
name = "{project_name}"
|
|
@@ -392,8 +401,8 @@ authors = [
|
|
|
392
401
|
]
|
|
393
402
|
|
|
394
403
|
dependencies = [
|
|
395
|
-
|
|
396
|
-
"
|
|
404
|
+
{infrakit_dep},
|
|
405
|
+
"{pydantic_dep}",
|
|
397
406
|
{llm_deps}]
|
|
398
407
|
|
|
399
408
|
[project.optional-dependencies]
|