Read a question from a .txt file and turn it into a good looking PyQt5 desktop app that solves it, using Gemini (directly or through a Cloudflare Worker). The interface is generated as a Qt Designer .ui file and the logic as a test.py that loads it.
Project description
PyQt6-extensions
A command line tool named extend. You put a question in a .txt file, run one
command, and it uses Google's Gemini model to write a good looking PyQt5
desktop app that actually solves the question. The interface comes back as a Qt
Designer file (designer.ui) and the logic as a Python file (test.py) that
loads it with PyQt5.uic — the same clean split you would get from Qt Designer by
hand. It launches the app to check it starts without crashing, asks Gemini to fix
anything that breaks, and saves both files.
The clever part: instead of putting a Gemini key on every user's machine, the tool can talk to a small Cloudflare Worker that you deploy once. Your Gemini key lives only inside that Worker as a secret, so people can use the tool on your key without ever seeing it.
extend question.txt
What it does
- Reads the question from the
.txtfile you point it at. - Asks how big you want the program (a hint for the model).
- Sends the question to Gemini (through your Worker, or directly) and asks for
two files: a
designer.ui(a Qt Designer XML layout) for the interface and atest.pythat loads it withPyQt5.uicand adds the logic that solves the task. - Launches the generated app headless — with
designer.uisitting next totest.pyso the load path works — to make sure it starts. The.uiis also checked as valid XML. If anything crashes, the error goes back to Gemini for a fix (up to--attemptstimes). - Saves both
designer.uiandtest.pynext to your question file.
With
--plainthere is no interface, so it stays a singletest.pyfile.
Install
pip install . # the tool + PyQt5 (needed to run the apps)
pip install ".[direct]" # also add this if you will call Gemini directly
Once published you would instead run pip install PyQt6-extensions.
Two ways to run it
A) Through your Cloudflare Worker (recommended — your key stays hidden)
Deploy the Worker in cloudflare-worker/ once (steps below), then point the tool
at it. Users need no Gemini key of their own.
The easiest way to share it: after you deploy, paste your Worker URL into
pyqt6_extensions/config.py:
DEFAULT_WORKER_URL = "https://pyqt6-extensions-worker.YOURNAME.workers.dev"
Now anyone you give these files to can just run extend question.txt with no
setup — no key, no URL, no access code. (You can also override per run with
--worker-url or the EXTEND_WORKER_URL environment variable.)
B) Directly with your own Gemini key (good for local development)
pip install ".[direct]"
export GEMINI_API_KEY="your_key_here"
extend question.txt --lines 60
If both are set, the Worker wins.
Deploy the Cloudflare Worker
The Worker is the piece that holds your key and calls Gemini. Everything is in
cloudflare-worker/.
npm install -g wrangler # Cloudflare's CLI
cd cloudflare-worker
wrangler login
# store your key as a SECRET (it never lives in the code)
wrangler secret put GEMINI_API_KEY # paste your Gemini key
wrangler deploy
wrangler deploy prints a URL like
https://pyqt6-extensions-worker.YOURNAME.workers.dev. Paste that into
pyqt6_extensions/config.py (or share it as EXTEND_WORKER_URL).
- The
GEMINI_API_KEYis a secret, set only withwrangler secret put. It never appears in the code, the repo, or the files you hand out. wrangler.tomlships withALLOW_OPEN = "true", which means no access code: anyone with the URL can use it. That is what you asked for.- If you ever want to lock it down later, delete the
ALLOW_OPENline and runwrangler secret put ACCESS_CODE; callers then pass it with--access-code.
Because it is open, you pay for everyone who has the URL. If usage or cost ever becomes a worry, add an access code or rate limiting.
Use it
Put your question in a text file:
# question.txt
A tip calculator: enter the bill and a tip percent, show the tip and the total.
Then run:
extend question.txt --lines 60
This writes two files next to the question: designer.ui and test.py. Open the
result with python test.py (keep designer.ui in the same folder — test.py
loads it from next to itself) and you get a styled PyQt5 window that does the job.
You can also open designer.ui in Qt Designer to tweak the look by hand.
Run it truly in the background
extend question.txt --lines 60 --background
# returns immediately, keeps working while you use your editor,
# and writes a progress log next to test.py
Change what you already made
Instead of starting over, hand the files you already generated back to Gemini with
a change request. It reads test.py (and designer.ui, if present) from the
output location, applies your change, re-checks it, and saves the result:
extend question.txt --prompt "make the button green and add a Clear button"
You can also run it without the question file, right where the files live:
extend --prompt "use a bigger font for the result" # acts on ./test.py + ./designer.ui
extend --prompt "add an About dialog" -o build/test.py # or point -o at the file
If the existing app is still a single self-contained file (for example one made
before the two-file split), --prompt will split it into designer.ui + test.py
while applying your change.
--promptneeds a direct Gemini key or an up-to-date Worker, because the change request is a newer feature. If your default Worker predates it, redeploy it (cd cloudflare-worker && wrangler deploy) or run withGEMINI_API_KEYset.
Make a plain text program instead of a GUI
extend question.txt --lines 20 --plain
Options
| Option | What it does |
|---|---|
--prompt "..." |
Change the files you already made instead of starting fresh. The question file is optional with this. |
--lines N |
Rough size hint for the model. Asked for if left out. |
--worker-url URL |
Your Cloudflare Worker URL. Falls back to EXTEND_WORKER_URL. |
--access-code CODE |
Access code for the Worker. Falls back to EXTEND_ACCESS_CODE. |
--api-key KEY |
Gemini key for direct calls. Falls back to GEMINI_API_KEY. |
--model NAME |
Gemini model for direct calls. Default gemini-3.1-pro-preview. |
--plain |
Make a simple text program instead of a PyQt5 app. |
--output PATH, -o PATH |
Where to save test.py. Default next to the question. designer.ui is written in the same folder. |
--attempts N |
How many times to auto-fix bugs. Default 4. |
--background |
Detach and keep working even if you close the terminal. Needs --lines. |
--quiet |
Print nothing while it works. |
How the checking works
- The code is parsed first, so syntax errors are caught immediately.
- The
designer.uifile is checked as valid XML with a<ui>root before anything runs, so a broken layout is caught early and sent back for a fix. - For a GUI app both files are written to a temporary folder together and the
app is launched headless (
QT_QPA_PLATFORM=offscreen), soPyQt5.uicreally loadsdesigner.ui. The Qt event loop is short circuited so a healthy app builds its whole window and then exits cleanly. If it crashes while starting, or hangs before the window opens, the error is sent back to Gemini for a fix. This confirms the app really runs, but it cannot prove the answer is correct, so still check the result yourself. - If PyQt5 or a display is not available on your machine, the launch step is skipped (the code is still syntax checked) and you are told so.
- For a
--plainprogram it is run with sample input and a time limit, and any crash or endless loop is sent back for a fix.
A note on the model name
You asked for "Gemini 3.1 pro preview". The real id is gemini-3.1-pro-preview
(the older gemini-3-pro-preview was retired). It is the default. If your key is
not allow listed for it, both the tool and the Worker fall back to
gemini-2.5-pro.
A note on the package name
PyQt6-extensions is the name you chose, so it is what this uses, even though the
generated apps use PyQt5. If you ever publish to public PyPI, that name may be
flagged as misleading; renaming is just the name field in pyproject.toml.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyqt6_extensions-0.3.0.tar.gz.
File metadata
- Download URL: pyqt6_extensions-0.3.0.tar.gz
- Upload date:
- Size: 21.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a372aefd42091111b7b92b37f1f00cd9ec10c04f38168231f53365a96588f6e
|
|
| MD5 |
91c83bcefcf42e7d9b8f74e24455fe9e
|
|
| BLAKE2b-256 |
6e1d2836ebae7d59b203f8d21ee3e79c3dd008814ba432006b96804bcc88b8f7
|
File details
Details for the file pyqt6_extensions-0.3.0-py3-none-any.whl.
File metadata
- Download URL: pyqt6_extensions-0.3.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6377453df7c72f03d00a011992e10111d0137a8e96ea632093575bbd47a1f065
|
|
| MD5 |
275cf6792c931f3525dbf3471f232541
|
|
| BLAKE2b-256 |
8a00dfe499f29ffc7ac82d00ce9011908584c632f4c03831f9a9a5126258c0f0
|