banko-ai-assistant 1.0.8__py3-none-any.whl → 1.0.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- banko_ai/cli.py +4 -4
- banko_ai/vector_search/generator.py +115 -48
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/METADATA +1 -1
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/RECORD +8 -8
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/WHEEL +0 -0
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/entry_points.txt +0 -0
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/licenses/LICENSE +0 -0
- {banko_ai_assistant-1.0.8.dist-info → banko_ai_assistant-1.0.10.dist-info}/top_level.txt +0 -0
banko_ai/cli.py
CHANGED
@@ -73,8 +73,8 @@ def run(host, port, debug, generate_data, no_data, clear_data, background):
|
|
73
73
|
click.echo("Clearing existing data...")
|
74
74
|
generator.clear_expenses()
|
75
75
|
|
76
|
-
generator.generate_and_save(generate_data)
|
77
|
-
click.echo(f"✅ Successfully generated {
|
76
|
+
actual_count = generator.generate_and_save(generate_data)
|
77
|
+
click.echo(f"✅ Successfully generated {actual_count} expense records")
|
78
78
|
except Exception as e:
|
79
79
|
click.echo(f"❌ Error generating data: {e}")
|
80
80
|
return
|
@@ -220,8 +220,8 @@ def start(host, port, generate_data, no_data, clear_data):
|
|
220
220
|
click.echo("Clearing existing data...")
|
221
221
|
generator.clear_expenses()
|
222
222
|
|
223
|
-
generator.generate_and_save(generate_data)
|
224
|
-
click.echo(f"✅ Successfully generated {
|
223
|
+
actual_count = generator.generate_and_save(generate_data)
|
224
|
+
click.echo(f"✅ Successfully generated {actual_count} expense records")
|
225
225
|
except Exception as e:
|
226
226
|
click.echo(f"❌ Error generating data: {e}")
|
227
227
|
return
|
@@ -224,56 +224,123 @@ class EnhancedExpenseGenerator:
|
|
224
224
|
return expenses
|
225
225
|
|
226
226
|
def save_expenses_to_database(self, expenses: List[Dict[str, Any]]) -> int:
|
227
|
-
"""Save expenses to the database."""
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
227
|
+
"""Save expenses to the database with retry logic for CockroachDB."""
|
228
|
+
import pandas as pd
|
229
|
+
import time
|
230
|
+
import random
|
231
|
+
from sqlalchemy.exc import OperationalError
|
232
|
+
|
233
|
+
# Prepare data for insertion
|
234
|
+
data_to_insert = []
|
235
|
+
for expense in expenses:
|
236
|
+
data_to_insert.append({
|
237
|
+
'expense_id': expense['expense_id'],
|
238
|
+
'user_id': expense['user_id'],
|
239
|
+
'expense_date': expense['expense_date'],
|
240
|
+
'expense_amount': expense['expense_amount'],
|
241
|
+
'shopping_type': expense['shopping_type'],
|
242
|
+
'description': expense['description'],
|
243
|
+
'merchant': expense['merchant'],
|
244
|
+
'payment_method': expense['payment_method'],
|
245
|
+
'recurring': expense['recurring'],
|
246
|
+
'tags': expense['tags'],
|
247
|
+
'embedding': expense['embedding']
|
248
|
+
})
|
249
|
+
|
250
|
+
# Insert in smaller batches to reduce transaction conflicts
|
251
|
+
batch_size = 50 # Reduced from 100 to minimize conflicts
|
252
|
+
total_inserted = 0
|
253
|
+
total_batches = (len(data_to_insert) + batch_size - 1) // batch_size
|
254
|
+
|
255
|
+
print(f"📊 Inserting {len(data_to_insert)} records in {total_batches} batches of {batch_size}")
|
256
|
+
|
257
|
+
for i in range(0, len(data_to_insert), batch_size):
|
258
|
+
batch = data_to_insert[i:i + batch_size]
|
259
|
+
|
260
|
+
# Retry logic for CockroachDB transaction conflicts
|
261
|
+
max_retries = 5
|
262
|
+
retry_count = 0
|
263
|
+
|
264
|
+
while retry_count < max_retries:
|
265
|
+
try:
|
266
|
+
with self.engine.connect() as conn:
|
267
|
+
# Use pandas to insert the batch
|
268
|
+
df = pd.DataFrame(batch)
|
269
|
+
df.to_sql('expenses', conn, if_exists='append', index=False, method='multi')
|
270
|
+
conn.commit()
|
271
|
+
total_inserted += len(batch)
|
272
|
+
batch_num = i//batch_size + 1
|
273
|
+
print(f"✅ Batch {batch_num}/{total_batches}: {len(batch)} records inserted (Total: {total_inserted})")
|
274
|
+
break # Success, exit retry loop
|
275
|
+
|
276
|
+
except OperationalError as e:
|
277
|
+
# Check if it's a CockroachDB serialization failure (SQL state 40001)
|
278
|
+
if "40001" in str(e) or "SerializationFailure" in str(e) or "restart transaction" in str(e).lower():
|
279
|
+
retry_count += 1
|
280
|
+
if retry_count < max_retries:
|
281
|
+
# Exponential backoff with jitter
|
282
|
+
base_delay = 0.1 * (2 ** retry_count)
|
283
|
+
jitter = random.uniform(0, 0.1)
|
284
|
+
delay = base_delay + jitter
|
285
|
+
print(f"Transaction conflict detected, retrying in {delay:.2f}s (attempt {retry_count}/{max_retries})")
|
286
|
+
time.sleep(delay)
|
287
|
+
continue
|
288
|
+
else:
|
289
|
+
print(f"Max retries exceeded for batch {i//batch_size + 1}: {e}")
|
290
|
+
return total_inserted
|
291
|
+
else:
|
292
|
+
# Non-retryable error
|
293
|
+
print(f"Non-retryable database error: {e}")
|
294
|
+
return total_inserted
|
295
|
+
|
296
|
+
except Exception as e:
|
297
|
+
print(f"Unexpected error saving batch {i//batch_size + 1}: {e}")
|
298
|
+
return total_inserted
|
299
|
+
|
300
|
+
return total_inserted
|
265
301
|
|
266
302
|
def clear_expenses(self) -> bool:
|
267
|
-
"""Clear all expenses from the database."""
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
303
|
+
"""Clear all expenses from the database with retry logic."""
|
304
|
+
import time
|
305
|
+
import random
|
306
|
+
from sqlalchemy import text
|
307
|
+
from sqlalchemy.exc import OperationalError
|
308
|
+
|
309
|
+
max_retries = 5
|
310
|
+
retry_count = 0
|
311
|
+
|
312
|
+
while retry_count < max_retries:
|
313
|
+
try:
|
314
|
+
with self.engine.connect() as conn:
|
315
|
+
conn.execute(text("DELETE FROM expenses"))
|
316
|
+
conn.commit()
|
317
|
+
return True
|
318
|
+
|
319
|
+
except OperationalError as e:
|
320
|
+
# Check if it's a CockroachDB serialization failure (SQL state 40001)
|
321
|
+
if "40001" in str(e) or "SerializationFailure" in str(e) or "restart transaction" in str(e).lower():
|
322
|
+
retry_count += 1
|
323
|
+
if retry_count < max_retries:
|
324
|
+
# Exponential backoff with jitter
|
325
|
+
base_delay = 0.1 * (2 ** retry_count)
|
326
|
+
jitter = random.uniform(0, 0.1)
|
327
|
+
delay = base_delay + jitter
|
328
|
+
print(f"Transaction conflict detected while clearing, retrying in {delay:.2f}s (attempt {retry_count}/{max_retries})")
|
329
|
+
time.sleep(delay)
|
330
|
+
continue
|
331
|
+
else:
|
332
|
+
print(f"Max retries exceeded while clearing expenses: {e}")
|
333
|
+
return False
|
334
|
+
else:
|
335
|
+
# Non-retryable error
|
336
|
+
print(f"Non-retryable database error while clearing: {e}")
|
337
|
+
return False
|
338
|
+
|
339
|
+
except Exception as e:
|
340
|
+
print(f"Unexpected error clearing expenses: {e}")
|
341
|
+
return False
|
342
|
+
|
343
|
+
return False
|
277
344
|
|
278
345
|
def get_expense_count(self) -> int:
|
279
346
|
"""Get the current number of expenses in the database."""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: banko-ai-assistant
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.10
|
4
4
|
Summary: AI-powered expense analysis and RAG system with CockroachDB vector search and multi-provider AI support
|
5
5
|
Author-email: Virag Tripathi <virag.tripathi@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -1,6 +1,6 @@
|
|
1
1
|
banko_ai/__init__.py,sha256=G1InyKemqQxP9xx6yGZgolBmrmOLSpBXqGYY8LaFOeo,568
|
2
2
|
banko_ai/__main__.py,sha256=vySUZt0uAzogVu6yURIlLJ1Ig5bdxT_55oiiaiZKqA8,185
|
3
|
-
banko_ai/cli.py,sha256=
|
3
|
+
banko_ai/cli.py,sha256=SsCsikOykmTM_uId-n0ivilKXu1hKch17XXwhMHfFnU,13760
|
4
4
|
banko_ai/ai_providers/__init__.py,sha256=JdBgw5Mji2pe9nU-aiRYUmJuZk0q8KbcMtbpMJC5Dq8,483
|
5
5
|
banko_ai/ai_providers/aws_provider.py,sha256=-tR-8tlEeSL-Fspx05tTMFguvQylkW_pz0PI2XJEByM,13074
|
6
6
|
banko_ai/ai_providers/base.py,sha256=zbuAgkHIfJ0YkG83LXzieJuvXBcB2-nx7NhbL-I4Pf0,4725
|
@@ -151,14 +151,14 @@ banko_ai/utils/database.py,sha256=sJYAFTApkWReEJuMbbBDiz7XfgiiEd6lPSSyF6BQDpk,77
|
|
151
151
|
banko_ai/utils/migration.py,sha256=j1lYUVZyYMcMvxZUOFymoK19QTPqkDZFXD-iysVCnQo,4764
|
152
152
|
banko_ai/vector_search/__init__.py,sha256=vYksnkUU4FA8XBNzYZIH4FoGjXCx9oIbrDeapSzrNuE,621
|
153
153
|
banko_ai/vector_search/enrichment.py,sha256=sRnFLNG9WGfq8j44T7krxHI-Lc2RSH68mt0IT0GTHBA,10203
|
154
|
-
banko_ai/vector_search/generator.py,sha256=
|
154
|
+
banko_ai/vector_search/generator.py,sha256=vEM-t6FYxcbOlpPTZ3t0oZFI9-4Hkto7YsRq81peT5M,16812
|
155
155
|
banko_ai/vector_search/search.py,sha256=k3wo3zFJH9o-kBc-vAS-bdmM3LGX2vIk3u4cRA5QPXo,16915
|
156
156
|
banko_ai/web/__init__.py,sha256=hjWVVxYpIZhOAN1qBf4xTd36a5AUHM03Q8BF8pykhJQ,363
|
157
157
|
banko_ai/web/app.py,sha256=9xBe6RsyEUQvpDhsRckJ4pzk5x2RZWEhVs8DiJg4zqs,27675
|
158
158
|
banko_ai/web/auth.py,sha256=js6qIixSFHyLbETDm8GNLCPrDkCDcaQZPFOrqtZP1uw,2125
|
159
|
-
banko_ai_assistant-1.0.
|
160
|
-
banko_ai_assistant-1.0.
|
161
|
-
banko_ai_assistant-1.0.
|
162
|
-
banko_ai_assistant-1.0.
|
163
|
-
banko_ai_assistant-1.0.
|
164
|
-
banko_ai_assistant-1.0.
|
159
|
+
banko_ai_assistant-1.0.10.dist-info/licenses/LICENSE,sha256=skG0LkywIClj8fgSIXiG6o9vUDJ678BKBObIyJ19OMw,1075
|
160
|
+
banko_ai_assistant-1.0.10.dist-info/METADATA,sha256=Ugkk7LSgJQLwWCadl80MttT6tI4pnAswJGmmmTzNnUE,13244
|
161
|
+
banko_ai_assistant-1.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
162
|
+
banko_ai_assistant-1.0.10.dist-info/entry_points.txt,sha256=IxPjBjMvbpCp-ikCA43bOSbYboTGPX4HYcZlvu2_vcA,47
|
163
|
+
banko_ai_assistant-1.0.10.dist-info/top_level.txt,sha256=xNMa9Z67UssefOQ2ubFObtqUYIfYmCIclfz0xdo5OPE,9
|
164
|
+
banko_ai_assistant-1.0.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|