Created
May 8, 2025 20:47
-
-
Save davipatti/493292920365b9ef9a36195b980a3589 to your computer and use it in GitHub Desktop.
Fetch a random image from an immich server that contains particular people, resize and pad that image, and return it in a fastapi response. Used for fetching and resizing images to display on a raspberry pi pico which an inky 7.3 e-ink screen.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from typing import Annotated, Union | |
import io | |
import json | |
import requests | |
from fastapi import FastAPI, Query | |
from fastapi.responses import Response | |
from PIL import Image, ImageOps | |
import pillow_heif # pip install pillow-heif | |
URL = "http://ip:2283" | |
API_KEY = "xxx" | |
def search_person(name: str) -> requests.Response: | |
return requests.request( | |
"GET", | |
f"{URL}/api/search/person?name={name}", | |
headers={"Accept": "application/json", "x-api-key": API_KEY}, | |
data={}, | |
) | |
def get_person_id(name: str) -> str: | |
response = search_person(name) | |
data = response.json() | |
if len(data) == 1: | |
return data[0]["id"] | |
else: | |
raise ValueError(f"multiple matches for {name}") | |
def search_random(person_ids, n=1): | |
return requests.request( | |
"POST", | |
f"{URL}/api/search/random", | |
headers={ | |
"Content-Type": "application/json", | |
"Accept": "application/json", | |
"x-api-key": API_KEY, | |
}, | |
data=json.dumps( | |
{"personIds": person_ids, "type": "IMAGE", "withDeleted": False, "size": n} | |
), | |
) | |
def download_asset(id): | |
return requests.request( | |
"GET", | |
f"{URL}/api/assets/{id}/original", | |
headers={ | |
"Accept": "application/octet-stream", | |
"x-api-key": API_KEY, | |
}, | |
data={}, | |
) | |
app = FastAPI() | |
@app.get("/immich/") | |
def get_immich( | |
names: Annotated[Union[list[str], None], Query()], width: int = 600, height: int = 448 | |
) -> Response: | |
""" | |
Entry point that fetches a random image that contains at least one of the names | |
passed, resizes and pads it according to a width and height and then returns | |
it as a Response. | |
""" | |
person_ids = [get_person_id(name) for name in names] | |
# Fetch a random asset that contains these person_ids | |
random = search_random(person_ids=person_ids, n=1) | |
data = random.json()[0] | |
random_id = data["id"] | |
file_format = data["originalFileName"].split(".")[-1].lower() | |
download_resp = download_asset(random_id) | |
if file_format == "heic": | |
heif_file = pillow_heif.open_heif(io.BytesIO(download_resp.content)) | |
img = Image.frombytes( | |
heif_file.mode, | |
heif_file.size, | |
heif_file.data, | |
"raw", | |
heif_file.mode, | |
heif_file.stride, | |
) | |
else: | |
img = Image.open(io.BytesIO(download_resp.content)) | |
# Pad the image as requested | |
padded = ImageOps.pad(img, (width, height)) | |
# Return the padded image as "image/jpeg" in a response | |
# Create a bytes buffer to hold the JPEG image data | |
img_byte_arr = io.BytesIO() | |
# Save the padded image as JPEG to the buffer | |
padded.save(img_byte_arr, format="JPEG") | |
# Seek to the beginning of the buffer | |
img_byte_arr.seek(0) | |
# Return the image as a response | |
return Response(content=img_byte_arr.getvalue(), media_type="image/jpeg") | |
if __name__ == "__main__": | |
import uvicorn | |
uvicorn.run(app, host="0.0.0.0", port=5678) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment