Travel Scrapbook
Travel photo scrapbook API: image uploads, thumbnails and place tags as computed columns
One app.py with 1 table, 4 computed columns, 4 HTTP routes. Needs pixeltable[serve]>=0.7.14. Updated 2026-09-26.
app.py
"""Travel Scrapbook API built with Pixeltable.pxt schema update app.py scrapbookpxt service run app.py scrapbook"""import pixeltable as pxtimport pixeltable.functions as pxtffrom pixeltable.serving import FastAPIRouterfrom udfs import caption_blurb, orientation, trip_tag# ---- tables ----TableModel = pxt.model_base()class Scrapbook(TableModel, name='scrapbook'):id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)city: pxt.Stringcountry: pxt.Stringtaken_on: pxt.String | Nonecaption: pxt.String | Nonephoto: pxt.Imagethumb = photo.resize((64, 48)) # stored media, generated once per photoplace = trip_tag(city, country)shape = orientation(photo)blurb = caption_blurb(caption)# ---- queries ----@pxt.querydef photos_in(country: str):"""Photos from one country, by date."""return Scrapbook.where(Scrapbook.country == country).select(Scrapbook.id, Scrapbook.place, Scrapbook.taken_on, Scrapbook.shape, Scrapbook.blurb).order_by(Scrapbook.taken_on)@pxt.querydef latest_thumb(city: str):"""The most recent thumbnail for a city (served as an image file)."""return Scrapbook.where(Scrapbook.city == city).order_by(Scrapbook.id, asc=False).limit(1).select(Scrapbook.thumb)# ---- routes ----scrapbook_api = FastAPIRouter(name='scrapbook_api')scrapbook_api.add_insert_route(Scrapbook, path='/photos',inputs=[Scrapbook.city, Scrapbook.country, Scrapbook.taken_on, Scrapbook.caption],uploadfile_inputs=[Scrapbook.photo],outputs=[Scrapbook.id, Scrapbook.place, Scrapbook.shape, Scrapbook.blurb],)scrapbook_api.add_update_route(Scrapbook, path='/photos/caption', inputs=[Scrapbook.caption],outputs=[Scrapbook.id, Scrapbook.blurb])scrapbook_api.add_query_route(path='/photos/by-country', query=photos_in, method='get')scrapbook_api.add_query_route(path='/photos/thumb', query=latest_thumb, method='get', one_row=True,return_fileresponse=True)
What app.py declares
Each row links to its line.
- runs on insert
- stored
- index
- route
Run it
Needs uv. The routes then answer on port 8000.
terminal
git clone https://github.com/pierrebrunelle/pixeltable-travel-scrapbookcd pixeltable-travel-scrapbookuv syncuv run pxt schema update app.py scrapbookuv run python seed.py scrapbookuv run pxt service run app.py scrapbook --port 8000
Related apps
- Climbing Route ToposClimbing-route topo registry API: photo uploads with thumbnails, grayscale copies, grade bands and index-backed crag lookupsShares: Images, video and audio, UDFs, File uploads
- Mural RegistryPublic-art mural registry API: wall photo uploads with thumbnails, grayscale copies and color tagsShares: Images, video and audio, UDFs, File uploads
- Video searchVideo frames extracted at one per second and indexed with CLIP, searchable by text or by image.Shares: Images, video and audio, File uploads