Compare commits

...

4 Commits

Author SHA1 Message Date
5cf3c8d0c1 Add image assets 2024-03-01 17:50:33 +01:00
7b3210169a Update training info in readme 2024-03-01 17:20:02 +01:00
e34845ab24 Add comment 2023-12-25 19:05:27 +01:00
400753a9a2 Allow custom data directory 2023-12-25 14:35:01 +01:00
14 changed files with 34 additions and 32 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/mstile-150x150.png?v=1"/>
<TileColor>#a36490</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Public/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@ -5,13 +5,13 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="robots" content="noindex"/> <meta name="robots" content="noindex"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png?v=1"/> <link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png?v=1"/>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/icons/favicon-32x32.png?v=1"/> <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png?v=1"/>
<link rel="icon" type="image/png" sizes="16x16" href="/assets/icons/favicon-16x16.png?v=1"/> <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png?v=1"/>
<link rel="manifest" href="/assets/icons/site.webmanifest?v=1"/> <link rel="manifest" href="/assets/site.webmanifest?v=1"/>
<link rel="shortcut icon" href="/assets/icons/favicon.ico?v=1"/> <link rel="shortcut icon" href="/assets/favicon.ico?v=1"/>
<meta name="msapplication-TileColor" content="#da532c"> <meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-config" content="/assets/icons/browserconfig.xml?v=1"/> <meta name="msapplication-config" content="/assets/browserconfig.xml?v=1"/>
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff"/>
<link href="grid.css?v=2" rel="stylesheet"/> <link href="grid.css?v=2" rel="stylesheet"/>
<meta name="author" content="Christoph Hagen"/> <meta name="author" content="Christoph Hagen"/>

View File

@ -51,31 +51,7 @@ Note: The data for the mosaic is currently not updated automatically, since Swif
## Classifier training ## Classifier training
The main server is running on Linux, which doesn't provide the CreateML framework required for classifier training. The main server is running on Linux, which doesn't provide the CreateML framework required for classifier training.
This has to be done on macOS using the `train.swift` script in the `Training` folder. This has to be done on macOS using the [Caps-Train](https://christophhagen.de/git/ch/Caps-Train) repository.
It will:
- Fetch the current image catalog by checking missing and changed images
- Train a classifier on the image set
- Increment the classifier version and upload the new model
- Update the list of caps which can be recognized using the classifier
- Create missing thumbnails for each cap for the cap grid
A configuration file is required to run the training, with a valid access token for the server:
```json
{
"imageDirectory": "../Public/images",
"classifierModelPath": "../Public/classifier.mlmodel",
"trainingIterations": 20,
"serverPath": "https://mydomain.com/caps",
"authenticationToken": "mysecretkey",
}
```
The configuration file `config.json` must be located in the folder from which the script is run.
```bash
swift train.swift
```
## Future work ## Future work
- Create thumbnails on the server using [JPEG](https://github.com/kelvin13/jpeg) - Create thumbnails on the server using [JPEG](https://github.com/kelvin13/jpeg)

View File

@ -3,6 +3,7 @@
"maxBodySize" : "2mb", "maxBodySize" : "2mb",
"logPath": "\/var\/log\/caps/metrics", "logPath": "\/var\/log\/caps/metrics",
"serveFiles": true, "serveFiles": true,
"dataDirectory" : "/ch/data/caps",
"writers" : [ "writers" : [
"auth_key_1" "auth_key_1"
] ]

View File

@ -20,6 +20,20 @@ struct Config: Codable {
/// Authentication tokens for remotes allowed to write /// Authentication tokens for remotes allowed to write
let writers: [String] let writers: [String]
/**
The folder where the data should be stored.
If the folder is set to `nil`, then the `Resources` folder is used.
*/
let dataDirectory: String?
func customDataDirectory(or publicDirectory: String) -> URL {
guard let dataDirectory else {
return URL(fileURLWithPath: publicDirectory)
}
return URL(fileURLWithPath: dataDirectory)
}
func logURL(possiblyRelativeTo resourcesDirectory: URL) -> URL { func logURL(possiblyRelativeTo resourcesDirectory: URL) -> URL {
guard let logPath else { guard let logPath else {
return resourcesDirectory.appendingPathComponent("logs") return resourcesDirectory.appendingPathComponent("logs")

View File

@ -31,7 +31,8 @@ func configure(_ app: Application) async throws {
app.http.server.configuration.port = config.port app.http.server.configuration.port = config.port
app.routes.defaultMaxBodySize = .init(stringLiteral: config.maxBodySize) app.routes.defaultMaxBodySize = .init(stringLiteral: config.maxBodySize)
server = CapServer(in: URL(fileURLWithPath: publicDirectory)) let dataDirectory = config.customDataDirectory(or: publicDirectory)
server = CapServer(in: dataDirectory)
provider = .init(observer: monitor, accessManager: config.writers) provider = .init(observer: monitor, accessManager: config.writers)
provider.asyncScheduler = asyncScheduler provider.asyncScheduler = asyncScheduler