fin-infra 0.1.59__py3-none-any.whl → 0.1.61__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.
- fin_infra/analytics/models.py +1 -1
- fin_infra/analytics/spending.py +5 -5
- fin_infra/categorization/llm_layer.py +1 -1
- fin_infra/chat/__init__.py +3 -3
- fin_infra/chat/ease.py +8 -8
- fin_infra/chat/planning.py +7 -7
- fin_infra/crypto/insights.py +11 -11
- fin_infra/documents/analysis.py +5 -5
- fin_infra/goals/management.py +6 -6
- fin_infra/net_worth/ease.py +3 -3
- fin_infra/net_worth/insights.py +7 -7
- fin_infra/recurring/detectors_llm.py +10 -10
- fin_infra/recurring/insights.py +10 -10
- fin_infra/recurring/normalizers.py +10 -10
- fin_infra/tax/tlh.py +5 -5
- {fin_infra-0.1.59.dist-info → fin_infra-0.1.61.dist-info}/METADATA +2 -1
- {fin_infra-0.1.59.dist-info → fin_infra-0.1.61.dist-info}/RECORD +20 -20
- {fin_infra-0.1.59.dist-info → fin_infra-0.1.61.dist-info}/LICENSE +0 -0
- {fin_infra-0.1.59.dist-info → fin_infra-0.1.61.dist-info}/WHEEL +0 -0
- {fin_infra-0.1.59.dist-info → fin_infra-0.1.61.dist-info}/entry_points.txt +0 -0
fin_infra/analytics/models.py
CHANGED
|
@@ -114,7 +114,7 @@ class SpendingInsight(BaseModel):
|
|
|
114
114
|
class PersonalizedSpendingAdvice(BaseModel):
|
|
115
115
|
"""LLM-generated personalized spending advice.
|
|
116
116
|
|
|
117
|
-
Uses ai-infra
|
|
117
|
+
Uses ai-infra LLM for structured output generation.
|
|
118
118
|
"""
|
|
119
119
|
|
|
120
120
|
model_config = ConfigDict(extra="forbid")
|
fin_infra/analytics/spending.py
CHANGED
|
@@ -12,7 +12,7 @@ Generic Applicability:
|
|
|
12
12
|
|
|
13
13
|
Features:
|
|
14
14
|
- Statistical analysis: Top merchants, category breakdowns, trends, anomalies
|
|
15
|
-
- LLM-powered insights: Personalized recommendations using ai-infra
|
|
15
|
+
- LLM-powered insights: Personalized recommendations using ai-infra LLM
|
|
16
16
|
- Graceful degradation: Falls back to rule-based insights if LLM unavailable
|
|
17
17
|
- Cost-effective: Structured output for predictable token usage (<$0.01/insight)
|
|
18
18
|
|
|
@@ -427,12 +427,12 @@ async def generate_spending_insights(
|
|
|
427
427
|
) -> "PersonalizedSpendingAdvice":
|
|
428
428
|
"""Generate personalized spending insights using LLM.
|
|
429
429
|
|
|
430
|
-
Uses ai-infra
|
|
430
|
+
Uses ai-infra LLM for structured output generation with financial context.
|
|
431
431
|
|
|
432
432
|
Args:
|
|
433
433
|
spending_insight: Analyzed spending data from analyze_spending()
|
|
434
434
|
user_context: Optional context (income, goals, budget, preferences)
|
|
435
|
-
llm_provider: Optional
|
|
435
|
+
llm_provider: Optional LLM instance (defaults to Google Gemini)
|
|
436
436
|
|
|
437
437
|
Returns:
|
|
438
438
|
PersonalizedSpendingAdvice with LLM-generated recommendations
|
|
@@ -468,14 +468,14 @@ async def generate_spending_insights(
|
|
|
468
468
|
|
|
469
469
|
# Try to import ai-infra LLM (optional dependency)
|
|
470
470
|
try:
|
|
471
|
-
from ai_infra.llm import
|
|
471
|
+
from ai_infra.llm import LLM
|
|
472
472
|
except ImportError:
|
|
473
473
|
# Graceful degradation: return rule-based insights
|
|
474
474
|
return _generate_rule_based_insights(spending_insight, user_context)
|
|
475
475
|
|
|
476
476
|
# Initialize LLM if not provided
|
|
477
477
|
if llm_provider is None:
|
|
478
|
-
llm_provider =
|
|
478
|
+
llm_provider = LLM()
|
|
479
479
|
|
|
480
480
|
# Build financial context prompt
|
|
481
481
|
prompt = _build_spending_insights_prompt(spending_insight, user_context)
|
|
@@ -20,7 +20,7 @@ from pydantic import BaseModel, Field
|
|
|
20
20
|
|
|
21
21
|
# ai-infra imports
|
|
22
22
|
try:
|
|
23
|
-
from ai_infra.llm import
|
|
23
|
+
from ai_infra.llm import LLM
|
|
24
24
|
from ai_infra.llm.providers import Providers
|
|
25
25
|
except ImportError:
|
|
26
26
|
raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
|
fin_infra/chat/__init__.py
CHANGED
|
@@ -10,10 +10,10 @@ NOT tied to net worth specifically - works across ALL fin-infra domains:
|
|
|
10
10
|
|
|
11
11
|
Example:
|
|
12
12
|
from fin_infra.conversation import FinancialPlanningConversation
|
|
13
|
-
from ai_infra.llm import
|
|
13
|
+
from ai_infra.llm import LLM
|
|
14
14
|
from svc_infra.cache import get_cache
|
|
15
15
|
|
|
16
|
-
llm =
|
|
16
|
+
llm = LLM()
|
|
17
17
|
cache = get_cache()
|
|
18
18
|
conversation = FinancialPlanningConversation(
|
|
19
19
|
llm=llm,
|
|
@@ -101,7 +101,7 @@ def add_financial_conversation(
|
|
|
101
101
|
|
|
102
102
|
Integration:
|
|
103
103
|
- Uses user_router (requires authentication)
|
|
104
|
-
- Powered by ai-infra
|
|
104
|
+
- Powered by ai-infra LLM (multi-provider support)
|
|
105
105
|
- Uses svc-infra cache for conversation history (24h TTL)
|
|
106
106
|
- Cost: ~$0.018/user/month with Google Gemini
|
|
107
107
|
|
fin_infra/chat/ease.py
CHANGED
|
@@ -13,8 +13,8 @@ Example:
|
|
|
13
13
|
conversation = easy_financial_conversation(provider="openai")
|
|
14
14
|
|
|
15
15
|
# Custom LLM instance
|
|
16
|
-
from ai_infra.llm import
|
|
17
|
-
llm =
|
|
16
|
+
from ai_infra.llm import LLM
|
|
17
|
+
llm = LLM(temperature=0.3)
|
|
18
18
|
conversation = easy_financial_conversation(llm=llm)
|
|
19
19
|
"""
|
|
20
20
|
|
|
@@ -33,12 +33,12 @@ def easy_financial_conversation(
|
|
|
33
33
|
Easy builder for financial planning conversation.
|
|
34
34
|
|
|
35
35
|
One-call setup with sensible defaults:
|
|
36
|
-
- LLM: ai-infra
|
|
36
|
+
- LLM: ai-infra LLM (Google Gemini default)
|
|
37
37
|
- Cache: svc-infra cache (24h TTL)
|
|
38
38
|
- Provider: Google (cheapest, $0.018/user/month)
|
|
39
39
|
|
|
40
40
|
Args:
|
|
41
|
-
llm: Optional ai-infra
|
|
41
|
+
llm: Optional ai-infra LLM instance (auto-created if None)
|
|
42
42
|
cache: Optional svc-infra cache instance (auto-created if None)
|
|
43
43
|
provider: LLM provider ("google", "openai", "anthropic")
|
|
44
44
|
model_name: Optional model name override (uses provider defaults)
|
|
@@ -62,16 +62,16 @@ def easy_financial_conversation(
|
|
|
62
62
|
conversation = easy_financial_conversation(provider="openai")
|
|
63
63
|
|
|
64
64
|
# Custom LLM instance
|
|
65
|
-
from ai_infra.llm import
|
|
66
|
-
llm =
|
|
65
|
+
from ai_infra.llm import LLM
|
|
66
|
+
llm = LLM(temperature=0.3)
|
|
67
67
|
conversation = easy_financial_conversation(llm=llm)
|
|
68
68
|
"""
|
|
69
69
|
# Auto-create LLM if not provided
|
|
70
70
|
if llm is None:
|
|
71
71
|
try:
|
|
72
|
-
from ai_infra.llm import
|
|
72
|
+
from ai_infra.llm import LLM
|
|
73
73
|
|
|
74
|
-
llm =
|
|
74
|
+
llm = LLM()
|
|
75
75
|
except ImportError:
|
|
76
76
|
raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
|
|
77
77
|
|
fin_infra/chat/planning.py
CHANGED
|
@@ -10,19 +10,19 @@ Provides conversational interface for financial Q&A:
|
|
|
10
10
|
- Personalized advice (uses current net worth, goals, historical data)
|
|
11
11
|
- Natural dialogue (flexible responses, not forced JSON structure)
|
|
12
12
|
|
|
13
|
-
**Design Choice**: Uses `
|
|
13
|
+
**Design Choice**: Uses `LLM.achat()` for natural conversation (NOT `with_structured_output()`).
|
|
14
14
|
Conversation should be flexible and natural, not rigidly structured. Other modules (insights,
|
|
15
15
|
categorization, goals) correctly use structured output because they need predictable schemas.
|
|
16
16
|
|
|
17
|
-
Uses ai-infra
|
|
17
|
+
Uses ai-infra LLM for natural conversation.
|
|
18
18
|
Caches conversation context for 24h (target: $0.018/user/month cost).
|
|
19
19
|
|
|
20
20
|
Example:
|
|
21
|
-
from ai_infra.llm import
|
|
21
|
+
from ai_infra.llm import LLM
|
|
22
22
|
from svc_infra.cache import get_cache
|
|
23
23
|
from fin_infra.conversation import FinancialPlanningConversation
|
|
24
24
|
|
|
25
|
-
llm =
|
|
25
|
+
llm = LLM()
|
|
26
26
|
cache = get_cache()
|
|
27
27
|
conversation = FinancialPlanningConversation(
|
|
28
28
|
llm=llm,
|
|
@@ -196,10 +196,10 @@ class FinancialPlanningConversation:
|
|
|
196
196
|
Cost: ~$0.0054/conversation (10 turns with context caching)
|
|
197
197
|
|
|
198
198
|
Example:
|
|
199
|
-
from ai_infra.llm import
|
|
199
|
+
from ai_infra.llm import LLM
|
|
200
200
|
from svc_infra.cache import get_cache
|
|
201
201
|
|
|
202
|
-
llm =
|
|
202
|
+
llm = LLM()
|
|
203
203
|
cache = get_cache()
|
|
204
204
|
conversation = FinancialPlanningConversation(
|
|
205
205
|
llm=llm,
|
|
@@ -232,7 +232,7 @@ class FinancialPlanningConversation:
|
|
|
232
232
|
Initialize conversation manager.
|
|
233
233
|
|
|
234
234
|
Args:
|
|
235
|
-
llm: ai-infra
|
|
235
|
+
llm: ai-infra LLM instance
|
|
236
236
|
cache: svc-infra cache instance (for context storage)
|
|
237
237
|
provider: LLM provider ("google", "openai", "anthropic")
|
|
238
238
|
model_name: Model name (default: gemini-2.0-flash-exp)
|
fin_infra/crypto/insights.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""Crypto portfolio insights using ai-infra LLM.
|
|
2
2
|
|
|
3
3
|
This module generates personalized insights for cryptocurrency holdings using
|
|
4
|
-
ai-infra's
|
|
4
|
+
ai-infra's LLM for intelligent analysis and recommendations.
|
|
5
5
|
|
|
6
|
-
CRITICAL: Uses ai-infra.llm.
|
|
6
|
+
CRITICAL: Uses ai-infra.llm.LLM (NEVER custom LLM clients).
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from __future__ import annotations
|
|
@@ -15,7 +15,7 @@ from typing import TYPE_CHECKING
|
|
|
15
15
|
from pydantic import BaseModel, Field
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
|
-
from ai_infra.llm import
|
|
18
|
+
from ai_infra.llm import LLM
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class CryptoInsight(BaseModel):
|
|
@@ -56,13 +56,13 @@ class CryptoHolding(BaseModel):
|
|
|
56
56
|
async def generate_crypto_insights(
|
|
57
57
|
user_id: str,
|
|
58
58
|
holdings: list[CryptoHolding],
|
|
59
|
-
llm:
|
|
59
|
+
llm: LLM | None = None,
|
|
60
60
|
total_portfolio_value: Decimal | None = None,
|
|
61
61
|
) -> list[CryptoInsight]:
|
|
62
62
|
"""
|
|
63
63
|
Generate personalized crypto insights using ai-infra LLM.
|
|
64
64
|
|
|
65
|
-
Uses ai-infra.llm.
|
|
65
|
+
Uses ai-infra.llm.LLM for intelligent analysis based on:
|
|
66
66
|
- Portfolio concentration (diversification recommendations)
|
|
67
67
|
- Performance trends (gains/losses)
|
|
68
68
|
- Risk assessment (volatility, allocation %)
|
|
@@ -71,15 +71,15 @@ async def generate_crypto_insights(
|
|
|
71
71
|
Args:
|
|
72
72
|
user_id: User identifier
|
|
73
73
|
holdings: List of crypto holdings
|
|
74
|
-
llm:
|
|
74
|
+
llm: LLM instance (if None, uses default Google Gemini)
|
|
75
75
|
total_portfolio_value: Total portfolio value including non-crypto assets
|
|
76
76
|
|
|
77
77
|
Returns:
|
|
78
78
|
List of personalized CryptoInsight objects
|
|
79
79
|
|
|
80
80
|
Example:
|
|
81
|
-
>>> from ai_infra.llm import
|
|
82
|
-
>>> llm =
|
|
81
|
+
>>> from ai_infra.llm import LLM
|
|
82
|
+
>>> llm = LLM(provider="google_genai", model="gemini-2.0-flash-exp")
|
|
83
83
|
>>> holdings = [
|
|
84
84
|
... CryptoHolding(
|
|
85
85
|
... symbol="BTC",
|
|
@@ -206,14 +206,14 @@ async def _generate_llm_insights(
|
|
|
206
206
|
holdings: list[CryptoHolding],
|
|
207
207
|
total_crypto_value: Decimal,
|
|
208
208
|
total_portfolio_value: Decimal | None,
|
|
209
|
-
llm:
|
|
209
|
+
llm: LLM,
|
|
210
210
|
) -> list[CryptoInsight]:
|
|
211
211
|
"""
|
|
212
|
-
Generate AI-powered insights using ai-infra
|
|
212
|
+
Generate AI-powered insights using ai-infra LLM.
|
|
213
213
|
|
|
214
214
|
Uses natural language conversation (NO output_schema) for personalized advice.
|
|
215
215
|
|
|
216
|
-
CRITICAL: Uses ai-infra.llm.
|
|
216
|
+
CRITICAL: Uses ai-infra.llm.LLM (never custom LLM clients).
|
|
217
217
|
"""
|
|
218
218
|
insights = []
|
|
219
219
|
|
fin_infra/documents/analysis.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
AI-powered document analysis and insights.
|
|
3
3
|
|
|
4
4
|
Uses rule-based analysis (simulated AI) for financial documents.
|
|
5
|
-
Production: Use ai-infra
|
|
5
|
+
Production: Use ai-infra LLM for real AI-powered insights.
|
|
6
6
|
|
|
7
7
|
Quick Start:
|
|
8
8
|
>>> from fin_infra.documents.analysis import analyze_document
|
|
@@ -14,7 +14,7 @@ Quick Start:
|
|
|
14
14
|
>>> print(result.recommendations)
|
|
15
15
|
|
|
16
16
|
Production Integration:
|
|
17
|
-
- Use ai-infra
|
|
17
|
+
- Use ai-infra LLM for all LLM calls (never custom clients)
|
|
18
18
|
- Cache analysis results (24h TTL via svc-infra cache)
|
|
19
19
|
- Track LLM costs per user (ai-infra cost tracking)
|
|
20
20
|
- Add disclaimers for financial advice
|
|
@@ -68,7 +68,7 @@ async def analyze_document(
|
|
|
68
68
|
|
|
69
69
|
Notes:
|
|
70
70
|
- Current: Rule-based analysis (simulated AI)
|
|
71
|
-
- Production: Use ai-infra
|
|
71
|
+
- Production: Use ai-infra LLM (never custom LLM clients)
|
|
72
72
|
- Production: Check cache before analysis (svc-infra cache, 24h TTL)
|
|
73
73
|
- Production: Track LLM costs (ai-infra cost tracking)
|
|
74
74
|
- Production: Add disclaimer: "Not a substitute for certified financial advisor"
|
|
@@ -218,7 +218,7 @@ def _analyze_tax_document(ocr_text: str, metadata: dict, document_id: str) -> "D
|
|
|
218
218
|
|
|
219
219
|
Notes:
|
|
220
220
|
- Current: Rule-based analysis (simulated AI)
|
|
221
|
-
- Production: Use ai-infra
|
|
221
|
+
- Production: Use ai-infra LLM with financial tax prompt
|
|
222
222
|
- Production: Include tax bracket information
|
|
223
223
|
- Production: Suggest W-4 adjustments if applicable
|
|
224
224
|
- Production: Identify potential deductions or credits
|
|
@@ -318,7 +318,7 @@ def _analyze_bank_statement(ocr_text: str, metadata: dict, document_id: str) ->
|
|
|
318
318
|
|
|
319
319
|
Notes:
|
|
320
320
|
- Current: Rule-based analysis (simulated AI)
|
|
321
|
-
- Production: Use ai-infra
|
|
321
|
+
- Production: Use ai-infra LLM with spending analysis prompt
|
|
322
322
|
- Production: Identify unusual transactions or patterns
|
|
323
323
|
- Production: Compare to typical spending (if available)
|
|
324
324
|
- Production: Suggest budget optimizations
|
fin_infra/goals/management.py
CHANGED
|
@@ -7,14 +7,14 @@ Provides 4 goal types with validation and progress tracking:
|
|
|
7
7
|
3. Debt-Free Goal: Debt payoff schedule with APR calculations
|
|
8
8
|
4. Wealth Milestone: Project growth to target net worth
|
|
9
9
|
|
|
10
|
-
Uses ai-infra
|
|
10
|
+
Uses ai-infra LLM for validation + local math for calculations.
|
|
11
11
|
Weekly progress check-ins via svc-infra.jobs scheduler ($0.0036/user/month).
|
|
12
12
|
|
|
13
13
|
Example:
|
|
14
|
-
from ai_infra.llm import
|
|
14
|
+
from ai_infra.llm import LLM
|
|
15
15
|
from fin_infra.goals.management import FinancialGoalTracker
|
|
16
16
|
|
|
17
|
-
llm =
|
|
17
|
+
llm = LLM()
|
|
18
18
|
tracker = FinancialGoalTracker(
|
|
19
19
|
llm=llm,
|
|
20
20
|
provider="google",
|
|
@@ -475,9 +475,9 @@ class FinancialGoalTracker:
|
|
|
475
475
|
Cost: ~$0.0009/validation, ~$0.0009/week for progress ($0.0036/user/month)
|
|
476
476
|
|
|
477
477
|
Example:
|
|
478
|
-
from ai_infra.llm import
|
|
478
|
+
from ai_infra.llm import LLM
|
|
479
479
|
|
|
480
|
-
llm =
|
|
480
|
+
llm = LLM()
|
|
481
481
|
tracker = FinancialGoalTracker(llm=llm, provider="google")
|
|
482
482
|
|
|
483
483
|
# Validate goal
|
|
@@ -503,7 +503,7 @@ class FinancialGoalTracker:
|
|
|
503
503
|
Initialize goal tracker.
|
|
504
504
|
|
|
505
505
|
Args:
|
|
506
|
-
llm: ai-infra
|
|
506
|
+
llm: ai-infra LLM instance
|
|
507
507
|
provider: LLM provider ("google", "openai", "anthropic")
|
|
508
508
|
model_name: Model name (default: gemini-2.0-flash-exp)
|
|
509
509
|
"""
|
fin_infra/net_worth/ease.py
CHANGED
|
@@ -368,7 +368,7 @@ def easy_net_worth(
|
|
|
368
368
|
|
|
369
369
|
if enable_llm:
|
|
370
370
|
try:
|
|
371
|
-
from ai_infra.llm import
|
|
371
|
+
from ai_infra.llm import LLM
|
|
372
372
|
except ImportError:
|
|
373
373
|
raise ImportError(
|
|
374
374
|
"LLM features require ai-infra package. " "Install with: pip install ai-infra"
|
|
@@ -387,8 +387,8 @@ def easy_net_worth(
|
|
|
387
387
|
f"Unknown llm_provider: {llm_provider}. " f"Use 'google', 'openai', or 'anthropic'"
|
|
388
388
|
)
|
|
389
389
|
|
|
390
|
-
# Create shared
|
|
391
|
-
llm =
|
|
390
|
+
# Create shared LLM instance
|
|
391
|
+
llm = LLM()
|
|
392
392
|
|
|
393
393
|
# Create LLM components (deferred import to avoid circular dependency)
|
|
394
394
|
# These modules will be created in Section 17 V2 implementation
|
fin_infra/net_worth/insights.py
CHANGED
|
@@ -7,14 +7,14 @@ Provides 4 types of insights:
|
|
|
7
7
|
3. Goal Recommendations: Validate financial goals and suggest paths
|
|
8
8
|
4. Asset Allocation Advice: Portfolio rebalancing based on age/risk
|
|
9
9
|
|
|
10
|
-
Uses ai-infra
|
|
10
|
+
Uses ai-infra LLM with structured output (Pydantic schemas).
|
|
11
11
|
Caches insights for 24h (target: 95%+ hit rate, $0.042/user/month cost).
|
|
12
12
|
|
|
13
13
|
Example:
|
|
14
|
-
from ai_infra.llm import
|
|
14
|
+
from ai_infra.llm import LLM
|
|
15
15
|
from fin_infra.net_worth.insights import NetWorthInsightsGenerator
|
|
16
16
|
|
|
17
|
-
llm =
|
|
17
|
+
llm = LLM()
|
|
18
18
|
generator = NetWorthInsightsGenerator(
|
|
19
19
|
llm=llm,
|
|
20
20
|
provider="google",
|
|
@@ -379,7 +379,7 @@ class NetWorthInsightsGenerator:
|
|
|
379
379
|
"""
|
|
380
380
|
Generate LLM-powered financial insights for net worth tracking.
|
|
381
381
|
|
|
382
|
-
Uses ai-infra
|
|
382
|
+
Uses ai-infra LLM with structured output (Pydantic schemas).
|
|
383
383
|
Supports 4 insight types:
|
|
384
384
|
1. Wealth trends (analyze net worth changes)
|
|
385
385
|
2. Debt reduction (prioritize payoff by APR)
|
|
@@ -389,9 +389,9 @@ class NetWorthInsightsGenerator:
|
|
|
389
389
|
Cost: ~$0.042/user/month (1 insight/day, 24h cache, Google Gemini)
|
|
390
390
|
|
|
391
391
|
Example:
|
|
392
|
-
from ai_infra.llm import
|
|
392
|
+
from ai_infra.llm import LLM
|
|
393
393
|
|
|
394
|
-
llm =
|
|
394
|
+
llm = LLM()
|
|
395
395
|
generator = NetWorthInsightsGenerator(
|
|
396
396
|
llm=llm,
|
|
397
397
|
provider="google",
|
|
@@ -412,7 +412,7 @@ class NetWorthInsightsGenerator:
|
|
|
412
412
|
Initialize insights generator.
|
|
413
413
|
|
|
414
414
|
Args:
|
|
415
|
-
llm: ai-infra
|
|
415
|
+
llm: ai-infra LLM instance
|
|
416
416
|
provider: LLM provider ("google", "openai", "anthropic")
|
|
417
417
|
model_name: Model name (default: gemini-2.0-flash-exp)
|
|
418
418
|
"""
|
|
@@ -7,7 +7,7 @@ Handles edge cases where statistical methods fail:
|
|
|
7
7
|
- Gym fees with annual waived months or promotional discounts
|
|
8
8
|
- Streaming services with rare price changes
|
|
9
9
|
|
|
10
|
-
Uses ai-infra
|
|
10
|
+
Uses ai-infra LLM with few-shot prompting for 88% accuracy.
|
|
11
11
|
Only called for ambiguous patterns (20-40% variance, ~10% of patterns).
|
|
12
12
|
"""
|
|
13
13
|
|
|
@@ -20,9 +20,9 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
|
20
20
|
|
|
21
21
|
# Lazy import for optional dependency (ai-infra)
|
|
22
22
|
try:
|
|
23
|
-
from ai_infra.llm import
|
|
23
|
+
from ai_infra.llm import LLM
|
|
24
24
|
except ImportError:
|
|
25
|
-
|
|
25
|
+
LLM = None # type: ignore
|
|
26
26
|
|
|
27
27
|
logger = logging.getLogger(__name__)
|
|
28
28
|
|
|
@@ -31,7 +31,7 @@ class VariableRecurringPattern(BaseModel):
|
|
|
31
31
|
"""
|
|
32
32
|
Result of LLM variable amount detection.
|
|
33
33
|
|
|
34
|
-
Output schema for
|
|
34
|
+
Output schema for LLM structured output.
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
37
|
is_recurring: bool = Field(
|
|
@@ -149,11 +149,11 @@ class VariableDetectorLLM:
|
|
|
149
149
|
Layer 4 of 4-layer hybrid architecture:
|
|
150
150
|
- Only called when variance is 20-40% (ambiguous, ~10% of patterns)
|
|
151
151
|
- Statistical methods handle <20% variance (85% coverage)
|
|
152
|
-
- Uses
|
|
152
|
+
- Uses LLM to understand semantic variance (seasonal, spikes)
|
|
153
153
|
|
|
154
154
|
Flow:
|
|
155
155
|
1. Receive merchant name, amounts, date pattern
|
|
156
|
-
2. Call
|
|
156
|
+
2. Call LLM with few-shot prompt
|
|
157
157
|
3. Return VariableRecurringPattern
|
|
158
158
|
4. Update budget tracking
|
|
159
159
|
"""
|
|
@@ -182,13 +182,13 @@ class VariableDetectorLLM:
|
|
|
182
182
|
self.max_cost_per_day = max_cost_per_day
|
|
183
183
|
self.max_cost_per_month = max_cost_per_month
|
|
184
184
|
|
|
185
|
-
# Initialize
|
|
186
|
-
if
|
|
185
|
+
# Initialize LLM
|
|
186
|
+
if LLM is None:
|
|
187
187
|
raise ImportError(
|
|
188
188
|
"ai-infra required for LLM variable detection. Install: pip install ai-infra"
|
|
189
189
|
)
|
|
190
190
|
|
|
191
|
-
self.llm =
|
|
191
|
+
self.llm = LLM()
|
|
192
192
|
|
|
193
193
|
# Budget tracking (in-memory for simplicity, should use Redis in production)
|
|
194
194
|
self._daily_cost = 0.0
|
|
@@ -263,7 +263,7 @@ class VariableDetectorLLM:
|
|
|
263
263
|
date_pattern: str,
|
|
264
264
|
) -> VariableRecurringPattern:
|
|
265
265
|
"""
|
|
266
|
-
Call
|
|
266
|
+
Call LLM for variable amount detection.
|
|
267
267
|
|
|
268
268
|
Uses few-shot prompting with 5 examples.
|
|
269
269
|
Structured output via Pydantic schema.
|
fin_infra/recurring/insights.py
CHANGED
|
@@ -6,7 +6,7 @@ Provides on-demand insights for users:
|
|
|
6
6
|
- Top subscriptions by cost
|
|
7
7
|
- Cost-saving recommendations (bundle deals, unused subscriptions)
|
|
8
8
|
|
|
9
|
-
Uses ai-infra
|
|
9
|
+
Uses ai-infra LLM with few-shot prompting.
|
|
10
10
|
Caches results for 24 hours (80% hit rate expected) → <1ms latency.
|
|
11
11
|
Triggered via GET /recurring/insights API endpoint (not automatic).
|
|
12
12
|
"""
|
|
@@ -21,9 +21,9 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
|
21
21
|
|
|
22
22
|
# Lazy import for optional dependency (ai-infra)
|
|
23
23
|
try:
|
|
24
|
-
from ai_infra.llm import
|
|
24
|
+
from ai_infra.llm import LLM
|
|
25
25
|
except ImportError:
|
|
26
|
-
|
|
26
|
+
LLM = None # type: ignore
|
|
27
27
|
|
|
28
28
|
logger = logging.getLogger(__name__)
|
|
29
29
|
|
|
@@ -32,7 +32,7 @@ class SubscriptionInsights(BaseModel):
|
|
|
32
32
|
"""
|
|
33
33
|
Natural language subscription insights.
|
|
34
34
|
|
|
35
|
-
Output schema for
|
|
35
|
+
Output schema for LLM structured output.
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
38
|
summary: str = Field(
|
|
@@ -150,7 +150,7 @@ class SubscriptionInsightsGenerator:
|
|
|
150
150
|
|
|
151
151
|
Layer 5 of 4-layer hybrid architecture (on-demand, optional):
|
|
152
152
|
1. Check cache first (80% hit rate, 24h TTL) → <1ms
|
|
153
|
-
2. Call
|
|
153
|
+
2. Call LLM if cache miss → 300-500ms
|
|
154
154
|
3. Cache result for 24 hours
|
|
155
155
|
4. Return SubscriptionInsights
|
|
156
156
|
|
|
@@ -187,13 +187,13 @@ class SubscriptionInsightsGenerator:
|
|
|
187
187
|
self.max_cost_per_day = max_cost_per_day
|
|
188
188
|
self.max_cost_per_month = max_cost_per_month
|
|
189
189
|
|
|
190
|
-
# Initialize
|
|
191
|
-
if
|
|
190
|
+
# Initialize LLM
|
|
191
|
+
if LLM is None:
|
|
192
192
|
raise ImportError(
|
|
193
193
|
"ai-infra required for insights generation. Install: pip install ai-infra"
|
|
194
194
|
)
|
|
195
195
|
|
|
196
|
-
self.llm =
|
|
196
|
+
self.llm = LLM()
|
|
197
197
|
|
|
198
198
|
# Initialize cache if enabled
|
|
199
199
|
self.cache = None
|
|
@@ -235,7 +235,7 @@ class SubscriptionInsightsGenerator:
|
|
|
235
235
|
Flow:
|
|
236
236
|
1. Check cache (80% hit rate, key: insights:{user_id}) → <1ms
|
|
237
237
|
2. Check budget (daily/monthly caps)
|
|
238
|
-
3. Call
|
|
238
|
+
3. Call LLM if cache miss → 300-500ms
|
|
239
239
|
4. Cache result (24h TTL)
|
|
240
240
|
5. Return SubscriptionInsights
|
|
241
241
|
|
|
@@ -357,7 +357,7 @@ class SubscriptionInsightsGenerator:
|
|
|
357
357
|
subscriptions: list[dict[str, Any]],
|
|
358
358
|
) -> SubscriptionInsights:
|
|
359
359
|
"""
|
|
360
|
-
Call
|
|
360
|
+
Call LLM for insights generation.
|
|
361
361
|
|
|
362
362
|
Uses few-shot prompting with 3 examples.
|
|
363
363
|
Structured output via Pydantic schema.
|
|
@@ -7,7 +7,7 @@ Handles cryptic merchant names that fail pattern-based normalization:
|
|
|
7
7
|
- Store numbers: #1234, store-specific identifiers
|
|
8
8
|
- Legal entities: Inc, LLC, Corp, Ltd
|
|
9
9
|
|
|
10
|
-
Uses ai-infra
|
|
10
|
+
Uses ai-infra LLM with few-shot prompting for 90-95% accuracy.
|
|
11
11
|
Caches results for 7 days (95% hit rate expected) → <1ms latency.
|
|
12
12
|
Falls back to RapidFuzz if LLM fails or disabled.
|
|
13
13
|
"""
|
|
@@ -22,9 +22,9 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
|
22
22
|
|
|
23
23
|
# Lazy import for optional dependency (ai-infra)
|
|
24
24
|
try:
|
|
25
|
-
from ai_infra.llm import
|
|
25
|
+
from ai_infra.llm import LLM
|
|
26
26
|
except ImportError:
|
|
27
|
-
|
|
27
|
+
LLM = None # type: ignore
|
|
28
28
|
|
|
29
29
|
logger = logging.getLogger(__name__)
|
|
30
30
|
|
|
@@ -33,7 +33,7 @@ class MerchantNormalized(BaseModel):
|
|
|
33
33
|
"""
|
|
34
34
|
Result of LLM merchant name normalization.
|
|
35
35
|
|
|
36
|
-
Output schema for
|
|
36
|
+
Output schema for LLM structured output.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
39
|
canonical_name: str = Field(
|
|
@@ -129,7 +129,7 @@ class MerchantNormalizer:
|
|
|
129
129
|
|
|
130
130
|
Layer 2 of 4-layer hybrid architecture:
|
|
131
131
|
1. Check cache first (95% hit rate, 7-day TTL) → <1ms
|
|
132
|
-
2. Call
|
|
132
|
+
2. Call LLM if cache miss → 200-400ms
|
|
133
133
|
3. Cache result for 7 days
|
|
134
134
|
4. Return MerchantNormalized
|
|
135
135
|
|
|
@@ -172,13 +172,13 @@ class MerchantNormalizer:
|
|
|
172
172
|
self.max_cost_per_day = max_cost_per_day
|
|
173
173
|
self.max_cost_per_month = max_cost_per_month
|
|
174
174
|
|
|
175
|
-
# Initialize
|
|
176
|
-
if
|
|
175
|
+
# Initialize LLM
|
|
176
|
+
if LLM is None:
|
|
177
177
|
raise ImportError(
|
|
178
178
|
"ai-infra required for LLM normalization. Install: pip install ai-infra"
|
|
179
179
|
)
|
|
180
180
|
|
|
181
|
-
self.llm =
|
|
181
|
+
self.llm = LLM()
|
|
182
182
|
|
|
183
183
|
# Initialize cache if enabled
|
|
184
184
|
self.cache = None
|
|
@@ -220,7 +220,7 @@ class MerchantNormalizer:
|
|
|
220
220
|
Flow:
|
|
221
221
|
1. Check cache (95% hit rate) → <1ms
|
|
222
222
|
2. Check budget (daily/monthly caps)
|
|
223
|
-
3. Call
|
|
223
|
+
3. Call LLM if cache miss → 200-400ms
|
|
224
224
|
4. Validate confidence threshold
|
|
225
225
|
5. Cache result (7-day TTL)
|
|
226
226
|
6. Return MerchantNormalized
|
|
@@ -332,7 +332,7 @@ class MerchantNormalizer:
|
|
|
332
332
|
|
|
333
333
|
async def _call_llm(self, merchant_name: str) -> MerchantNormalized:
|
|
334
334
|
"""
|
|
335
|
-
Call
|
|
335
|
+
Call LLM for merchant normalization.
|
|
336
336
|
|
|
337
337
|
Uses few-shot prompting with 20 examples.
|
|
338
338
|
Structured output via Pydantic schema.
|
fin_infra/tax/tlh.py
CHANGED
|
@@ -43,13 +43,13 @@ Production Notes:
|
|
|
43
43
|
- Use svc-infra jobs to run daily TLH scans (cron: "0 9 * * 1-5" for weekday mornings)
|
|
44
44
|
- Cache results with 24h TTL (market prices change daily)
|
|
45
45
|
- Integrate with brokerage API for recent trades (wash sale checking)
|
|
46
|
-
- Use ai-infra
|
|
46
|
+
- Use ai-infra LLM for intelligent replacement suggestions (sector analysis, correlation)
|
|
47
47
|
- Add compliance logging for all TLH recommendations (audit trail)
|
|
48
48
|
- Consider state tax rates in addition to federal (varies by state)
|
|
49
49
|
|
|
50
50
|
Cost Considerations:
|
|
51
51
|
- Market data: Use fin_infra.markets for current prices (~$0.01/quote)
|
|
52
|
-
- LLM suggestions: Use ai-infra
|
|
52
|
+
- LLM suggestions: Use ai-infra LLM for replacements (~$0.001/suggestion)
|
|
53
53
|
- Target: <$0.05/user/month for TLH analysis
|
|
54
54
|
"""
|
|
55
55
|
|
|
@@ -230,7 +230,7 @@ def find_tlh_opportunities(
|
|
|
230
230
|
Production Notes:
|
|
231
231
|
- Use svc-infra cache with 24h TTL: @cache_read(ttl=86400)
|
|
232
232
|
- Fetch recent_trades from brokerage API (last 90 days)
|
|
233
|
-
- Use ai-infra
|
|
233
|
+
- Use ai-infra LLM for intelligent replacement suggestions
|
|
234
234
|
- Log all recommendations to svc-infra audit log
|
|
235
235
|
- Consider state tax rates in addition to federal
|
|
236
236
|
"""
|
|
@@ -434,7 +434,7 @@ def _suggest_replacement(symbol: str, asset_class: str) -> str:
|
|
|
434
434
|
Provides a similar exposure without triggering wash sale.
|
|
435
435
|
Uses simple rules based on common symbols and asset classes.
|
|
436
436
|
|
|
437
|
-
Production: Use ai-infra
|
|
437
|
+
Production: Use ai-infra LLM for intelligent suggestions based on:
|
|
438
438
|
- Sector/industry analysis
|
|
439
439
|
- Correlation with original security
|
|
440
440
|
- Market cap similarity
|
|
@@ -454,7 +454,7 @@ def _suggest_replacement(symbol: str, asset_class: str) -> str:
|
|
|
454
454
|
'ARKK' # Innovation ETF
|
|
455
455
|
"""
|
|
456
456
|
# Simple rule-based suggestions (v1)
|
|
457
|
-
# TODO: Replace with ai-infra
|
|
457
|
+
# TODO: Replace with ai-infra LLM for intelligent suggestions
|
|
458
458
|
replacements = {
|
|
459
459
|
# Tech stocks → sector ETFs
|
|
460
460
|
"AAPL": "VGT", # Tech ETF
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: fin-infra
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.61
|
|
4
4
|
Summary: Financial infrastructure toolkit: banking connections, market data, credit, cashflows, and brokerage integrations
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: finance,banking,plaid,brokerage,markets,credit,tax,cashflow,fintech,infra
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
19
19
|
Classifier: Topic :: Office/Business :: Financial
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Dist: ai-infra (>=0.1.142)
|
|
22
23
|
Requires-Dist: cashews[redis] (>=7.0)
|
|
23
24
|
Requires-Dist: ccxt (>=4.0.0)
|
|
24
25
|
Requires-Dist: httpx (>=0.25.0)
|
|
@@ -4,13 +4,13 @@ fin_infra/analytics/__init__.py,sha256=aiuNnii0vc34XlNzrSiMbz33lzgmR7W1nHkmAEXav
|
|
|
4
4
|
fin_infra/analytics/add.py,sha256=a8ZcVc0-3gxq64IFs9fN7XVMayzE6RCCnBWV3zzc7GU,12832
|
|
5
5
|
fin_infra/analytics/cash_flow.py,sha256=3ff2FEhQKVzhrKnCHPoH6QkzREcvYLi1tqj6vkRjxi8,10246
|
|
6
6
|
fin_infra/analytics/ease.py,sha256=p8WwFP4ivvFsvZzYRCZZVHgnPThiODve9r4-m0xnxQQ,14343
|
|
7
|
-
fin_infra/analytics/models.py,sha256=
|
|
7
|
+
fin_infra/analytics/models.py,sha256=cK6VKLZ763zXfn9REXOnLGx0v3Q8bUa-vH8aoNs2w-A,8215
|
|
8
8
|
fin_infra/analytics/portfolio.py,sha256=HvJ1kKve0MhyQ6VJbLFEuNnRCdoddu84dxLyLF9Xg3s,26511
|
|
9
9
|
fin_infra/analytics/projections.py,sha256=7cuG6w1KXq8sd3UNufu5aOcxG5n-foswrHqrgWWKQUM,9186
|
|
10
10
|
fin_infra/analytics/rebalancing.py,sha256=K3S7KQiIU2LwyAwWN9VrSly4AOl24vN9tz_JX7I9FJ8,14642
|
|
11
11
|
fin_infra/analytics/savings.py,sha256=tavIRZtu9FjCm-DeWg5f060GcsdgD-cl-vgKOnieOUw,7574
|
|
12
12
|
fin_infra/analytics/scenarios.py,sha256=LE_dZVkbxxAx5sxitGhiOhZfWTlYtVbIvS9pEXkijLc,12246
|
|
13
|
-
fin_infra/analytics/spending.py,sha256=
|
|
13
|
+
fin_infra/analytics/spending.py,sha256=zXTcYAj_fWQtzOHgSN4P0dSIm80Q5eke6T3LbWltjyU,25882
|
|
14
14
|
fin_infra/banking/__init__.py,sha256=wva1SEyrH2po79YycQ_00ZyC2tVeuO3uYcyvudOW484,22267
|
|
15
15
|
fin_infra/banking/history.py,sha256=1ufAwkTnXr-QJetFzJl4xA2e3dqd1-TkT8pf46MNfho,10630
|
|
16
16
|
fin_infra/banking/utils.py,sha256=B2ebnTeUz-56l8XMBWnf2txFOr0bXIo3cKPio7_bhc4,15711
|
|
@@ -33,13 +33,13 @@ fin_infra/categorization/__init__.py,sha256=7551OjE668A_Bhm07QSTBkm4PD3uCOEwdz05
|
|
|
33
33
|
fin_infra/categorization/add.py,sha256=jbxM51MyIFsAcleCMzP1I5jYV9EsKALzBCnuzKk76sc,6328
|
|
34
34
|
fin_infra/categorization/ease.py,sha256=NudJBqFByS0YONPn_4O_Q7QYIiVCCgNbAhn-ugJpa0Y,5826
|
|
35
35
|
fin_infra/categorization/engine.py,sha256=VxVuLym_RkKK0xpZrfLKuksFVoURmXICgdik7KpxXMs,12075
|
|
36
|
-
fin_infra/categorization/llm_layer.py,sha256=
|
|
36
|
+
fin_infra/categorization/llm_layer.py,sha256=JkzTTdlUWtiCBzKgNAGWvhR7Qt4-UVc12itD2BlxwlQ,12695
|
|
37
37
|
fin_infra/categorization/models.py,sha256=O8ceQOM0ljRh0jkmnjV7CK5Jyq1DI3lG07UTeeMheNg,5931
|
|
38
38
|
fin_infra/categorization/rules.py,sha256=m3OogJY0hJe5BrmZqOvOKS2-HRdW4Y5jvvtlPDn9Pn8,12884
|
|
39
39
|
fin_infra/categorization/taxonomy.py,sha256=qsgo7VJkM6GFBBOaTRHWP82vl5SinRKnMsj4ICarEyQ,13281
|
|
40
|
-
fin_infra/chat/__init__.py,sha256=
|
|
41
|
-
fin_infra/chat/ease.py,sha256=
|
|
42
|
-
fin_infra/chat/planning.py,sha256=
|
|
40
|
+
fin_infra/chat/__init__.py,sha256=_4yQ7jRgrOgQAeiplrOnPJnTk9Ojc4Mdxg9thHhI_MQ,6837
|
|
41
|
+
fin_infra/chat/ease.py,sha256=8T0BQUkWQVpaTooD5-ZtinackkciqGargXnzWzayj3M,3113
|
|
42
|
+
fin_infra/chat/planning.py,sha256=gmVo7t-KLohEaI3r8rJ_-6EFtMnpEmlfl8JhZLAHx94,17936
|
|
43
43
|
fin_infra/cli/__init__.py,sha256=7M8gKULnui4__9kXRKRHgETuFwZlacK9xrq5rSZ31CM,376
|
|
44
44
|
fin_infra/cli/cmds/__init__.py,sha256=BvL3wRoUl3cO5wesv1Cqoatup7VeYMhq82tS19iNZHE,136
|
|
45
45
|
fin_infra/cli/cmds/scaffold_cmds.py,sha256=HZrnJ6NgTBYbt6LuJeoi7JKJgWE_umX9v7zjtwYfP-g,7659
|
|
@@ -56,10 +56,10 @@ fin_infra/credit/experian/parser.py,sha256=7ptdLyTWWqHWqCo1CXn6L7XaIn9ZRRuOaATbF
|
|
|
56
56
|
fin_infra/credit/experian/provider.py,sha256=iG2cyftdc7c2pvKWVfeNd3vF_ylNayyhgyUG7Jnl1VI,13766
|
|
57
57
|
fin_infra/credit/mock.py,sha256=xKWZk3fhuIYRfiZkNc9fbHUNViNKjmOLSj0MTI1f4ik,5356
|
|
58
58
|
fin_infra/crypto/__init__.py,sha256=HpplYEY8GiBz55ehYRDQxs8SWJIW1smBs9eFOKt_nzI,8318
|
|
59
|
-
fin_infra/crypto/insights.py,sha256=
|
|
59
|
+
fin_infra/crypto/insights.py,sha256=J1aPT05soNJrhvClZGa-SNyJ-KYsQFm6PSGcoukwdfo,11651
|
|
60
60
|
fin_infra/documents/__init__.py,sha256=Ub1hbX3PTrBSsBdcbL8PFf6oq8jSH4pYxW45-qOYPqs,1909
|
|
61
61
|
fin_infra/documents/add.py,sha256=ztSFCY42hfLLgUbXefxvf_AAbzaxJ6xpEZJpcHE8g7c,8133
|
|
62
|
-
fin_infra/documents/analysis.py,sha256=
|
|
62
|
+
fin_infra/documents/analysis.py,sha256=zY5OQEIlq3JLNND_cg2KheFdryUmIecPOR2lR6oKhPw,13992
|
|
63
63
|
fin_infra/documents/ease.py,sha256=rnxEIMjf6vLvD-h5WD4wM6PwmcB4iUtAtnvGxbFA5zA,9625
|
|
64
64
|
fin_infra/documents/models.py,sha256=5MK5Mvs7s6HfNuNldT4xxwLGV4z1f7vNJLwDD-jalgw,6889
|
|
65
65
|
fin_infra/documents/ocr.py,sha256=cuXzrx6k3GIhiaB4-OMPyroB6GBdXuvXP7LAcs0ZV5o,9596
|
|
@@ -68,7 +68,7 @@ fin_infra/exceptions.py,sha256=woCazH0RxnGcrmsSA3NMZF4Ygr2dtI4tfzKNiFZ10AA,16953
|
|
|
68
68
|
fin_infra/goals/__init__.py,sha256=Vg8LKLlDoRiWHsJX7wu5Zcc-86NNLpHoLTjYVkGi2c4,2130
|
|
69
69
|
fin_infra/goals/add.py,sha256=cNf0H7EzssMeCYHBWQPW4lHoz1uUWhGMVUUqGMKhNtk,20566
|
|
70
70
|
fin_infra/goals/funding.py,sha256=6wn25N0VTYfKLzZWhEn0xdC0ft49qdElkQFc9IwmdPk,9334
|
|
71
|
-
fin_infra/goals/management.py,sha256=
|
|
71
|
+
fin_infra/goals/management.py,sha256=_DA4lHvcNJVCKLusSU1tIbPc_2Ya8KqXY_67ku6Asws,33815
|
|
72
72
|
fin_infra/goals/milestones.py,sha256=MTh3iyJSkDjLNYE1RtmyY4MuxqaGTgohTGU0NAbJaV0,9967
|
|
73
73
|
fin_infra/goals/models.py,sha256=DxUrYJqlfKdrmFBucNikLbto3NgxoiJAmsL3v0LR4DQ,10237
|
|
74
74
|
fin_infra/goals/scaffold_templates/README.md,sha256=CoE_3I2K32orOFH6CvfVBaJBTGDYIESd5-48V7vU1FI,9974
|
|
@@ -106,9 +106,9 @@ fin_infra/net_worth/__init__.py,sha256=EjEuHNg8gEfFwbfko1-o5j-gSUZ2FcO9h7l05C-zA
|
|
|
106
106
|
fin_infra/net_worth/add.py,sha256=5xYy2L5hEEPiQNF79i-ArWVztLXk2XM97DoZYNWGAz8,23100
|
|
107
107
|
fin_infra/net_worth/aggregator.py,sha256=grif-N8qk77L_JQ4IlcOJaKKP1qpxel0lIV_ll3HgjI,12646
|
|
108
108
|
fin_infra/net_worth/calculator.py,sha256=JERDtZyFurw5x2NYqfHvJzv6qigamI3AFfR-wesTj_E,13133
|
|
109
|
-
fin_infra/net_worth/ease.py,sha256=
|
|
109
|
+
fin_infra/net_worth/ease.py,sha256=XvOaowgj64JLKOtEq-B8MIc3fgrysL4vG8m1e5j-ukY,15094
|
|
110
110
|
fin_infra/net_worth/goals.py,sha256=BJGxdsMjvgQDELFEJo-ai3DvsAzUNXvzMXkwovHr8yQ,1238
|
|
111
|
-
fin_infra/net_worth/insights.py,sha256=
|
|
111
|
+
fin_infra/net_worth/insights.py,sha256=vVK4BtfHNJGb1wyk9XD0fLpoadATTdorF8OxHOgD9b0,25222
|
|
112
112
|
fin_infra/net_worth/models.py,sha256=pTdPEA0TiIrV2PT0381ftaQIMnnKciUqJYntdFrAaCQ,22711
|
|
113
113
|
fin_infra/net_worth/scaffold_templates/README.md,sha256=Wqd6ksqFjmtNdDFOWVV_duuAcePWwiu3_YgkVM9N_WY,14363
|
|
114
114
|
fin_infra/net_worth/scaffold_templates/__init__.py,sha256=OKeMCC_JNw6m8rBWr_wesOIJ1OR9LCBeIkXKahbCGC4,132
|
|
@@ -147,12 +147,12 @@ fin_infra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
147
147
|
fin_infra/recurring/__init__.py,sha256=ihMPywft8pGqzMu6EXxbQCU7ByoMl_dvad00gWV1mnk,2308
|
|
148
148
|
fin_infra/recurring/add.py,sha256=bOvpRbtMjWYqNpq8dTR6aCNsR0iTRMyXWGZyMWQZk8A,18573
|
|
149
149
|
fin_infra/recurring/detector.py,sha256=1e6PRoBAT2NxoGAgcVHAWwpPtznkJMaYSrJtvSq0YqM,20154
|
|
150
|
-
fin_infra/recurring/detectors_llm.py,sha256=
|
|
150
|
+
fin_infra/recurring/detectors_llm.py,sha256=Gz0rArX2MwAvjW97ceqKUFe8F0Fxt9RzLBwPPjd_NSg,11482
|
|
151
151
|
fin_infra/recurring/ease.py,sha256=OrpxGHi8kt6LkMmww5l0Xy2pU-5hP_dR4IgdOiaIRaU,11179
|
|
152
|
-
fin_infra/recurring/insights.py,sha256=
|
|
152
|
+
fin_infra/recurring/insights.py,sha256=l0j0Qste9I3VGsUxneoVfEPLBI8-rLWzO8fn1jZHZd8,15868
|
|
153
153
|
fin_infra/recurring/models.py,sha256=N4G_LM0xZr3ptHtlqOmcsw3AL2v9g7IX92SmBljkNek,8894
|
|
154
154
|
fin_infra/recurring/normalizer.py,sha256=LIZU90BTshsFvswu5pjLPIvIoWbUTXxzTWBOrmzJ6pI,9725
|
|
155
|
-
fin_infra/recurring/normalizers.py,sha256=
|
|
155
|
+
fin_infra/recurring/normalizers.py,sha256=8yFx2yshw7aaxMDInoF4YLfEyPkTERAM9vQwHBAFpW4,15912
|
|
156
156
|
fin_infra/recurring/summary.py,sha256=1Wte58ZZkEFulkb-nnpwfC5h7C_JrqByy47itdVdWwc,14665
|
|
157
157
|
fin_infra/scaffold/__init__.py,sha256=OyD8ZtIC4eNTHqD16rbpT8KU0TpZUI6VV4xne4vpaHg,831
|
|
158
158
|
fin_infra/scaffold/budgets.py,sha256=XXOLlEcyBXVwdbJB__qObRXJ0oe1okwDT_-5tG8c9Yk,9515
|
|
@@ -168,13 +168,13 @@ fin_infra/security/token_store.py,sha256=lNnGUlQCJImc-OAcHbHij8xYHkV3jb6MgBpwEra
|
|
|
168
168
|
fin_infra/settings.py,sha256=xitpBQJmuvSy9prQhvXOW1scbwB1KAyGD8XqYgU_hQU,1388
|
|
169
169
|
fin_infra/tax/__init__.py,sha256=NXUjV-k-rw4774pookY3UOwEXYRQauJze6Yift5RjW0,6107
|
|
170
170
|
fin_infra/tax/add.py,sha256=xmy0hXsWzEj5p-_9A5hkljFjF_FpnbCQQZ5e8FPChBI,14568
|
|
171
|
-
fin_infra/tax/tlh.py,sha256=
|
|
171
|
+
fin_infra/tax/tlh.py,sha256=6OlZ3Gb13rSFrmW7vPqVTq_NB45D110iHgCwzYp2nTA,21523
|
|
172
172
|
fin_infra/utils/__init__.py,sha256=gKacLSWMAis--pasd8AuVN7ap0e9Z1TjRGur0J23EDo,648
|
|
173
173
|
fin_infra/utils/http.py,sha256=wgXo5amXyzAX49v_lRUvp4Xxq8nodX32CMJyWl6u89I,568
|
|
174
174
|
fin_infra/utils/retry.py,sha256=p4i4heGdHkLsqLHuHY4riwOkuLjbbfbUE8cA4t3UAgQ,1052
|
|
175
175
|
fin_infra/version.py,sha256=4t_crzhrLum--oyowUMxtjBTzUtWp7oRTF22ewEvJG4,49
|
|
176
|
-
fin_infra-0.1.
|
|
177
|
-
fin_infra-0.1.
|
|
178
|
-
fin_infra-0.1.
|
|
179
|
-
fin_infra-0.1.
|
|
180
|
-
fin_infra-0.1.
|
|
176
|
+
fin_infra-0.1.61.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
|
|
177
|
+
fin_infra-0.1.61.dist-info/METADATA,sha256=KMCtxNsFrBD0F_hOCvy9yYmnis_O0DMwR32pjxEUI2Q,10218
|
|
178
|
+
fin_infra-0.1.61.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
179
|
+
fin_infra-0.1.61.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
|
|
180
|
+
fin_infra-0.1.61.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|