Desktop GUI (PySide6)
ThesisAgents ships an optional desktop interface built on PySide6. It wraps the existing CLI flow (search → results table → export) in a window so users who don’t want a terminal can still drive the project.
Install
The GUI is gated behind a separate extra to avoid forcing PySide6 (~80 MB) on CLI / MCP users who don’t need it:
pip install thesisagents[gui]
If you also want the rich-tier enrichment path:
pip install thesisagents[gui,intelligence,mcp]
Launch
Three equivalent entry points:
thesisagents-gui # PyPI console script
thesisagents gui # CLI subcommand
py -m thesisagents gui # module entry, useful while developing
The Windows release .exe also accepts thesisagents.exe gui —
the bundle includes PySide6 and the source plugins so no extra
install is needed.
Tabs
The window has four tabs. All four are functional in this release.
Search
The core search → export flow.
Query — keyword string (UTF-8; CJK works).
Sources — checkbox grid; pre-selected to the same default set as the CLI (
arxiv,semantic_scholar,openalex,pubmed,dblp,crossref,openaire,europepmc,doaj,hal). Opt-in plugins (scholar,ieee,springer,core) are unchecked until you tick them and have the corresponding env var set in Settings.Slide language — picks the language for any
.pptxexported from this run. Defaults to English.Max results per source — 1 … 200 (same as the CLI
--max).Year from / Year to — leave at
—to disable.Top-tier venues only — mirrors the CLI’s default; un-tick to keep every result.
Press Search. The query runs on a worker thread so the UI stays responsive; the status bar reports progress and the results table populates when the run finishes.
Press Export…, pick an output directory, and the standard
.pptx + .xlsx + .bib triple lands there.
Settings
API keys, contact email, cookies file, and UI language are stored
locally via Qt’s
QSettings
(Windows registry, macOS plist, Linux ini). Saving a value also
exports the matching environment variable into the current process,
so the source plugins pick it up without a shell restart.
Fields:
UI label |
Env var written |
|---|---|
Anthropic API key |
|
Semantic Scholar API key |
|
NCBI / PubMed API key |
|
IEEE Xplore API key |
|
Springer Nature API key |
|
Crossref Plus token |
|
Contact email |
|
PDF cookies file |
|
Empty values clear the corresponding env var. Restart the app to refresh fetcher singletons that cached the env value at construction time.
Enrich
Drives the per-paper PDF + LLM enrichment step. The Search tab emits
a collection_ready signal as soon as the results table populates;
the Enrich tab catches it and renders a per-paper row showing:
The paper’s BibTeX key + title (clickable → opens the URL).
A PDF column — green tick when a
pdf_urlis on file (Unpaywall / S2 / arXiv / CORE.ac.uk lifted it), grey dash otherwise.An Enrich action that runs either the Python pipeline (Anthropic API, needs
ANTHROPIC_API_KEYin Settings) or surfaces the LLM-as-agent path for runs without an API key.A progress strip across the bottom — the worker reports the current paper, elapsed seconds, and a per-paper success/failure tally.
Authored summaries are merged back onto the in-memory PaperCollection,
so a subsequent Export picks up the rich-tier layout automatically.
Deck
The pre-export deck-shaping controls. Wires ExportOptions fields
behind Qt widgets:
Light mode checkbox — unchecked (default) ships the dark deck (slide bg
#12151B, body text#E5E7EB, brighter teal accent#2DD4BF). Tick it for the printable / well-lit-room variant (white bg + navy text). Mirrors the CLI--light-modeflag.Max slides per paper — integer spinner. Defaults to 25;
0means unlimited.Max figures per paper — controls how many
figures=entries the rich-tier layout actually renders. The priority trim keeps the cover / references / contributions slides intact and drops Q&A / figure / paper-table slides first when the cap kicks in.Include abstract checkbox — when off, the deck skips the abstract slide entirely (useful for an “executive overview only” variant).
The PPTX inspector / editor surface (drives pptx_inspect /
pptx_update_slide / pptx_reorder_slides / pptx_delete_slide /
pptx_add_slide) is wired to the same shape names the exporter
produces — title, meta, body, kpi, rq_question, figure,
accent_top, accent_left — so the editor list view labels each
slide by its semantic role rather than by raw shape index.
i18n
The UI ships in all 14 languages that the slide-deck exporter supports: English, 繁體中文, 简体中文, 日本語, Español, Français, Deutsch, 한국어, Português, Русский, Italiano, Tiếng Việt, हिन्दी, Bahasa Indonesia.
Pick the language under Settings → Interface language (the dropdown shows each language in its own script). Restart the app to apply.
First-run behaviour: if no language is saved yet, the app reads
the OS locale via QLocale().name() and maps it to the closest
supported code (e.g. zh_TW → zh-tw, es_ES → es,
zh-Hant-TW → zh-tw). Unsupported locales fall back to English.
Two separate i18n tables live in the repo:
thesisagents/gui/i18n.py— UI labels (this page).thesisagents/exporters/i18n.py— slide-deck output strings.
They’re kept in lockstep by tests/gui/test_i18n.py::test_supported _languages_match_deck_table. Adding a key is a single-file change;
the per-key, per-language coverage test catches any missing entry
at PR time.
Responsive layout & HiDPI
The window has a minimum size of 900×600 (still fits a 720p laptop) and a default of 1280×800.
Each tab page lives inside a
QScrollAreawithwidgetResizable=True, so the form widgets stretch horizontally with the window width and reveal a vertical scrollbar when the window shrinks below the form’s natural height.HiDPI scaling is enabled at boot via
QT_ENABLE_HIGHDPI_SCALING=1andQT_SCALE_FACTOR_ROUNDING_POLICY=PassThrough. Both are set beforeQApplicationis constructed, which is the only safe time to pin them.The default font is bumped to point size 10 (Qt’s platform default is 8 on some Windows machines) so CJK glyphs stay readable on dense screens. The font family list includes Windows-shipped CJK / Devanagari fallbacks (Microsoft JhengHei UI, Yu Gothic UI, Malgun Gothic, Nirmala UI) so a missing glyph in the primary font cascades cleanly rather than rendering a tofu box.
Threading model
Every backend call runs off the main thread:
AsyncWorkerwraps a coroutine factory and callsasyncio.runinsideQRunnable.run— used forrun_search, single-paper fetches, anything that toucheshttpx.AsyncClient.BlockingWorkerwraps a plain function — used forexport_collection, which renders the.pptxvia python-pptx.
Both emit finished(object) / failed(object) signals on
completion; the receiving slot lives on the main thread so it can
update widgets safely.
Testing the GUI
The test suite under tests/gui/ uses pytest-qt (installed by
the [dev] extra). It mocks the backend so no live HTTP is made:
pip install -e ".[dev]"
py -m pytest tests/gui/
Tests fall into three families: i18n coverage, Qt model behaviour, and page-level wiring (a search button click populates the table, the export button stays disabled until results arrive, settings round-trip through QSettings).
Known limitations
The Settings page does not validate keys against the live API — validation would leak the key into HTTP logs and slow down save. An invalid key surfaces later as a
ConfigError/ 401 from the relevant source plugin.The window does not yet remember its size / position between runs. Add
QMainWindow.saveGeometry/restoreGeometryif you want that.