theJayTea / WritingTools

The world's smartest system-wide grammar assistant; a better version of the Apple Intelligence Writing Tools. Works with the free Gemini API, local LLMs, and other cloud providers.
GNU General Public License v3.0
426 stars 22 forks source link

Optimize the size of the executable #9

Open user1823 opened 1 week ago

user1823 commented 1 week ago

First of all, thanks for this great software. It is indeed very useful.

However, I feel that the size of the executable is too large for a software that just sends a prompt to an online service (Gemini) and fetches the result.

Is it possible to reduce the size of the executable somehow? For example, by reducing the number of dependencies or by substituting some of the dependencies by slimmer alternatives (like replacing PySide6 with PySide6-Essentials)?

Nisekoi-1 commented 1 week ago

Yeah, 100 MB of RAM is a bit much.

theJayTea commented 1 week ago

Hi @user1823 !

You're right, it does use more RAM than I'd like (although the CPU usage is super low).

I slimmed down the PySide6 implementation with a new Build File, and tried a whole lot of optimisations with it but I can't seem to get it down below 100 MB myself without using something like UPX (which results in antivirus false positives).

I'd welcome any contributions you can make to optimising the file size!

user1823 commented 1 week ago

Sorry, but I don't have the necessary expertise to help you with this.

But, maybe you can try using --onedir instead of --onefile with PyInstaller locally and see which component occupies the largest amount of disk space, and then try to optimize that.

Anyway, congratulations for reducing the file size by ~10 MB despite including additional functionality.

theJayTea commented 1 week ago

I already tried both of them lol, they both made it larger (~150-200 MB) XD

It's the libraries that occupy the most space, and I've stripped them as much as I currently could.

And haha thanks.

Nisekoi-1 commented 1 week ago

Would it be possible to implement a feature where the app enters 'sleep' mode to use less RAM while running in the background? When assigned keys are pressed, the app would 'wake up,' albeit with a slightly slower response speed. It would remain active for 5-10 minutes before going back to 'sleep'. This could be made an optional toggle for users who prefer to keep the app running continuously with faster response times.

user1823 commented 1 week ago

Would it be possible to implement a feature where the app enters 'sleep' mode to use less RAM while running in the background?

I think Windows does that automatically. In the screenshot below, see that Writing Tools is using just 3.6 MB of RAM. When the app first starts, it uses ~100 MB of RAM, but the RAM usage eventually decreases to ~3-4 MB.

image

The current issue is aimed at reducing the size of the .exe file.

Vadim-Karpenko commented 1 week ago

Building from source results in 66.8MB for me. The only difference is that I use virtualenv to make sure I have only the required stuff installed and nothing else. image

Try the following

pip install virtualenv
virtualenv myvenv
myvens\Scripts\activate

Then, install the requirements and build the file. It should make a difference.

uninstall-your-browser commented 1 week ago

Maybe you could use nuitka. It could also reduce the start up time for the application too. The documentation is a little bit hard to follow, but it has a plugin for pyside (--enable-plugin=pyside6)

You might want to use the pyside6-essential package which excludes alot of the stuff that you are excluding in the pyinstaller build script.

Also, I noticed you talked about packaging for Linux on reddit. The only cross-distro way I found to do that with a pyside app is to make it a flatpak. There are a few other potential problems, but maybe that would be better to talk about in a separate issue.

theJayTea commented 1 week ago

@Vadim-Karpenko , wow. I did use a venv, but I don’t think I did it optimally/correctly, so I’ll work on this for the next update and re-compilation. Thanks for sharing that!

theJayTea commented 1 week ago

@uninstall-your-browser , I did initially use Nuitka (the first release uses it!) but it led to constant antivirus false positives, unfortunately. This is a difficult choice.

I looked into PySide6-Essentials, but swapping from PySide6 import... to from PySide6-Essentials import did not work at all.

I don't have a perfect grasp on how they've structured this, but it seems that the main pyside-6 is already just the essentials, with the additional stuff as pyside-6 addons (which we're not using)?

Regardless, in the build script, I explicitly excluded almost all the other PySide6 stuff that we aren't using.

uninstall-your-browser commented 1 week ago

I looked into PySide6-Essentials, but swapping from PySide6 import... to from PySide6-Essentials import did not work at all.

I don't think you need to change anything, it just excludes some extra stuff like the web browser view

Were the AV problems with building it or running it? Because I think it does something funny with injecting resources into the exe when building, which is something that viruses typically do.

theJayTea commented 6 days ago

Nuitka caused problems when running it. This is a known issue with it.

The reason is that it obfuscates and minifies the code a ton (to make it smaller), which is also something that malware does to hide its functionality.

In addition, it converts the Python code to C and uses a C compiler, further obfuscating what's going on.

It was so bad that even adding exclusions in my AV software didn't reliably work, across PCs and AVs haha.

theJayTea commented 6 days ago

I tried using PySide6-Essentials again. While it resulted in a 45mb exe, the program didn't work with it (the pop-up never showed up) :(

nightkall commented 5 days ago

Building from source results in 66.8MB for me. The only difference is that I use virtualenv to make sure I have only the required stuff installed and nothing else. image

Try the following

pip install virtualenv
virtualenv myvenv
myvens\Scripts\activate

Then, install the requirements and build the file. It should make a difference.

I tried that

pip install virtualenv
virtualenv myvenv
myvenv\Scripts\activate

While in (myvenv), then:

cd path\to\Windows_and_Linux
pip install -r requirements.txt
pip install pyinstaller
pythonw pyinstaller-build-script.py

The compiled .exe is in \WritingTools\Windows_and_Linux\dist\Writing Tools.exe and is 62,8 MB (65.936.818 bytes) in file size and 500 MB+ in memory size.

rfV5JGaT3H

So yes, it's smaller but it has more VirusTotal antivirus positives than the official release:

Official Writing.Tools.v4.zip VirusTotal report: NpPmT78d3T

My compiled version VirusTotal report: VCYW9KjKUi

And more threads: 3aSioAOtP5

theJayTea commented 5 days ago

Hey @nightkall, it's great to know that it compiled to a much smaller file size for you. I don't think I used the venv correctly, and PyInstaller must've included a lot more installed packages for me (I'd first installed pyside6-essentials and it didn't work, and then installed the whole pyside 6 again in my venv so that may have added to bloat?). Regardless, for the next release I'll compile it in my VM inside a venv to just get this optimised and remove any scope of my error haha.

About the memory use, it doesn't actually use up ~500MB, that's comitted memory (not in use, just the OS saying that it could use that much if it wanted to).

image

It's quite normal for committed memory to report higher than the memory actually in use - Task Manager: image

With that said, I'm sure we can optimise memory use further down the line, as it is a bit much.

About the threads, that's curious. Did you launch both of them around the same time? I'm trying to rule out it being a minor memory leak.

nightkall commented 3 days ago

About the memory use, it doesn't actually use up ~500MB, that's comitted memory (not in use, just the OS saying that it could use that much if it wanted to). It's quite normal for committed memory to report higher than the memory actually in use - Task Manager:

You're right about the committed memory, I forgot to show Working set column.

It's quite normal for committed memory to report higher than the memory actually in use - Task Manager: About the threads, that's curious. Did you launch both of them around the same time? I'm trying to rule out it being a minor memory leak.

I just launched both at the same time and your compiled version has more threads than mine by default, without invoking any commands.

Here is an updated screenshot:

Writing Tools Mem-Threads