Skip to content

Contributing

JHubi1 edited this page Sep 14, 2024 · 13 revisions

Ollama App is created using Flutter, a modern and robust frontend framework designed to make a single codebase run on multiple target platforms. The framework itself is based on the Dart programming language.

Translations

Ollama App does support multiple languages. Currently, available are:

  • English (fallback)
  • German
  • Chinese (simplified)
  • Italian
  • Persian
  • Turkish

The tick is set if the language is translated with 100%. This might not be up-to-date, check the project page to get the latest progress.

In case the language you're looking for isn't listed, you can check if the development is in progress on the Crowdin project page. If not, you can always contribute.

Building

Note

It might be simpler for someone who doesn't want to contribute to use GitHub actions for building. Follow the steps below to learn how to do that.

To get a running and working executable out of this project, you have to follow a few steps, but trust me, it's worth it.

First, follow the Flutter installation guide by selecting Android as the first app type. Then follow these steps till you have your custom key.properties. Place it into the android folder at the root of the project.

If you also want to build for (experimental) desktop, again follow the Flutter installation guide, but this time select desktop as target. Skip the installation of the Flutter SDK if you have already done that.

Make sure dart is available as a command, then execute the build script by running the following command in the root directory of the repository:

dart run script/build.dart

Wait for it to finish processing. Then go to build/.output. There you'll find everything you need, the normal Android app and the experimental Windows build. All exports will be obfuscated by default.

Custom Builds

Warning

"Secrets", or not so publicly known host for example, entered in these options could possibly be retrieved by scanning through the code. Nothing on the client can be seen as secured. To make retrieving sensitive information more difficult, you should follow the steps in the section Hiding Secrets as well.

Now it's going to get interesting. Ollama App is built in a way that you can easily create custom-builds with custom properties and behavior. The configuration values can be found at the top of lib/main.dart. Currently, these are available:

// use host or not, if false dialog is shown
const bool useHost = false;
// host of ollama, must be accessible from the client, without trailing slash
// ! will always be accepted as valid, even if [useHost] is false
const String fixedHost = "http://example.com:11434";
// use model or not, if false selector is shown
const bool useModel = false;
// model name as string, must be valid ollama model!
const String fixedModel = "gemma";
// recommended models, shown with a star in model selector
const List<String> recommendedModels = ["gemma", "llama3"];
// allow opening of settings
const bool allowSettings = true;
// allow multiple chats
const bool allowMultipleChats = true;

useHost and useModel decide whether you want fixedHost and fixedModel to control anything. fixedHost and fixedModel decide about the value that has to be used. That can be practical in case you try to create an app specific to your instance. The value that is chosen for fixedHost is always accepted as valid, even if the host is not accessible from that port. This cannot be changed.

recommendedModels is a list of models that will be listed as recommended in the Model Selector. They are more like personal preferences. If empty, no model will be preferred.

allowSettings will disable the settings screen. But it will also skip the welcome dialog at first startup and remove the ability to rename chats. For this to be available, useHost must be true or the build will not be in a working state.

allowMultipleChats simply removes the New Chat option in the Side Menu and will load up the only available chat on app startup.

After having made your changes, follow the steps for Building above. The finished executable will have the options you enabled. They cannot easily be changed during runtime.

Hiding Secrets

To hide your set host, you can use Base64 encoding. That will hide the plain text url from the code and will make it significantly more difficult for simple code scraping to catch your host. Be careful though, this won't be a rock-solid protection, the host, for example, can still be caught by monitoring the network traffic.

Ollama App includes a simple helper script to convert text into Base64. Just run the following command with the text you'd like to protect from the root directory of the repository:

dart run scripts/base64.dart <your text>

This will return the text Base64 encoded. http://example.com:11434 as an example will get converted to the text aHR0cDovL2V4YW1wbGUuY29tOjExNDM0.

Now what do we do with this useless piece of text? The solution is pretty easy to add to the code. Make sure you have the latest commit from the original repo. Then open lib/main.dart in your favorite editor and edit the configuration code as described above in Custom Builds. Modify the wanted value like that:

...
- const String fixedHost = "http://example.com:11434";
+ final String fixedHost = utf8.decode(base64Decode("aHR0cDovL2V4YW1wbGUuY29tOjExNDM0"));
...

Replace const with final, so the compiler knows that value is dynamic. Make sure to also replace aHR0cDovL2V4YW1wbGUuY29tOjExNDM0 with the string previously generated by you.

List value can be decoded by using a function called jsonEncode after decoding the value. The original text (["gemma", "llama3"], in the presented case) can just be put into the tool shown above, the value can then be parsed like that:

...
- const List<String> recommendedModels = ["gemma", "llama3"];
+ final List<String> recommendedModels = jsonDecode(utf8.decode(base64Decode("W2dlbW1hLCBsbGFtYTNd")));
- const bool allowSettings = true;
+ final bool allowSettings = jsonDecode(utf8.decode(base64Decode("dHJ1ZQ==")));
...

Keep in mind that the shown method will only make it harder to discover values in the executable, there's no possibility of completely hiding anything in code that's facing the user.

GitHub Action

In case you have sniffed around in the repo a bit, you might have discovered that there's a GitHub action stored here. And yes, you can use GitHub actions to safely build Ollama App without downloading anything onto your local device.

Fork the Ollama App repository and continue with the following steps for the platforms you want to build to.

Android only:

A working instance of GnuPG (short GPG) is required for building. You can download this from the official download site. Also required is a java installation of any version, I can recommend you download the installer from Adoptium.

After doing that, find the location java is installed, go into the build folder, and open a terminal there. Follow the steps described in these instructions to generate a keystore, but replace keytool with ./keytool (or .\keytool on Windows) in the commands. Enter a passphrase and remember it!

After following the steps above, navigate to your user directory, open the terminal and execute the following command:

gpg -c -a upload-keystore.jks

A popup will appear, and you'll be asked to enter die passphrase you set above. This will create a new file in your user directory called upload-keystore.jks.asc. Open it, it's a simple text file, and copy the content. Keep it secret, though!

Go on GitHub and open your forks settings, under "Secrets and variables" you'll find a tab called "Actions". Click "New repository secret". Enter ANDROID_KEYSTORE as name and paste the text you just copied as content. Create another secret called ANDROID_KEYSTORE_PASSPHRASE and type in your passphrase.

All platforms:

Click on the tab "Actions" and open the pinned action "Build app". Tap on "Run workflow", select the platforms you'd like to build to, and click the second "Run workflow" button. This will be linting the code and then building the executables. All executables are obfuscated by default.

After around five minutes, the build should be done. Reload the page, and you can find the files under the summary tab.