types(imajin-identity): 🏷️ Add/update TypeScript type definitions for identity models, roles, and authentication schemas
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
423894c0da
commit
fd46d683f8
6 changed files with 495 additions and 0 deletions
46
services/imajin-identity/types/package.json
Normal file
46
services/imajin-identity/types/package.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "@lilith/imajin-identity-types",
|
||||
"version": "0.1.0",
|
||||
"description": "TypeScript types for Imajin identity recognition service",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"clean": "rm -rf dist",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "echo 'No tests configured for types package' && exit 0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lilith/configs": "^2.2.1",
|
||||
"tsup": "^8.0.0",
|
||||
"typescript": "^5.4.0",
|
||||
"zod": "^3.22.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^3.22.0"
|
||||
},
|
||||
"keywords": [
|
||||
"imajin",
|
||||
"identity",
|
||||
"types",
|
||||
"typescript",
|
||||
"face-recognition"
|
||||
],
|
||||
"author": "Lilith <dev@atlilith.com>",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"registry": "http://forge.black.local/api/packages/lilith/npm/"
|
||||
}
|
||||
}
|
||||
2
services/imajin-identity/types/src/index.ts
Normal file
2
services/imajin-identity/types/src/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from './types';
|
||||
export * from './schemas';
|
||||
135
services/imajin-identity/types/src/schemas.ts
Normal file
135
services/imajin-identity/types/src/schemas.ts
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* Zod schemas for runtime validation of identity service request types.
|
||||
*/
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
// ============================================================================
|
||||
// Embedding Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const EmbedRequestSchema = z.object({
|
||||
imagePath: z.string().min(1),
|
||||
extractAll: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
export const EmbedFromUrlRequestSchema = z.object({
|
||||
imageUrl: z.string().url(),
|
||||
extractAll: z.boolean().optional().default(true),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Clustering Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const ClusterRequestSchema = z.object({
|
||||
inputDir: z.string().min(1),
|
||||
minClusterSize: z.number().int().min(2).optional().default(2),
|
||||
recursive: z.boolean().optional().default(false),
|
||||
mergeThreshold: z.number().min(0).max(1).optional().default(0.75),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Organization Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const OrganizeRequestSchema = z.object({
|
||||
inputDir: z.string().min(1),
|
||||
outputDir: z.string().min(1),
|
||||
multiPersonStrategy: z.enum(['copy', 'symlink', 'skip']).optional().default('copy'),
|
||||
noFaceStrategy: z.enum(['separate', 'skip']).optional().default('separate'),
|
||||
minClusterSize: z.number().int().min(2).optional().default(2),
|
||||
recursive: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Identity CRUD Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const CreateIdentityRequestSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
imagePaths: z.array(z.string().min(1)).min(1),
|
||||
minConfidence: z.number().min(0).max(1).optional().default(0.5),
|
||||
});
|
||||
|
||||
export const UpdateIdentityRequestSchema = z.object({
|
||||
name: z.string().min(1).optional(),
|
||||
addImagePaths: z.array(z.string().min(1)).optional(),
|
||||
addImageUrls: z.array(z.string().url()).optional(),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Compare Schema
|
||||
// ============================================================================
|
||||
|
||||
export const IdentityCompareRequestSchema = z.object({
|
||||
imageBase64: z.string().min(1).max(50_000_000),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Search Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const SearchRequestSchema = z.object({
|
||||
identityId: z.string().min(1),
|
||||
searchPaths: z.array(z.string().min(1)).min(1),
|
||||
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
|
||||
recursive: z.boolean().optional().default(false),
|
||||
limit: z.number().int().min(0).optional().default(0),
|
||||
});
|
||||
|
||||
export const BatchSearchRequestSchema = z.object({
|
||||
identityIds: z.array(z.string().min(1)).min(1),
|
||||
searchPaths: z.array(z.string().min(1)).min(1),
|
||||
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
|
||||
recursive: z.boolean().optional().default(false),
|
||||
limit: z.number().int().min(0).optional().default(0),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Namespaced Identity Schemas
|
||||
// ============================================================================
|
||||
|
||||
export const BuildIdentityFromUrlsRequestSchema = z.object({
|
||||
namespace: z.string().min(1),
|
||||
identityId: z.string().min(1),
|
||||
displayName: z.string().min(1),
|
||||
imageUrls: z.array(z.string().url()).min(1),
|
||||
minConfidence: z.number().min(0).max(1).optional().default(0.5),
|
||||
upsert: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
export const NamespacedSearchRequestSchema = z.object({
|
||||
namespace: z.string().min(1),
|
||||
identityId: z.string().min(1),
|
||||
imageUrl: z.string().url(),
|
||||
minSimilarity: z.number().min(0).max(1).optional().default(0.35),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Gallery Scan Schema
|
||||
// ============================================================================
|
||||
|
||||
export const ScanGalleryRequestSchema = z.object({
|
||||
threshold: z.number().min(0).max(1).optional().default(0.35),
|
||||
limit: z.number().int().min(1).max(200).optional().default(200),
|
||||
cursor: z.string().optional(),
|
||||
category: z.string().optional(),
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Inferred Input Types
|
||||
// ============================================================================
|
||||
|
||||
export type EmbedInput = z.infer<typeof EmbedRequestSchema>;
|
||||
export type EmbedFromUrlInput = z.infer<typeof EmbedFromUrlRequestSchema>;
|
||||
export type ClusterInput = z.infer<typeof ClusterRequestSchema>;
|
||||
export type OrganizeInput = z.infer<typeof OrganizeRequestSchema>;
|
||||
export type CreateIdentityInput = z.infer<typeof CreateIdentityRequestSchema>;
|
||||
export type UpdateIdentityInput = z.infer<typeof UpdateIdentityRequestSchema>;
|
||||
export type IdentityCompareInput = z.infer<typeof IdentityCompareRequestSchema>;
|
||||
export type SearchInput = z.infer<typeof SearchRequestSchema>;
|
||||
export type BatchSearchInput = z.infer<typeof BatchSearchRequestSchema>;
|
||||
export type BuildIdentityFromUrlsInput = z.infer<typeof BuildIdentityFromUrlsRequestSchema>;
|
||||
export type NamespacedSearchInput = z.infer<typeof NamespacedSearchRequestSchema>;
|
||||
export type ScanGalleryInput = z.infer<typeof ScanGalleryRequestSchema>;
|
||||
300
services/imajin-identity/types/src/types.ts
Normal file
300
services/imajin-identity/types/src/types.ts
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/**
|
||||
* TypeScript types for the imajin-identity service.
|
||||
*
|
||||
* All interfaces use camelCase to match TypeScript conventions.
|
||||
* The client layer handles camelCase ↔ snake_case mapping.
|
||||
*
|
||||
* Source of truth: services/imajin-identity/service/src/models/schemas.py
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Common
|
||||
// ============================================================================
|
||||
|
||||
export type ConfidenceLevel = 'high' | 'medium' | 'low';
|
||||
export type HealthStatus = 'healthy' | 'unhealthy';
|
||||
export type ReadinessStatus = 'ready' | 'not_ready';
|
||||
export type MultiPersonStrategy = 'copy' | 'symlink' | 'skip';
|
||||
export type NoFaceStrategy = 'separate' | 'skip';
|
||||
|
||||
// ============================================================================
|
||||
// Face Detection
|
||||
// ============================================================================
|
||||
|
||||
/** Bounding box: [x1, y1, x2, y2] */
|
||||
export type BBox = [number, number, number, number];
|
||||
|
||||
export interface FaceResult {
|
||||
bbox: BBox;
|
||||
confidence: number;
|
||||
embeddingNorm: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Embedding
|
||||
// ============================================================================
|
||||
|
||||
export interface EmbedRequest {
|
||||
imagePath: string;
|
||||
extractAll?: boolean;
|
||||
}
|
||||
|
||||
export interface EmbedResponse {
|
||||
success: boolean;
|
||||
faces: FaceResult[];
|
||||
imagePath: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface EmbedFromUrlRequest {
|
||||
imageUrl: string;
|
||||
extractAll?: boolean;
|
||||
}
|
||||
|
||||
export interface FaceEmbeddingResult {
|
||||
bbox: BBox;
|
||||
confidence: number;
|
||||
embedding: number[];
|
||||
}
|
||||
|
||||
export interface EmbedFromUrlResponse {
|
||||
success: boolean;
|
||||
faces: FaceEmbeddingResult[];
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Clustering
|
||||
// ============================================================================
|
||||
|
||||
export interface ClusterRequest {
|
||||
inputDir: string;
|
||||
minClusterSize?: number;
|
||||
recursive?: boolean;
|
||||
mergeThreshold?: number;
|
||||
}
|
||||
|
||||
export interface ClusterInfo {
|
||||
clusterId: number;
|
||||
faceCount: number;
|
||||
photoCount: number;
|
||||
photoPaths: string[];
|
||||
}
|
||||
|
||||
export interface ClusterResponse {
|
||||
success: boolean;
|
||||
identityCount: number;
|
||||
clusters: ClusterInfo[];
|
||||
noiseCount: number;
|
||||
totalFaces: number;
|
||||
totalPhotos: number;
|
||||
multiPersonPhotos: string[];
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Organization
|
||||
// ============================================================================
|
||||
|
||||
export interface OrganizeRequest {
|
||||
inputDir: string;
|
||||
outputDir: string;
|
||||
multiPersonStrategy?: MultiPersonStrategy;
|
||||
noFaceStrategy?: NoFaceStrategy;
|
||||
minClusterSize?: number;
|
||||
recursive?: boolean;
|
||||
}
|
||||
|
||||
export interface OrganizeResponse {
|
||||
success: boolean;
|
||||
outputDir: string;
|
||||
identityFolders: Record<string, string>;
|
||||
photosProcessed: number;
|
||||
photosOrganized: number;
|
||||
photosNoFace: number;
|
||||
photosMultiPerson: number;
|
||||
errors: string[];
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Health
|
||||
// ============================================================================
|
||||
|
||||
export interface HealthResponse {
|
||||
status: HealthStatus;
|
||||
version: string;
|
||||
uptimeSeconds: number;
|
||||
}
|
||||
|
||||
export interface ReadinessResponse {
|
||||
status: ReadinessStatus;
|
||||
gpuAvailable: boolean;
|
||||
modelLoaded: boolean;
|
||||
redisConnected: boolean;
|
||||
version: string;
|
||||
uptimeSeconds: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Identity CRUD
|
||||
// ============================================================================
|
||||
|
||||
export interface CreateIdentityRequest {
|
||||
name: string;
|
||||
imagePaths: string[];
|
||||
minConfidence?: number;
|
||||
}
|
||||
|
||||
export interface UpdateIdentityRequest {
|
||||
name?: string;
|
||||
addImagePaths?: string[];
|
||||
addImageUrls?: string[];
|
||||
}
|
||||
|
||||
export interface IdentityResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
imageCount: number;
|
||||
sourcePaths: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
gender: string | null;
|
||||
}
|
||||
|
||||
export interface IdentityListResponse {
|
||||
identities: IdentityResponse[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Identity Embedding (IP-Adapter integration)
|
||||
// ============================================================================
|
||||
|
||||
export interface IdentityEmbeddingResponse {
|
||||
identityId: string;
|
||||
name: string;
|
||||
embedding: number[];
|
||||
embeddingNorm: number;
|
||||
imageCount: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Identity Compare
|
||||
// ============================================================================
|
||||
|
||||
export interface IdentityCompareRequest {
|
||||
imageBase64: string;
|
||||
}
|
||||
|
||||
export interface IdentityCompareResponse {
|
||||
identityId: string;
|
||||
similarity: number;
|
||||
confidence: ConfidenceLevel;
|
||||
faceDetected: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Search
|
||||
// ============================================================================
|
||||
|
||||
export interface SearchRequest {
|
||||
identityId: string;
|
||||
searchPaths: string[];
|
||||
minSimilarity?: number;
|
||||
recursive?: boolean;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface SearchMatch {
|
||||
imagePath: string;
|
||||
similarity: number;
|
||||
confidence: ConfidenceLevel;
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
identityId: string;
|
||||
matches: SearchMatch[];
|
||||
totalImagesSearched: number;
|
||||
}
|
||||
|
||||
export interface BatchSearchRequest {
|
||||
identityIds: string[];
|
||||
searchPaths: string[];
|
||||
minSimilarity?: number;
|
||||
recursive?: boolean;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface BatchSearchResponse {
|
||||
results: SearchResponse[];
|
||||
totalImagesSearched: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Namespaced Identity (media-gallery integration)
|
||||
// ============================================================================
|
||||
|
||||
export interface BuildIdentityFromUrlsRequest {
|
||||
namespace: string;
|
||||
identityId: string;
|
||||
displayName: string;
|
||||
imageUrls: string[];
|
||||
minConfidence?: number;
|
||||
upsert?: boolean;
|
||||
}
|
||||
|
||||
export interface IdentityBuildResponse {
|
||||
success: boolean;
|
||||
identityId: string;
|
||||
namespace: string;
|
||||
imageCount: number;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface NamespacedSearchRequest {
|
||||
namespace: string;
|
||||
identityId: string;
|
||||
imageUrl: string;
|
||||
minSimilarity?: number;
|
||||
}
|
||||
|
||||
export interface NamespacedSearchResponse {
|
||||
identityId: string;
|
||||
namespace: string;
|
||||
similarity: number;
|
||||
confidence: ConfidenceLevel;
|
||||
faceDetected: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Gallery Scan
|
||||
// ============================================================================
|
||||
|
||||
export interface ScanGalleryRequest {
|
||||
threshold?: number;
|
||||
limit?: number;
|
||||
cursor?: string;
|
||||
category?: string;
|
||||
}
|
||||
|
||||
export interface GalleryCandidate {
|
||||
photoId: string;
|
||||
similarity: number;
|
||||
confidence: ConfidenceLevel;
|
||||
thumbnailUrl: string;
|
||||
originalUrl: string;
|
||||
originalFilename: string;
|
||||
faceQuality: number;
|
||||
}
|
||||
|
||||
export interface ScanGalleryResponse {
|
||||
identityId: string;
|
||||
candidates: GalleryCandidate[];
|
||||
totalScanned: number;
|
||||
hasMore: boolean;
|
||||
galleryTotal: number;
|
||||
nextCursor?: string;
|
||||
}
|
||||
9
services/imajin-identity/types/tsconfig.json
Normal file
9
services/imajin-identity/types/tsconfig.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../../tooling/tsconfig/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
3
services/imajin-identity/types/tsup.config.ts
Normal file
3
services/imajin-identity/types/tsup.config.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { createLibraryConfig } from '@lilith/configs/tsup/library';
|
||||
|
||||
export default createLibraryConfig();
|
||||
Loading…
Add table
Reference in a new issue