vedana-backoffice 0.1.0__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.
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import reflex as rx
6
+
7
+ from vedana_backoffice.states.chat import ChatState
8
+ from vedana_backoffice.states.common import AppVersionState, TelegramBotState
9
+
10
+
11
+ def telegram_link_box() -> rx.Component:
12
+ return rx.box(
13
+ rx.cond(
14
+ TelegramBotState.has_bot,
15
+ rx.link(
16
+ rx.hstack(
17
+ rx.text("Telegram", font_size="1.1em"),
18
+ # rx.icon("external-link", stroke_width=1, size=10),
19
+ # spacing="1",
20
+ ),
21
+ href=TelegramBotState.bot_url,
22
+ is_external=True,
23
+ ),
24
+ ),
25
+ on_mount=TelegramBotState.load_bot_info,
26
+ )
27
+
28
+
29
+ def data_model_reload_btn() -> rx.Component:
30
+ return rx.button(
31
+ "Reload Data Model",
32
+ variant="soft",
33
+ color_scheme="blue",
34
+ on_click=ChatState.reload_data_model,
35
+ loading=ChatState.is_refreshing_dm,
36
+ )
37
+
38
+
39
+ def app_header() -> rx.Component:
40
+ return rx.box(
41
+ rx.hstack(
42
+ rx.hstack(
43
+ rx.link("Vedana Backoffice", href="/", font_weight="bold", font_size="1.25em"),
44
+ rx.markdown(AppVersionState.version), # type: ignore[operator]
45
+ align="center",
46
+ spacing="3",
47
+ ),
48
+ rx.hstack(
49
+ data_model_reload_btn(),
50
+ rx.link("ETL", href="/etl", font_size="1.1em"),
51
+ rx.cond(
52
+ AppVersionState.eval_enabled,
53
+ rx.link("Eval", href="/eval", font_size="1.1em"),
54
+ rx.fragment(),
55
+ ),
56
+ rx.link("Chat", href="/chat", font_size="1.1em"),
57
+ rx.link("JIMS", href="/jims", font_size="1.1em"),
58
+ telegram_link_box(),
59
+ rx.color_mode.button(), # type: ignore[attr-defined]
60
+ spacing="6",
61
+ align="center",
62
+ ),
63
+ justify="between",
64
+ align="center",
65
+ width="100%",
66
+ ),
67
+ width="100%",
68
+ padding="0.5em 1.25em",
69
+ border_bottom="1px solid #e5e7eb",
70
+ position="sticky",
71
+ top="0",
72
+ background_color=rx.color_mode_cond(light="white", dark="black"),
73
+ style={
74
+ "backdrop-filter": "blur(10px)", # enables non-transparent background
75
+ },
76
+ z_index="10",
77
+ )
78
+
79
+
80
+ def themed_data_table(
81
+ *,
82
+ data: rx.Var | list[Any],
83
+ columns: rx.Var | list[str],
84
+ width: str | rx.Var = "fit-content",
85
+ max_width: str | rx.Var = "100%",
86
+ **kwargs: Any,
87
+ ) -> rx.Component:
88
+ """Wrap rx.data_table with shared styling so it matches the app theme."""
89
+
90
+ default_kwargs = {"pagination": True, "search": True, "sort": True}
91
+ table_kwargs = {**default_kwargs, **kwargs}
92
+
93
+ table_style = table_kwargs.pop("style", {})
94
+ table_style = {"width": "fit-content", "minWidth": "100%", **table_style}
95
+
96
+ container_style: dict[str, Any] = {
97
+ "width": width,
98
+ "maxWidth": max_width,
99
+ "minWidth": "fit-content",
100
+ }
101
+
102
+ return rx.box(
103
+ rx.data_table(data=data, columns=columns, style=table_style, **table_kwargs),
104
+ class_name="datatable-surface",
105
+ style=container_style,
106
+ )
107
+
108
+
109
+ def breadcrumbs(items: list[tuple[str, str]]) -> rx.Component:
110
+ parts: list[rx.Component] = []
111
+ for idx, (label, href) in enumerate(items):
112
+ parts.append(rx.link(label, href=href))
113
+ if idx < len(items) - 1:
114
+ parts.append(rx.text("→", color="#9ca3af"))
115
+ return rx.hstack(*parts, spacing="2", padding_y="0.5em")
@@ -0,0 +1,71 @@
1
+ from datetime import datetime
2
+ from typing import Any
3
+
4
+ import orjson as json
5
+
6
+
7
+ def datetime_to_age(created_at: datetime, compact: bool = True) -> str:
8
+ """Convert a datetime to a human-readable age string.
9
+
10
+ For datetimes less than 7 days old, returns relative time.
11
+ For older datetimes, returns absolute date format (e.g., "2025 Aug 24 14:30").
12
+
13
+ Args:
14
+ created_at: The datetime to convert
15
+ compact: If True, uses compact format (e.g., "2h", "3d14h").
16
+ If False, uses verbose format (e.g., "2 hours", "3 days 14 hours").
17
+ """
18
+ now = datetime.now()
19
+
20
+ # created_at_dt = created_at
21
+ # if created_at_dt.tzinfo is None:
22
+ # created_at_dt = created_at_dt.replace(tzinfo=timezone.utc)
23
+ # time_diff = now - created_at_dt
24
+
25
+ time_diff = now - created_at
26
+
27
+ if time_diff.days < 7:
28
+ # Human readable relative time
29
+ if time_diff.days > 0:
30
+ hours = time_diff.seconds // 3600
31
+ if hours > 0:
32
+ if compact:
33
+ return f"{time_diff.days}d{hours}h"
34
+ else:
35
+ return f"{time_diff.days} days {hours} hours"
36
+ else:
37
+ if compact:
38
+ return f"{time_diff.days}d"
39
+ else:
40
+ return f"{time_diff.days} days"
41
+ elif time_diff.seconds >= 3600:
42
+ hours = time_diff.seconds // 3600
43
+ if compact:
44
+ return f"{hours}h"
45
+ else:
46
+ return f"{hours} hours"
47
+ elif time_diff.seconds >= 60:
48
+ minutes = time_diff.seconds // 60
49
+ if compact:
50
+ return f"{minutes}m"
51
+ else:
52
+ return f"{minutes} minutes"
53
+ else:
54
+ if compact:
55
+ return "1m"
56
+ else:
57
+ return "1 minute"
58
+ else:
59
+ # Absolute date format
60
+ return created_at.strftime("%Y %b %d %H:%M")
61
+
62
+
63
+ def safe_render_value(v: Any) -> str:
64
+ try:
65
+ s = json.dumps(v).decode() if isinstance(v, (dict, list)) else str(v)
66
+ except Exception:
67
+ try:
68
+ s = repr(v)
69
+ except Exception:
70
+ s = "<error rendering value>"
71
+ return s
@@ -0,0 +1,23 @@
1
+ import reflex as rx
2
+
3
+ from vedana_backoffice.pages.chat import page as chat_page
4
+ from vedana_backoffice.pages.etl import page as etl_page
5
+ from vedana_backoffice.pages.jims_thread_list_page import jims_thread_list_page
6
+ from vedana_backoffice.pages.main_dashboard import page as main_dashboard_page
7
+ from vedana_backoffice.states.chat import ChatState
8
+ from vedana_backoffice.states.common import EVAL_ENABLED
9
+ from vedana_backoffice.states.etl import EtlState
10
+ from vedana_backoffice.states.main_dashboard import DashboardState
11
+
12
+ app = rx.App(stylesheets=["/styles.css"])
13
+ app.add_page(main_dashboard_page, route="/", title="Vedana Backoffice", on_load=DashboardState.load_dashboard)
14
+ app.add_page(etl_page, route="/etl", title="ETL", on_load=EtlState.load_pipeline_metadata)
15
+ app.add_page(chat_page, route="/chat", title="Chat", on_load=ChatState.reset_session)
16
+ app.add_page(jims_thread_list_page, route="/jims", title="JIMS")
17
+
18
+ # Eval page is only available when GRIST_TEST_SET_DOC_ID is configured
19
+ if EVAL_ENABLED:
20
+ from vedana_backoffice.pages.eval import page as eval_page
21
+ from vedana_backoffice.states.eval import EvalState
22
+
23
+ app.add_page(eval_page, route="/eval", title="Evaluation", on_load=EvalState.load_eval_data)
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: vedana-backoffice
3
+ Version: 0.1.0
4
+ Summary: Reflex-based admin/backoffice UI for Vedana
5
+ Author-email: Andrey Tatarinov <a@tatarinov.co>, Timur Sheydaev <tsheyd@epoch8.co>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: orjson>=3.11.3
8
+ Requires-Dist: reflex<0.9.0,>=0.8.25
9
+ Requires-Dist: vedana-core
10
+ Requires-Dist: vedana-etl
@@ -0,0 +1,30 @@
1
+ vedana_backoffice/Caddyfile,sha256=jZlD85_2e_eWggNFAtzkWN75uKuoHSbwWgeyWwibYhA,317
2
+ vedana_backoffice/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ vedana_backoffice/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ vedana_backoffice/start_services.py,sha256=94k2xrgIYXWhRfurR7XM-uMoXXL09RG0HFzyRRh9Nrs,974
5
+ vedana_backoffice/state.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ vedana_backoffice/ui.py,sha256=yKPAwUJZ_8cYzswqCV7nUxihvcrHw_DszeI1lbTaTbM,3618
7
+ vedana_backoffice/util.py,sha256=RVN9ezjNkSnrlT3pBIrSvQQLyf-TZ2WzP_AYxRGks_Q,2209
8
+ vedana_backoffice/vedana_backoffice.py,sha256=WlwF8hTBmkYOlgj9vE3k58MqDcj8FIbMNXZRsUXnjKg,1224
9
+ vedana_backoffice/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ vedana_backoffice/components/etl_graph.py,sha256=m3eFU8NO2z0GCMBnaj4I8a30AG7uerRq30sead8re9A,5256
11
+ vedana_backoffice/components/ui_chat.py,sha256=wpwSz-IP8uthKQEtrarZOZ4Pfg9sENboadic6bBlsj0,7746
12
+ vedana_backoffice/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ vedana_backoffice/graph/build.py,sha256=5BnL45bPGpNXLvsR6H05WFUCoqKMS0jj_MrcCZjX8N0,5706
14
+ vedana_backoffice/pages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ vedana_backoffice/pages/chat.py,sha256=h0bjV_I8zi9ifX8jKPigBsHw-nnYMrhkoijN_VTSyXA,8891
16
+ vedana_backoffice/pages/etl.py,sha256=oms6KqEcgTujx8l8akgAbJIBAZik1brZ5YXF8IoBxWY,13967
17
+ vedana_backoffice/pages/eval.py,sha256=jEkiIs4xiyUx-k24qsIHLzxKGZHHDq5FjLmI9FpPo90,39307
18
+ vedana_backoffice/pages/jims_thread_list_page.py,sha256=ZogjE7XQW2Zuyzcy4mod8qQECvtPOSuJv5CkUsGVfeM,36561
19
+ vedana_backoffice/pages/main_dashboard.py,sha256=odi4V5Bf-qukPLN9f8whgaYWikL6D7v5kzqB4rm3T10,21350
20
+ vedana_backoffice/states/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ vedana_backoffice/states/chat.py,sha256=xZwnqhzVIhnfGRPAWPcgZg9_boM3Crvmu-gieh1QMfs,13980
22
+ vedana_backoffice/states/common.py,sha256=wI3ZCDeuV4_pkVQ-Q_Z0lgC8TQPs_eIT2nPqD-5rtjs,1977
23
+ vedana_backoffice/states/etl.py,sha256=1eLahWMm0Zd3oBDpOAJ_rfqHMPgRIJ_InwYzhm52hoo,68261
24
+ vedana_backoffice/states/eval.py,sha256=nDfDL5ifL_q2vWWBEPwtWomUG_dhJxOMlIWOndOtjxM,76897
25
+ vedana_backoffice/states/jims.py,sha256=gM0iZInD40-AebWY9gOzn5oJjAx7wyA_QliTluzMoZ8,19927
26
+ vedana_backoffice/states/main_dashboard.py,sha256=9AcWo2nl5L-hTymxr-Stbu2s5nTGl9CVxTA9mHu8Rt4,32388
27
+ vedana_backoffice-0.1.0.dist-info/METADATA,sha256=pVGuXZu-o9ly1pKf5iFjAllvTOPD3iMYXGpGNNmFfCI,341
28
+ vedana_backoffice-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
29
+ vedana_backoffice-0.1.0.dist-info/entry_points.txt,sha256=WyUmp5EmDq_dB9RjzEim4L-XmDhPDxYI7ptab4A1EJc,87
30
+ vedana_backoffice-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vedana-backoffice-with-caddy = vedana_backoffice.start_services:main