1330 lines
46 KiB
HTML
1330 lines
46 KiB
HTML
|
|
<!doctype html>
|
|
<html lang="en" class="no-js">
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
<meta name="description" content="Face-recognition pipeline for finding on-screen actor presence in film/TV, built on KPN++">
|
|
|
|
|
|
|
|
<link rel="canonical" href="https://pages.tourolle.paris/dtourolle/scene-actor-extraction/service-conversion/">
|
|
|
|
|
|
<link rel="prev" href="../optimizer-experiments/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="icon" href="../assets/images/favicon.png">
|
|
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.7">
|
|
|
|
|
|
|
|
<title>Service Conversion (proposal) - scene-actor-extraction</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../assets/stylesheets/main.ec1eaa64.min.css">
|
|
|
|
|
|
<link rel="stylesheet" href="../assets/stylesheets/palette.ab4e12ef.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
|
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../stylesheets/extra.css">
|
|
|
|
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="amber">
|
|
|
|
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
|
<label class="md-overlay" for="__drawer"></label>
|
|
<div data-md-component="skip">
|
|
|
|
|
|
<a href="#conversion-to-service-a-native-idle-gpu-worker" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
</div>
|
|
<div data-md-component="announce">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<header class="md-header" data-md-component="header">
|
|
<nav class="md-header__inner md-grid" aria-label="Header">
|
|
<a href=".." title="scene-actor-extraction" class="md-header__button md-logo" aria-label="scene-actor-extraction" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
|
|
|
</a>
|
|
<label class="md-header__button md-icon" for="__drawer">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
|
</label>
|
|
<div class="md-header__title" data-md-component="header-title">
|
|
<div class="md-header__ellipsis">
|
|
<div class="md-header__topic">
|
|
<span class="md-ellipsis">
|
|
scene-actor-extraction
|
|
</span>
|
|
</div>
|
|
<div class="md-header__topic" data-md-component="header-topic">
|
|
<span class="md-ellipsis">
|
|
|
|
Service Conversion (proposal)
|
|
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<form class="md-header__option" data-md-component="palette">
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="amber" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg>
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_0" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg>
|
|
</label>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-header__button md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
</label>
|
|
<div class="md-search" data-md-component="search" role="dialog">
|
|
<label class="md-search__overlay" for="__search"></label>
|
|
<div class="md-search__inner" role="search">
|
|
<form class="md-search__form" name="search">
|
|
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
|
<label class="md-search__icon md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
|
</label>
|
|
<nav class="md-search__options" aria-label="Search">
|
|
|
|
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
|
</button>
|
|
</nav>
|
|
|
|
</form>
|
|
<div class="md-search__output">
|
|
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
|
<div class="md-search-result" data-md-component="search-result">
|
|
<div class="md-search-result__meta">
|
|
Initializing search
|
|
</div>
|
|
<ol class="md-search-result__list" role="presentation"></ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-header__source">
|
|
<a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
dtourolle/scene-actor-extraction
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
</header>
|
|
|
|
<div class="md-container" data-md-component="container">
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
|
|
<div class="md-grid">
|
|
<ul class="md-tabs__list">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href=".." class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Home
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../best-model/" class="md-tabs__link">
|
|
|
|
|
|
|
|
Findings
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../model-bakeoff/" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Model Bake-off & Re-tune (full log)
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item">
|
|
<a href="../optimizer-experiments/" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Optimizer Experiments (prior round)
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-tabs__item md-tabs__item--active">
|
|
<a href="./" class="md-tabs__link">
|
|
|
|
|
|
|
|
|
|
|
|
Service Conversion (proposal)
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
|
|
|
|
<main class="md-main" data-md-component="main">
|
|
<div class="md-main__inner md-grid">
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
|
|
<label class="md-nav__title" for="__drawer">
|
|
<a href=".." title="scene-actor-extraction" class="md-nav__button md-logo" aria-label="scene-actor-extraction" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
|
|
|
</a>
|
|
scene-actor-extraction
|
|
</label>
|
|
|
|
<div class="md-nav__source">
|
|
<a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
dtourolle/scene-actor-extraction
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href=".." class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Home
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Findings
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_2">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
|
|
|
|
Findings
|
|
|
|
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../best-model/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Best Model
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../gallery-scope/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Gallery Scope (Full vs. Limited)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../pose-expansion/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Pose Expansion
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../lvface-deep-dive/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
LVFace Deep Dive
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../model-bakeoff/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Model Bake-off & Re-tune (full log)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../optimizer-experiments/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Optimizer Experiments (prior round)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active">
|
|
|
|
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__link md-nav__link--active" for="__toc">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Service Conversion (proposal)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<a href="./" class="md-nav__link md-nav__link--active">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
|
|
|
|
Service Conversion (proposal)
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-idea" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The idea
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#what-already-exists-reuse-dont-rebuild" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
What already exists (reuse, don't rebuild)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#installer-config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Installer config
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#dependencies-via-the-system-package-manager" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Dependencies via the system package manager
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#what-build_installpy-does" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
What build_install.py does
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-worker-service-supervisor" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The worker service (supervisor)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-lock-gate" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The lock gate
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#on-resume-hard-stop-re-queue-its-free" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
On resume: hard stop + re-queue (it's free)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-end-to-end-ux" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The end-to-end UX
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#implementation-plan-follow-up-commits" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Implementation plan (follow-up commits)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#settled-decisions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Settled decisions
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#open-questions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Open questions
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-idea" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The idea
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#what-already-exists-reuse-dont-rebuild" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
What already exists (reuse, don't rebuild)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#installer-config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Installer config
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#dependencies-via-the-system-package-manager" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Dependencies via the system package manager
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#what-build_installpy-does" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
What build_install.py does
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-worker-service-supervisor" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The worker service (supervisor)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-lock-gate" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The lock gate
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#on-resume-hard-stop-re-queue-its-free" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
On resume: hard stop + re-queue (it's free)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#the-end-to-end-ux" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
The end-to-end UX
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#implementation-plan-follow-up-commits" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Implementation plan (follow-up commits)
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#settled-decisions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Settled decisions
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#open-questions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
|
|
Open questions
|
|
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-content" data-md-component="content">
|
|
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
|
|
|
|
|
|
<h1 id="conversion-to-service-a-native-idle-gpu-worker">Conversion to service — a native idle-GPU worker<a class="headerlink" href="#conversion-to-service-a-native-idle-gpu-worker" title="Permanent link">¶</a></h1>
|
|
<p>Status: <strong>design / proposal</strong>. Nothing here is built yet.</p>
|
|
<h2 id="the-idea">The idea<a class="headerlink" href="#the-idea" title="Permanent link">¶</a></h2>
|
|
<p>Turn the CLI tools into a <strong>turnkey batch worker that uses the machine's idle
|
|
GPU</strong>: it analyses newly-added Jellyfin media when you're not using the computer
|
|
(screen locked), and stops the instant you come back. It's an overnight job on
|
|
your own Linux box.</p>
|
|
<p><strong>No Docker.</strong> This runs on your own machine with your own drivers, so a container
|
|
buys little and costs a lot: GPU passthrough (nvidia-container-toolkit, or
|
|
<code>/dev/kfd</code>+<code>/dev/dri</code>+<code>video</code> group for ROCm) is the single most fragile part of a
|
|
containerised setup, and it exists <em>only</em> because of the container. Natively, the
|
|
GPU just works with the drivers you already have, and the media paths Jellyfin
|
|
reports are just real paths — no re-mounting. So we ship a <strong>native installer</strong>
|
|
instead of an image builder.</p>
|
|
<p>Two deliverables:</p>
|
|
<ol>
|
|
<li><strong>An installer</strong> — <code>scripts/build_install.py</code>. Detects your distro, ensures the
|
|
GPU/build dependencies are present (via <code>dnf</code>/<code>pacman</code>), compiles <code>scene_analyze</code>
|
|
for your GPU, and installs the binary + Python glue + two systemd <strong>user</strong>
|
|
units under <code>~/.local</code>.</li>
|
|
<li><strong>A screen-lock gate</strong> — one of those systemd units watches logind lock/unlock
|
|
and starts/stops the worker. Lock → analyse. Unlock → stop.</li>
|
|
</ol>
|
|
<h2 id="what-already-exists-reuse-dont-rebuild">What already exists (reuse, don't rebuild)<a class="headerlink" href="#what-already-exists-reuse-dont-rebuild" title="Permanent link">¶</a></h2>
|
|
<p>The processing loop is already implemented — this is packaging, building, and
|
|
lock-gating, not new pipeline logic.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Piece</th>
|
|
<th>Where</th>
|
|
<th>What it does</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Analysis engine</td>
|
|
<td><code>build/scene_analyze</code></td>
|
|
<td>Video → face detect/align/embed → gallery match → result JSON</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Backend selection</td>
|
|
<td><a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction/raw/commit/4b5557974bef8783bacc375c0869e8f589d1b0a3/CMakeLists.txt"><code>CMakeLists.txt</code></a> (<code>SAE_INFERENCE_BACKEND</code>, <code>SAE_GEMM_BACKEND</code>)</td>
|
|
<td>ORT/TRT + ROCm/CUDA, chosen <strong>at build time</strong></td>
|
|
</tr>
|
|
<tr>
|
|
<td>New-media queue</td>
|
|
<td>JRay plugin → <code>GET /Plugins/JRay/Tasks/Pending</code></td>
|
|
<td>Backlog of items with no results yet</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Worker loop</td>
|
|
<td><a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction/raw/commit/4b5557974bef8783bacc375c0869e8f589d1b0a3/scripts/run_from_jellyfin.py"><code>scripts/run_from_jellyfin.py</code></a><code>--worker</code></td>
|
|
<td>Poll Pending → run <code>scene_analyze</code> → push results</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Result push</td>
|
|
<td><code>PUT /Plugins/JRay/Items/{id}/Truth</code></td>
|
|
<td>Stores per-actor scene windows back in Jellyfin</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Incremental gallery</td>
|
|
<td><a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction/raw/commit/4b5557974bef8783bacc375c0869e8f589d1b0a3/scripts/make_jellyfin_gallery.py"><code>scripts/make_jellyfin_gallery.py</code></a><code>--merge</code></td>
|
|
<td>Embeds only cast not already in the gallery</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Secrets loader</td>
|
|
<td><code>.env</code> via <a href="https://gitea.tourolle.paris/dtourolle/scene-actor-extraction/raw/commit/4b5557974bef8783bacc375c0869e8f589d1b0a3/scripts/sae_env.py"><code>scripts/sae_env.py</code></a></td>
|
|
<td><code>JELLYFIN_URL</code>, <code>JELLYFIN_API_KEY</code>, <code>TMDB_API_KEY</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<h2 id="installer-config">Installer config<a class="headerlink" href="#installer-config" title="Permanent link">¶</a></h2>
|
|
<p>One file. Build-time settings (fixed when we compile) vs. run-time settings (in the
|
|
worker's <code>.env</code>, editable without recompiling).</p>
|
|
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># install.yaml — consumed by scripts/build_install.py</span>
|
|
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>
|
|
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="nt">platform</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">nvidia</span><span class="w"> </span><span class="c1"># nvidia | amd | cpu → picks the cmake backend</span>
|
|
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="nt">model</span><span class="p">:</span>
|
|
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="nt">arcface</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LVFace-B_Glint360K.onnx</span><span class="w"> </span><span class="c1"># embedder compiled against; gallery MUST match</span>
|
|
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="nt">schedule</span><span class="p">:</span>
|
|
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="nt">gallery_scan_interval</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">24h</span><span class="w"> </span><span class="c1"># incremental --merge cadence; 0 disables the scanner</span>
|
|
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="nt">prefix</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">~/.local</span><span class="w"> </span><span class="c1"># install root (bin, share, systemd user units)</span>
|
|
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>
|
|
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="c1"># runtime (written to the worker .env, not compiled in):</span>
|
|
</span><span id="__span-0-11"><a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="nt">runtime</span><span class="p">:</span>
|
|
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="w"> </span><span class="nt">jellyfin_url</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">http://localhost:8096</span>
|
|
</span><span id="__span-0-13"><a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a><span class="w"> </span><span class="c1"># JELLYFIN_API_KEY / TMDB_API_KEY are filled into .env by hand after install</span>
|
|
</span></code></pre></div>
|
|
<p><strong>Secrets never go in the repo or a build artifact</strong> — the installer writes a
|
|
<code>.env</code> under the install prefix with blanks for the keys, and you fill them in
|
|
once. <code>sae_env.py</code> already loads it.</p>
|
|
<p><strong>Model ⇄ gallery coupling (guard, don't just document):</strong> embeddings from
|
|
different recognition models aren't interchangeable. We compile against one
|
|
embedder; the gallery must be built with the same one. Stamp the embedder name
|
|
into <code>gallery.json</code>, and have the worker <strong>refuse to start</strong> if the gallery's
|
|
embedder ≠ the configured <code>model.arcface</code>, rather than silently mismatching.</p>
|
|
<h2 id="dependencies-via-the-system-package-manager">Dependencies via the system package manager<a class="headerlink" href="#dependencies-via-the-system-package-manager" title="Permanent link">¶</a></h2>
|
|
<p>The heavy build/runtime deps (OpenCV, ffmpeg, the GPU stack) are best provided by
|
|
the distro, not vendored. The installer ships a per-distro dependency list and
|
|
either installs them or prints the exact command. Targets: <strong>Fedora (dnf)</strong> and
|
|
<strong>Arch (pacman)</strong> first.</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Dependency</th>
|
|
<th>Fedora (dnf)</th>
|
|
<th>Arch (pacman)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>OpenCV</td>
|
|
<td><code>opencv-devel</code></td>
|
|
<td><code>opencv</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>ffmpeg</td>
|
|
<td><code>ffmpeg-free</code>/<code>ffmpeg</code> (RPM Fusion)</td>
|
|
<td><code>ffmpeg</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>CMake / toolchain</td>
|
|
<td><code>cmake gcc-c++</code></td>
|
|
<td><code>cmake gcc</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>CUDA + TensorRT (nvidia)</td>
|
|
<td>NVIDIA CUDA repo + <code>libnvinfer-*</code></td>
|
|
<td><code>cuda</code>, <code>tensorrt</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>ROCm (amd)</td>
|
|
<td><code>rocm-hip-sdk</code> / <code>rocblas-devel</code></td>
|
|
<td><code>rocm-hip-sdk</code>, <code>rocblas</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>ONNX Runtime</td>
|
|
<td><strong>not packaged</strong> — installer fetches a pinned release tarball into the prefix</td>
|
|
<td>AUR <code>onnxruntime</code> (or same pinned-tarball fallback)</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>So the flow is: <strong>detect distro → check each package → install via the native
|
|
manager (or print <code>sudo dnf install …</code> / <code>sudo pacman -S …</code>)</strong>, with ONNX Runtime
|
|
as the one known gap the installer fills itself (a pinned upstream release
|
|
extracted under the install prefix, so it doesn't depend on a system package that
|
|
may not exist). CUDA/ROCm being present is <em>assumed</em> — you already run a GPU
|
|
desktop; the installer verifies and points you at the vendor repo if not.</p>
|
|
<h2 id="what-build_installpy-does">What <code>build_install.py</code> does<a class="headerlink" href="#what-build_installpy-does" title="Permanent link">¶</a></h2>
|
|
<div class="language-text highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>build_install.py install.yaml
|
|
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a> │
|
|
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a> ├─ detect distro (dnf vs pacman) and platform from config
|
|
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a> ├─ ensure deps: install via manager, or print the exact command; fetch ONNX Runtime if needed
|
|
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a> ├─ cmake + build scene_analyze with the platform's backend flags:
|
|
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a> │ nvidia → -DSAE_INFERENCE_BACKEND=TRT -DSAE_GEMM_BACKEND=CUDA
|
|
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a> │ amd → -DSAE_INFERENCE_BACKEND=ORT -DSAE_GEMM_BACKEND=ROCM
|
|
</span><span id="__span-1-8"><a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a> │ cpu → -DSAE_INFERENCE_BACKEND=ORT (CPU EP; slow, for smoke tests)
|
|
</span><span id="__span-1-9"><a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a> ├─ install into <prefix>:
|
|
</span><span id="__span-1-10"><a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a> │ bin/sae-scene-analyze the compiled binary
|
|
</span><span id="__span-1-11"><a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a> │ share/sae-worker/ Python glue + a venv (requests, etc.), models/
|
|
</span><span id="__span-1-12"><a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a> │ share/sae-worker/.env runtime config (keys blank, url from config)
|
|
</span><span id="__span-1-13"><a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a> ├─ install systemd --user units:
|
|
</span><span id="__span-1-14"><a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a> │ sae-worker.service runs the worker + gallery-scan supervisor
|
|
</span><span id="__span-1-15"><a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a> │ sae-lock-gate.service watches logind lock/unlock, start/stops the worker
|
|
</span><span id="__span-1-16"><a id="__codelineno-1-16" name="__codelineno-1-16" href="#__codelineno-1-16"></a> └─ print next steps (edit .env, `systemctl --user enable --now sae-lock-gate`)
|
|
</span></code></pre></div>
|
|
<h2 id="the-worker-service-supervisor">The worker service (supervisor)<a class="headerlink" href="#the-worker-service-supervisor" title="Permanent link">¶</a></h2>
|
|
<p><code>sae-worker.service</code> runs a small Python supervisor as its main process:</p>
|
|
<ul>
|
|
<li>starts the <strong>worker loop</strong> (<code>run_from_jellyfin.py --worker</code>) — the hot path,</li>
|
|
<li>starts a <strong>gallery-scan timer</strong> — sleeps <code>gallery_scan_interval</code>, runs
|
|
<code>make_jellyfin_gallery.py --merge</code>, repeats,</li>
|
|
<li>exits cleanly on SIGTERM (see re-queue below).</li>
|
|
</ul>
|
|
<h2 id="the-lock-gate">The lock gate<a class="headerlink" href="#the-lock-gate" title="Permanent link">¶</a></h2>
|
|
<p><code>sae-lock-gate.service</code> runs a tiny watcher that subscribes to logind
|
|
lock/unlock signals and drives the worker service:</p>
|
|
<div class="language-text highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>screen locks → systemctl --user start sae-worker.service
|
|
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a>screen unlocks → systemctl --user stop sae-worker.service (SIGTERM)
|
|
</span></code></pre></div>
|
|
<p><strong>Screen-lock is the only signal — deliberately.</strong> We don't also gate on GPU/CPU
|
|
load, because our own worker <em>is</em> the load: a load threshold would form a feedback
|
|
loop (worker starts → GPU spikes → threshold trips → worker stops → load drops →
|
|
restart → …). Lock state is external to what the worker does, so it can't
|
|
oscillate.</p>
|
|
<p>Signal source is desktop-dependent: logind <code>Lock</code>/<code>Unlock</code> (GNOME/KDE via
|
|
<code>loginctl</code>/D-Bus) covers most setups; a <code>swayidle</code>/<code>xss-lock</code> hook is the fallback
|
|
for wlroots/X-only compositors. The installer picks based on what's present.</p>
|
|
<h2 id="on-resume-hard-stop-re-queue-its-free">On resume: hard stop + re-queue (it's free)<a class="headerlink" href="#on-resume-hard-stop-re-queue-its-free" title="Permanent link">¶</a></h2>
|
|
<p>Stopping the worker mid-analysis costs nothing to reschedule, because of how the
|
|
JRay queue works: <strong>an item only leaves <code>/Tasks/Pending</code> once its results are
|
|
pushed</strong> (<code>push_truth</code>). A worker stopped mid-<code>scene_analyze</code> simply leaves that
|
|
item Pending — next lock picks it up again. No re-queue bookkeeping.</p>
|
|
<p>Two small correctness requirements (the only worker changes needed):</p>
|
|
<ol>
|
|
<li><strong>Never push a partial result.</strong> Already true — <code>push_truth</code> runs only after
|
|
<code>scene_analyze</code> returns; a killed run pushes nothing. ✓ (keep it that way).</li>
|
|
<li><strong>Clean up on signal.</strong> <code>process_item</code> writes a temp filtered-gallery file and
|
|
unlinks it in a <code>finally</code>; a SIGKILL skips <code>finally</code>. Fix: write temps under a
|
|
dir the worker wipes on start, and/or a SIGTERM handler that unlinks before
|
|
exit. Minor.</li>
|
|
</ol>
|
|
<p>Accepted trade-off: a partially-analysed title restarts from scratch next lock.
|
|
Fine for an overnight/idle workload; no mid-video checkpointing.</p>
|
|
<h2 id="the-end-to-end-ux">The end-to-end UX<a class="headerlink" href="#the-end-to-end-ux" title="Permanent link">¶</a></h2>
|
|
<div class="language-bash highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1"># once: build + install for your GPU + model</span>
|
|
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>./scripts/build_install.py<span class="w"> </span>install.yaml
|
|
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="c1"># detects Fedora/Arch, ensures deps, compiles, installs units under ~/.local</span>
|
|
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a>
|
|
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="c1"># once: set your keys, enable the gate</span>
|
|
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="nv">$EDITOR</span><span class="w"> </span>~/.local/share/sae-worker/.env<span class="w"> </span><span class="c1"># JELLYFIN_API_KEY, TMDB_API_KEY</span>
|
|
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a>systemctl<span class="w"> </span>--user<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>--now<span class="w"> </span>sae-lock-gate.service
|
|
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a>
|
|
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="c1"># from then on: nothing. Lock your screen → it analyses. Unlock → it stops.</span>
|
|
</span></code></pre></div>
|
|
<p>No Docker, no GPU passthrough config, no media re-mounting — the worker sees the
|
|
same filesystem and GPU as everything else on the box.</p>
|
|
<h2 id="implementation-plan-follow-up-commits">Implementation plan (follow-up commits)<a class="headerlink" href="#implementation-plan-follow-up-commits" title="Permanent link">¶</a></h2>
|
|
<p>Ordered so each step stands alone:</p>
|
|
<ol>
|
|
<li><strong>installer skeleton</strong> — <code>scripts/build_install.py</code>: parse <code>install.yaml</code>,
|
|
distro detect, dependency check/print (start with cpu platform so it builds
|
|
without a GPU), cmake+build, copy into prefix.</li>
|
|
<li><strong>supervisor + cleanup</strong> — <code>scripts/service.py</code> (worker loop + gallery-scan
|
|
timer + SIGTERM); temp-file cleanup fix in <code>run_from_jellyfin.py</code>.</li>
|
|
<li><strong>systemd units + lock gate</strong> — generate/install <code>sae-worker.service</code>,
|
|
<code>sae-lock-gate.service</code>, and the logind lock watcher.</li>
|
|
<li><strong>gallery/model guard</strong> — stamp embedder into <code>gallery.json</code>; startup mismatch
|
|
check.</li>
|
|
<li><strong>platform + distro matrix</strong> — nvidia/amd backends; dnf/pacman dep lists; ONNX
|
|
Runtime fetch fallback.</li>
|
|
<li><strong>docs</strong> — README "Run on your idle GPU" section.</li>
|
|
</ol>
|
|
<h2 id="settled-decisions">Settled decisions<a class="headerlink" href="#settled-decisions" title="Permanent link">¶</a></h2>
|
|
<ul>
|
|
<li><strong>ONNX Runtime build</strong> — the installer fetches the <strong>ROCm ORT</strong> release. It
|
|
serves the <code>amd</code> platform, and its CPU execution provider covers the <code>cpu</code>
|
|
smoke-test fallback too, so one download handles both. (nvidia uses raw TRT and
|
|
doesn't need ORT.)</li>
|
|
<li><strong><code>dnf</code>/<code>pacman</code> invocation</strong> — <strong>auto-install.</strong> The installer runs <code>sudo dnf
|
|
install …</code> / <code>sudo pacman -S …</code> itself (prompting for sudo), rather than only
|
|
printing the command. It still prints what it's about to install first.</li>
|
|
<li><strong>Distro coverage</strong> — <strong>Fedora + Arch only</strong> for now. Debian/Ubuntu (<code>apt</code>) is
|
|
out of scope.</li>
|
|
</ul>
|
|
<h2 id="open-questions">Open questions<a class="headerlink" href="#open-questions" title="Permanent link">¶</a></h2>
|
|
<p><em>(none blocking — the spec above is buildable as-is.)</em></p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
|
|
|
|
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
|
</div>
|
|
|
|
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
|
|
Back to top
|
|
</button>
|
|
|
|
</main>
|
|
|
|
<footer class="md-footer">
|
|
|
|
|
|
|
|
<nav class="md-footer__inner md-grid" aria-label="Footer" >
|
|
|
|
|
|
<a href="../optimizer-experiments/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Optimizer Experiments (prior round)">
|
|
<div class="md-footer__button md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
|
</div>
|
|
<div class="md-footer__title">
|
|
<span class="md-footer__direction">
|
|
Previous
|
|
</span>
|
|
<div class="md-ellipsis">
|
|
Optimizer Experiments (prior round)
|
|
</div>
|
|
</div>
|
|
</a>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-copyright">
|
|
|
|
|
|
Made with
|
|
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
|
Material for MkDocs
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
<div class="md-dialog" data-md-component="dialog">
|
|
<div class="md-dialog__inner md-typeset"></div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<script id="__config" type="application/json">{"annotate": null, "base": "..", "features": ["navigation.tabs", "navigation.sections", "navigation.top", "navigation.footer", "content.code.copy", "content.code.annotate"], "search": "../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
|
|
|
|
|
|
<script src="../assets/javascripts/bundle.d7400e89.min.js"></script>
|
|
|
|
|
|
</body>
|
|
</html> |