Update app.py
Browse files
app.py
CHANGED
@@ -20,19 +20,73 @@ def read_and_process_data(url, user_name):
|
|
20 |
- unique_count (кол-во уникальных записей)
|
21 |
- df_daily: [date, count, user]
|
22 |
"""
|
|
|
|
|
23 |
print(f"\n=== [{user_name}] чтение CSV ===")
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
print(f"[{user_name}] Исходное кол-во строк: {len(df)}")
|
26 |
|
|
|
27 |
cols = ["gender", "generation", "industry", "opf", "timestamp"]
|
28 |
df = df[[c for c in cols if c in df.columns]].copy()
|
29 |
print(f"[{user_name}] После отбора столбцов: {df.shape}")
|
30 |
|
31 |
-
# Удаляем дубликаты
|
32 |
df_unique = df.drop_duplicates(subset=["gender", "generation", "industry", "opf"]).copy()
|
33 |
print(f"[{user_name}] После drop_duplicates: {df_unique.shape}")
|
34 |
|
35 |
-
# Преобразуем timestamp -> date
|
36 |
df_unique["timestamp"] = pd.to_numeric(df_unique["timestamp"], errors='coerce')
|
37 |
df_unique["date"] = pd.to_datetime(df_unique["timestamp"], unit="s", origin="unix", errors='coerce').dt.date
|
38 |
|
@@ -44,6 +98,7 @@ def read_and_process_data(url, user_name):
|
|
44 |
# Группировка по датам
|
45 |
df_daily = df_unique.groupby("date").size().reset_index(name="count")
|
46 |
df_daily["user"] = user_name
|
|
|
47 |
return unique_count, df_daily
|
48 |
|
49 |
|
|
|
20 |
- unique_count (кол-во уникальных записей)
|
21 |
- df_daily: [date, count, user]
|
22 |
"""
|
23 |
+
import requests, base64, io
|
24 |
+
|
25 |
print(f"\n=== [{user_name}] чтение CSV ===")
|
26 |
+
|
27 |
+
# 1) Предположим, что в url указано что-то вроде
|
28 |
+
# "https://github.com/username/repo/blob/main/messages.csv"
|
29 |
+
# или "https://raw.githubusercontent.com/..."
|
30 |
+
# Чтобы использовать API, нужно получить путь (owner, repo, path).
|
31 |
+
# Если у вас уже есть "https://raw.githubusercontent.com/<owner>/<repo>/main/messages.csv",
|
32 |
+
# то придётся вручную подставить значения owner/repo/file_path для Contents API.
|
33 |
+
|
34 |
+
# Пример разбора url (упрощённо):
|
35 |
+
# - Здесь у нас raw-ссылки, например:
|
36 |
+
# "https://raw.githubusercontent.com/fruitpicker01/Storage_Lera_2025/main/messages.csv"
|
37 |
+
# => owner = "fruitpicker01", repo = "Storage_Lera_2025", path = "messages.csv"
|
38 |
+
# В зависимости от структуры URL меняйте parse_* как нужно
|
39 |
+
|
40 |
+
# !!! ВАЖНО: Если у вас несколько веток/папок, подставьте их правильно ниже.
|
41 |
+
import re
|
42 |
+
|
43 |
+
pattern = re.compile(r"https://raw\.githubusercontent\.com/([^/]+)/([^/]+)/([^/]+)/(.+)")
|
44 |
+
m = pattern.match(url)
|
45 |
+
if not m:
|
46 |
+
# не узнали структуру: fallback - просто пробуем pd.read_csv напрямую
|
47 |
+
print(f"[{user_name}] URL не совпадает с raw.githubusercontent.com, читаем напрямую...")
|
48 |
+
df = pd.read_csv(url, na_values=["Не выбрано"])
|
49 |
+
else:
|
50 |
+
owner = m.group(1)
|
51 |
+
repo_name = m.group(2)
|
52 |
+
branch = m.group(3)
|
53 |
+
file_path = m.group(4) # например "messages.csv"
|
54 |
+
|
55 |
+
# 2) Обращаемся к GitHub Contents API
|
56 |
+
api_url = f"https://api.github.com/repos/{owner}/{repo_name}/contents/{file_path}?ref={branch}"
|
57 |
+
print(f"[{user_name}] Пытаемся Contents API: {api_url}")
|
58 |
+
resp = requests.get(api_url)
|
59 |
+
if resp.status_code != 200:
|
60 |
+
print(f"[{user_name}] Не удалось получить JSON (статус={resp.status_code}), читаем напрямую...")
|
61 |
+
df = pd.read_csv(url, na_values=["Не выбрано"])
|
62 |
+
else:
|
63 |
+
data_json = resp.json()
|
64 |
+
size = data_json.get("size", 0)
|
65 |
+
file_content_encoded = data_json.get("content")
|
66 |
+
download_url = data_json.get("download_url")
|
67 |
+
|
68 |
+
if not file_content_encoded or size > 1_000_000:
|
69 |
+
# Большой файл или отсутствует content => используем download_url
|
70 |
+
print(f"[{user_name}] Файл крупнее 1 МБ или content отсутствует, скачиваем по download_url={download_url}")
|
71 |
+
resp2 = requests.get(download_url)
|
72 |
+
resp2.raise_for_status()
|
73 |
+
csv_text = resp2.text
|
74 |
+
df = pd.read_csv(io.StringIO(csv_text), na_values=["Не выбрано"])
|
75 |
+
else:
|
76 |
+
# Получаем Base64 и декодируем
|
77 |
+
file_bytes = base64.b64decode(file_content_encoded)
|
78 |
+
df = pd.read_csv(io.StringIO(file_bytes.decode("utf-8")), na_values=["Не выбрано"])
|
79 |
+
|
80 |
print(f"[{user_name}] Исходное кол-во строк: {len(df)}")
|
81 |
|
82 |
+
# Дальше та же логика, что у вас была
|
83 |
cols = ["gender", "generation", "industry", "opf", "timestamp"]
|
84 |
df = df[[c for c in cols if c in df.columns]].copy()
|
85 |
print(f"[{user_name}] После отбора столбцов: {df.shape}")
|
86 |
|
|
|
87 |
df_unique = df.drop_duplicates(subset=["gender", "generation", "industry", "opf"]).copy()
|
88 |
print(f"[{user_name}] После drop_duplicates: {df_unique.shape}")
|
89 |
|
|
|
90 |
df_unique["timestamp"] = pd.to_numeric(df_unique["timestamp"], errors='coerce')
|
91 |
df_unique["date"] = pd.to_datetime(df_unique["timestamp"], unit="s", origin="unix", errors='coerce').dt.date
|
92 |
|
|
|
98 |
# Группировка по датам
|
99 |
df_daily = df_unique.groupby("date").size().reset_index(name="count")
|
100 |
df_daily["user"] = user_name
|
101 |
+
|
102 |
return unique_count, df_daily
|
103 |
|
104 |
|