javaxFlash 2.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 Javas Antony
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,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: javaxFlash
3
+ Version: 2.1.0
4
+ Summary: Lightweight local-first AI router with javaxFlash and DeepSeek.
5
+ Author: Javas Antony
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/javaxFlash/
8
+ Keywords: ai,client,router,gemini,deepseek
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: requests>=2.31.0
20
+ Dynamic: license-file
21
+
22
+ # javaxFlash
23
+
24
+ `javaxFlash` adalah library Python kecil untuk mengakses beberapa endpoint AI lewat satu client API yang sederhana.
25
+
26
+ Tujuan library ini:
27
+
28
+ - memberi satu entry point yang ringan: `FlashClient`
29
+ - memudahkan pindah antara provider `flash` dan `deepseek`
30
+ - mendukung auto routing atau provider manual
31
+ - mengembalikan format respons yang konsisten
32
+
33
+ ## Cocok untuk apa
34
+
35
+ - pertanyaan cepat dengan provider default `flash`
36
+ - prompt reasoning yang lebih berat dengan `deepseek`
37
+ - eksperimen lokal tanpa harus menulis wrapper request berulang-ulang
38
+
39
+ ## Install
40
+
41
+ Install package inti:
42
+
43
+ ```bash
44
+ python -m pip install -r requirements.txt
45
+ python -m pip install -e .
46
+ ```
47
+
48
+ Kalau ingin menjalankan contoh interaktif di folder `examples`, install juga `rich`:
49
+
50
+ ```bash
51
+ python -m pip install rich
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ Contoh paling sederhana:
57
+
58
+ ```python
59
+ from javaxFlash import FlashClient
60
+
61
+ client = FlashClient()
62
+
63
+ response = client.flash("Jelaskan konsep Q-learning dengan sederhana")
64
+
65
+ print(response.text)
66
+ print(response.provider)
67
+ print(response.model_used)
68
+ ```
69
+
70
+ Alias `ask()` juga tersedia:
71
+
72
+ ```python
73
+ response = client.ask("Apa itu Python?")
74
+ print(response.text)
75
+ ```
76
+
77
+ ## Cara Kerja Singkat
78
+
79
+ Secara default, `FlashClient` akan:
80
+
81
+ 1. menerima prompt dari user
82
+ 2. memilih provider berdasarkan mode atau auto routing
83
+ 3. mengirim request ke endpoint provider
84
+ 4. mengembalikan hasil dalam bentuk `FlashResponse`
85
+
86
+ Kalau provider utama gagal dan fallback aktif, client akan mencoba provider cadangan.
87
+
88
+ ## Memilih Provider
89
+
90
+ ### 1. Auto routing
91
+
92
+ Auto routing cocok kalau kamu ingin library memilih provider secara otomatis.
93
+
94
+ ```python
95
+ response = client.flash("Bandingkan REST dan GraphQL untuk project kecil", auto_route=True)
96
+ ```
97
+
98
+ ### 2. Fast mode
99
+
100
+ Gunakan saat ingin jawaban cepat.
101
+
102
+ ```python
103
+ response = client.flash("Apa itu Python?", mode="fast")
104
+ ```
105
+
106
+ ### 3. Reasoning mode
107
+
108
+ Gunakan saat prompt butuh analisis lebih dalam.
109
+
110
+ ```python
111
+ response = client.flash("Kenapa algoritma ini gagal dan bagaimana cara debug-nya?", mode="reasoning")
112
+ ```
113
+
114
+ ### 4. Paksa provider tertentu
115
+
116
+ Kalau kamu sudah tahu provider mana yang ingin dipakai:
117
+
118
+ ```python
119
+ response = client.flash("Gunakan provider cepat", provider="flash")
120
+ response = client.flash("Analisis bug ini", provider="deepseek")
121
+ ```
122
+
123
+ ## Konfigurasi Dasar
124
+
125
+ Kalau ingin mengubah perilaku default client:
126
+
127
+ ```python
128
+ from javaxFlash import FlashClient, FlashConfig
129
+
130
+ config = FlashConfig(
131
+ timeout=30.0,
132
+ auto_route=True,
133
+ fallback_enabled=True,
134
+ default_system_instruction="You are javaxFlash, a concise and practical AI assistant.",
135
+ )
136
+
137
+ client = FlashClient(config=config)
138
+ ```
139
+
140
+ Field config yang paling sering dipakai:
141
+
142
+ - `timeout`: timeout request HTTP
143
+ - `auto_route`: aktif/nonaktif routing otomatis
144
+ - `fallback_enabled`: coba provider cadangan saat request gagal
145
+ - `default_system_instruction`: system prompt default
146
+ - `default_gemini_model`: nama model untuk provider `flash`
147
+ - `deepseek_temperature`: temperature default untuk DeepSeek
148
+ - `debug`: tampilkan log sederhana saat development
149
+ - `request_logging`: aktifkan logging request
150
+
151
+ ## Custom System Instruction
152
+
153
+ Kamu bisa memberi system instruction per request:
154
+
155
+ ```python
156
+ response = client.flash(
157
+ "Bantu saya menyusun rencana automation",
158
+ system_instruction="You are an AI assistant focused on backend automation and practical implementation.",
159
+ )
160
+ ```
161
+
162
+ Atau menjadikannya default lewat `FlashConfig`.
163
+
164
+ ## Response Object
165
+
166
+ Setiap request mengembalikan `FlashResponse` dengan struktur yang konsisten:
167
+
168
+ ```python
169
+ response.text
170
+ response.model_used
171
+ response.provider
172
+ response.raw
173
+ response.route_reason
174
+ response.error
175
+ ```
176
+
177
+ Penjelasan singkat:
178
+
179
+ - `text`: isi jawaban utama
180
+ - `model_used`: nama model yang dilaporkan provider
181
+ - `provider`: provider yang benar-benar dipakai
182
+ - `raw`: payload JSON mentah dari endpoint
183
+ - `route_reason`: alasan routing yang dipilih client
184
+ - `error`: pesan error jika request gagal
185
+
186
+ Contoh:
187
+
188
+ ```python
189
+ response = client.flash("Jelaskan recursion")
190
+
191
+ if response.error:
192
+ print("Error:", response.error)
193
+ else:
194
+ print(response.text)
195
+ print("Provider:", response.provider)
196
+ print("Reason:", response.route_reason)
197
+ ```
198
+
199
+ ## Parameter yang Bisa Dipakai Saat Request
200
+
201
+ API utama:
202
+
203
+ ```python
204
+ client.flash(
205
+ prompt,
206
+ mode=None,
207
+ provider=None,
208
+ auto_route=None,
209
+ system_instruction=None,
210
+ fallback_provider=None,
211
+ **kwargs,
212
+ )
213
+ ```
214
+
215
+ Parameter penting:
216
+
217
+ - `prompt`: isi permintaan user
218
+ - `mode`: `fast` atau `reasoning`
219
+ - `provider`: paksa provider tertentu
220
+ - `auto_route`: override perilaku routing default
221
+ - `system_instruction`: system instruction per request
222
+ - `fallback_provider`: provider cadangan jika request utama gagal
223
+ - `**kwargs`: parameter tambahan yang diteruskan ke provider
224
+
225
+ Contoh `kwargs`:
226
+
227
+ ```python
228
+ response = client.flash(
229
+ "Jelaskan greedy algorithm",
230
+ provider="deepseek",
231
+ temperature=0.2,
232
+ )
233
+ ```
234
+
235
+ ## Menjalankan Contoh Interaktif
236
+
237
+ Contoh interaktif ada di `examples/basic_usage.py`.
238
+
239
+ Jalankan dengan:
240
+
241
+ ```bash
242
+ python examples/basic_usage.py
243
+ ```
244
+
245
+ atau:
246
+
247
+ ```bash
248
+ python -m examples.basic_usage
249
+ ```
250
+
251
+ ## Struktur Project
252
+
253
+ File yang paling penting:
254
+
255
+ - `javaxFlash/client.py`: entry point utama library
256
+ - `javaxFlash/config.py`: konfigurasi client
257
+ - `javaxFlash/router.py`: logika pemilihan provider
258
+ - `javaxFlash/providers.py`: implementasi request ke provider
259
+ - `javaxFlash/models.py`: model respons
260
+
261
+ ## Catatan Penting
262
+
263
+ - `flash` di library ini adalah nama provider cepat yang dibacking oleh endpoint Gemini Lite.
264
+ - `deepseek` dipakai untuk prompt yang lebih berat atau mode reasoning.
265
+ - Output akhir tetap bergantung pada endpoint upstream yang dipanggil library ini.
266
+ - Library ini sekarang stateless; tidak ada fitur memory atau penyimpanan percakapan lokal.
267
+
268
+ ## Minimal Example
269
+
270
+ Kalau ingin contoh paling ringkas untuk dipakai di project lain:
271
+
272
+ ```python
273
+ from javaxFlash import FlashClient
274
+
275
+ client = FlashClient()
276
+ response = client.flash("Buat ringkasan tentang REST API", mode="fast")
277
+
278
+ if response.error:
279
+ raise RuntimeError(response.error)
280
+
281
+ print(response.text)
282
+ ```
@@ -0,0 +1,261 @@
1
+ # javaxFlash
2
+
3
+ `javaxFlash` adalah library Python kecil untuk mengakses beberapa endpoint AI lewat satu client API yang sederhana.
4
+
5
+ Tujuan library ini:
6
+
7
+ - memberi satu entry point yang ringan: `FlashClient`
8
+ - memudahkan pindah antara provider `flash` dan `deepseek`
9
+ - mendukung auto routing atau provider manual
10
+ - mengembalikan format respons yang konsisten
11
+
12
+ ## Cocok untuk apa
13
+
14
+ - pertanyaan cepat dengan provider default `flash`
15
+ - prompt reasoning yang lebih berat dengan `deepseek`
16
+ - eksperimen lokal tanpa harus menulis wrapper request berulang-ulang
17
+
18
+ ## Install
19
+
20
+ Install package inti:
21
+
22
+ ```bash
23
+ python -m pip install -r requirements.txt
24
+ python -m pip install -e .
25
+ ```
26
+
27
+ Kalau ingin menjalankan contoh interaktif di folder `examples`, install juga `rich`:
28
+
29
+ ```bash
30
+ python -m pip install rich
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ Contoh paling sederhana:
36
+
37
+ ```python
38
+ from javaxFlash import FlashClient
39
+
40
+ client = FlashClient()
41
+
42
+ response = client.flash("Jelaskan konsep Q-learning dengan sederhana")
43
+
44
+ print(response.text)
45
+ print(response.provider)
46
+ print(response.model_used)
47
+ ```
48
+
49
+ Alias `ask()` juga tersedia:
50
+
51
+ ```python
52
+ response = client.ask("Apa itu Python?")
53
+ print(response.text)
54
+ ```
55
+
56
+ ## Cara Kerja Singkat
57
+
58
+ Secara default, `FlashClient` akan:
59
+
60
+ 1. menerima prompt dari user
61
+ 2. memilih provider berdasarkan mode atau auto routing
62
+ 3. mengirim request ke endpoint provider
63
+ 4. mengembalikan hasil dalam bentuk `FlashResponse`
64
+
65
+ Kalau provider utama gagal dan fallback aktif, client akan mencoba provider cadangan.
66
+
67
+ ## Memilih Provider
68
+
69
+ ### 1. Auto routing
70
+
71
+ Auto routing cocok kalau kamu ingin library memilih provider secara otomatis.
72
+
73
+ ```python
74
+ response = client.flash("Bandingkan REST dan GraphQL untuk project kecil", auto_route=True)
75
+ ```
76
+
77
+ ### 2. Fast mode
78
+
79
+ Gunakan saat ingin jawaban cepat.
80
+
81
+ ```python
82
+ response = client.flash("Apa itu Python?", mode="fast")
83
+ ```
84
+
85
+ ### 3. Reasoning mode
86
+
87
+ Gunakan saat prompt butuh analisis lebih dalam.
88
+
89
+ ```python
90
+ response = client.flash("Kenapa algoritma ini gagal dan bagaimana cara debug-nya?", mode="reasoning")
91
+ ```
92
+
93
+ ### 4. Paksa provider tertentu
94
+
95
+ Kalau kamu sudah tahu provider mana yang ingin dipakai:
96
+
97
+ ```python
98
+ response = client.flash("Gunakan provider cepat", provider="flash")
99
+ response = client.flash("Analisis bug ini", provider="deepseek")
100
+ ```
101
+
102
+ ## Konfigurasi Dasar
103
+
104
+ Kalau ingin mengubah perilaku default client:
105
+
106
+ ```python
107
+ from javaxFlash import FlashClient, FlashConfig
108
+
109
+ config = FlashConfig(
110
+ timeout=30.0,
111
+ auto_route=True,
112
+ fallback_enabled=True,
113
+ default_system_instruction="You are javaxFlash, a concise and practical AI assistant.",
114
+ )
115
+
116
+ client = FlashClient(config=config)
117
+ ```
118
+
119
+ Field config yang paling sering dipakai:
120
+
121
+ - `timeout`: timeout request HTTP
122
+ - `auto_route`: aktif/nonaktif routing otomatis
123
+ - `fallback_enabled`: coba provider cadangan saat request gagal
124
+ - `default_system_instruction`: system prompt default
125
+ - `default_gemini_model`: nama model untuk provider `flash`
126
+ - `deepseek_temperature`: temperature default untuk DeepSeek
127
+ - `debug`: tampilkan log sederhana saat development
128
+ - `request_logging`: aktifkan logging request
129
+
130
+ ## Custom System Instruction
131
+
132
+ Kamu bisa memberi system instruction per request:
133
+
134
+ ```python
135
+ response = client.flash(
136
+ "Bantu saya menyusun rencana automation",
137
+ system_instruction="You are an AI assistant focused on backend automation and practical implementation.",
138
+ )
139
+ ```
140
+
141
+ Atau menjadikannya default lewat `FlashConfig`.
142
+
143
+ ## Response Object
144
+
145
+ Setiap request mengembalikan `FlashResponse` dengan struktur yang konsisten:
146
+
147
+ ```python
148
+ response.text
149
+ response.model_used
150
+ response.provider
151
+ response.raw
152
+ response.route_reason
153
+ response.error
154
+ ```
155
+
156
+ Penjelasan singkat:
157
+
158
+ - `text`: isi jawaban utama
159
+ - `model_used`: nama model yang dilaporkan provider
160
+ - `provider`: provider yang benar-benar dipakai
161
+ - `raw`: payload JSON mentah dari endpoint
162
+ - `route_reason`: alasan routing yang dipilih client
163
+ - `error`: pesan error jika request gagal
164
+
165
+ Contoh:
166
+
167
+ ```python
168
+ response = client.flash("Jelaskan recursion")
169
+
170
+ if response.error:
171
+ print("Error:", response.error)
172
+ else:
173
+ print(response.text)
174
+ print("Provider:", response.provider)
175
+ print("Reason:", response.route_reason)
176
+ ```
177
+
178
+ ## Parameter yang Bisa Dipakai Saat Request
179
+
180
+ API utama:
181
+
182
+ ```python
183
+ client.flash(
184
+ prompt,
185
+ mode=None,
186
+ provider=None,
187
+ auto_route=None,
188
+ system_instruction=None,
189
+ fallback_provider=None,
190
+ **kwargs,
191
+ )
192
+ ```
193
+
194
+ Parameter penting:
195
+
196
+ - `prompt`: isi permintaan user
197
+ - `mode`: `fast` atau `reasoning`
198
+ - `provider`: paksa provider tertentu
199
+ - `auto_route`: override perilaku routing default
200
+ - `system_instruction`: system instruction per request
201
+ - `fallback_provider`: provider cadangan jika request utama gagal
202
+ - `**kwargs`: parameter tambahan yang diteruskan ke provider
203
+
204
+ Contoh `kwargs`:
205
+
206
+ ```python
207
+ response = client.flash(
208
+ "Jelaskan greedy algorithm",
209
+ provider="deepseek",
210
+ temperature=0.2,
211
+ )
212
+ ```
213
+
214
+ ## Menjalankan Contoh Interaktif
215
+
216
+ Contoh interaktif ada di `examples/basic_usage.py`.
217
+
218
+ Jalankan dengan:
219
+
220
+ ```bash
221
+ python examples/basic_usage.py
222
+ ```
223
+
224
+ atau:
225
+
226
+ ```bash
227
+ python -m examples.basic_usage
228
+ ```
229
+
230
+ ## Struktur Project
231
+
232
+ File yang paling penting:
233
+
234
+ - `javaxFlash/client.py`: entry point utama library
235
+ - `javaxFlash/config.py`: konfigurasi client
236
+ - `javaxFlash/router.py`: logika pemilihan provider
237
+ - `javaxFlash/providers.py`: implementasi request ke provider
238
+ - `javaxFlash/models.py`: model respons
239
+
240
+ ## Catatan Penting
241
+
242
+ - `flash` di library ini adalah nama provider cepat yang dibacking oleh endpoint Gemini Lite.
243
+ - `deepseek` dipakai untuk prompt yang lebih berat atau mode reasoning.
244
+ - Output akhir tetap bergantung pada endpoint upstream yang dipanggil library ini.
245
+ - Library ini sekarang stateless; tidak ada fitur memory atau penyimpanan percakapan lokal.
246
+
247
+ ## Minimal Example
248
+
249
+ Kalau ingin contoh paling ringkas untuk dipakai di project lain:
250
+
251
+ ```python
252
+ from javaxFlash import FlashClient
253
+
254
+ client = FlashClient()
255
+ response = client.flash("Buat ringkasan tentang REST API", mode="fast")
256
+
257
+ if response.error:
258
+ raise RuntimeError(response.error)
259
+
260
+ print(response.text)
261
+ ```
@@ -0,0 +1,5 @@
1
+ from .client import FlashClient
2
+ from .config import FlashConfig
3
+ from .models import FlashResponse
4
+
5
+ __all__ = ["FlashClient", "FlashConfig", "FlashResponse"]
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from .config import FlashConfig
6
+ from .models import FlashResponse
7
+ from .providers import DeepSeekProvider, FlashProvider, ProviderError
8
+ from .router import FlashRouter
9
+
10
+
11
+ class FlashClient:
12
+ def __init__(self, config: FlashConfig | None = None):
13
+ self.config = config or FlashConfig()
14
+ self.router = FlashRouter()
15
+ self.providers = {
16
+ "deepseek": DeepSeekProvider(self.config),
17
+ "gemini": FlashProvider(self.config),
18
+ "flash": FlashProvider(self.config),
19
+ }
20
+
21
+ def flash(
22
+ self,
23
+ prompt: str,
24
+ *,
25
+ mode: str | None = None,
26
+ provider: str | None = None,
27
+ auto_route: bool | None = None,
28
+ system_instruction: str | None = None,
29
+ fallback_provider: str | None = None,
30
+ **kwargs: Any,
31
+ ) -> FlashResponse:
32
+ auto_route = self.config.auto_route if auto_route is None else auto_route
33
+ if provider == "flash":
34
+ provider = "gemini"
35
+ if fallback_provider == "flash":
36
+ fallback_provider = "gemini"
37
+ instruction = system_instruction or self.config.default_system_instruction
38
+
39
+ decision = self.router.choose(
40
+ prompt=prompt,
41
+ mode=mode,
42
+ forced_provider=provider,
43
+ auto_route=auto_route,
44
+ default_provider=self.config.default_provider,
45
+ )
46
+ chosen_provider = decision.provider
47
+
48
+ try:
49
+ response = self.providers[chosen_provider].request(
50
+ prompt,
51
+ system_prompt=instruction,
52
+ **kwargs,
53
+ )
54
+ response.route_reason = decision.reason
55
+ response.provider = "flash" if chosen_provider == "gemini" else chosen_provider
56
+ except ProviderError as exc:
57
+ if not self.config.fallback_enabled and not fallback_provider:
58
+ return self._error_response(chosen_provider, str(exc), decision.reason)
59
+ backup = fallback_provider or self._other_provider(chosen_provider)
60
+ try:
61
+ response = self.providers[backup].request(
62
+ prompt,
63
+ system_prompt=instruction,
64
+ **kwargs,
65
+ )
66
+ response.route_reason = f"{decision.reason}; fallback to {backup} after {chosen_provider} failed"
67
+ response.provider = "flash" if backup == "gemini" else backup
68
+ except ProviderError as fallback_exc:
69
+ return self._error_response(
70
+ chosen_provider,
71
+ f"{exc} | fallback failed: {fallback_exc}",
72
+ decision.reason,
73
+ )
74
+
75
+ return response
76
+
77
+ def ask(self, prompt: str, **kwargs: Any) -> FlashResponse:
78
+ return self.flash(prompt, **kwargs)
79
+
80
+ def _other_provider(self, provider: str) -> str:
81
+ return "gemini" if provider == "deepseek" else "deepseek"
82
+
83
+ def _error_response(
84
+ self,
85
+ provider: str,
86
+ error: str,
87
+ route_reason: str,
88
+ ) -> FlashResponse:
89
+ public_provider = "flash" if provider == "gemini" else provider
90
+ return FlashResponse(
91
+ text="",
92
+ model_used=self.config.default_model_name if public_provider == "flash" else provider,
93
+ provider=public_provider,
94
+ raw=None,
95
+ route_reason=route_reason,
96
+ error=error,
97
+ )
98
+
99
+
100
+ AIClient = FlashClient
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(slots=True)
7
+ class FlashConfig:
8
+ timeout: float = 30.0
9
+ default_provider: str = "flash"
10
+ default_model_name: str = "javaxFlash"
11
+ default_gemini_model: str = "gemini-2.0-flash-lite"
12
+ deepseek_temperature: float = 0.7
13
+ auto_route: bool = True
14
+ debug: bool = False
15
+ request_logging: bool = False
16
+ fallback_enabled: bool = True
17
+ default_system_instruction: str = (
18
+ "You are javaxFlash, a practical, concise, and helpful AI assistant."
19
+ )
20
+
21
+
22
+ AIClientConfig = FlashConfig
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+
7
+ @dataclass(slots=True)
8
+ class FlashResponse:
9
+ text: str
10
+ model_used: str
11
+ provider: str
12
+ raw: Any = None
13
+ route_reason: str = ""
14
+ error: str | None = None
15
+
16
+
17
+ AIResponse = FlashResponse
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any
5
+
6
+ import requests
7
+
8
+ from .config import FlashConfig
9
+ from .models import FlashResponse
10
+
11
+
12
+ class ProviderError(RuntimeError):
13
+ pass
14
+
15
+
16
+ class BaseProvider(ABC):
17
+ name: str
18
+ endpoint: str
19
+
20
+ def __init__(self, config: FlashConfig):
21
+ self.config = config
22
+
23
+ @abstractmethod
24
+ def build_params(
25
+ self,
26
+ prompt: str,
27
+ system_prompt: str | None = None,
28
+ **kwargs: Any,
29
+ ) -> dict[str, Any]:
30
+ raise NotImplementedError
31
+
32
+ def request(
33
+ self,
34
+ prompt: str,
35
+ system_prompt: str | None = None,
36
+ **kwargs: Any,
37
+ ) -> FlashResponse:
38
+ params = self.build_params(prompt=prompt, system_prompt=system_prompt, **kwargs)
39
+ self._log(f"[{self.name}] GET {self.endpoint} params={params}")
40
+ try:
41
+ response = requests.get(
42
+ self.endpoint,
43
+ params=params,
44
+ timeout=self.config.timeout,
45
+ )
46
+ response.raise_for_status()
47
+ except requests.Timeout as exc:
48
+ raise ProviderError(f"{self.name} request timed out after {self.config.timeout}s") from exc
49
+ except requests.RequestException as exc:
50
+ raise ProviderError(f"{self.name} request failed: {exc}") from exc
51
+
52
+ try:
53
+ raw = response.json()
54
+ except ValueError as exc:
55
+ raise ProviderError(f"{self.name} returned invalid JSON") from exc
56
+
57
+ text = self.extract_text(raw)
58
+ if not text:
59
+ raise ProviderError(f"{self.name} response did not contain usable text")
60
+
61
+ return FlashResponse(
62
+ text=text.strip(),
63
+ model_used=self.extract_model(raw, **kwargs),
64
+ provider=self.name,
65
+ raw=raw,
66
+ )
67
+
68
+ def extract_text(self, raw: Any) -> str:
69
+ if isinstance(raw, str):
70
+ return raw
71
+
72
+ if isinstance(raw, dict):
73
+ for key in ("text", "response", "answer", "result", "message", "content"):
74
+ value = raw.get(key)
75
+ if isinstance(value, str) and value.strip():
76
+ return value
77
+ data = raw.get("data")
78
+ if isinstance(data, dict):
79
+ for key in ("text", "response", "answer", "result", "message", "content"):
80
+ value = data.get(key)
81
+ if isinstance(value, str) and value.strip():
82
+ return value
83
+ parts = data.get("parts")
84
+ if isinstance(parts, list):
85
+ collected: list[str] = []
86
+ for part in parts:
87
+ if isinstance(part, dict):
88
+ text = part.get("text")
89
+ if isinstance(text, str) and text.strip():
90
+ collected.append(text.strip())
91
+ if collected:
92
+ return "\n".join(collected)
93
+ return ""
94
+
95
+ def extract_model(self, raw: Any, **kwargs: Any) -> str:
96
+ if isinstance(raw, dict):
97
+ for key in ("model", "model_used"):
98
+ value = raw.get(key)
99
+ if isinstance(value, str) and value.strip():
100
+ return value
101
+ return kwargs.get("model", self.name)
102
+
103
+ def _log(self, message: str) -> None:
104
+ if self.config.debug or self.config.request_logging:
105
+ print(message)
106
+
107
+
108
+ class DeepSeekProvider(BaseProvider):
109
+ name = "deepseek"
110
+ endpoint = "https://api.siputzx.my.id/api/ai/deepseekr1"
111
+
112
+ def build_params(
113
+ self,
114
+ prompt: str,
115
+ system_prompt: str | None = None,
116
+ **kwargs: Any,
117
+ ) -> dict[str, Any]:
118
+ temperature = kwargs.get("temperature", self.config.deepseek_temperature)
119
+ return {
120
+ "prompt": prompt,
121
+ "system": system_prompt or self.config.default_system_instruction,
122
+ "temperature": temperature,
123
+ }
124
+
125
+
126
+ class FlashProvider(BaseProvider):
127
+ name = "flash"
128
+ endpoint = "https://api.siputzx.my.id/api/ai/gemini-lite"
129
+
130
+ def build_params(
131
+ self,
132
+ prompt: str,
133
+ system_prompt: str | None = None,
134
+ **kwargs: Any,
135
+ ) -> dict[str, Any]:
136
+ if system_prompt:
137
+ prompt = f"System instruction: {system_prompt}\n\nUser request: {prompt}"
138
+ return {
139
+ "prompt": prompt,
140
+ "model": kwargs.get("model", self.config.default_gemini_model),
141
+ }
142
+
143
+ def extract_model(self, raw: Any, **kwargs: Any) -> str:
144
+ value = super().extract_model(raw, **kwargs)
145
+ return self.config.default_model_name if value == self.name else value
146
+
147
+
148
+ GeminiLiteProvider = FlashProvider
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+
6
+ @dataclass(slots=True)
7
+ class RouteDecision:
8
+ provider: str
9
+ reason: str
10
+
11
+
12
+ class FlashRouter:
13
+ COMPLEX_KEYWORDS = {
14
+ "debug",
15
+ "bug",
16
+ "error",
17
+ "reasoning",
18
+ "step-by-step",
19
+ "step by step",
20
+ "architecture",
21
+ "design",
22
+ "plan",
23
+ "strategy",
24
+ "analyze",
25
+ "analysis",
26
+ "compare",
27
+ "tradeoff",
28
+ "why",
29
+ "kenapa",
30
+ "mengapa",
31
+ "refactor",
32
+ "algorithm",
33
+ "infinite loop",
34
+ "q-learning",
35
+ "rl",
36
+ "root cause",
37
+ }
38
+ SIMPLE_PREFIXES = (
39
+ "apa ",
40
+ "what ",
41
+ "who ",
42
+ "when ",
43
+ "where ",
44
+ "define ",
45
+ "jelaskan singkat",
46
+ "summarize ",
47
+ "ringkas ",
48
+ )
49
+
50
+ def choose(
51
+ self,
52
+ prompt: str,
53
+ mode: str | None = None,
54
+ forced_provider: str | None = None,
55
+ auto_route: bool = True,
56
+ default_provider: str = "flash",
57
+ ) -> RouteDecision:
58
+ if forced_provider == "flash":
59
+ forced_provider = "gemini"
60
+
61
+ if forced_provider:
62
+ return RouteDecision(
63
+ provider=forced_provider,
64
+ reason=f"provider forced explicitly: {forced_provider}",
65
+ )
66
+
67
+ if mode == "reasoning":
68
+ return RouteDecision(provider="deepseek", reason="reasoning mode requested")
69
+ if mode == "fast":
70
+ return RouteDecision(provider="gemini", reason="fast mode requested (Flash)")
71
+
72
+ if not auto_route:
73
+ resolved = "gemini" if default_provider == "flash" else default_provider
74
+ return RouteDecision(
75
+ provider=resolved,
76
+ reason=f"auto routing disabled, using default provider {default_provider}",
77
+ )
78
+
79
+ normalized = prompt.strip().lower()
80
+ if any(token in normalized for token in self.COMPLEX_KEYWORDS):
81
+ return RouteDecision(
82
+ provider="deepseek",
83
+ reason="prompt contains complex reasoning/debugging keywords",
84
+ )
85
+ if len(normalized.split()) <= 12 or normalized.startswith(self.SIMPLE_PREFIXES):
86
+ return RouteDecision(
87
+ provider="gemini",
88
+ reason="prompt looks short or fact-oriented",
89
+ )
90
+ if "?" in normalized and len(normalized.split()) <= 20:
91
+ return RouteDecision(
92
+ provider="gemini",
93
+ reason="prompt looks like a quick question",
94
+ )
95
+ return RouteDecision(
96
+ provider="deepseek",
97
+ reason="defaulted to deeper reasoning for broader prompt",
98
+ )
99
+
100
+
101
+ PromptRouter = FlashRouter
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: javaxFlash
3
+ Version: 2.1.0
4
+ Summary: Lightweight local-first AI router with javaxFlash and DeepSeek.
5
+ Author: Javas Antony
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://pypi.org/project/javaxFlash/
8
+ Keywords: ai,client,router,gemini,deepseek
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: requests>=2.31.0
20
+ Dynamic: license-file
21
+
22
+ # javaxFlash
23
+
24
+ `javaxFlash` adalah library Python kecil untuk mengakses beberapa endpoint AI lewat satu client API yang sederhana.
25
+
26
+ Tujuan library ini:
27
+
28
+ - memberi satu entry point yang ringan: `FlashClient`
29
+ - memudahkan pindah antara provider `flash` dan `deepseek`
30
+ - mendukung auto routing atau provider manual
31
+ - mengembalikan format respons yang konsisten
32
+
33
+ ## Cocok untuk apa
34
+
35
+ - pertanyaan cepat dengan provider default `flash`
36
+ - prompt reasoning yang lebih berat dengan `deepseek`
37
+ - eksperimen lokal tanpa harus menulis wrapper request berulang-ulang
38
+
39
+ ## Install
40
+
41
+ Install package inti:
42
+
43
+ ```bash
44
+ python -m pip install -r requirements.txt
45
+ python -m pip install -e .
46
+ ```
47
+
48
+ Kalau ingin menjalankan contoh interaktif di folder `examples`, install juga `rich`:
49
+
50
+ ```bash
51
+ python -m pip install rich
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ Contoh paling sederhana:
57
+
58
+ ```python
59
+ from javaxFlash import FlashClient
60
+
61
+ client = FlashClient()
62
+
63
+ response = client.flash("Jelaskan konsep Q-learning dengan sederhana")
64
+
65
+ print(response.text)
66
+ print(response.provider)
67
+ print(response.model_used)
68
+ ```
69
+
70
+ Alias `ask()` juga tersedia:
71
+
72
+ ```python
73
+ response = client.ask("Apa itu Python?")
74
+ print(response.text)
75
+ ```
76
+
77
+ ## Cara Kerja Singkat
78
+
79
+ Secara default, `FlashClient` akan:
80
+
81
+ 1. menerima prompt dari user
82
+ 2. memilih provider berdasarkan mode atau auto routing
83
+ 3. mengirim request ke endpoint provider
84
+ 4. mengembalikan hasil dalam bentuk `FlashResponse`
85
+
86
+ Kalau provider utama gagal dan fallback aktif, client akan mencoba provider cadangan.
87
+
88
+ ## Memilih Provider
89
+
90
+ ### 1. Auto routing
91
+
92
+ Auto routing cocok kalau kamu ingin library memilih provider secara otomatis.
93
+
94
+ ```python
95
+ response = client.flash("Bandingkan REST dan GraphQL untuk project kecil", auto_route=True)
96
+ ```
97
+
98
+ ### 2. Fast mode
99
+
100
+ Gunakan saat ingin jawaban cepat.
101
+
102
+ ```python
103
+ response = client.flash("Apa itu Python?", mode="fast")
104
+ ```
105
+
106
+ ### 3. Reasoning mode
107
+
108
+ Gunakan saat prompt butuh analisis lebih dalam.
109
+
110
+ ```python
111
+ response = client.flash("Kenapa algoritma ini gagal dan bagaimana cara debug-nya?", mode="reasoning")
112
+ ```
113
+
114
+ ### 4. Paksa provider tertentu
115
+
116
+ Kalau kamu sudah tahu provider mana yang ingin dipakai:
117
+
118
+ ```python
119
+ response = client.flash("Gunakan provider cepat", provider="flash")
120
+ response = client.flash("Analisis bug ini", provider="deepseek")
121
+ ```
122
+
123
+ ## Konfigurasi Dasar
124
+
125
+ Kalau ingin mengubah perilaku default client:
126
+
127
+ ```python
128
+ from javaxFlash import FlashClient, FlashConfig
129
+
130
+ config = FlashConfig(
131
+ timeout=30.0,
132
+ auto_route=True,
133
+ fallback_enabled=True,
134
+ default_system_instruction="You are javaxFlash, a concise and practical AI assistant.",
135
+ )
136
+
137
+ client = FlashClient(config=config)
138
+ ```
139
+
140
+ Field config yang paling sering dipakai:
141
+
142
+ - `timeout`: timeout request HTTP
143
+ - `auto_route`: aktif/nonaktif routing otomatis
144
+ - `fallback_enabled`: coba provider cadangan saat request gagal
145
+ - `default_system_instruction`: system prompt default
146
+ - `default_gemini_model`: nama model untuk provider `flash`
147
+ - `deepseek_temperature`: temperature default untuk DeepSeek
148
+ - `debug`: tampilkan log sederhana saat development
149
+ - `request_logging`: aktifkan logging request
150
+
151
+ ## Custom System Instruction
152
+
153
+ Kamu bisa memberi system instruction per request:
154
+
155
+ ```python
156
+ response = client.flash(
157
+ "Bantu saya menyusun rencana automation",
158
+ system_instruction="You are an AI assistant focused on backend automation and practical implementation.",
159
+ )
160
+ ```
161
+
162
+ Atau menjadikannya default lewat `FlashConfig`.
163
+
164
+ ## Response Object
165
+
166
+ Setiap request mengembalikan `FlashResponse` dengan struktur yang konsisten:
167
+
168
+ ```python
169
+ response.text
170
+ response.model_used
171
+ response.provider
172
+ response.raw
173
+ response.route_reason
174
+ response.error
175
+ ```
176
+
177
+ Penjelasan singkat:
178
+
179
+ - `text`: isi jawaban utama
180
+ - `model_used`: nama model yang dilaporkan provider
181
+ - `provider`: provider yang benar-benar dipakai
182
+ - `raw`: payload JSON mentah dari endpoint
183
+ - `route_reason`: alasan routing yang dipilih client
184
+ - `error`: pesan error jika request gagal
185
+
186
+ Contoh:
187
+
188
+ ```python
189
+ response = client.flash("Jelaskan recursion")
190
+
191
+ if response.error:
192
+ print("Error:", response.error)
193
+ else:
194
+ print(response.text)
195
+ print("Provider:", response.provider)
196
+ print("Reason:", response.route_reason)
197
+ ```
198
+
199
+ ## Parameter yang Bisa Dipakai Saat Request
200
+
201
+ API utama:
202
+
203
+ ```python
204
+ client.flash(
205
+ prompt,
206
+ mode=None,
207
+ provider=None,
208
+ auto_route=None,
209
+ system_instruction=None,
210
+ fallback_provider=None,
211
+ **kwargs,
212
+ )
213
+ ```
214
+
215
+ Parameter penting:
216
+
217
+ - `prompt`: isi permintaan user
218
+ - `mode`: `fast` atau `reasoning`
219
+ - `provider`: paksa provider tertentu
220
+ - `auto_route`: override perilaku routing default
221
+ - `system_instruction`: system instruction per request
222
+ - `fallback_provider`: provider cadangan jika request utama gagal
223
+ - `**kwargs`: parameter tambahan yang diteruskan ke provider
224
+
225
+ Contoh `kwargs`:
226
+
227
+ ```python
228
+ response = client.flash(
229
+ "Jelaskan greedy algorithm",
230
+ provider="deepseek",
231
+ temperature=0.2,
232
+ )
233
+ ```
234
+
235
+ ## Menjalankan Contoh Interaktif
236
+
237
+ Contoh interaktif ada di `examples/basic_usage.py`.
238
+
239
+ Jalankan dengan:
240
+
241
+ ```bash
242
+ python examples/basic_usage.py
243
+ ```
244
+
245
+ atau:
246
+
247
+ ```bash
248
+ python -m examples.basic_usage
249
+ ```
250
+
251
+ ## Struktur Project
252
+
253
+ File yang paling penting:
254
+
255
+ - `javaxFlash/client.py`: entry point utama library
256
+ - `javaxFlash/config.py`: konfigurasi client
257
+ - `javaxFlash/router.py`: logika pemilihan provider
258
+ - `javaxFlash/providers.py`: implementasi request ke provider
259
+ - `javaxFlash/models.py`: model respons
260
+
261
+ ## Catatan Penting
262
+
263
+ - `flash` di library ini adalah nama provider cepat yang dibacking oleh endpoint Gemini Lite.
264
+ - `deepseek` dipakai untuk prompt yang lebih berat atau mode reasoning.
265
+ - Output akhir tetap bergantung pada endpoint upstream yang dipanggil library ini.
266
+ - Library ini sekarang stateless; tidak ada fitur memory atau penyimpanan percakapan lokal.
267
+
268
+ ## Minimal Example
269
+
270
+ Kalau ingin contoh paling ringkas untuk dipakai di project lain:
271
+
272
+ ```python
273
+ from javaxFlash import FlashClient
274
+
275
+ client = FlashClient()
276
+ response = client.flash("Buat ringkasan tentang REST API", mode="fast")
277
+
278
+ if response.error:
279
+ raise RuntimeError(response.error)
280
+
281
+ print(response.text)
282
+ ```
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ javaxFlash/__init__.py
5
+ javaxFlash/client.py
6
+ javaxFlash/config.py
7
+ javaxFlash/models.py
8
+ javaxFlash/providers.py
9
+ javaxFlash/router.py
10
+ javaxFlash.egg-info/PKG-INFO
11
+ javaxFlash.egg-info/SOURCES.txt
12
+ javaxFlash.egg-info/dependency_links.txt
13
+ javaxFlash.egg-info/requires.txt
14
+ javaxFlash.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.31.0
@@ -0,0 +1 @@
1
+ javaxFlash
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "javaxFlash"
7
+ version = "2.1.0"
8
+ description = "Lightweight local-first AI router with javaxFlash and DeepSeek."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [
12
+ { name = "Javas Antony" }
13
+ ]
14
+ requires-python = ">=3.10"
15
+ dependencies = [
16
+ "requests>=2.31.0",
17
+ ]
18
+ keywords = ["ai", "client", "router", "gemini", "deepseek"]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ ]
28
+
29
+ [tool.setuptools]
30
+ packages = ["javaxFlash"]
31
+
32
+ [tool.setuptools.package-data]
33
+
34
+ [project.urls]
35
+ "Homepage" = "https://pypi.org/project/javaxFlash/"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+