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.
@@ -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 CoreLLM for structured output generation.
117
+ Uses ai-infra LLM for structured output generation.
118
118
  """
119
119
 
120
120
  model_config = ConfigDict(extra="forbid")
@@ -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 CoreLLM
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 CoreLLM for structured output generation with financial context.
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 CoreLLM instance (defaults to Google Gemini)
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 CoreLLM
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 = CoreLLM()
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 CoreLLM as LLM
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")
@@ -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 CoreLLM
13
+ from ai_infra.llm import LLM
14
14
  from svc_infra.cache import get_cache
15
15
 
16
- llm = CoreLLM()
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 CoreLLM (multi-provider support)
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 CoreLLM
17
- llm = CoreLLM(temperature=0.3)
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 CoreLLM (Google Gemini default)
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 CoreLLM instance (auto-created if None)
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 CoreLLM
66
- llm = CoreLLM(temperature=0.3)
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 CoreLLM
72
+ from ai_infra.llm import LLM
73
73
 
74
- llm = CoreLLM()
74
+ llm = LLM()
75
75
  except ImportError:
76
76
  raise ImportError("ai-infra not installed. Install with: pip install ai-infra")
77
77
 
@@ -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 `CoreLLM.achat()` for natural conversation (NOT `with_structured_output()`).
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 CoreLLM for natural conversation.
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 CoreLLM
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 = CoreLLM()
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 CoreLLM
199
+ from ai_infra.llm import LLM
200
200
  from svc_infra.cache import get_cache
201
201
 
202
- llm = CoreLLM()
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 CoreLLM instance
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)
@@ -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 CoreLLM for intelligent analysis and recommendations.
4
+ ai-infra's LLM for intelligent analysis and recommendations.
5
5
 
6
- CRITICAL: Uses ai-infra.llm.CoreLLM (NEVER custom LLM clients).
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 CoreLLM
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: CoreLLM | None = None,
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.CoreLLM for intelligent analysis based on:
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: CoreLLM instance (if None, uses default Google Gemini)
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 CoreLLM
82
- >>> llm = CoreLLM(provider="google_genai", model="gemini-2.0-flash-exp")
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: CoreLLM,
209
+ llm: LLM,
210
210
  ) -> list[CryptoInsight]:
211
211
  """
212
- Generate AI-powered insights using ai-infra CoreLLM.
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.CoreLLM (never custom LLM clients).
216
+ CRITICAL: Uses ai-infra.llm.LLM (never custom LLM clients).
217
217
  """
218
218
  insights = []
219
219
 
@@ -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 CoreLLM for real AI-powered insights.
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 CoreLLM for all LLM calls (never custom clients)
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 CoreLLM (never custom LLM clients)
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 CoreLLM with financial tax prompt
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 CoreLLM with spending analysis prompt
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
@@ -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 CoreLLM for validation + local math for calculations.
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 CoreLLM
14
+ from ai_infra.llm import LLM
15
15
  from fin_infra.goals.management import FinancialGoalTracker
16
16
 
17
- llm = CoreLLM()
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 CoreLLM
478
+ from ai_infra.llm import LLM
479
479
 
480
- llm = CoreLLM()
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 CoreLLM instance
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
  """
@@ -368,7 +368,7 @@ def easy_net_worth(
368
368
 
369
369
  if enable_llm:
370
370
  try:
371
- from ai_infra.llm import CoreLLM
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 CoreLLM instance
391
- llm = CoreLLM()
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
@@ -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 CoreLLM with structured output (Pydantic schemas).
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 CoreLLM
14
+ from ai_infra.llm import LLM
15
15
  from fin_infra.net_worth.insights import NetWorthInsightsGenerator
16
16
 
17
- llm = CoreLLM()
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 CoreLLM with structured output (Pydantic schemas).
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 CoreLLM
392
+ from ai_infra.llm import LLM
393
393
 
394
- llm = CoreLLM()
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 CoreLLM instance
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 CoreLLM with few-shot prompting for 88% accuracy.
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 CoreLLM
23
+ from ai_infra.llm import LLM
24
24
  except ImportError:
25
- CoreLLM = None # type: ignore
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 CoreLLM structured output.
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 CoreLLM to understand semantic variance (seasonal, spikes)
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 CoreLLM with few-shot prompt
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 CoreLLM
186
- if CoreLLM is None:
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 = CoreLLM()
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 CoreLLM for variable amount detection.
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.
@@ -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 CoreLLM with few-shot prompting.
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 CoreLLM
24
+ from ai_infra.llm import LLM
25
25
  except ImportError:
26
- CoreLLM = None # type: ignore
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 CoreLLM structured output.
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 CoreLLM if cache miss → 300-500ms
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 CoreLLM
191
- if CoreLLM is None:
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 = CoreLLM()
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 CoreLLM if cache miss → 300-500ms
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 CoreLLM for insights generation.
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 CoreLLM with few-shot prompting for 90-95% accuracy.
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 CoreLLM
25
+ from ai_infra.llm import LLM
26
26
  except ImportError:
27
- CoreLLM = None # type: ignore
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 CoreLLM structured output.
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 CoreLLM if cache miss → 200-400ms
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 CoreLLM
176
- if CoreLLM is None:
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 = CoreLLM()
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 CoreLLM if cache miss → 200-400ms
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 CoreLLM for merchant normalization.
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 CoreLLM for intelligent replacement suggestions (sector analysis, correlation)
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 CoreLLM for replacements (~$0.001/suggestion)
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 CoreLLM for intelligent replacement suggestions
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 CoreLLM for intelligent suggestions based on:
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 CoreLLM for intelligent suggestions
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.59
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=isOUaCuSGG_kYCFAjlt9kPIkrjlNOcqbB3-xf-r8B_Q,8219
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=Md8iOFKkvFbNmIGV56mVDTYJbZ7oNtK-rMAZiNX2j2E,25902
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=kRPtxLyIpCsYjH1NtaIL_WvJX5Y9tOsdDkYbFCTggSU,12706
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=xDW8Q7L9Pj2i27f6V9tTRS1Xmsz6eDVXrGvWZ9VEG-s,6849
41
- fin_infra/chat/ease.py,sha256=ZUUHT_Rk5IsZDQDBQ6XectyP-ivgs99kPvMMkgJJyaQ,3145
42
- fin_infra/chat/planning.py,sha256=5W8JZknLmcOKA9vdUwA1Tnj5uPw-3liGC1txKMf8XRA,17964
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=fuGFKkOkZoYKit29_kbH1T2XWvbMKVmhFUd57E2XOmQ,11695
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=MOtfjEWRDqmT_KyT31kfQ8pcfQ06oyeKkVLRMz-jQRg,14012
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=5A2jytyZT9CdW9VxrEG4_GiZ8F528yXNf6VNTZAzHjs,33839
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=wrQ5zI2nVsbSCVFQXBSEt0DMI6xK-jv5m0AyZkyuOx8,15106
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=4GUyV-YEXgBs0ZuBx1OnSV0B2N-e0jvKoIgQ2yB7M7g,25250
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=Op6auE7BOsgZG8LWtEWvYSLeF3mBPU0W2XlEs-GvZqI,11522
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=fO4i518Zwxb2efLDX9PwlZee9rSAnZ8FPKY2viQBUjs,15908
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=E-D4CdN-sykLnsVgpZyn3H7Wwa-34NjvHrLg8esGT9Q,15952
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=QFnepLuJW8L71SccRTE54eN5ILyDGs1XNG5p-aVM_b8,21543
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.59.dist-info/LICENSE,sha256=wK-Ya7Ylxa38dSIZRhvNj1ZVLIrHC-BAI8v38PNADiA,1061
177
- fin_infra-0.1.59.dist-info/METADATA,sha256=MfgW2XzEuyOEBV2AuCEtaWaZHL8ao4937WLKgAGyeRc,10182
178
- fin_infra-0.1.59.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
179
- fin_infra-0.1.59.dist-info/entry_points.txt,sha256=Sr1uikvALZMeKm-DIkeKG4L9c4SNqysXGO_IRF8_9eU,53
180
- fin_infra-0.1.59.dist-info/RECORD,,
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,,