My agentic slop goes here. Not intended for anyone else!
1# Immiche - Immich API Client Library
2
3A clean Eio-based OCaml library for interacting with Immich instances, focusing on people and face recognition data.
4
5## Overview
6
7Immiche provides a straightforward API for interacting with Immich's people management endpoints. It uses the Requests library for HTTP operations and follows Eio patterns for concurrency and resource management.
8
9## Features
10
11- Fetch all people from an Immich instance
12- Search for people by name
13- Fetch individual person details
14- Download person thumbnails
15- Full Eio integration (no Lwt dependency)
16- Type-safe API with result types for error handling
17
18## API
19
20### Types
21
22```ocaml
23(* Client type - encapsulates session with connection pooling *)
24type ('clock, 'net) t
25
26type person = {
27 id: string;
28 name: string;
29 birth_date: string option;
30 thumbnail_path: string;
31 is_hidden: bool;
32}
33
34type people_response = {
35 total: int;
36 visible: int;
37 people: person list;
38}
39```
40
41### Client Creation
42
43#### `create`
44Create an Immich client with connection pooling.
45
46```ocaml
47val create :
48 sw:Eio.Switch.t ->
49 env:< clock: _ ; net: _ ; fs: _ ; .. > ->
50 ?requests_session:('clock, 'net) Requests.t ->
51 base_url:string ->
52 api_key:string ->
53 unit -> ('clock, 'net) t
54```
55
56**Parameters:**
57- `sw` - Eio switch for resource management
58- `env` - Eio environment (provides clock, net, fs)
59- `requests_session` - Optional Requests session for connection pooling. If not provided, a new session is created.
60- `base_url` - Base URL of the Immich instance (e.g., "https://photos.example.com")
61- `api_key` - API key for authentication
62
63**Returns:** An Immich client configured for the specified instance
64
65### API Functions
66
67All API functions take a client as their first parameter. The client automatically handles:
68- Connection pooling (reuses TCP connections)
69- Authentication (API key set as default header)
70- Base URL configuration
71
72#### `fetch_people`
73Fetch all people from an Immich instance.
74
75```ocaml
76val fetch_people : ('clock, 'net) t -> people_response
77```
78
79#### `search_person`
80Search for people by name.
81
82```ocaml
83val search_person : ('clock, 'net) t -> name:string -> person list
84```
85
86#### `fetch_person`
87Fetch details for a specific person.
88
89```ocaml
90val fetch_person : ('clock, 'net) t -> person_id:string -> person
91```
92
93#### `download_thumbnail`
94Download a person's thumbnail image.
95
96```ocaml
97val download_thumbnail :
98 ('clock, 'net) t ->
99 fs:_ Eio.Path.t ->
100 person_id:string ->
101 output_path:string ->
102 (unit, [> `Msg of string]) result
103```
104
105## Example Usage
106
107### Basic Usage
108
109```ocaml
110open Eio.Std
111
112let () =
113 Eio_main.run @@ fun env ->
114 Switch.run @@ fun sw ->
115
116 (* Create client once with connection pooling *)
117 let client = Immiche.create ~sw ~env
118 ~base_url:"https://photos.example.com"
119 ~api_key:"your-api-key" () in
120
121 (* Fetch all people - connection pooling automatic *)
122 let response = Immiche.fetch_people client in
123 Printf.printf "Total people: %d\n" response.total;
124
125 (* Search for a person - reuses connections *)
126 let results = Immiche.search_person client ~name:"John" in
127
128 (* Download first result's thumbnail *)
129 match results with
130 | person :: _ ->
131 let result = Immiche.download_thumbnail client
132 ~fs:(Eio.Stdenv.fs env)
133 ~person_id:person.id
134 ~output_path:"thumbnail.jpg" in
135 begin match result with
136 | Ok () -> print_endline "Thumbnail downloaded!"
137 | Error (`Msg err) -> Printf.eprintf "Error: %s\n" err
138 end
139 | [] -> print_endline "No results found"
140```
141
142### Sharing Connection Pools
143
144You can share a `Requests.t` session across multiple API clients for maximum connection reuse:
145
146```ocaml
147Eio_main.run @@ fun env ->
148Switch.run @@ fun sw ->
149
150 (* Create shared Requests session *)
151 let shared_session = Requests.create ~sw env in
152
153 (* Create multiple clients sharing the same connection pools *)
154 let immich1 = Immiche.create ~sw ~env ~requests_session:shared_session
155 ~base_url:"https://photos1.example.com"
156 ~api_key:"key1" () in
157
158 let immich2 = Immiche.create ~sw ~env ~requests_session:shared_session
159 ~base_url:"https://photos2.example.com"
160 ~api_key:"key2" () in
161
162 (* Both clients share the same connection pools! *)
163 let people1 = Immiche.fetch_people immich1 in
164 let people2 = Immiche.fetch_people immich2 in
165 ()
166```
167
168## Dependencies
169
170- `eio` - Concurrent I/O library
171- `requests` - HTTP client library
172- `ezjsonm` - JSON parsing
173- `uri` - URI encoding
174- `fmt` - Formatting
175- `ptime` - Time handling
176
177## Implementation Notes
178
179- Uses `Requests.t` for session-based HTTP requests with connection pooling
180- Authentication via `x-api-key` header (set as default on session creation)
181- Direct Eio style - no Lwt dependencies
182- Connection pools shared across derived sessions
183- Extracted and adapted from `bushel/bin/bushel_faces.ml`
184
185## Benefits
186
187✅ **Connection Pooling** - Automatic TCP connection reuse across requests
188✅ **Clean API** - Session-level configuration passed once, not per-request
189✅ **Injectable Sessions** - Can share `Requests.t` across multiple libraries
190✅ **Type Safety** - Client parameterized by clock/net types
191✅ **Immutable Configuration** - Derived sessions don't affect original
192
193## License
194
195ISC