Skip to content

Commit 294466e

Browse files
Merge pull request #37 from ncj-dneg/ncj-dneg-update-trial-ui-limits
Add trial mode UI restrictions
2 parents 77ce078 + cadd3e6 commit 294466e

14 files changed

Lines changed: 70 additions & 34 deletions

interface/app.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
psutil = None
120120

121121

122-
APP_NAME = "DrunkenBot LLM-IDE"
122+
APP_NAME = "DrunkenBot-IDE"
123123
# Bump on every release that should require a version-ceiling check against
124124
# licenses -- this is what license_client.check_license_at_launch compares
125125
# against a license's version_ceiling/grace_period_until.
@@ -195,35 +195,31 @@ def _ensure_valid_license(splash: "StartupValidationSplash") -> bool:
195195
"[OK] License valid"
196196
+ (" (offline grace period)" if result.used_offline_grace else "")
197197
)
198+
QApplication.instance().setProperty("license_valid", True)
198199
return True
199200
initial_message = result.reason
200201
else:
201202
initial_message = "No license activated on this machine yet."
202203

203-
# A QSplashScreen-style window is designed to stay on top of other
204-
# windows during startup -- which means it can end up covering a newly
205-
# created dialog instead of the other way around. Hide it while the
206-
# dialog is up rather than fight window-stacking order; it isn't doing
207-
# anything useful to look at during activation anyway.
208204
splash.hide()
209205
try:
210-
while True:
211-
dialog = LicenseActivationDialog(APP_VERSION, LICENSE_SERVER_URL, initial_message)
212-
dialog.setWindowIcon(MainWindow._static_app_icon())
213-
dialog.show()
214-
dialog.raise_()
215-
dialog.activateWindow()
216-
if dialog.exec() != QDialog.Accepted:
217-
LOGGER.info("License activation cancelled by user; exiting.")
218-
QApplication.instance().setProperty("startup_aborted", True)
219-
return False
206+
dialog = LicenseActivationDialog(APP_VERSION, LICENSE_SERVER_URL, initial_message)
207+
dialog.setWindowIcon(MainWindow._static_app_icon())
208+
if dialog.exec() == QDialog.Accepted and dialog.result_info is not None:
209+
QApplication.instance().setProperty("license_valid", True)
220210
splash.append_log("[OK] License activated")
221211
return True
212+
if dialog.trial_requested:
213+
QApplication.instance().setProperty("license_valid", False)
214+
splash.append_log("[TRIAL] User selected trial version")
215+
return True
216+
LOGGER.info("License activation cancelled by user; exiting.")
217+
QApplication.instance().setProperty("startup_aborted", True)
218+
return False
222219
finally:
223220
splash.show()
224221
splash.raise_()
225222

226-
227223
def main(app: Optional[QApplication] = None, splash: Optional[StartupSplash] = None) -> None:
228224
"""Launch the PySide6 desktop application."""
229225

interface/license_activation_dialog.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ def __init__(self, app_version: str, server_url: str, initial_message: str = "")
105105
self._app_version = app_version
106106
self._server_url = server_url
107107
self.result_info: LicenseCheckResult | None = None
108+
self.trial_requested = False
108109

109-
self.setWindowTitle("Activate DrunkenBot LLM-IDE")
110+
self.setWindowTitle("Activate DrunkenBot-IDE")
110111
self.setModal(True)
111112
self.setMinimumWidth(480)
112113

@@ -132,7 +133,10 @@ def __init__(self, app_version: str, server_url: str, initial_message: str = "")
132133
self._activate_button.clicked.connect(self._on_activate_clicked)
133134
self._exit_button = QPushButton("Exit")
134135
self._exit_button.clicked.connect(self.reject)
136+
self._trial_button = QPushButton("Open Trial Version")
137+
self._trial_button.clicked.connect(self._open_trial)
135138
button_row.addWidget(self._activate_button)
139+
button_row.addWidget(self._trial_button)
136140
button_row.addWidget(self._exit_button)
137141
layout.addLayout(button_row)
138142

@@ -162,6 +166,11 @@ def _on_activate_clicked(self) -> None:
162166

163167
self._show_status(result.reason)
164168

169+
def _open_trial(self) -> None:
170+
"""Close the dialog and request restricted trial mode."""
171+
self.trial_requested = True
172+
self.accept()
173+
165174
def _show_status(self, message: str) -> None:
166175
"""Display a status/error message in the dialog.
167176

interface/main_window_part1.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ def __init__(self) -> None:
1515
LOGGER.info("Creating %s main window", APP_NAME)
1616
if QApplication.instance():
1717
QApplication.instance().setFont(QFont("Arial", 10))
18-
self.setWindowTitle(APP_NAME)
18+
licensed = bool(QApplication.instance().property("license_valid"))
19+
self.setWindowTitle(
20+
f"{APP_NAME} {APP_VERSION} "
21+
f"({'licensed' if licensed else 'Trial Version'})"
22+
)
1923
self.setWindowIcon(self._app_icon())
2024
self._windows_icon_handles: list[int] = []
2125
self.resize(1240, 820)
@@ -372,7 +376,11 @@ def show_chat_only_mode(self) -> None:
372376
if hasattr(self, "side_rail"):
373377
self.side_rail.hide()
374378
self._switch_page(8)
375-
self.setWindowTitle("DrunkenBot - Chat")
379+
licensed = bool(QApplication.instance().property("license_valid"))
380+
self.setWindowTitle(
381+
f"{APP_NAME} {APP_VERSION} "
382+
f"({'licensed' if licensed else 'Trial Version'})"
383+
)
376384
self.resize(980, 760)
377385

378386
def resizeEvent(self, event: Any) -> None:

interface/main_window_part11.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
class MainWindowPart11:
1010
def prepare_dataset(self) -> None:
11+
if not bool(QApplication.instance().property("license_valid")):
12+
self.context_length.setValue(min(self.context_length.value(), 1000))
1113
"""Collect dataset options and start dataset preparation."""
1214

1315
config = self._dataset_config_from_ui()
@@ -282,6 +284,11 @@ def _update_online_dataset_stage_controls(self) -> None:
282284

283285
if not hasattr(self, "dataset_stage"):
284286
return
287+
if not bool(QApplication.instance().property("license_valid")):
288+
self.include_conversation_datasets.setChecked(False)
289+
self.include_conversation_datasets.setEnabled(False)
290+
if hasattr(self, "external_dataset_download_button"):
291+
self.external_dataset_download_button.setEnabled(False)
285292
stage = self._dataset_stage_value()
286293
allowed = set(CONVERSATION_DATASET_PRESETS)
287294
include_online = self.include_conversation_datasets.isChecked()
@@ -422,5 +429,3 @@ def _selected_default_data_paths(self) -> list[Path]:
422429
for path, item in self.default_data_actions.items()
423430
if item.checkState(0) == Qt.Checked
424431
]
425-
426-

interface/main_window_part16.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ def _run_training_preflight(self, model_config: ModelConfig, training_config: Tr
312312
return True
313313

314314
def start_training(self) -> None:
315+
if not bool(QApplication.instance().property("license_valid")):
316+
self.train_context_length.setValue(min(self.train_context_length.value(), 1000))
315317
"""Collect training options and start model training."""
316318

317319
launch_target = self._training_launch_target_value()
@@ -388,4 +390,3 @@ def start_training(self) -> None:
388390
task_kind="training",
389391
)
390392

391-

interface/main_window_part17.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ def _append_chat_markdown(self, role: str, content: str) -> None:
382382
self._add_chat_message("user" if role.lower() in {"you", "user"} else "assistant", content)
383383

384384
def create_bundle(self) -> None:
385+
if not bool(QApplication.instance().property("license_valid")):
386+
self.export_log.append("Export Bay is available only in the licensed version.")
387+
return
385388
"""Create a portable model export bundle."""
386389

387390
self.export_log.append("Creating model bundle...")
@@ -397,6 +400,8 @@ def create_bundle(self) -> None:
397400
self.export_status.setText("Export: bundle created")
398401

399402
def quantize_model(self) -> None:
403+
if not bool(QApplication.instance().property("license_valid")):
404+
return
400405
"""Create a quantized FP16 checkpoint when selected."""
401406

402407
mode = self.quant_mode.currentText()
@@ -418,6 +423,8 @@ def quantize_model(self) -> None:
418423
self.export_status.setText("Export: FP16 checkpoint ready")
419424

420425
def export_hf_package(self) -> None:
426+
if not bool(QApplication.instance().property("license_valid")):
427+
return
421428
"""Create an HF-style MicroGPT package."""
422429

423430
self.export_log.append("Creating HF-style MicroGPT package...")
@@ -433,4 +440,3 @@ def export_hf_package(self) -> None:
433440
self.export_log.append("Note: this package is MicroGPT model_type, not a llama.cpp-supported Llama model.")
434441
self.export_status.setText("Export: HF package ready")
435442

436-

interface/main_window_part18.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
class MainWindowPart18:
1010
def export_llama_adapter(self) -> None:
11+
if not bool(QApplication.instance().property("license_valid")):
12+
return
1113
"""Create a directly loadable Llama-family package when compatible."""
1214

1315
self.export_log.append("Creating Llama-compatible adapter package...")
@@ -23,6 +25,8 @@ def export_llama_adapter(self) -> None:
2325
self.export_status.setText("Export: Llama adapter ready")
2426

2527
def convert_hf_to_gguf(self) -> None:
28+
if not bool(QApplication.instance().property("license_valid")):
29+
return
2630
"""Convert an HF-compatible model folder to GGUF through llama.cpp."""
2731

2832
model_dir_text = self.export_model_dir.text().strip()
@@ -92,4 +96,3 @@ def _apply_preset(self, preset: str) -> None:
9296
self.n_layer.setValue(8)
9397

9498

95-

interface/startup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
)
3535

3636

37-
APP_NAME = "DrunkenBot LLM-IDE"
37+
APP_NAME = "DrunkenBot-IDE"
3838
WINDOWS_APP_ID = "DrunkenBot.LLMIDE"
3939
LOGGER = logging.getLogger(__name__)
4040
APP_HOME_DIR = Path.home() / ".drunkenbot_ide"
@@ -353,7 +353,7 @@ def _build_ui(self) -> None:
353353

354354
body = QLabel(
355355
"Startup checks are complete.\n"
356-
"Choose how you want to begin with DrunkenBot LLM-IDE."
356+
"Choose how you want to begin with DrunkenBot-IDE."
357357
)
358358
body.setObjectName("Body")
359359
body.setAlignment(Qt.AlignLeft)

interface/startup_splash.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class StartupSplash(QDialog):
1515

1616
def __init__(self) -> None:
1717
super().__init__()
18-
self.setWindowTitle("DrunkenBot LLM-IDE")
18+
self.setWindowTitle("DrunkenBot-IDE")
1919
self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
2020
self.setModal(True)
2121
self.setMinimumSize(560, 760)
@@ -42,7 +42,7 @@ def __init__(self) -> None:
4242
else:
4343
logo.setPixmap(pixmap.scaled(118, 118, Qt.KeepAspectRatio, Qt.SmoothTransformation))
4444
logo.setAlignment(Qt.AlignCenter)
45-
title = QLabel("DrunkenBot LLM-IDE")
45+
title = QLabel("DrunkenBot-IDE")
4646
title.setObjectName("Title")
4747
title.setFont(QFont("Arial", 22))
4848
header.addWidget(logo)

interface/tabs/dataset_plan_tab.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from PySide6.QtCore import Qt
88
from PySide6.QtWidgets import (
9+
QApplication,
910
QCheckBox,
1011
QComboBox,
1112
QFormLayout,
@@ -265,6 +266,8 @@ def build_dataset_plan_tab(window) -> QWidget:
265266
window.external_dataset_download_button = QPushButton("Download latest dataset")
266267
window._tip(window.external_dataset_download_button, "Download, verify, and extract the latest dataset release into the install folder.")
267268
window.external_dataset_download_button.clicked.connect(window.download_latest_external_dataset)
269+
trial_mode = not bool(QApplication.instance().property("license_valid"))
270+
window.external_dataset_download_button.setEnabled(not trial_mode)
268271
external_form.addRow("Install folder", window._path_row(window.external_dataset_dir, directory=True))
269272
external_form.addRow("Status", window.external_dataset_version)
270273
external_form.addRow("", window.external_dataset_download_button)
@@ -287,6 +290,7 @@ def build_dataset_plan_tab(window) -> QWidget:
287290
window.dataset_stage.setMaximumWidth(240)
288291
window.include_conversation_datasets = QCheckBox("Online")
289292
window.include_conversation_datasets.setChecked(False)
293+
window.include_conversation_datasets.setEnabled(not trial_mode)
290294
purpose_row = QWidget()
291295
purpose_layout = QHBoxLayout(purpose_row)
292296
purpose_layout.setContentsMargins(0, 0, 0, 0)
@@ -320,6 +324,7 @@ def build_dataset_plan_tab(window) -> QWidget:
320324
conversation_form.addRow("Custom HF dataset", window.custom_huggingface_dataset)
321325
window.custom_huggingface_download = QPushButton("Download custom dataset")
322326
window.custom_huggingface_download.clicked.connect(window._download_custom_huggingface_dataset)
327+
window.custom_huggingface_download.setEnabled(not trial_mode)
323328
window._tip(window.custom_huggingface_download, "Enable the custom dataset and download it during the next dataset preparation run.")
324329
conversation_form.addRow("", window.custom_huggingface_download)
325330
window.conversation_sample_limit = window._spin(0, 2_000_000, 20000)
@@ -455,4 +460,3 @@ def populate_default_data_tree(window: Any, root: Path) -> None:
455460
tree.blockSignals(False)
456461
if not window.default_data_actions:
457462
tree.addTopLevelItem(QTreeWidgetItem(["No project/default data files were found.", "", ""]))
458-

0 commit comments

Comments
 (0)