yeref 0.24.68__py3-none-any.whl → 0.24.70__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.
yeref/yeref.py CHANGED
@@ -16240,7 +16240,7 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16240
16240
 
16241
16241
  months = ["2025-06", "2025-07", "2025-08", "2025-09"]
16242
16242
  data_users = []
16243
- for _ in range(20):
16243
+ for _ in range(30):
16244
16244
  # дата входа
16245
16245
  entry_month = random.choice(months)
16246
16246
  entry_day = random.randint(1, 28)
@@ -16302,7 +16302,6 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16302
16302
  ))
16303
16303
  print(f"gen {data_users=}")
16304
16304
 
16305
-
16306
16305
  cohorts = defaultdict(set)
16307
16306
  activity_months = defaultdict(set)
16308
16307
 
@@ -16312,9 +16311,6 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16312
16311
  USER_DT = USER_VARS.get("USER_DT", "")
16313
16312
  USER_DAU = USER_LSTS.get("USER_DAU", [])
16314
16313
 
16315
- if not USER_DT:
16316
- continue
16317
-
16318
16314
  entry_mo = datetime.strptime(USER_DT, "%d-%m-%Y_%H-%M-%S").strftime("%Y-%m")
16319
16315
  cohorts[entry_mo].add(USER_TID)
16320
16316
 
@@ -16368,7 +16364,7 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16368
16364
  row.append(str(val))
16369
16365
  row_sum += val
16370
16366
  else:
16371
- row.append("")
16367
+ row.append("0")
16372
16368
 
16373
16369
  row.append(str(row_sum))
16374
16370
  table.append(row)
@@ -16394,7 +16390,7 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16394
16390
  for r in table:
16395
16391
  writer.writerow(r)
16396
16392
  writer.writerow([])
16397
- writer.writerow([f"Avg monthly cohort churn: {avg_churn:.2f}%"])
16393
+ writer.writerow([f"Churn ~ ×{avg_churn:.0f} monthly"])
16398
16394
 
16399
16395
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
16400
16396
  await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
@@ -16404,7 +16400,6 @@ async def return_cohort_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16404
16400
  await asyncio.sleep(round(random.uniform(0, 1), 2))
16405
16401
 
16406
16402
 
16407
-
16408
16403
  async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16409
16404
  try:
16410
16405
  sql = 'SELECT USER_TID, USER_VARS, USER_LSTS FROM "USER"'
@@ -16412,7 +16407,7 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16412
16407
 
16413
16408
  months = ["2025-06", "2025-07", "2025-08", "2025-09"]
16414
16409
  data_users = []
16415
- for _ in range(20):
16410
+ for _ in range(30):
16416
16411
  # дата входа
16417
16412
  entry_month = random.choice(months)
16418
16413
  entry_day = random.randint(1, 28)
@@ -16474,57 +16469,89 @@ async def return_retention_metrics(bot, PROJECT_USERNAME, EXTRA_D, BASE_P):
16474
16469
  ))
16475
16470
  print(f"gen {data_users=}")
16476
16471
 
16477
- # собираем выручку по пользователю и месяцу
16478
- user_month_rev = defaultdict(lambda: defaultdict(float))
16472
+ # Собираем платежи и дату входа для каждого пользователя
16473
+ rev_by_cohort = defaultdict(lambda: defaultdict(float))
16474
+ cohort_users = defaultdict(set)
16475
+
16479
16476
  for USER_TID, USER_VARS, USER_LSTS in data_users:
16477
+ USER_VARS = json.loads(USER_VARS or "{}")
16480
16478
  USER_LSTS = json.loads(USER_LSTS or "{}")
16479
+ dt_entry_raw = USER_VARS.get("USER_DT", "").split("_")[0]
16480
+ if not dt_entry_raw:
16481
+ continue
16482
+ cohort_mo = datetime.strptime(dt_entry_raw, "%d-%m-%Y").strftime("%Y-%m")
16483
+ cohort_users[cohort_mo].add(USER_TID)
16484
+
16481
16485
  for pay in USER_LSTS.get("USER_PAYMENTS", []):
16482
- dt_p = datetime.strptime(pay.get("DT_START", ""), "%d-%m-%Y_%H-%M-%S")
16483
- mo = dt_p.strftime("%Y-%m")
16486
+ dt_pay = datetime.strptime(pay.get("DT_START", ""), "%d-%m-%Y_%H-%M-%S")
16487
+ pay_mo = dt_pay.strftime("%Y-%m")
16488
+ # вычисляем разницу в месяцах
16489
+ y0, m0 = map(int, cohort_mo.split("-"))
16490
+ y1, m1 = map(int, pay_mo.split("-"))
16491
+ offset = (y1 - y0) * 12 + (m1 - m0)
16492
+ if offset < 0:
16493
+ continue
16484
16494
  amt = float(pay.get("AMOUNT", 0)) * 0.013
16485
- user_month_rev[USER_TID][mo] += amt
16486
-
16487
- # список всех месяцев с выручкой, отсортированный
16488
- all_months = sorted({mo for revs in user_month_rev.values() for mo in revs.keys()})
16495
+ rev_by_cohort[cohort_mo][offset] += amt
16489
16496
 
16490
- results = []
16491
- for idx, mo in enumerate(all_months):
16492
- if idx == 0:
16493
- results.append({"MO": mo, "NRR": ""})
16494
- continue
16495
- prev_mo = all_months[idx - 1]
16496
- # общая выручка в prev_mo
16497
- prev_total = sum(user_month_rev[u][prev_mo] for u in user_month_rev if prev_mo in user_month_rev[u])
16498
- if prev_total == 0:
16499
- results.append({"MO": mo, "NRR": ""})
16500
- continue
16501
- # выручка текущего месяца от тех же пользователей
16502
- curr_existing = sum(
16503
- user_month_rev[u][mo]
16504
- for u in user_month_rev
16505
- if prev_mo in user_month_rev[u] and mo in user_month_rev[u]
16506
- )
16507
- nrr = curr_existing / prev_total
16508
- results.append({"MO": mo, "NRR": f"{nrr * 100:.2f}"})
16497
+ cohort_months = sorted(cohort_users.keys())
16498
+ # Определяем максимальный период
16499
+ max_offset = 0
16500
+ for c in cohort_months:
16501
+ if rev_by_cohort[c]:
16502
+ max_offset = max(max_offset, max(rev_by_cohort[c].keys()))
16509
16503
 
16510
- # средний NRR (арифметическое по ненулевым)
16511
- vals = [float(r["NRR"]) for r in results if r["NRR"]]
16512
- avg_nrr = f"{(sum(vals) / len(vals)):.2f}" if vals else ""
16504
+ # Сумма выручки M1 для каждой когорты
16505
+ base_rev = {c: rev_by_cohort[c].get(0, 0.0) for c in cohort_months}
16513
16506
 
16507
+ # Формируем CSV-таблицу
16514
16508
  path = os.path.join(EXTRA_D, "4_retention_metrics.csv")
16515
16509
  with open(path, "w", newline="", encoding="utf-8") as f:
16516
16510
  writer = csv.writer(f)
16517
- writer.writerow(["MO", "NRR (%)"])
16518
- for r in results:
16519
- writer.writerow([r["MO"], r["NRR"]])
16511
+ # Заголовок
16512
+ header = ["Месяц / Когорта"]
16513
+ for c in cohort_months:
16514
+ header.append(f"{c} ({len(cohort_users[c])})")
16515
+ header.append("∑")
16516
+ writer.writerow(header)
16517
+
16518
+ # Строки M1..M{max_offset+1}
16519
+ for i in range(max_offset + 1):
16520
+ row_label = f"M{i+1} ({i} мес)"
16521
+ row = [row_label]
16522
+ row_sum = 0.0
16523
+ for c in cohort_months:
16524
+ rev = rev_by_cohort[c].get(i, 0.0)
16525
+ if rev > 0 and base_rev[c] > 0:
16526
+ pct = rev / base_rev[c] * 100
16527
+ cell = f"{rev:.1f} ({pct:.0f}%)"
16528
+ row.append(cell)
16529
+ row_sum += rev
16530
+ else:
16531
+ row.append("")
16532
+ row.append(f"{row_sum:.1f}")
16533
+ writer.writerow(row)
16534
+
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
+
16520
16545
  writer.writerow([])
16521
- writer.writerow([f"Avg NRR (%)", avg_nrr])
16546
+ writer.writerow([f"Avg monthly NRR growth:", f"{avg_growth:.2f}%"])
16522
16547
 
16523
16548
  thumb = types.FSInputFile(os.path.join(EXTRA_D, "parse.jpg"))
16524
16549
  await bot.send_document(chat_id=my_tid, document=types.FSInputFile(path), thumbnail=thumb)
16550
+
16525
16551
  except Exception as e:
16526
16552
  logger.info(log_ % str(e))
16527
16553
  await asyncio.sleep(round(random.uniform(0, 1), 2))
16554
+
16528
16555
  # endregion
16529
16556
 
16530
16557
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yeref
3
- Version: 0.24.68
3
+ Version: 0.24.70
4
4
  Summary: desc-f
5
5
  Author: john smith
6
6
  Dynamic: author
@@ -0,0 +1,8 @@
1
+ yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
+ yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
+ yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
+ yeref/yeref.py,sha256=9crFt-rMlJKd6CMsBLeZntC-QyIuoR-HWEHpdSMSp2Y,1054355
5
+ yeref-0.24.70.dist-info/METADATA,sha256=Wk8AM-uXSJhM6tsUyDvQ0ge55kTBWQfPtgBpMtRzQ3Q,119
6
+ yeref-0.24.70.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ yeref-0.24.70.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
+ yeref-0.24.70.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- yeref/__init__.py,sha256=Qpv3o6Xa78VdLcsSRmctGtpnYE9btpAkCekgGhgJyXM,49
2
- yeref/l_.py,sha256=LMX_olmJwq-tgoALJCnhV_fGrL_i_43yBLkLIcEVqGo,1176743
3
- yeref/tonweb.js,sha256=Jf6aFOQ1OIY4q7fINYz-m5LsI3seMus124M5SYYZmtE,443659
4
- yeref/yeref.py,sha256=wj8Ry-Kst9NVBxFartZ_KiD8jV8vnI-vaXcd8gxCypE,1053269
5
- yeref-0.24.68.dist-info/METADATA,sha256=AXFOBvqFgt55P4tLo-orKHy9TKtWq80UTwiOZGbzyQk,119
6
- yeref-0.24.68.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- yeref-0.24.68.dist-info/top_level.txt,sha256=yCQKchWHbfV-3OuQPYRdi2loypD-nmbDJbtt3OuKKkY,6
8
- yeref-0.24.68.dist-info/RECORD,,