mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
feat(server): ocr sync
This commit is contained in:
Generated
+1
@@ -582,6 +582,7 @@ Class | Method | HTTP request | Description
|
|||||||
- [SyncAssetFaceV2](doc//SyncAssetFaceV2.md)
|
- [SyncAssetFaceV2](doc//SyncAssetFaceV2.md)
|
||||||
- [SyncAssetMetadataDeleteV1](doc//SyncAssetMetadataDeleteV1.md)
|
- [SyncAssetMetadataDeleteV1](doc//SyncAssetMetadataDeleteV1.md)
|
||||||
- [SyncAssetMetadataV1](doc//SyncAssetMetadataV1.md)
|
- [SyncAssetMetadataV1](doc//SyncAssetMetadataV1.md)
|
||||||
|
- [SyncAssetOcrV1](doc//SyncAssetOcrV1.md)
|
||||||
- [SyncAssetV1](doc//SyncAssetV1.md)
|
- [SyncAssetV1](doc//SyncAssetV1.md)
|
||||||
- [SyncAuthUserV1](doc//SyncAuthUserV1.md)
|
- [SyncAuthUserV1](doc//SyncAuthUserV1.md)
|
||||||
- [SyncEntityType](doc//SyncEntityType.md)
|
- [SyncEntityType](doc//SyncEntityType.md)
|
||||||
|
|||||||
Generated
+1
@@ -321,6 +321,7 @@ part 'model/sync_asset_face_v1.dart';
|
|||||||
part 'model/sync_asset_face_v2.dart';
|
part 'model/sync_asset_face_v2.dart';
|
||||||
part 'model/sync_asset_metadata_delete_v1.dart';
|
part 'model/sync_asset_metadata_delete_v1.dart';
|
||||||
part 'model/sync_asset_metadata_v1.dart';
|
part 'model/sync_asset_metadata_v1.dart';
|
||||||
|
part 'model/sync_asset_ocr_v1.dart';
|
||||||
part 'model/sync_asset_v1.dart';
|
part 'model/sync_asset_v1.dart';
|
||||||
part 'model/sync_auth_user_v1.dart';
|
part 'model/sync_auth_user_v1.dart';
|
||||||
part 'model/sync_entity_type.dart';
|
part 'model/sync_entity_type.dart';
|
||||||
|
|||||||
Generated
+2
@@ -688,6 +688,8 @@ class ApiClient {
|
|||||||
return SyncAssetMetadataDeleteV1.fromJson(value);
|
return SyncAssetMetadataDeleteV1.fromJson(value);
|
||||||
case 'SyncAssetMetadataV1':
|
case 'SyncAssetMetadataV1':
|
||||||
return SyncAssetMetadataV1.fromJson(value);
|
return SyncAssetMetadataV1.fromJson(value);
|
||||||
|
case 'SyncAssetOcrV1':
|
||||||
|
return SyncAssetOcrV1.fromJson(value);
|
||||||
case 'SyncAssetV1':
|
case 'SyncAssetV1':
|
||||||
return SyncAssetV1.fromJson(value);
|
return SyncAssetV1.fromJson(value);
|
||||||
case 'SyncAuthUserV1':
|
case 'SyncAuthUserV1':
|
||||||
|
|||||||
+217
@@ -0,0 +1,217 @@
|
|||||||
|
//
|
||||||
|
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||||
|
//
|
||||||
|
// @dart=2.18
|
||||||
|
|
||||||
|
// ignore_for_file: unused_element, unused_import
|
||||||
|
// ignore_for_file: always_put_required_named_parameters_first
|
||||||
|
// ignore_for_file: constant_identifier_names
|
||||||
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
|
|
||||||
|
part of openapi.api;
|
||||||
|
|
||||||
|
class SyncAssetOcrV1 {
|
||||||
|
/// Returns a new [SyncAssetOcrV1] instance.
|
||||||
|
SyncAssetOcrV1({
|
||||||
|
required this.assetId,
|
||||||
|
required this.boxScore,
|
||||||
|
required this.id,
|
||||||
|
required this.isVisible,
|
||||||
|
required this.text,
|
||||||
|
required this.textScore,
|
||||||
|
required this.x1,
|
||||||
|
required this.x2,
|
||||||
|
required this.x3,
|
||||||
|
required this.x4,
|
||||||
|
required this.y1,
|
||||||
|
required this.y2,
|
||||||
|
required this.y3,
|
||||||
|
required this.y4,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Asset ID
|
||||||
|
String assetId;
|
||||||
|
|
||||||
|
/// Confidence score of the bounding box
|
||||||
|
num boxScore;
|
||||||
|
|
||||||
|
/// OCR entry ID
|
||||||
|
String id;
|
||||||
|
|
||||||
|
/// Whether the OCR entry is visible
|
||||||
|
bool isVisible;
|
||||||
|
|
||||||
|
/// Recognized text content
|
||||||
|
String text;
|
||||||
|
|
||||||
|
/// Confidence score of the recognized text
|
||||||
|
num textScore;
|
||||||
|
|
||||||
|
/// Top-left X coordinate (normalized 0–1)
|
||||||
|
num x1;
|
||||||
|
|
||||||
|
/// Top-right X coordinate (normalized 0–1)
|
||||||
|
num x2;
|
||||||
|
|
||||||
|
/// Bottom-right X coordinate (normalized 0–1)
|
||||||
|
num x3;
|
||||||
|
|
||||||
|
/// Bottom-left X coordinate (normalized 0–1)
|
||||||
|
num x4;
|
||||||
|
|
||||||
|
/// Top-left Y coordinate (normalized 0–1)
|
||||||
|
num y1;
|
||||||
|
|
||||||
|
/// Top-right Y coordinate (normalized 0–1)
|
||||||
|
num y2;
|
||||||
|
|
||||||
|
/// Bottom-right Y coordinate (normalized 0–1)
|
||||||
|
num y3;
|
||||||
|
|
||||||
|
/// Bottom-left Y coordinate (normalized 0–1)
|
||||||
|
num y4;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => identical(this, other) || other is SyncAssetOcrV1 &&
|
||||||
|
other.assetId == assetId &&
|
||||||
|
other.boxScore == boxScore &&
|
||||||
|
other.id == id &&
|
||||||
|
other.isVisible == isVisible &&
|
||||||
|
other.text == text &&
|
||||||
|
other.textScore == textScore &&
|
||||||
|
other.x1 == x1 &&
|
||||||
|
other.x2 == x2 &&
|
||||||
|
other.x3 == x3 &&
|
||||||
|
other.x4 == x4 &&
|
||||||
|
other.y1 == y1 &&
|
||||||
|
other.y2 == y2 &&
|
||||||
|
other.y3 == y3 &&
|
||||||
|
other.y4 == y4;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
// ignore: unnecessary_parenthesis
|
||||||
|
(assetId.hashCode) +
|
||||||
|
(boxScore.hashCode) +
|
||||||
|
(id.hashCode) +
|
||||||
|
(isVisible.hashCode) +
|
||||||
|
(text.hashCode) +
|
||||||
|
(textScore.hashCode) +
|
||||||
|
(x1.hashCode) +
|
||||||
|
(x2.hashCode) +
|
||||||
|
(x3.hashCode) +
|
||||||
|
(x4.hashCode) +
|
||||||
|
(y1.hashCode) +
|
||||||
|
(y2.hashCode) +
|
||||||
|
(y3.hashCode) +
|
||||||
|
(y4.hashCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'SyncAssetOcrV1[assetId=$assetId, boxScore=$boxScore, id=$id, isVisible=$isVisible, text=$text, textScore=$textScore, x1=$x1, x2=$x2, x3=$x3, x4=$x4, y1=$y1, y2=$y2, y3=$y3, y4=$y4]';
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final json = <String, dynamic>{};
|
||||||
|
json[r'assetId'] = this.assetId;
|
||||||
|
json[r'boxScore'] = this.boxScore;
|
||||||
|
json[r'id'] = this.id;
|
||||||
|
json[r'isVisible'] = this.isVisible;
|
||||||
|
json[r'text'] = this.text;
|
||||||
|
json[r'textScore'] = this.textScore;
|
||||||
|
json[r'x1'] = this.x1;
|
||||||
|
json[r'x2'] = this.x2;
|
||||||
|
json[r'x3'] = this.x3;
|
||||||
|
json[r'x4'] = this.x4;
|
||||||
|
json[r'y1'] = this.y1;
|
||||||
|
json[r'y2'] = this.y2;
|
||||||
|
json[r'y3'] = this.y3;
|
||||||
|
json[r'y4'] = this.y4;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [SyncAssetOcrV1] instance and imports its values from
|
||||||
|
/// [value] if it's a [Map], null otherwise.
|
||||||
|
// ignore: prefer_constructors_over_static_methods
|
||||||
|
static SyncAssetOcrV1? fromJson(dynamic value) {
|
||||||
|
upgradeDto(value, "SyncAssetOcrV1");
|
||||||
|
if (value is Map) {
|
||||||
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
|
return SyncAssetOcrV1(
|
||||||
|
assetId: mapValueOfType<String>(json, r'assetId')!,
|
||||||
|
boxScore: num.parse('${json[r'boxScore']}'),
|
||||||
|
id: mapValueOfType<String>(json, r'id')!,
|
||||||
|
isVisible: mapValueOfType<bool>(json, r'isVisible')!,
|
||||||
|
text: mapValueOfType<String>(json, r'text')!,
|
||||||
|
textScore: num.parse('${json[r'textScore']}'),
|
||||||
|
x1: num.parse('${json[r'x1']}'),
|
||||||
|
x2: num.parse('${json[r'x2']}'),
|
||||||
|
x3: num.parse('${json[r'x3']}'),
|
||||||
|
x4: num.parse('${json[r'x4']}'),
|
||||||
|
y1: num.parse('${json[r'y1']}'),
|
||||||
|
y2: num.parse('${json[r'y2']}'),
|
||||||
|
y3: num.parse('${json[r'y3']}'),
|
||||||
|
y4: num.parse('${json[r'y4']}'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<SyncAssetOcrV1> listFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final result = <SyncAssetOcrV1>[];
|
||||||
|
if (json is List && json.isNotEmpty) {
|
||||||
|
for (final row in json) {
|
||||||
|
final value = SyncAssetOcrV1.fromJson(row);
|
||||||
|
if (value != null) {
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toList(growable: growable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, SyncAssetOcrV1> mapFromJson(dynamic json) {
|
||||||
|
final map = <String, SyncAssetOcrV1>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
final value = SyncAssetOcrV1.fromJson(entry.value);
|
||||||
|
if (value != null) {
|
||||||
|
map[entry.key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// maps a json object with a list of SyncAssetOcrV1-objects as value to a dart map
|
||||||
|
static Map<String, List<SyncAssetOcrV1>> mapListFromJson(dynamic json, {bool growable = false,}) {
|
||||||
|
final map = <String, List<SyncAssetOcrV1>>{};
|
||||||
|
if (json is Map && json.isNotEmpty) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
json = json.cast<String, dynamic>();
|
||||||
|
for (final entry in json.entries) {
|
||||||
|
map[entry.key] = SyncAssetOcrV1.listFromJson(entry.value, growable: growable,);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of required keys that must be present in a JSON.
|
||||||
|
static const requiredKeys = <String>{
|
||||||
|
'assetId',
|
||||||
|
'boxScore',
|
||||||
|
'id',
|
||||||
|
'isVisible',
|
||||||
|
'text',
|
||||||
|
'textScore',
|
||||||
|
'x1',
|
||||||
|
'x2',
|
||||||
|
'x3',
|
||||||
|
'x4',
|
||||||
|
'y1',
|
||||||
|
'y2',
|
||||||
|
'y3',
|
||||||
|
'y4',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
+3
@@ -31,6 +31,7 @@ class SyncEntityType {
|
|||||||
static const assetExifV1 = SyncEntityType._(r'AssetExifV1');
|
static const assetExifV1 = SyncEntityType._(r'AssetExifV1');
|
||||||
static const assetMetadataV1 = SyncEntityType._(r'AssetMetadataV1');
|
static const assetMetadataV1 = SyncEntityType._(r'AssetMetadataV1');
|
||||||
static const assetMetadataDeleteV1 = SyncEntityType._(r'AssetMetadataDeleteV1');
|
static const assetMetadataDeleteV1 = SyncEntityType._(r'AssetMetadataDeleteV1');
|
||||||
|
static const assetOcrV1 = SyncEntityType._(r'AssetOcrV1');
|
||||||
static const partnerV1 = SyncEntityType._(r'PartnerV1');
|
static const partnerV1 = SyncEntityType._(r'PartnerV1');
|
||||||
static const partnerDeleteV1 = SyncEntityType._(r'PartnerDeleteV1');
|
static const partnerDeleteV1 = SyncEntityType._(r'PartnerDeleteV1');
|
||||||
static const partnerAssetV1 = SyncEntityType._(r'PartnerAssetV1');
|
static const partnerAssetV1 = SyncEntityType._(r'PartnerAssetV1');
|
||||||
@@ -82,6 +83,7 @@ class SyncEntityType {
|
|||||||
assetExifV1,
|
assetExifV1,
|
||||||
assetMetadataV1,
|
assetMetadataV1,
|
||||||
assetMetadataDeleteV1,
|
assetMetadataDeleteV1,
|
||||||
|
assetOcrV1,
|
||||||
partnerV1,
|
partnerV1,
|
||||||
partnerDeleteV1,
|
partnerDeleteV1,
|
||||||
partnerAssetV1,
|
partnerAssetV1,
|
||||||
@@ -168,6 +170,7 @@ class SyncEntityTypeTypeTransformer {
|
|||||||
case r'AssetExifV1': return SyncEntityType.assetExifV1;
|
case r'AssetExifV1': return SyncEntityType.assetExifV1;
|
||||||
case r'AssetMetadataV1': return SyncEntityType.assetMetadataV1;
|
case r'AssetMetadataV1': return SyncEntityType.assetMetadataV1;
|
||||||
case r'AssetMetadataDeleteV1': return SyncEntityType.assetMetadataDeleteV1;
|
case r'AssetMetadataDeleteV1': return SyncEntityType.assetMetadataDeleteV1;
|
||||||
|
case r'AssetOcrV1': return SyncEntityType.assetOcrV1;
|
||||||
case r'PartnerV1': return SyncEntityType.partnerV1;
|
case r'PartnerV1': return SyncEntityType.partnerV1;
|
||||||
case r'PartnerDeleteV1': return SyncEntityType.partnerDeleteV1;
|
case r'PartnerDeleteV1': return SyncEntityType.partnerDeleteV1;
|
||||||
case r'PartnerAssetV1': return SyncEntityType.partnerAssetV1;
|
case r'PartnerAssetV1': return SyncEntityType.partnerAssetV1;
|
||||||
|
|||||||
+3
@@ -31,6 +31,7 @@ class SyncRequestType {
|
|||||||
static const assetsV1 = SyncRequestType._(r'AssetsV1');
|
static const assetsV1 = SyncRequestType._(r'AssetsV1');
|
||||||
static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1');
|
static const assetExifsV1 = SyncRequestType._(r'AssetExifsV1');
|
||||||
static const assetMetadataV1 = SyncRequestType._(r'AssetMetadataV1');
|
static const assetMetadataV1 = SyncRequestType._(r'AssetMetadataV1');
|
||||||
|
static const assetOcrV1 = SyncRequestType._(r'AssetOcrV1');
|
||||||
static const authUsersV1 = SyncRequestType._(r'AuthUsersV1');
|
static const authUsersV1 = SyncRequestType._(r'AuthUsersV1');
|
||||||
static const memoriesV1 = SyncRequestType._(r'MemoriesV1');
|
static const memoriesV1 = SyncRequestType._(r'MemoriesV1');
|
||||||
static const memoryToAssetsV1 = SyncRequestType._(r'MemoryToAssetsV1');
|
static const memoryToAssetsV1 = SyncRequestType._(r'MemoryToAssetsV1');
|
||||||
@@ -55,6 +56,7 @@ class SyncRequestType {
|
|||||||
assetsV1,
|
assetsV1,
|
||||||
assetExifsV1,
|
assetExifsV1,
|
||||||
assetMetadataV1,
|
assetMetadataV1,
|
||||||
|
assetOcrV1,
|
||||||
authUsersV1,
|
authUsersV1,
|
||||||
memoriesV1,
|
memoriesV1,
|
||||||
memoryToAssetsV1,
|
memoryToAssetsV1,
|
||||||
@@ -114,6 +116,7 @@ class SyncRequestTypeTypeTransformer {
|
|||||||
case r'AssetsV1': return SyncRequestType.assetsV1;
|
case r'AssetsV1': return SyncRequestType.assetsV1;
|
||||||
case r'AssetExifsV1': return SyncRequestType.assetExifsV1;
|
case r'AssetExifsV1': return SyncRequestType.assetExifsV1;
|
||||||
case r'AssetMetadataV1': return SyncRequestType.assetMetadataV1;
|
case r'AssetMetadataV1': return SyncRequestType.assetMetadataV1;
|
||||||
|
case r'AssetOcrV1': return SyncRequestType.assetOcrV1;
|
||||||
case r'AuthUsersV1': return SyncRequestType.authUsersV1;
|
case r'AuthUsersV1': return SyncRequestType.authUsersV1;
|
||||||
case r'MemoriesV1': return SyncRequestType.memoriesV1;
|
case r'MemoriesV1': return SyncRequestType.memoriesV1;
|
||||||
case r'MemoryToAssetsV1': return SyncRequestType.memoryToAssetsV1;
|
case r'MemoryToAssetsV1': return SyncRequestType.memoryToAssetsV1;
|
||||||
|
|||||||
@@ -22944,6 +22944,83 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"SyncAssetOcrV1": {
|
||||||
|
"properties": {
|
||||||
|
"assetId": {
|
||||||
|
"description": "Asset ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"boxScore": {
|
||||||
|
"description": "Confidence score of the bounding box",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"description": "OCR entry ID",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isVisible": {
|
||||||
|
"description": "Whether the OCR entry is visible",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"description": "Recognized text content",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"textScore": {
|
||||||
|
"description": "Confidence score of the recognized text",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"x1": {
|
||||||
|
"description": "Top-left X coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"x2": {
|
||||||
|
"description": "Top-right X coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"x3": {
|
||||||
|
"description": "Bottom-right X coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"x4": {
|
||||||
|
"description": "Bottom-left X coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y1": {
|
||||||
|
"description": "Top-left Y coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y2": {
|
||||||
|
"description": "Top-right Y coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y3": {
|
||||||
|
"description": "Bottom-right Y coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"y4": {
|
||||||
|
"description": "Bottom-left Y coordinate (normalized 0–1)",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"assetId",
|
||||||
|
"boxScore",
|
||||||
|
"id",
|
||||||
|
"isVisible",
|
||||||
|
"text",
|
||||||
|
"textScore",
|
||||||
|
"x1",
|
||||||
|
"x2",
|
||||||
|
"x3",
|
||||||
|
"x4",
|
||||||
|
"y1",
|
||||||
|
"y2",
|
||||||
|
"y3",
|
||||||
|
"y4"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"SyncAssetV1": {
|
"SyncAssetV1": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"checksum": {
|
"checksum": {
|
||||||
@@ -23165,6 +23242,7 @@
|
|||||||
"AssetExifV1",
|
"AssetExifV1",
|
||||||
"AssetMetadataV1",
|
"AssetMetadataV1",
|
||||||
"AssetMetadataDeleteV1",
|
"AssetMetadataDeleteV1",
|
||||||
|
"AssetOcrV1",
|
||||||
"PartnerV1",
|
"PartnerV1",
|
||||||
"PartnerDeleteV1",
|
"PartnerDeleteV1",
|
||||||
"PartnerAssetV1",
|
"PartnerAssetV1",
|
||||||
@@ -23461,6 +23539,7 @@
|
|||||||
"AssetsV1",
|
"AssetsV1",
|
||||||
"AssetExifsV1",
|
"AssetExifsV1",
|
||||||
"AssetMetadataV1",
|
"AssetMetadataV1",
|
||||||
|
"AssetOcrV1",
|
||||||
"AuthUsersV1",
|
"AuthUsersV1",
|
||||||
"MemoriesV1",
|
"MemoriesV1",
|
||||||
"MemoryToAssetsV1",
|
"MemoryToAssetsV1",
|
||||||
|
|||||||
@@ -3073,6 +3073,36 @@ export type SyncAssetMetadataV1 = {
|
|||||||
/** Value */
|
/** Value */
|
||||||
value: object;
|
value: object;
|
||||||
};
|
};
|
||||||
|
export type SyncAssetOcrV1 = {
|
||||||
|
/** Asset ID */
|
||||||
|
assetId: string;
|
||||||
|
/** Confidence score of the bounding box */
|
||||||
|
boxScore: number;
|
||||||
|
/** OCR entry ID */
|
||||||
|
id: string;
|
||||||
|
/** Whether the OCR entry is visible */
|
||||||
|
isVisible: boolean;
|
||||||
|
/** Recognized text content */
|
||||||
|
text: string;
|
||||||
|
/** Confidence score of the recognized text */
|
||||||
|
textScore: number;
|
||||||
|
/** Top-left X coordinate (normalized 0–1) */
|
||||||
|
x1: number;
|
||||||
|
/** Top-right X coordinate (normalized 0–1) */
|
||||||
|
x2: number;
|
||||||
|
/** Bottom-right X coordinate (normalized 0–1) */
|
||||||
|
x3: number;
|
||||||
|
/** Bottom-left X coordinate (normalized 0–1) */
|
||||||
|
x4: number;
|
||||||
|
/** Top-left Y coordinate (normalized 0–1) */
|
||||||
|
y1: number;
|
||||||
|
/** Top-right Y coordinate (normalized 0–1) */
|
||||||
|
y2: number;
|
||||||
|
/** Bottom-right Y coordinate (normalized 0–1) */
|
||||||
|
y3: number;
|
||||||
|
/** Bottom-left Y coordinate (normalized 0–1) */
|
||||||
|
y4: number;
|
||||||
|
};
|
||||||
export type SyncAssetV1 = {
|
export type SyncAssetV1 = {
|
||||||
/** Checksum */
|
/** Checksum */
|
||||||
checksum: string;
|
checksum: string;
|
||||||
@@ -7232,6 +7262,7 @@ export enum SyncEntityType {
|
|||||||
AssetExifV1 = "AssetExifV1",
|
AssetExifV1 = "AssetExifV1",
|
||||||
AssetMetadataV1 = "AssetMetadataV1",
|
AssetMetadataV1 = "AssetMetadataV1",
|
||||||
AssetMetadataDeleteV1 = "AssetMetadataDeleteV1",
|
AssetMetadataDeleteV1 = "AssetMetadataDeleteV1",
|
||||||
|
AssetOcrV1 = "AssetOcrV1",
|
||||||
PartnerV1 = "PartnerV1",
|
PartnerV1 = "PartnerV1",
|
||||||
PartnerDeleteV1 = "PartnerDeleteV1",
|
PartnerDeleteV1 = "PartnerDeleteV1",
|
||||||
PartnerAssetV1 = "PartnerAssetV1",
|
PartnerAssetV1 = "PartnerAssetV1",
|
||||||
@@ -7282,6 +7313,7 @@ export enum SyncRequestType {
|
|||||||
AssetsV1 = "AssetsV1",
|
AssetsV1 = "AssetsV1",
|
||||||
AssetExifsV1 = "AssetExifsV1",
|
AssetExifsV1 = "AssetExifsV1",
|
||||||
AssetMetadataV1 = "AssetMetadataV1",
|
AssetMetadataV1 = "AssetMetadataV1",
|
||||||
|
AssetOcrV1 = "AssetOcrV1",
|
||||||
AuthUsersV1 = "AuthUsersV1",
|
AuthUsersV1 = "AuthUsersV1",
|
||||||
MemoriesV1 = "MemoriesV1",
|
MemoriesV1 = "MemoriesV1",
|
||||||
MemoryToAssetsV1 = "MemoryToAssetsV1",
|
MemoryToAssetsV1 = "MemoryToAssetsV1",
|
||||||
|
|||||||
@@ -437,6 +437,23 @@ export const columns = {
|
|||||||
'asset_exif.rating',
|
'asset_exif.rating',
|
||||||
'asset_exif.fps',
|
'asset_exif.fps',
|
||||||
],
|
],
|
||||||
|
syncAssetOcr: [
|
||||||
|
'id',
|
||||||
|
'assetId',
|
||||||
|
'x1',
|
||||||
|
'y1',
|
||||||
|
'x2',
|
||||||
|
'y2',
|
||||||
|
'x3',
|
||||||
|
'y3',
|
||||||
|
'x4',
|
||||||
|
'y4',
|
||||||
|
'text',
|
||||||
|
'boxScore',
|
||||||
|
'textScore',
|
||||||
|
'updateId',
|
||||||
|
'isVisible',
|
||||||
|
],
|
||||||
exif: [
|
exif: [
|
||||||
'asset_exif.assetId',
|
'asset_exif.assetId',
|
||||||
'asset_exif.autoStackId',
|
'asset_exif.autoStackId',
|
||||||
|
|||||||
@@ -218,6 +218,51 @@ export class SyncAssetExifV1 {
|
|||||||
fps!: number | null;
|
fps!: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExtraModel()
|
||||||
|
export class SyncAssetOcrV1 {
|
||||||
|
@ApiProperty({ description: 'OCR entry ID' })
|
||||||
|
id!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Asset ID' })
|
||||||
|
assetId!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Top-left X coordinate (normalized 0–1)' })
|
||||||
|
x1!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Top-left Y coordinate (normalized 0–1)' })
|
||||||
|
y1!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Top-right X coordinate (normalized 0–1)' })
|
||||||
|
x2!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Top-right Y coordinate (normalized 0–1)' })
|
||||||
|
y2!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Bottom-right X coordinate (normalized 0–1)' })
|
||||||
|
x3!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Bottom-right Y coordinate (normalized 0–1)' })
|
||||||
|
y3!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Bottom-left X coordinate (normalized 0–1)' })
|
||||||
|
x4!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Bottom-left Y coordinate (normalized 0–1)' })
|
||||||
|
y4!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Confidence score of the bounding box' })
|
||||||
|
boxScore!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Confidence score of the recognized text' })
|
||||||
|
textScore!: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Recognized text content' })
|
||||||
|
text!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Whether the OCR entry is visible' })
|
||||||
|
isVisible!: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@ExtraModel()
|
@ExtraModel()
|
||||||
export class SyncAssetMetadataV1 {
|
export class SyncAssetMetadataV1 {
|
||||||
@ApiProperty({ description: 'Asset ID' })
|
@ApiProperty({ description: 'Asset ID' })
|
||||||
@@ -480,6 +525,7 @@ export type SyncItem = {
|
|||||||
[SyncEntityType.AssetMetadataV1]: SyncAssetMetadataV1;
|
[SyncEntityType.AssetMetadataV1]: SyncAssetMetadataV1;
|
||||||
[SyncEntityType.AssetMetadataDeleteV1]: SyncAssetMetadataDeleteV1;
|
[SyncEntityType.AssetMetadataDeleteV1]: SyncAssetMetadataDeleteV1;
|
||||||
[SyncEntityType.AssetExifV1]: SyncAssetExifV1;
|
[SyncEntityType.AssetExifV1]: SyncAssetExifV1;
|
||||||
|
[SyncEntityType.AssetOcrV1]: SyncAssetOcrV1;
|
||||||
[SyncEntityType.PartnerAssetV1]: SyncAssetV1;
|
[SyncEntityType.PartnerAssetV1]: SyncAssetV1;
|
||||||
[SyncEntityType.PartnerAssetBackfillV1]: SyncAssetV1;
|
[SyncEntityType.PartnerAssetBackfillV1]: SyncAssetV1;
|
||||||
[SyncEntityType.PartnerAssetDeleteV1]: SyncAssetDeleteV1;
|
[SyncEntityType.PartnerAssetDeleteV1]: SyncAssetDeleteV1;
|
||||||
|
|||||||
@@ -721,6 +721,7 @@ export enum SyncRequestType {
|
|||||||
AssetsV1 = 'AssetsV1',
|
AssetsV1 = 'AssetsV1',
|
||||||
AssetExifsV1 = 'AssetExifsV1',
|
AssetExifsV1 = 'AssetExifsV1',
|
||||||
AssetMetadataV1 = 'AssetMetadataV1',
|
AssetMetadataV1 = 'AssetMetadataV1',
|
||||||
|
AssetOcrV1 = 'AssetOcrV1',
|
||||||
AuthUsersV1 = 'AuthUsersV1',
|
AuthUsersV1 = 'AuthUsersV1',
|
||||||
MemoriesV1 = 'MemoriesV1',
|
MemoriesV1 = 'MemoriesV1',
|
||||||
MemoryToAssetsV1 = 'MemoryToAssetsV1',
|
MemoryToAssetsV1 = 'MemoryToAssetsV1',
|
||||||
@@ -747,6 +748,7 @@ export enum SyncEntityType {
|
|||||||
AssetExifV1 = 'AssetExifV1',
|
AssetExifV1 = 'AssetExifV1',
|
||||||
AssetMetadataV1 = 'AssetMetadataV1',
|
AssetMetadataV1 = 'AssetMetadataV1',
|
||||||
AssetMetadataDeleteV1 = 'AssetMetadataDeleteV1',
|
AssetMetadataDeleteV1 = 'AssetMetadataDeleteV1',
|
||||||
|
AssetOcrV1 = 'AssetOcrV1',
|
||||||
|
|
||||||
PartnerV1 = 'PartnerV1',
|
PartnerV1 = 'PartnerV1',
|
||||||
PartnerDeleteV1 = 'PartnerDeleteV1',
|
PartnerDeleteV1 = 'PartnerDeleteV1',
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export class SyncRepository {
|
|||||||
assetExif: AssetExifSync;
|
assetExif: AssetExifSync;
|
||||||
assetFace: AssetFaceSync;
|
assetFace: AssetFaceSync;
|
||||||
assetMetadata: AssetMetadataSync;
|
assetMetadata: AssetMetadataSync;
|
||||||
|
assetOcr: AssetOcrSync;
|
||||||
authUser: AuthUserSync;
|
authUser: AuthUserSync;
|
||||||
memory: MemorySync;
|
memory: MemorySync;
|
||||||
memoryToAsset: MemoryToAssetSync;
|
memoryToAsset: MemoryToAssetSync;
|
||||||
@@ -77,6 +78,7 @@ export class SyncRepository {
|
|||||||
this.assetExif = new AssetExifSync(this.db);
|
this.assetExif = new AssetExifSync(this.db);
|
||||||
this.assetFace = new AssetFaceSync(this.db);
|
this.assetFace = new AssetFaceSync(this.db);
|
||||||
this.assetMetadata = new AssetMetadataSync(this.db);
|
this.assetMetadata = new AssetMetadataSync(this.db);
|
||||||
|
this.assetOcr = new AssetOcrSync(this.db);
|
||||||
this.authUser = new AuthUserSync(this.db);
|
this.authUser = new AuthUserSync(this.db);
|
||||||
this.memory = new MemorySync(this.db);
|
this.memory = new MemorySync(this.db);
|
||||||
this.memoryToAsset = new MemoryToAssetSync(this.db);
|
this.memoryToAsset = new MemoryToAssetSync(this.db);
|
||||||
@@ -772,3 +774,14 @@ class AssetMetadataSync extends BaseSync {
|
|||||||
.stream();
|
.stream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AssetOcrSync extends BaseSync {
|
||||||
|
@GenerateSql({ params: [dummyQueryOptions, DummyValue.UUID], stream: true })
|
||||||
|
getUpserts(options: SyncQueryOptions, userId: string) {
|
||||||
|
return this.upsertQuery('asset_ocr', options)
|
||||||
|
.select(columns.syncAssetOcr)
|
||||||
|
.innerJoin('asset', 'asset.id', 'asset_ocr.assetId')
|
||||||
|
.where('asset.ownerId', '=', userId)
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Kysely, sql } from 'kysely';
|
||||||
|
|
||||||
|
export async function up(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`ALTER TABLE "asset_ocr" ADD "updateId" uuid NOT NULL DEFAULT immich_uuid_v7();`.execute(db);
|
||||||
|
await sql`CREATE INDEX "asset_ocr_updateId_idx" ON "asset_ocr" ("updateId");`.execute(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(db: Kysely<any>): Promise<void> {
|
||||||
|
await sql`DROP INDEX "asset_ocr_updateId_idx";`.execute(db);
|
||||||
|
await sql`ALTER TABLE "asset_ocr" DROP COLUMN "updateId";`.execute(db);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Column, ForeignKeyColumn, Generated, PrimaryGeneratedColumn, Table } from '@immich/sql-tools';
|
import { Column, ForeignKeyColumn, Generated, PrimaryGeneratedColumn, Table } from '@immich/sql-tools';
|
||||||
|
import { UpdateIdColumn } from 'src/decorators';
|
||||||
import { AssetTable } from 'src/schema/tables/asset.table';
|
import { AssetTable } from 'src/schema/tables/asset.table';
|
||||||
|
|
||||||
@Table('asset_ocr')
|
@Table('asset_ocr')
|
||||||
@@ -45,4 +46,7 @@ export class AssetOcrTable {
|
|||||||
|
|
||||||
@Column({ type: 'boolean', default: true })
|
@Column({ type: 'boolean', default: true })
|
||||||
isVisible!: Generated<boolean>;
|
isVisible!: Generated<boolean>;
|
||||||
|
|
||||||
|
@UpdateIdColumn({ index: true })
|
||||||
|
updateId!: Generated<string>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ export class SyncService extends BaseService {
|
|||||||
[SyncRequestType.AssetFacesV1]: async () => this.syncAssetFacesV1(options, response, checkpointMap),
|
[SyncRequestType.AssetFacesV1]: async () => this.syncAssetFacesV1(options, response, checkpointMap),
|
||||||
[SyncRequestType.AssetFacesV2]: async () => this.syncAssetFacesV2(options, response, checkpointMap),
|
[SyncRequestType.AssetFacesV2]: async () => this.syncAssetFacesV2(options, response, checkpointMap),
|
||||||
[SyncRequestType.UserMetadataV1]: () => this.syncUserMetadataV1(options, response, checkpointMap),
|
[SyncRequestType.UserMetadataV1]: () => this.syncUserMetadataV1(options, response, checkpointMap),
|
||||||
|
[SyncRequestType.AssetOcrV1]: () => this.syncAssetOcrV1(options, response, checkpointMap, auth),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const type of SYNC_TYPES_ORDER.filter((type) => dto.types.includes(type))) {
|
for (const type of SYNC_TYPES_ORDER.filter((type) => dto.types.includes(type))) {
|
||||||
@@ -855,6 +856,23 @@ export class SyncService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async syncAssetOcrV1(
|
||||||
|
options: SyncQueryOptions,
|
||||||
|
response: Writable,
|
||||||
|
checkpointMap: CheckpointMap,
|
||||||
|
auth: AuthDto,
|
||||||
|
) {
|
||||||
|
const upsertType = SyncEntityType.AssetOcrV1;
|
||||||
|
const upserts = this.syncRepository.assetOcr.getUpserts(
|
||||||
|
{ ...options, ack: checkpointMap[upsertType] },
|
||||||
|
auth.user.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
for await (const { updateId, ...data } of upserts) {
|
||||||
|
send(response, { type: upsertType, ids: [updateId], data });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async upsertBackfillCheckpoint(item: { type: SyncEntityType; sessionId: string; createId: string }) {
|
private async upsertBackfillCheckpoint(item: { type: SyncEntityType; sessionId: string; createId: string }) {
|
||||||
const { type, sessionId, createId } = item;
|
const { type, sessionId, createId } = item;
|
||||||
await this.syncCheckpointRepository.upsertAll([
|
await this.syncCheckpointRepository.upsertAll([
|
||||||
|
|||||||
Reference in New Issue
Block a user