Merge branch 'development' of DigiFi/digifi-Analytics into master
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
- Connect to transcation data source
|
||||||
|
- Analyze transition data
|
||||||
|
- Detect salary
|
||||||
|
- Inform event of salary
|
||||||
|
- SAFETY - report transaction import gaps
|
||||||
|
- SAFETY - report database connections
|
||||||
|
- SAFETY - report when event cannot be reached
|
||||||
@@ -23,6 +23,7 @@ from .data_loader import DataLoader
|
|||||||
from .salary_predictor import SalaryPredictor
|
from .salary_predictor import SalaryPredictor
|
||||||
from .salary_earner_analyzer import SalaryEarnerAnalyzer
|
from .salary_earner_analyzer import SalaryEarnerAnalyzer
|
||||||
from .db_operations import DatabaseOperations
|
from .db_operations import DatabaseOperations
|
||||||
|
from .salary_detect import SalaryDetect
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -59,6 +60,8 @@ df = None
|
|||||||
salary_predictor = None
|
salary_predictor = None
|
||||||
salary_earner_analyzer = None
|
salary_earner_analyzer = None
|
||||||
|
|
||||||
|
salary_detect = SalaryDetect()
|
||||||
|
|
||||||
class AnalysisResponse(BaseModel):
|
class AnalysisResponse(BaseModel):
|
||||||
"""Response model for analysis endpoints."""
|
"""Response model for analysis endpoints."""
|
||||||
message: str
|
message: str
|
||||||
@@ -87,6 +90,10 @@ async def startup_event():
|
|||||||
try:
|
try:
|
||||||
logger.info("Initializing pipeline...")
|
logger.info("Initializing pipeline...")
|
||||||
|
|
||||||
|
# Start autonomous salary detection loop
|
||||||
|
salary_detect.start()
|
||||||
|
logger.info("Started autonomous salary detection loop.")
|
||||||
|
|
||||||
# Print network information
|
# Print network information
|
||||||
hostname = socket.gethostname()
|
hostname = socket.gethostname()
|
||||||
ip_address = socket.gethostbyname(hostname)
|
ip_address = socket.gethostbyname(hostname)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ Configuration settings for the salary analytics package.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
import random
|
||||||
|
|
||||||
# Load environment variables
|
# Load environment variables
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@@ -76,4 +77,24 @@ OUTPUT_PATHS = {
|
|||||||
"inconsistent_model": os.path.join(MODEL_DIR, "inconsistent_model.joblib"),
|
"inconsistent_model": os.path.join(MODEL_DIR, "inconsistent_model.joblib"),
|
||||||
"consistent_scaler": os.path.join(MODEL_DIR, "consistent_scaler.joblib"),
|
"consistent_scaler": os.path.join(MODEL_DIR, "consistent_scaler.joblib"),
|
||||||
"inconsistent_scaler": os.path.join(MODEL_DIR, "inconsistent_scaler.joblib")
|
"inconsistent_scaler": os.path.join(MODEL_DIR, "inconsistent_scaler.joblib")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIMBRELLA_BASE_URL = os.getenv("SIMBRELLA_BASE_URL", "http://127.0.0.1:6337")
|
||||||
|
SIMBRELLA_ENDPOINT_RAC_CHECKS = os.getenv("SIMBRELLA_ENDPOINT_RAC_CHECKS","api/rac-check")
|
||||||
|
|
||||||
|
# Salary Detect Endpoint Config
|
||||||
|
SALARY_DETECT_URL = "http://www.simbrellang.net:5000/autocall/analytic-salary-detect"
|
||||||
|
SALARY_DETECT_HEADERS = {
|
||||||
|
"accept": "/",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
SALARY_DETECT_PAYLOADS = [
|
||||||
|
{"salaryDate": "2022-01-01", "customerId": "CN621868", "accountId": "2017821799", "salaryAmount": 200000},
|
||||||
|
{"customerId": "CUC2268333011", "accountId": "ACC8116931898", "salaryDate": "2025-07-08", "salaryAmount": 200000},
|
||||||
|
{"customerId": "CUC2163677018", "accountId": "ACC8118539484", "salaryDate": "2025-07-08", "salaryAmount": 200000},
|
||||||
|
{"customerId": "CUC1968062010", "accountId": "ACC8115473093", "salaryDate": "2025-07-08", "salaryAmount": 200000},
|
||||||
|
{"customerId": "CUC1302360013", "accountId": "ACC8117628489", "salaryDate": "2025-07-08", "salaryAmount": 200000}
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_random_salary_payload():
|
||||||
|
return [random.choice(SALARY_DETECT_PAYLOADS)]
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
import httpx
|
||||||
|
import json
|
||||||
|
from salary_analytics.config import SIMBRELLA_BASE_URL, SIMBRELLA_ENDPOINT_RAC_CHECKS
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SimbrellaIntegration:
|
||||||
|
BASE_URL = SIMBRELLA_BASE_URL
|
||||||
|
ENDPOINT_RAC_CHECKS = SIMBRELLA_ENDPOINT_RAC_CHECKS
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def rac_check(customer_id, account_id, transaction_id):
|
||||||
|
"""
|
||||||
|
Calls the RACCheck endpoit
|
||||||
|
"""
|
||||||
|
url = f"{SimbrellaIntegration.BASE_URL}/{SimbrellaIntegration.ENDPOINT_RAC_CHECKS}"
|
||||||
|
logger.info(f"Contacting Rack Checks EndPoint: {str(url)}", exc_info=True)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"customerId": customer_id,
|
||||||
|
"accountId": account_id,
|
||||||
|
"transactionId": str(transaction_id),
|
||||||
|
"fbnTransactionId": str(transaction_id),
|
||||||
|
"countryCode": "NG",
|
||||||
|
"channel": "USSD"
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-api-key": f"{settings.VALID_API_KEY}",
|
||||||
|
"App-Id": f"{settings.VALID_APP_ID}",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = httpx.post(url, json=payload, headers=headers, timeout=10.0)
|
||||||
|
|
||||||
|
logger.info(f"This is Response: {str(response)}", exc_info=True)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"RACCheck API call failed: {str(e)}", exc_info=True)
|
||||||
|
raise Exception(f"RACCheck API call failed: {str(e)}")
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
import requests
|
||||||
|
from .config import SALARY_DETECT_URL, SALARY_DETECT_HEADERS, get_random_salary_payload
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SalaryDetect:
|
||||||
|
def __init__(self):
|
||||||
|
self._running = False
|
||||||
|
self._thread = None
|
||||||
|
|
||||||
|
def _run(self):
|
||||||
|
while self._running:
|
||||||
|
logger.info(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Detecting salary...")
|
||||||
|
try:
|
||||||
|
payload = get_random_salary_payload()
|
||||||
|
response = requests.post(SALARY_DETECT_URL, headers=SALARY_DETECT_HEADERS, json=payload)
|
||||||
|
logger.info(f"POST {SALARY_DETECT_URL} status: {response.status_code}, response: {response.text}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error during POST: {e}")
|
||||||
|
logger.info(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Salary detection complete")
|
||||||
|
time.sleep(120)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if not self._running:
|
||||||
|
self._running = True
|
||||||
|
self._thread = threading.Thread(target=self._run, daemon=True)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._running = False
|
||||||
|
if self._thread:
|
||||||
|
self._thread.join()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user