yeref 0.24.70__tar.gz → 0.24.71__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {yeref-0.24.70 → yeref-0.24.71}/PKG-INFO +1 -1
- {yeref-0.24.70 → yeref-0.24.71}/setup.py +1 -1
- {yeref-0.24.70 → yeref-0.24.71}/yeref/yeref.py +17 -94
- {yeref-0.24.70 → yeref-0.24.71}/yeref.egg-info/PKG-INFO +1 -1
- {yeref-0.24.70 → yeref-0.24.71}/pyproject.toml +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/setup.cfg +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref/__init__.py +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref/l_.py +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref/tonweb.js +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref.egg-info/SOURCES.txt +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref.egg-info/dependency_links.txt +0 -0
- {yeref-0.24.70 → yeref-0.24.71}/yeref.egg-info/top_level.txt +0 -0
@@ -16405,71 +16405,6 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16405
16405
|
sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
|
16406
16406
|
data_users = await db_select_pg(sql, (), BASE_P)
|
16407
16407
|
|
16408
|
-
months = ["2025-06", "2025-07", "2025-08", "2025-09"]
|
16409
|
-
data_users = []
|
16410
|
-
for _ in range(30):
|
16411
|
-
# дата входа
|
16412
|
-
entry_month = random.choice(months)
|
16413
|
-
entry_day = random.randint(1, 28)
|
16414
|
-
entry_date = f"{entry_month}-{entry_day:02}"
|
16415
|
-
entry_dt_obj = datetime.strptime(entry_date, '%Y-%m-%d')
|
16416
|
-
entry_dt = f"{entry_dt_obj.strftime('%d-%m-%Y')}_{datetime.now().strftime('%H-%M-%S')}"
|
16417
|
-
utm = random.choice(["/start", "/startapp"])
|
16418
|
-
|
16419
|
-
# месяцы от входа и дальше
|
16420
|
-
valid_months = [m for m in months if datetime.strptime(m + "-01", "%Y-%m-%d") >= entry_dt_obj.replace(day=1)]
|
16421
|
-
if not valid_months:
|
16422
|
-
valid_months = [entry_month]
|
16423
|
-
|
16424
|
-
user_mau = sorted(random.sample(valid_months, k=random.randint(1, len(valid_months))))
|
16425
|
-
user_dau_dates = set()
|
16426
|
-
txs, payments = [], []
|
16427
|
-
|
16428
|
-
# платеж
|
16429
|
-
if user_mau:
|
16430
|
-
pay_month = random.choice(user_mau)
|
16431
|
-
pay_day = random.randint(1, 28)
|
16432
|
-
pay_date = f"{pay_month}-{pay_day:02}"
|
16433
|
-
dt_pay = datetime.strptime(pay_date, "%Y-%m-%d")
|
16434
|
-
# if dt_pay >= entry_dt_obj:
|
16435
|
-
payments = [{
|
16436
|
-
"TYPE": random.choice(["don", "sub", "pst"]),
|
16437
|
-
"DT_START": f"{dt_pay.strftime('%d-%m-%Y')}_14-00-00",
|
16438
|
-
"DT_END": "0",
|
16439
|
-
"AMOUNT": str(random.randint(1, 10))
|
16440
|
-
}]
|
16441
|
-
user_dau_dates.add(pay_date)
|
16442
|
-
|
16443
|
-
# вход в приложение
|
16444
|
-
user_dau_dates.add(entry_date)
|
16445
|
-
for m in user_mau:
|
16446
|
-
day = random.randint(1, 28)
|
16447
|
-
visit = f"{m}-{day:02}"
|
16448
|
-
dt_visit = datetime.strptime(visit, "%Y-%m-%d")
|
16449
|
-
if dt_visit >= entry_dt_obj and random.random() < 0.7:
|
16450
|
-
user_dau_dates.add(visit)
|
16451
|
-
|
16452
|
-
# статусы (отток) с низкой вероятностью
|
16453
|
-
USER_STATUSES = []
|
16454
|
-
if random.random() < 0.2: # 10% шанс оттока
|
16455
|
-
churn_month = random.choice(valid_months)
|
16456
|
-
churn_day = random.randint(1, 28)
|
16457
|
-
churn_date = f"{churn_month}-{churn_day:02}"
|
16458
|
-
churn_ts = datetime.strptime(churn_date, "%Y-%m-%d").strftime("%d-%m-%Y") + "_23-59-59"
|
16459
|
-
USER_STATUSES = [{random.choice(["left", "kicked"]): churn_ts}]
|
16460
|
-
|
16461
|
-
user_dau = sorted(user_dau_dates)
|
16462
|
-
wallet = f"wallet{random.randint(1, 100)}" if txs else random.choice([f"wallet{random.randint(1, 100)}", ""])
|
16463
|
-
|
16464
|
-
data_users.append((
|
16465
|
-
random.randint(100000, 999999),
|
16466
|
-
json.dumps({"USER_WALLET": wallet, "USER_UTM": utm, "USER_DT": entry_dt}),
|
16467
|
-
json.dumps({"USER_DAU": user_dau, "USER_MAU": user_mau, "USER_TXS": txs,
|
16468
|
-
"USER_PAYMENTS": payments, "USER_STATUSES": USER_STATUSES})
|
16469
|
-
))
|
16470
|
-
print(f"gen {data_users=}")
|
16471
|
-
|
16472
|
-
# Собираем платежи и дату входа для каждого пользователя
|
16473
16408
|
rev_by_cohort = defaultdict(lambda: defaultdict(float))
|
16474
16409
|
cohort_users = defaultdict(set)
|
16475
16410
|
|
@@ -16485,7 +16420,6 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16485
16420
|
for pay in USER_LSTS.get("USER_PAYMENTS", []):
|
16486
16421
|
dt_pay = datetime.strptime(pay.get("DT_START", ""), "%d-%m-%Y_%H-%M-%S")
|
16487
16422
|
pay_mo = dt_pay.strftime("%Y-%m")
|
16488
|
-
# вычисляем разницу в месяцах
|
16489
16423
|
y0, m0 = map(int, cohort_mo.split("-"))
|
16490
16424
|
y1, m1 = map(int, pay_mo.split("-"))
|
16491
16425
|
offset = (y1 - y0) * 12 + (m1 - m0)
|
@@ -16495,56 +16429,45 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
|
|
16495
16429
|
rev_by_cohort[cohort_mo][offset] += amt
|
16496
16430
|
|
16497
16431
|
cohort_months = sorted(cohort_users.keys())
|
16498
|
-
|
16432
|
+
if not cohort_months:
|
16433
|
+
return
|
16434
|
+
|
16499
16435
|
max_offset = 0
|
16500
16436
|
for c in cohort_months:
|
16501
16437
|
if rev_by_cohort[c]:
|
16502
16438
|
max_offset = max(max_offset, max(rev_by_cohort[c].keys()))
|
16503
16439
|
|
16504
|
-
# Сумма выручки M1 для каждой когорты
|
16505
16440
|
base_rev = {c: rev_by_cohort[c].get(0, 0.0) for c in cohort_months}
|
16506
16441
|
|
16507
|
-
# Формируем CSV-таблицу
|
16508
16442
|
path = os.path.join(EXTRA_D, "4_retention_metrics.csv")
|
16509
16443
|
with open(path, "w", newline="", encoding="utf-8") as f:
|
16510
16444
|
writer = csv.writer(f)
|
16511
|
-
|
16512
|
-
|
16513
|
-
|
16514
|
-
header.append(f"{c} ({len(cohort_users[c])})")
|
16515
|
-
header.append("∑")
|
16445
|
+
header = ["Месяц / Когорта"] + [
|
16446
|
+
f"{c} ({len(cohort_users[c])})" for c in cohort_months
|
16447
|
+
] + ["∑"]
|
16516
16448
|
writer.writerow(header)
|
16517
16449
|
|
16518
|
-
# Строки M1..M{max_offset+1}
|
16519
16450
|
for i in range(max_offset + 1):
|
16520
|
-
|
16521
|
-
row = [row_label]
|
16451
|
+
row = [f"M{i+1} ({i} мес)"]
|
16522
16452
|
row_sum = 0.0
|
16523
16453
|
for c in cohort_months:
|
16524
16454
|
rev = rev_by_cohort[c].get(i, 0.0)
|
16525
|
-
if
|
16526
|
-
pct =
|
16527
|
-
cell = f"{rev:.1f} ({pct
|
16455
|
+
if i == 0:
|
16456
|
+
pct = 100
|
16457
|
+
cell = f"{rev:.1f} ({pct}%)"
|
16528
16458
|
row.append(cell)
|
16529
16459
|
row_sum += rev
|
16530
16460
|
else:
|
16531
|
-
|
16461
|
+
if base_rev[c] > 0 and rev > 0:
|
16462
|
+
pct = rev / base_rev[c] * 100
|
16463
|
+
cell = f"{rev:.1f} ({pct:.0f}%)"
|
16464
|
+
row.append(cell)
|
16465
|
+
row_sum += rev
|
16466
|
+
else:
|
16467
|
+
row.append("")
|
16532
16468
|
row.append(f"{row_sum:.1f}")
|
16533
16469
|
writer.writerow(row)
|
16534
16470
|
|
16535
|
-
# Средний рост NRR
|
16536
|
-
growths = []
|
16537
|
-
for c in cohort_months:
|
16538
|
-
for i in range(1, max_offset + 1):
|
16539
|
-
prev = rev_by_cohort[c].get(i - 1, 0.0)
|
16540
|
-
curr = rev_by_cohort[c].get(i, 0.0)
|
16541
|
-
if prev > 0:
|
16542
|
-
growths.append((curr - prev) / prev)
|
16543
|
-
avg_growth = (sum(growths) / len(growths) * 100) if growths else 0.0
|
16544
|
-
|
16545
|
-
writer.writerow([])
|
16546
|
-
writer.writerow([f"Avg monthly NRR growth:", f"{avg_growth:.2f}%"])
|
16547
|
-
|
16548
16471
|
thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
|
16549
16472
|
await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
|
16550
16473
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|