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.
- javaxflash-2.1.0/LICENSE +21 -0
- javaxflash-2.1.0/PKG-INFO +282 -0
- javaxflash-2.1.0/README.md +261 -0
- javaxflash-2.1.0/javaxFlash/__init__.py +5 -0
- javaxflash-2.1.0/javaxFlash/client.py +100 -0
- javaxflash-2.1.0/javaxFlash/config.py +22 -0
- javaxflash-2.1.0/javaxFlash/models.py +17 -0
- javaxflash-2.1.0/javaxFlash/providers.py +148 -0
- javaxflash-2.1.0/javaxFlash/router.py +101 -0
- javaxflash-2.1.0/javaxFlash.egg-info/PKG-INFO +282 -0
- javaxflash-2.1.0/javaxFlash.egg-info/SOURCES.txt +14 -0
- javaxflash-2.1.0/javaxFlash.egg-info/dependency_links.txt +1 -0
- javaxflash-2.1.0/javaxFlash.egg-info/requires.txt +1 -0
- javaxflash-2.1.0/javaxFlash.egg-info/top_level.txt +1 -0
- javaxflash-2.1.0/pyproject.toml +35 -0
- javaxflash-2.1.0/setup.cfg +4 -0
javaxflash-2.1.0/LICENSE
ADDED
|
@@ -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,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
|
+
|
|
@@ -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/"
|