ai-generator 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.
Files changed (72) hide show
  1. ai_generator-0.1.0/LICENSE +21 -0
  2. ai_generator-0.1.0/PKG-INFO +211 -0
  3. ai_generator-0.1.0/README.md +182 -0
  4. ai_generator-0.1.0/pyproject.toml +39 -0
  5. ai_generator-0.1.0/setup.cfg +4 -0
  6. ai_generator-0.1.0/src/ai_generator.egg-info/PKG-INFO +211 -0
  7. ai_generator-0.1.0/src/ai_generator.egg-info/SOURCES.txt +70 -0
  8. ai_generator-0.1.0/src/ai_generator.egg-info/dependency_links.txt +1 -0
  9. ai_generator-0.1.0/src/ai_generator.egg-info/requires.txt +23 -0
  10. ai_generator-0.1.0/src/ai_generator.egg-info/top_level.txt +1 -0
  11. ai_generator-0.1.0/src/aigen/__init__.py +77 -0
  12. ai_generator-0.1.0/src/aigen/config.py +99 -0
  13. ai_generator-0.1.0/src/aigen/constants/__init__.py +23 -0
  14. ai_generator-0.1.0/src/aigen/constants/audio.py +90 -0
  15. ai_generator-0.1.0/src/aigen/constants/defaults.py +8 -0
  16. ai_generator-0.1.0/src/aigen/constants/image.py +76 -0
  17. ai_generator-0.1.0/src/aigen/constants/text.py +329 -0
  18. ai_generator-0.1.0/src/aigen/constants/video.py +102 -0
  19. ai_generator-0.1.0/src/aigen/dispatch.py +124 -0
  20. ai_generator-0.1.0/src/aigen/generators/__init__.py +0 -0
  21. ai_generator-0.1.0/src/aigen/generators/audio.py +25 -0
  22. ai_generator-0.1.0/src/aigen/generators/image.py +10 -0
  23. ai_generator-0.1.0/src/aigen/generators/text.py +10 -0
  24. ai_generator-0.1.0/src/aigen/generators/video.py +16 -0
  25. ai_generator-0.1.0/src/aigen/providers/__init__.py +0 -0
  26. ai_generator-0.1.0/src/aigen/providers/alibaba/__init__.py +0 -0
  27. ai_generator-0.1.0/src/aigen/providers/alibaba/provider.py +149 -0
  28. ai_generator-0.1.0/src/aigen/providers/alibaba/text.py +6 -0
  29. ai_generator-0.1.0/src/aigen/providers/base.py +370 -0
  30. ai_generator-0.1.0/src/aigen/providers/cerebras/__init__.py +0 -0
  31. ai_generator-0.1.0/src/aigen/providers/cerebras/text.py +10 -0
  32. ai_generator-0.1.0/src/aigen/providers/claude/__init__.py +0 -0
  33. ai_generator-0.1.0/src/aigen/providers/claude/cli.py +126 -0
  34. ai_generator-0.1.0/src/aigen/providers/claude/text.py +140 -0
  35. ai_generator-0.1.0/src/aigen/providers/deepseek/__init__.py +0 -0
  36. ai_generator-0.1.0/src/aigen/providers/deepseek/text.py +6 -0
  37. ai_generator-0.1.0/src/aigen/providers/gemini/__init__.py +0 -0
  38. ai_generator-0.1.0/src/aigen/providers/gemini/provider.py +99 -0
  39. ai_generator-0.1.0/src/aigen/providers/gemini/text.py +98 -0
  40. ai_generator-0.1.0/src/aigen/providers/gemini/ttm.py +109 -0
  41. ai_generator-0.1.0/src/aigen/providers/gemini/utils.py +57 -0
  42. ai_generator-0.1.0/src/aigen/providers/groq/__init__.py +0 -0
  43. ai_generator-0.1.0/src/aigen/providers/groq/stt.py +84 -0
  44. ai_generator-0.1.0/src/aigen/providers/groq/text.py +6 -0
  45. ai_generator-0.1.0/src/aigen/providers/kie/__init__.py +0 -0
  46. ai_generator-0.1.0/src/aigen/providers/kie/provider.py +142 -0
  47. ai_generator-0.1.0/src/aigen/providers/kie/stt.py +102 -0
  48. ai_generator-0.1.0/src/aigen/providers/kie/text.py +105 -0
  49. ai_generator-0.1.0/src/aigen/providers/kie/ttm.py +130 -0
  50. ai_generator-0.1.0/src/aigen/providers/kie/tts.py +108 -0
  51. ai_generator-0.1.0/src/aigen/providers/kie/video.py +231 -0
  52. ai_generator-0.1.0/src/aigen/providers/kimi/__init__.py +0 -0
  53. ai_generator-0.1.0/src/aigen/providers/kimi/text.py +6 -0
  54. ai_generator-0.1.0/src/aigen/providers/minimax/__init__.py +0 -0
  55. ai_generator-0.1.0/src/aigen/providers/minimax/provider.py +105 -0
  56. ai_generator-0.1.0/src/aigen/providers/minimax/text.py +135 -0
  57. ai_generator-0.1.0/src/aigen/providers/minimax/ttm.py +120 -0
  58. ai_generator-0.1.0/src/aigen/providers/openai/__init__.py +0 -0
  59. ai_generator-0.1.0/src/aigen/providers/openai/cli.py +167 -0
  60. ai_generator-0.1.0/src/aigen/providers/openai/image.py +131 -0
  61. ai_generator-0.1.0/src/aigen/providers/openai/text.py +42 -0
  62. ai_generator-0.1.0/src/aigen/providers/openai_compat.py +130 -0
  63. ai_generator-0.1.0/src/aigen/providers/ttm_compact.py +68 -0
  64. ai_generator-0.1.0/src/aigen/providers/zai/__init__.py +0 -0
  65. ai_generator-0.1.0/src/aigen/providers/zai/provider.py +99 -0
  66. ai_generator-0.1.0/src/aigen/providers/zai/text.py +6 -0
  67. ai_generator-0.1.0/src/aigen/py.typed +0 -0
  68. ai_generator-0.1.0/src/aigen/registry.py +187 -0
  69. ai_generator-0.1.0/src/aigen/tiers.py +36 -0
  70. ai_generator-0.1.0/tests/test_config.py +58 -0
  71. ai_generator-0.1.0/tests/test_dispatch.py +133 -0
  72. ai_generator-0.1.0/tests/test_registry.py +41 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stamatios Stamou Jr
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,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-generator
3
+ Version: 0.1.0
4
+ Summary: Roteador de chamadas LLM por model/tier, multi-provider, com retorno consistente.
5
+ Author-email: Stamatios Stamou Jr <bushier.outsets.0c@icloud.com>
6
+ License: MIT
7
+ Keywords: llm,router,openai,gemini,anthropic,multi-provider
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: httpx>=0.24
12
+ Requires-Dist: requests>=2.28
13
+ Provides-Extra: openai
14
+ Requires-Dist: openai>=1.30; extra == "openai"
15
+ Provides-Extra: gemini
16
+ Requires-Dist: google-genai>=0.3; extra == "gemini"
17
+ Provides-Extra: claude
18
+ Requires-Dist: anthropic>=0.40; extra == "claude"
19
+ Provides-Extra: cerebras
20
+ Requires-Dist: cerebras-cloud-sdk>=1.0; extra == "cerebras"
21
+ Provides-Extra: all
22
+ Requires-Dist: openai>=1.30; extra == "all"
23
+ Requires-Dist: google-genai>=0.3; extra == "all"
24
+ Requires-Dist: anthropic>=0.40; extra == "all"
25
+ Requires-Dist: cerebras-cloud-sdk>=1.0; extra == "all"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # aigen
31
+
32
+ Roteador de chamadas LLM por **model/tier**, multi-provider, com **call/return consistente**.
33
+
34
+ Você escolhe um *tier* (`basic`/`advanced`/`pro`) ou uma key `model:provider`;
35
+ o pacote resolve o provider, instancia, chama e devolve sempre um dataclass
36
+ padronizado. Trocar de modelo ou provider = editar config, não código.
37
+
38
+ ## Instalação
39
+
40
+ SDKs de provider são **extras opcionais** — instale só os que usar:
41
+
42
+ ```bash
43
+ pip install "aigen[openai]" # OpenAI, Groq, z.ai, Kimi, Alibaba, DeepSeek (openai-compat)
44
+ pip install "aigen[gemini]" # Google Gemini
45
+ pip install "aigen[claude]" # Anthropic Claude
46
+ pip install "aigen[cerebras]" # Cerebras
47
+ pip install "aigen[all]" # tudo
48
+
49
+ # Desenvolvimento (editável):
50
+ pip install -e "/Users/ssjunior/Dev/llm-router[all]"
51
+ ```
52
+
53
+ Providers que falam HTTP puro (Kie, Minimax, imagens da Alibaba/z.ai, STT da Groq)
54
+ funcionam só com o core (`httpx`, `requests`).
55
+
56
+ ## Uso
57
+
58
+ Passe `tier` ('basic'/'advanced'/'pro') **ou** `model` ('model:provider'). `tier`
59
+ default é `'basic'`; `model=` sobrepõe. `prompt` é o 1º posicional; o resto é keyword.
60
+ (stt/tts não têm tabela de tier — exigem `model=`.)
61
+
62
+ ```python
63
+ import aigen
64
+
65
+ # por tier (resolve via constants/tiers.py)
66
+ r = aigen.generate_text('Resuma o texto X', tier='basic')
67
+ print(r.content) # JSON parseado (dict/list) ou str
68
+ print(r.total_tokens)
69
+
70
+ # por key explícita
71
+ r = aigen.generate_text('Resuma X', model='gemini-2.5-flash:gemini', system_instruction='...')
72
+
73
+ # timeout por chamada (texto) — default LLM_REQUEST_TIMEOUT (900s)
74
+ r = aigen.generate_text('Resuma X', tier='basic', timeout=60)
75
+ ```
76
+
77
+ ### Outras mídias
78
+
79
+ ```python
80
+ img = aigen.generate_image('um gato astronauta', tier='pro', files=[...])
81
+ video = aigen.generate_video('clipe contínuo de...', tier='basic', task='text_to_video')
82
+ music = aigen.generate_music('lo-fi chill', tier='pro', instrumental=True)
83
+ text = aigen.transcribe(audio_url, model='whisper-large-v3:groq') # stt/tts exigem model=
84
+ ```
85
+
86
+ ### Entry genérico (fila/worker)
87
+
88
+ Recebe o payload e o `mode` e despacha — mesma engine, mesmo tratamento de erro.
89
+ `payload` é o 1º posicional; `mode` é keyword com default `'text'`:
90
+
91
+ ```python
92
+ r = aigen.generate(prompt) # mode='text'
93
+ r = aigen.generate(prompt, mode='video', tier='basic', task='image_to_video')
94
+ r = aigen.generate(audio_url, mode='stt', model='whisper-large-v3:groq')
95
+ ```
96
+
97
+ `mode`: `text` · `image` · `video` · `music` · `stt` · `tts`.
98
+ `task` (só vídeo): `text_to_video` · `image_to_video`.
99
+
100
+ ## Contrato de retorno (uniforme)
101
+
102
+ **Sucesso** → retorna o dataclass do tipo. **Falha** → levanta exception tipada.
103
+ Igual para todas as mídias.
104
+
105
+ | Mídia | Função | Retorno (sucesso) |
106
+ |-------|--------|-------------------|
107
+ | Texto | `generate_text` | `TextResponse` |
108
+ | Imagem | `generate_image` | `ProviderResponse` |
109
+ | Vídeo | `generate_video` | `VideoResponse` |
110
+ | Música | `generate_music` | `TTMResponse` |
111
+ | STT | `transcribe` | `STTResponse` |
112
+ | TTS | `synthesize` | `TTSResponse` |
113
+
114
+ ### Taxonomia de erro
115
+
116
+ ```
117
+ ProviderError # base — terminal
118
+ ├─ ProviderBlocked # conteúdo barrado — .category: 'safety'|'copyright'|'other'
119
+ └─ ProviderRetryable # transitório (pode retry)
120
+ ├─ ProviderRateLimit # 429
121
+ └─ ProviderTimeout # timeout / rede
122
+ ```
123
+
124
+ Trata-se igual para qualquer mídia, num lugar só:
125
+
126
+ ```python
127
+ try:
128
+ r = aigen.generate_video(prompt, tier='basic')
129
+ use(r.videos)
130
+ except aigen.ProviderBlocked as e:
131
+ print('barrado:', e.category, e) # copyright / safety
132
+ except aigen.ProviderRetryable as e:
133
+ retry() # rede / ratelimit / timeout
134
+ except aigen.ProviderError as e:
135
+ fail(e) # terminal genérico
136
+ ```
137
+
138
+ Cada exception carrega `.provider`, `.model`, `.status_code`, `.response_time`, `.raw_error`.
139
+
140
+ ## Configuração
141
+
142
+ Duas coisas distintas:
143
+
144
+ - **Catálogo técnico** (`aigen/constants/{text,image,audio,video}.py`) — *fatos*
145
+ sobre providers: `api_key_env`, capabilities, créditos. Muda raro.
146
+ - **Roteamento por tier** (`aigen/tiers.py`) — a *decisão* de qual modelo cada
147
+ tier usa. Muda toda hora e difere por app.
148
+
149
+ O roteamento é **app-owned**: `aigen/tiers.py` traz só os defaults (pra funcionar
150
+ out-of-box); o **app é o dono** e sobrescreve no boot. Não edite o pacote instalado.
151
+
152
+ ```python
153
+ import aigen
154
+
155
+ # entry único — merge sobre os defaults (tiers não passados continuam valendo)
156
+ aigen.configure(
157
+ text={'basic': 'gemini-2.5-flash:gemini', 'pro': 'claude-sonnet-4-6:claude'},
158
+ image={'pro': 'gpt-image-2:openai'},
159
+ video={'basic': {'text_to_video': 'bytedance/seedance-1.5-pro:kie'}},
160
+ )
161
+
162
+ # replace=True → o app vira dono total daquela mídia (zera antes)
163
+ aigen.configure(text={'basic': 'glm-5.2:zai'}, replace=True)
164
+
165
+ # ajustes pontuais
166
+ aigen.set_tier('text', 'pro', 'gpt-5.4:openai')
167
+
168
+ # registrar provider/modelo novo no catálogo
169
+ aigen.register_provider('text', 'meu_provider', 'MEU_API_KEY', models={
170
+ 'meu-modelo': {'tier': 'pro', 'base_credits': 8},
171
+ })
172
+ aigen.register_model('text', 'openai', 'gpt-5.4', {'tier': 'pro', 'base_credits': 8})
173
+ ```
174
+
175
+ > Lugar claro e visível: um arquivo de config **no seu app** (ex.
176
+ > `settings/ai_tiers.py`) chamando `aigen.configure(...)` no boot — versionado
177
+ > junto do app, perto do resto da config dele.
178
+
179
+ ## API keys
180
+
181
+ Cada provider lê a key de uma variável de ambiente (campo `api_key_env` no catálogo).
182
+ Defaults: `GOOGLE_API_KEY`, `OPENAI_API_KEY`, `CLAUDE_API_KEY`, `GROQ_API_KEY`,
183
+ `CEREBRAS_API_KEY`, `ZAI_API_KEY`, `MOONSHOT_AI_API_KEY`, `DASHSCOPE_API_KEY`,
184
+ `DEEPSEEK_API_KEY`, `MINIMAX_API_KEY`, `KIE_API_KEY`.
185
+
186
+ ## Logs
187
+
188
+ Cada chamada emite no início (antes de bloquear) e no fim. Útil pra não ficar no
189
+ escuro durante esperas longas:
190
+
191
+ ```
192
+ generate START | mode=text model=glm-5.2:zai timeout=900
193
+ Z.AI text | model=glm-5.2 in=812 out=145 reasoning=0 total=957 time=3.41s
194
+ ```
195
+
196
+ O pacote só usa `logging.getLogger(__name__)` — **não** configura handler. Pra ver
197
+ na execução, o app habilita logging (uma vez, no boot):
198
+
199
+ ```python
200
+ import logging
201
+ logging.basicConfig(level=logging.INFO) # console (stderr), ao vivo
202
+ # logging.basicConfig(level=logging.INFO, filename='aigen.log') # só arquivo
203
+ ```
204
+
205
+ Sem isso, INFO vai pro vazio. As stats de fim podem ser desligadas com
206
+ `LOG_PROVIDER_STATS=0`; o log START fica.
207
+
208
+ ## Providers de texto
209
+
210
+ gemini · openai · claude (API e CLI) · codex_cli · groq · cerebras · deepseek ·
211
+ zai · kimi · minimax · alibaba · kie
@@ -0,0 +1,182 @@
1
+ # aigen
2
+
3
+ Roteador de chamadas LLM por **model/tier**, multi-provider, com **call/return consistente**.
4
+
5
+ Você escolhe um *tier* (`basic`/`advanced`/`pro`) ou uma key `model:provider`;
6
+ o pacote resolve o provider, instancia, chama e devolve sempre um dataclass
7
+ padronizado. Trocar de modelo ou provider = editar config, não código.
8
+
9
+ ## Instalação
10
+
11
+ SDKs de provider são **extras opcionais** — instale só os que usar:
12
+
13
+ ```bash
14
+ pip install "aigen[openai]" # OpenAI, Groq, z.ai, Kimi, Alibaba, DeepSeek (openai-compat)
15
+ pip install "aigen[gemini]" # Google Gemini
16
+ pip install "aigen[claude]" # Anthropic Claude
17
+ pip install "aigen[cerebras]" # Cerebras
18
+ pip install "aigen[all]" # tudo
19
+
20
+ # Desenvolvimento (editável):
21
+ pip install -e "/Users/ssjunior/Dev/llm-router[all]"
22
+ ```
23
+
24
+ Providers que falam HTTP puro (Kie, Minimax, imagens da Alibaba/z.ai, STT da Groq)
25
+ funcionam só com o core (`httpx`, `requests`).
26
+
27
+ ## Uso
28
+
29
+ Passe `tier` ('basic'/'advanced'/'pro') **ou** `model` ('model:provider'). `tier`
30
+ default é `'basic'`; `model=` sobrepõe. `prompt` é o 1º posicional; o resto é keyword.
31
+ (stt/tts não têm tabela de tier — exigem `model=`.)
32
+
33
+ ```python
34
+ import aigen
35
+
36
+ # por tier (resolve via constants/tiers.py)
37
+ r = aigen.generate_text('Resuma o texto X', tier='basic')
38
+ print(r.content) # JSON parseado (dict/list) ou str
39
+ print(r.total_tokens)
40
+
41
+ # por key explícita
42
+ r = aigen.generate_text('Resuma X', model='gemini-2.5-flash:gemini', system_instruction='...')
43
+
44
+ # timeout por chamada (texto) — default LLM_REQUEST_TIMEOUT (900s)
45
+ r = aigen.generate_text('Resuma X', tier='basic', timeout=60)
46
+ ```
47
+
48
+ ### Outras mídias
49
+
50
+ ```python
51
+ img = aigen.generate_image('um gato astronauta', tier='pro', files=[...])
52
+ video = aigen.generate_video('clipe contínuo de...', tier='basic', task='text_to_video')
53
+ music = aigen.generate_music('lo-fi chill', tier='pro', instrumental=True)
54
+ text = aigen.transcribe(audio_url, model='whisper-large-v3:groq') # stt/tts exigem model=
55
+ ```
56
+
57
+ ### Entry genérico (fila/worker)
58
+
59
+ Recebe o payload e o `mode` e despacha — mesma engine, mesmo tratamento de erro.
60
+ `payload` é o 1º posicional; `mode` é keyword com default `'text'`:
61
+
62
+ ```python
63
+ r = aigen.generate(prompt) # mode='text'
64
+ r = aigen.generate(prompt, mode='video', tier='basic', task='image_to_video')
65
+ r = aigen.generate(audio_url, mode='stt', model='whisper-large-v3:groq')
66
+ ```
67
+
68
+ `mode`: `text` · `image` · `video` · `music` · `stt` · `tts`.
69
+ `task` (só vídeo): `text_to_video` · `image_to_video`.
70
+
71
+ ## Contrato de retorno (uniforme)
72
+
73
+ **Sucesso** → retorna o dataclass do tipo. **Falha** → levanta exception tipada.
74
+ Igual para todas as mídias.
75
+
76
+ | Mídia | Função | Retorno (sucesso) |
77
+ |-------|--------|-------------------|
78
+ | Texto | `generate_text` | `TextResponse` |
79
+ | Imagem | `generate_image` | `ProviderResponse` |
80
+ | Vídeo | `generate_video` | `VideoResponse` |
81
+ | Música | `generate_music` | `TTMResponse` |
82
+ | STT | `transcribe` | `STTResponse` |
83
+ | TTS | `synthesize` | `TTSResponse` |
84
+
85
+ ### Taxonomia de erro
86
+
87
+ ```
88
+ ProviderError # base — terminal
89
+ ├─ ProviderBlocked # conteúdo barrado — .category: 'safety'|'copyright'|'other'
90
+ └─ ProviderRetryable # transitório (pode retry)
91
+ ├─ ProviderRateLimit # 429
92
+ └─ ProviderTimeout # timeout / rede
93
+ ```
94
+
95
+ Trata-se igual para qualquer mídia, num lugar só:
96
+
97
+ ```python
98
+ try:
99
+ r = aigen.generate_video(prompt, tier='basic')
100
+ use(r.videos)
101
+ except aigen.ProviderBlocked as e:
102
+ print('barrado:', e.category, e) # copyright / safety
103
+ except aigen.ProviderRetryable as e:
104
+ retry() # rede / ratelimit / timeout
105
+ except aigen.ProviderError as e:
106
+ fail(e) # terminal genérico
107
+ ```
108
+
109
+ Cada exception carrega `.provider`, `.model`, `.status_code`, `.response_time`, `.raw_error`.
110
+
111
+ ## Configuração
112
+
113
+ Duas coisas distintas:
114
+
115
+ - **Catálogo técnico** (`aigen/constants/{text,image,audio,video}.py`) — *fatos*
116
+ sobre providers: `api_key_env`, capabilities, créditos. Muda raro.
117
+ - **Roteamento por tier** (`aigen/tiers.py`) — a *decisão* de qual modelo cada
118
+ tier usa. Muda toda hora e difere por app.
119
+
120
+ O roteamento é **app-owned**: `aigen/tiers.py` traz só os defaults (pra funcionar
121
+ out-of-box); o **app é o dono** e sobrescreve no boot. Não edite o pacote instalado.
122
+
123
+ ```python
124
+ import aigen
125
+
126
+ # entry único — merge sobre os defaults (tiers não passados continuam valendo)
127
+ aigen.configure(
128
+ text={'basic': 'gemini-2.5-flash:gemini', 'pro': 'claude-sonnet-4-6:claude'},
129
+ image={'pro': 'gpt-image-2:openai'},
130
+ video={'basic': {'text_to_video': 'bytedance/seedance-1.5-pro:kie'}},
131
+ )
132
+
133
+ # replace=True → o app vira dono total daquela mídia (zera antes)
134
+ aigen.configure(text={'basic': 'glm-5.2:zai'}, replace=True)
135
+
136
+ # ajustes pontuais
137
+ aigen.set_tier('text', 'pro', 'gpt-5.4:openai')
138
+
139
+ # registrar provider/modelo novo no catálogo
140
+ aigen.register_provider('text', 'meu_provider', 'MEU_API_KEY', models={
141
+ 'meu-modelo': {'tier': 'pro', 'base_credits': 8},
142
+ })
143
+ aigen.register_model('text', 'openai', 'gpt-5.4', {'tier': 'pro', 'base_credits': 8})
144
+ ```
145
+
146
+ > Lugar claro e visível: um arquivo de config **no seu app** (ex.
147
+ > `settings/ai_tiers.py`) chamando `aigen.configure(...)` no boot — versionado
148
+ > junto do app, perto do resto da config dele.
149
+
150
+ ## API keys
151
+
152
+ Cada provider lê a key de uma variável de ambiente (campo `api_key_env` no catálogo).
153
+ Defaults: `GOOGLE_API_KEY`, `OPENAI_API_KEY`, `CLAUDE_API_KEY`, `GROQ_API_KEY`,
154
+ `CEREBRAS_API_KEY`, `ZAI_API_KEY`, `MOONSHOT_AI_API_KEY`, `DASHSCOPE_API_KEY`,
155
+ `DEEPSEEK_API_KEY`, `MINIMAX_API_KEY`, `KIE_API_KEY`.
156
+
157
+ ## Logs
158
+
159
+ Cada chamada emite no início (antes de bloquear) e no fim. Útil pra não ficar no
160
+ escuro durante esperas longas:
161
+
162
+ ```
163
+ generate START | mode=text model=glm-5.2:zai timeout=900
164
+ Z.AI text | model=glm-5.2 in=812 out=145 reasoning=0 total=957 time=3.41s
165
+ ```
166
+
167
+ O pacote só usa `logging.getLogger(__name__)` — **não** configura handler. Pra ver
168
+ na execução, o app habilita logging (uma vez, no boot):
169
+
170
+ ```python
171
+ import logging
172
+ logging.basicConfig(level=logging.INFO) # console (stderr), ao vivo
173
+ # logging.basicConfig(level=logging.INFO, filename='aigen.log') # só arquivo
174
+ ```
175
+
176
+ Sem isso, INFO vai pro vazio. As stats de fim podem ser desligadas com
177
+ `LOG_PROVIDER_STATS=0`; o log START fica.
178
+
179
+ ## Providers de texto
180
+
181
+ gemini · openai · claude (API e CLI) · codex_cli · groq · cerebras · deepseek ·
182
+ zai · kimi · minimax · alibaba · kie
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ai-generator"
7
+ version = "0.1.0"
8
+ description = "Roteador de chamadas LLM por model/tier, multi-provider, com retorno consistente."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name="Stamatios Stamou Jr", email="bushier.outsets.0c@icloud.com" }]
13
+ keywords = ["llm", "router", "openai", "gemini", "anthropic", "multi-provider"]
14
+ dependencies = [
15
+ "httpx>=0.24",
16
+ "requests>=2.28",
17
+ ]
18
+
19
+ [project.optional-dependencies]
20
+ openai = ["openai>=1.30"]
21
+ gemini = ["google-genai>=0.3"]
22
+ claude = ["anthropic>=0.40"]
23
+ cerebras = ["cerebras-cloud-sdk>=1.0"]
24
+ all = [
25
+ "openai>=1.30",
26
+ "google-genai>=0.3",
27
+ "anthropic>=0.40",
28
+ "cerebras-cloud-sdk>=1.0",
29
+ ]
30
+ dev = ["pytest>=7"]
31
+
32
+ [tool.pytest.ini_options]
33
+ testpaths = ["tests"]
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["src"]
37
+
38
+ [tool.setuptools.package-data]
39
+ aigen = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: ai-generator
3
+ Version: 0.1.0
4
+ Summary: Roteador de chamadas LLM por model/tier, multi-provider, com retorno consistente.
5
+ Author-email: Stamatios Stamou Jr <bushier.outsets.0c@icloud.com>
6
+ License: MIT
7
+ Keywords: llm,router,openai,gemini,anthropic,multi-provider
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: httpx>=0.24
12
+ Requires-Dist: requests>=2.28
13
+ Provides-Extra: openai
14
+ Requires-Dist: openai>=1.30; extra == "openai"
15
+ Provides-Extra: gemini
16
+ Requires-Dist: google-genai>=0.3; extra == "gemini"
17
+ Provides-Extra: claude
18
+ Requires-Dist: anthropic>=0.40; extra == "claude"
19
+ Provides-Extra: cerebras
20
+ Requires-Dist: cerebras-cloud-sdk>=1.0; extra == "cerebras"
21
+ Provides-Extra: all
22
+ Requires-Dist: openai>=1.30; extra == "all"
23
+ Requires-Dist: google-genai>=0.3; extra == "all"
24
+ Requires-Dist: anthropic>=0.40; extra == "all"
25
+ Requires-Dist: cerebras-cloud-sdk>=1.0; extra == "all"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # aigen
31
+
32
+ Roteador de chamadas LLM por **model/tier**, multi-provider, com **call/return consistente**.
33
+
34
+ Você escolhe um *tier* (`basic`/`advanced`/`pro`) ou uma key `model:provider`;
35
+ o pacote resolve o provider, instancia, chama e devolve sempre um dataclass
36
+ padronizado. Trocar de modelo ou provider = editar config, não código.
37
+
38
+ ## Instalação
39
+
40
+ SDKs de provider são **extras opcionais** — instale só os que usar:
41
+
42
+ ```bash
43
+ pip install "aigen[openai]" # OpenAI, Groq, z.ai, Kimi, Alibaba, DeepSeek (openai-compat)
44
+ pip install "aigen[gemini]" # Google Gemini
45
+ pip install "aigen[claude]" # Anthropic Claude
46
+ pip install "aigen[cerebras]" # Cerebras
47
+ pip install "aigen[all]" # tudo
48
+
49
+ # Desenvolvimento (editável):
50
+ pip install -e "/Users/ssjunior/Dev/llm-router[all]"
51
+ ```
52
+
53
+ Providers que falam HTTP puro (Kie, Minimax, imagens da Alibaba/z.ai, STT da Groq)
54
+ funcionam só com o core (`httpx`, `requests`).
55
+
56
+ ## Uso
57
+
58
+ Passe `tier` ('basic'/'advanced'/'pro') **ou** `model` ('model:provider'). `tier`
59
+ default é `'basic'`; `model=` sobrepõe. `prompt` é o 1º posicional; o resto é keyword.
60
+ (stt/tts não têm tabela de tier — exigem `model=`.)
61
+
62
+ ```python
63
+ import aigen
64
+
65
+ # por tier (resolve via constants/tiers.py)
66
+ r = aigen.generate_text('Resuma o texto X', tier='basic')
67
+ print(r.content) # JSON parseado (dict/list) ou str
68
+ print(r.total_tokens)
69
+
70
+ # por key explícita
71
+ r = aigen.generate_text('Resuma X', model='gemini-2.5-flash:gemini', system_instruction='...')
72
+
73
+ # timeout por chamada (texto) — default LLM_REQUEST_TIMEOUT (900s)
74
+ r = aigen.generate_text('Resuma X', tier='basic', timeout=60)
75
+ ```
76
+
77
+ ### Outras mídias
78
+
79
+ ```python
80
+ img = aigen.generate_image('um gato astronauta', tier='pro', files=[...])
81
+ video = aigen.generate_video('clipe contínuo de...', tier='basic', task='text_to_video')
82
+ music = aigen.generate_music('lo-fi chill', tier='pro', instrumental=True)
83
+ text = aigen.transcribe(audio_url, model='whisper-large-v3:groq') # stt/tts exigem model=
84
+ ```
85
+
86
+ ### Entry genérico (fila/worker)
87
+
88
+ Recebe o payload e o `mode` e despacha — mesma engine, mesmo tratamento de erro.
89
+ `payload` é o 1º posicional; `mode` é keyword com default `'text'`:
90
+
91
+ ```python
92
+ r = aigen.generate(prompt) # mode='text'
93
+ r = aigen.generate(prompt, mode='video', tier='basic', task='image_to_video')
94
+ r = aigen.generate(audio_url, mode='stt', model='whisper-large-v3:groq')
95
+ ```
96
+
97
+ `mode`: `text` · `image` · `video` · `music` · `stt` · `tts`.
98
+ `task` (só vídeo): `text_to_video` · `image_to_video`.
99
+
100
+ ## Contrato de retorno (uniforme)
101
+
102
+ **Sucesso** → retorna o dataclass do tipo. **Falha** → levanta exception tipada.
103
+ Igual para todas as mídias.
104
+
105
+ | Mídia | Função | Retorno (sucesso) |
106
+ |-------|--------|-------------------|
107
+ | Texto | `generate_text` | `TextResponse` |
108
+ | Imagem | `generate_image` | `ProviderResponse` |
109
+ | Vídeo | `generate_video` | `VideoResponse` |
110
+ | Música | `generate_music` | `TTMResponse` |
111
+ | STT | `transcribe` | `STTResponse` |
112
+ | TTS | `synthesize` | `TTSResponse` |
113
+
114
+ ### Taxonomia de erro
115
+
116
+ ```
117
+ ProviderError # base — terminal
118
+ ├─ ProviderBlocked # conteúdo barrado — .category: 'safety'|'copyright'|'other'
119
+ └─ ProviderRetryable # transitório (pode retry)
120
+ ├─ ProviderRateLimit # 429
121
+ └─ ProviderTimeout # timeout / rede
122
+ ```
123
+
124
+ Trata-se igual para qualquer mídia, num lugar só:
125
+
126
+ ```python
127
+ try:
128
+ r = aigen.generate_video(prompt, tier='basic')
129
+ use(r.videos)
130
+ except aigen.ProviderBlocked as e:
131
+ print('barrado:', e.category, e) # copyright / safety
132
+ except aigen.ProviderRetryable as e:
133
+ retry() # rede / ratelimit / timeout
134
+ except aigen.ProviderError as e:
135
+ fail(e) # terminal genérico
136
+ ```
137
+
138
+ Cada exception carrega `.provider`, `.model`, `.status_code`, `.response_time`, `.raw_error`.
139
+
140
+ ## Configuração
141
+
142
+ Duas coisas distintas:
143
+
144
+ - **Catálogo técnico** (`aigen/constants/{text,image,audio,video}.py`) — *fatos*
145
+ sobre providers: `api_key_env`, capabilities, créditos. Muda raro.
146
+ - **Roteamento por tier** (`aigen/tiers.py`) — a *decisão* de qual modelo cada
147
+ tier usa. Muda toda hora e difere por app.
148
+
149
+ O roteamento é **app-owned**: `aigen/tiers.py` traz só os defaults (pra funcionar
150
+ out-of-box); o **app é o dono** e sobrescreve no boot. Não edite o pacote instalado.
151
+
152
+ ```python
153
+ import aigen
154
+
155
+ # entry único — merge sobre os defaults (tiers não passados continuam valendo)
156
+ aigen.configure(
157
+ text={'basic': 'gemini-2.5-flash:gemini', 'pro': 'claude-sonnet-4-6:claude'},
158
+ image={'pro': 'gpt-image-2:openai'},
159
+ video={'basic': {'text_to_video': 'bytedance/seedance-1.5-pro:kie'}},
160
+ )
161
+
162
+ # replace=True → o app vira dono total daquela mídia (zera antes)
163
+ aigen.configure(text={'basic': 'glm-5.2:zai'}, replace=True)
164
+
165
+ # ajustes pontuais
166
+ aigen.set_tier('text', 'pro', 'gpt-5.4:openai')
167
+
168
+ # registrar provider/modelo novo no catálogo
169
+ aigen.register_provider('text', 'meu_provider', 'MEU_API_KEY', models={
170
+ 'meu-modelo': {'tier': 'pro', 'base_credits': 8},
171
+ })
172
+ aigen.register_model('text', 'openai', 'gpt-5.4', {'tier': 'pro', 'base_credits': 8})
173
+ ```
174
+
175
+ > Lugar claro e visível: um arquivo de config **no seu app** (ex.
176
+ > `settings/ai_tiers.py`) chamando `aigen.configure(...)` no boot — versionado
177
+ > junto do app, perto do resto da config dele.
178
+
179
+ ## API keys
180
+
181
+ Cada provider lê a key de uma variável de ambiente (campo `api_key_env` no catálogo).
182
+ Defaults: `GOOGLE_API_KEY`, `OPENAI_API_KEY`, `CLAUDE_API_KEY`, `GROQ_API_KEY`,
183
+ `CEREBRAS_API_KEY`, `ZAI_API_KEY`, `MOONSHOT_AI_API_KEY`, `DASHSCOPE_API_KEY`,
184
+ `DEEPSEEK_API_KEY`, `MINIMAX_API_KEY`, `KIE_API_KEY`.
185
+
186
+ ## Logs
187
+
188
+ Cada chamada emite no início (antes de bloquear) e no fim. Útil pra não ficar no
189
+ escuro durante esperas longas:
190
+
191
+ ```
192
+ generate START | mode=text model=glm-5.2:zai timeout=900
193
+ Z.AI text | model=glm-5.2 in=812 out=145 reasoning=0 total=957 time=3.41s
194
+ ```
195
+
196
+ O pacote só usa `logging.getLogger(__name__)` — **não** configura handler. Pra ver
197
+ na execução, o app habilita logging (uma vez, no boot):
198
+
199
+ ```python
200
+ import logging
201
+ logging.basicConfig(level=logging.INFO) # console (stderr), ao vivo
202
+ # logging.basicConfig(level=logging.INFO, filename='aigen.log') # só arquivo
203
+ ```
204
+
205
+ Sem isso, INFO vai pro vazio. As stats de fim podem ser desligadas com
206
+ `LOG_PROVIDER_STATS=0`; o log START fica.
207
+
208
+ ## Providers de texto
209
+
210
+ gemini · openai · claude (API e CLI) · codex_cli · groq · cerebras · deepseek ·
211
+ zai · kimi · minimax · alibaba · kie