Updated Contributing (markdown)

JHubi1 2024-08-05 16:34:39 +02:00
parent 6764c6db71
commit 618b9765d2
1 changed files with 67 additions and 18 deletions

@ -14,40 +14,89 @@ The tick is set if the language is translated with 100%. This might not be up-to
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](https://crowdin.com/project/ollama-app). If not, you can always contribute.
## Custom Builds
## Building
Now it's going to get interesting. The app is built in a way so you can easily create custom-builds. Currently, there are these values that can be customized:
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](https://docs.flutter.dev/get-started/install) by selecting Android as the first app type. Then follow [these steps](https://docs.flutter.dev/deployment/android#signing-the-app) 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](https://docs.flutter.dev/get-started/install), 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 or added as the default program for `.dart`. Then execute the build script by running the following command in the root directory of the repository:
```bash
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 retriefed 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](#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:
```dart
// use host or not, if false dialog is shown
const useHost = false;
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 fixedHost = "http://example.com:11434";
const String fixedHost = "http://example.com:11434";
// use model or not, if false selector is shown
const useModel = false;
const bool useModel = false;
// model name as string, must be valid ollama model!
const fixedModel = "gemma";
// recommended models, shown with as star in model selector
const recommendedModels = ["gemma", "llama3"];
const String fixedModel = "gemma";
// recommended models, shown with a star in model selector
const List<String> recommendedModels = ["gemma", "llama3"];
// allow opening of settings
const allowSettings = true;
const bool allowSettings = true;
// allow multiple chats
const allowMultipleChats = true;
const bool allowMultipleChats = true;
```
They can be found at the top of `lib/main.dart`. `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.
> `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](#model-selector). They are more like personal preferences. If empty, no model will be preferred.
> `recommendedModels` is a list of models that will be listed as recommended in the [Model Selector](#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.
> `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](#side-menu) and will load up the only available chat on app startup.
> `allowMultipleChats` simply removes the `New Chat` option in the [Side Menu](#side-menu) and will load up the only available chat on app startup.
## Building
After having made your changes, follow the steps for [Building](#building) above. The finished executable will have the options you enabled. They cannot easily be changed during runtime.
But how do you create a custom build?
#### Hiding Secrets
First, follow the [Flutter Installation Guide](https://docs.flutter.dev/get-started/install) by selecting Android as the first app type. Then follow [these steps](https://docs.flutter.dev/deployment/android#signing-the-app) till you have your custom `key.properties`. Place it into the `android` folder at the root of the project.
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.
Make sure dart is available as a command or added as the default program for `.dart`. Then execute `scripts/build.dart` and 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.
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:
```bash
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](#custom-builds). Modify the wanted value like that:
```dart
...
- 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:
```dart
...
- 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.