Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff3b8ebf1d | ||
|
|
13437e0d8b | ||
|
|
30b5ad7da7 | ||
|
|
b26c66dcce | ||
|
|
7556c836da | ||
|
|
ef99951360 | ||
|
|
0feafec7c9 | ||
|
|
edf19ab798 | ||
|
|
e5204a831a | ||
|
|
0e35dac951 | ||
|
|
8dd2255125 | ||
|
|
0e97e532a8 | ||
|
|
1477c53885 | ||
|
|
add7e22053 | ||
|
|
ea922356f1 | ||
|
|
e1423062e2 | ||
|
|
c374c262f5 | ||
|
|
84513d3fa7 | ||
|
|
d113c83189 | ||
|
|
584f23546a | ||
|
|
de02e25e6a | ||
|
|
7b73bf923a | ||
|
|
24d35cbde3 | ||
|
|
0e27339ab6 | ||
|
|
c599e07d4b | ||
|
|
4dcef8d6c5 | ||
|
|
59a2927a15 | ||
|
|
5e46f52ad2 | ||
|
|
bb7a9ed718 | ||
|
|
48332d2041 | ||
|
|
1141172b04 | ||
|
|
90b44e0975 | ||
|
|
06373817a2 | ||
|
|
88c42573a5 | ||
|
|
7c7d4934ae | ||
|
|
e1de98e783 | ||
|
|
fd078c399f | ||
|
|
bedc859d3c | ||
|
|
718dad688d | ||
|
|
a5ee3c05ce | ||
|
|
777c98cb33 | ||
|
|
c1155cb607 | ||
|
|
f33403fff8 | ||
|
|
079b490ede | ||
|
|
a3827646b9 | ||
|
|
22758da118 | ||
|
|
960a7c4eed | ||
|
|
ae60ac7657 | ||
|
|
f891e579c5 | ||
|
|
d98dc2855a | ||
|
|
eff696b49a | ||
|
|
ffdad9873d | ||
|
|
5c6603e63b | ||
|
|
3bf4d60a6f | ||
|
|
5f6daefc40 | ||
|
|
629d698ad9 | ||
|
|
71354e862a | ||
|
|
2a8ee3660b | ||
|
|
b4318f8d9e | ||
|
|
af5208035e | ||
|
|
d3ab598434 | ||
|
|
66c9ca0a0c | ||
|
|
81ec77625c | ||
|
|
1dfd6fea11 | ||
|
|
6aabeb9897 | ||
|
|
01d7ead1e7 | ||
|
|
042e424961 | ||
|
|
9fc2763096 | ||
|
|
c843c4abe3 | ||
|
|
cc1bed92d8 | ||
|
|
13bdc27566 | ||
|
|
fa1c494825 | ||
|
|
f99f1c5ccc | ||
|
|
3605b8da78 | ||
|
|
61e487fbee | ||
|
|
c12838b9fd | ||
|
|
d31526cfaf | ||
|
|
09a4650fd9 | ||
|
|
b98372bad8 | ||
|
|
e0f9c95689 | ||
|
|
9e4cdc4efc | ||
|
|
08941540cb | ||
|
|
fe29d014da | ||
|
|
be5f67fa96 | ||
|
|
e9aea3fc41 | ||
|
|
b7c96641a9 | ||
|
|
843852e19c | ||
|
|
f0c7126f80 | ||
|
|
b35d49c772 | ||
|
|
62396fce75 | ||
|
|
908d166173 | ||
|
|
662a469870 | ||
|
|
28e3bd9496 | ||
|
|
d9aaf8fa4e | ||
|
|
a2ebdc4cdd | ||
|
|
7db40f430d | ||
|
|
020306c94f | ||
|
|
2919ed68d1 | ||
|
|
45ef7c1916 | ||
|
|
43d2c976c3 | ||
|
|
a5299daf6e | ||
|
|
458116f118 | ||
|
|
2ea5737bbd | ||
|
|
5d2f673a81 | ||
|
|
e5885977df | ||
|
|
0bd2747069 | ||
|
|
4b5557974b | ||
|
|
93b6827b14 | ||
|
|
b1efefac6f | ||
|
|
4925443e56 | ||
|
|
d340da755a | ||
|
|
76df2f66aa | ||
|
|
6f0ad83a55 | ||
|
|
26139ffe8a | ||
|
|
41a277bc19 | ||
|
|
aca6147d69 | ||
|
|
65fee74585 | ||
|
|
1f5acc25df | ||
|
|
96b1c22194 | ||
|
|
3700c763dd | ||
|
|
66298026e2 | ||
|
|
152c34b1f4 | ||
|
|
aacaefb3dc | ||
|
|
ea92dd8150 | ||
|
|
0ee131a692 | ||
|
|
a3ba53ddf7 | ||
|
|
fc16d4a0e1 | ||
|
|
a1d6759abc | ||
|
|
d753062c6c |
@@ -0,0 +1 @@
|
|||||||
|
models/*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
name: Traceability Validation
|
||||||
|
|
||||||
|
# Mirrors JellyTau's .gitea/workflows/traceability-check.yml. The extractor is
|
||||||
|
# stdlib Python, so there is no toolchain install step and no jq.
|
||||||
|
#
|
||||||
|
# This workflow is component-agnostic: every repo-specific setting - which ID
|
||||||
|
# prefixes count, which file suffixes are source, which directories to scan,
|
||||||
|
# the threshold - lives in traceability.toml at the repo root, and the same
|
||||||
|
# extractor is shared by all three JRay components. Copying this file into
|
||||||
|
# another component needs no edits.
|
||||||
|
#
|
||||||
|
# NOTE: the runner here is an Intel N100 with no discrete GPU. This job is only
|
||||||
|
# ever static analysis of source comments plus markdown parsing, so it is cheap;
|
||||||
|
# the requirements it reports as "tagged but unexecuted" are the ones that need
|
||||||
|
# a GPU host, and they are deliberately never counted as covered.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-traces:
|
||||||
|
runs-on: linux/amd64
|
||||||
|
name: Check requirement traces
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Check Python is available
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
command -v python3 >/dev/null 2>&1 || {
|
||||||
|
echo "python3 is missing from the runner image."
|
||||||
|
echo "The traceability tooling is stdlib-only Python;"
|
||||||
|
echo "3.9+ with CLI flags, 3.11+ to read traceability.toml."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
python3 --version
|
||||||
|
|
||||||
|
# The gate's own arithmetic is the thing being trusted, so its tests run
|
||||||
|
# before it does. JellyTau's gate was believed for months while it was
|
||||||
|
# dividing by frozen literals; untested gate logic is how that happens.
|
||||||
|
- name: Test the extractor
|
||||||
|
run: python3 scripts/vendor/jray-project/scripts/traceability/test_extract_traces.py
|
||||||
|
|
||||||
|
# Threshold policy and every other repo-specific setting live in
|
||||||
|
# traceability.toml, not here, so local runs and CI runs cannot disagree
|
||||||
|
# about what "passing" means. Denominators come from docs/requirements.md
|
||||||
|
# at run time and are never hardcoded -- in this file or anywhere else.
|
||||||
|
#
|
||||||
|
# A misconfigured run (zero requirements parsed, zero files scanned) is a
|
||||||
|
# hard failure rather than a plausible-looking 0%.
|
||||||
|
- name: Traceability gate
|
||||||
|
run: sh scripts/vendor/jray-project/scripts/traceability/traceability-gate.sh
|
||||||
|
|
||||||
|
# AR-024's register row names its verification tier as "Static check --
|
||||||
|
# no bare cosine outside a tagged EXCEPTION". This is that check, and it
|
||||||
|
# belongs here rather than in unit-tests.yml because it is static
|
||||||
|
# analysis of source text, like everything else in this job, and needs
|
||||||
|
# no toolchain. It blocks: an untagged bare cosine is a defect by the
|
||||||
|
# invariant's own wording, not a warning.
|
||||||
|
- name: AR-024 — no bare cosine outside a recorded exception
|
||||||
|
run: python3 scripts/ci/check_raw_cosine.py
|
||||||
|
|
||||||
|
- name: Check modified files for traces
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
echo "Checking modified sources for TRACES tags..."
|
||||||
|
|
||||||
|
# The extensions come from the report the gate just wrote, which got
|
||||||
|
# them from traceability.toml. Restating them here would be a second
|
||||||
|
# place for the source-file definition to live, and the two would
|
||||||
|
# drift the first time a language is added.
|
||||||
|
PATTERN=$(python3 -c "
|
||||||
|
import json, re, sys
|
||||||
|
suffixes = json.load(open('traces-report.json'))['config']['sourceSuffixes']
|
||||||
|
print('(' + '|'.join(re.escape(s) + '\$' for s in suffixes) + ')')
|
||||||
|
")
|
||||||
|
echo "Source suffixes from traceability.toml: $PATTERN"
|
||||||
|
|
||||||
|
CHANGED=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD" \
|
||||||
|
| grep -E "$PATTERN" || true)
|
||||||
|
|
||||||
|
if [ -z "$CHANGED" ]; then
|
||||||
|
echo "No source files changed."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Changed files:"
|
||||||
|
echo "$CHANGED" | sed 's/^/ /'
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Advisory by design: not every file implements a requirement, and a
|
||||||
|
# tag on every function is noise that rots faster than it helps
|
||||||
|
# (CLAUDE.md: tag the unit that decides). This step exists to prompt,
|
||||||
|
# not to block. The blocking checks are in the gate step above.
|
||||||
|
#
|
||||||
|
# Piped into the loop rather than a here-string, and `case` rather
|
||||||
|
# than `[[ == ]]`, so this works under dash as well as bash. The loop
|
||||||
|
# body runs in a subshell, so misses are recorded in a file.
|
||||||
|
MISSING=$(mktemp)
|
||||||
|
echo "$CHANGED" | while IFS= read -r file; do
|
||||||
|
case "$file" in
|
||||||
|
*/test_*.py|*_test.py|*Tests.cs|tests/*|*/tests/*) continue ;;
|
||||||
|
esac
|
||||||
|
[ -f "$file" ] || continue
|
||||||
|
if ! grep -q 'TRACES:' "$file"; then
|
||||||
|
echo " no TRACES tag: $file"
|
||||||
|
echo "$file" >> "$MISSING"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
COUNT=$(wc -l < "$MISSING" | tr -d ' ')
|
||||||
|
rm -f "$MISSING"
|
||||||
|
|
||||||
|
if [ "$COUNT" -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "$COUNT changed file(s) carry no requirement tag."
|
||||||
|
echo "Format: // TRACES: AR-012, AR-013 | SR-002"
|
||||||
|
echo " (pipe separates requirement types, comma separates IDs)"
|
||||||
|
echo "A deliberate invariant exception is tagged separately:"
|
||||||
|
echo " // EXCEPTION: AR-024 <reason>"
|
||||||
|
echo "See CLAUDE.md and SPEC.md section 6."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Report summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "Traceability matrix: docs/traceability.md"
|
||||||
|
echo ""
|
||||||
|
head -40 docs/traceability.md || true
|
||||||
|
|
||||||
|
- name: Save reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: traceability-reports
|
||||||
|
path: |
|
||||||
|
traces-report.json
|
||||||
|
docs/traceability.md
|
||||||
|
retention-days: 30
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
name: Unit tests
|
||||||
|
|
||||||
|
# TRACES: DP-007 | PR-004
|
||||||
|
#
|
||||||
|
# The tier the verification strategy is built on, finally executing.
|
||||||
|
#
|
||||||
|
# docs/requirements.md describes a four-tier plan in which T1 (functor unit)
|
||||||
|
# and T2 (replay) are "the only tiers that can exist in CI at all", and the
|
||||||
|
# traceability gate reports a CI-scope coverage fraction over exactly those
|
||||||
|
# tiers. Until this workflow existed, nothing ran them: "covered" meant a
|
||||||
|
# TRACES tag was present in a file, not that any test had been executed. That
|
||||||
|
# is the same failure mode as counting a test that cannot run, one level up,
|
||||||
|
# and the gate cannot detect it because a tag is all it can see.
|
||||||
|
#
|
||||||
|
# The runner is an Intel N100 with no discrete GPU. Nothing here calls a model:
|
||||||
|
# T1 constructs node functors directly, and T2 replays a precomputed HDF5 dump.
|
||||||
|
# T3 (ORT CPU smoke) and T4 (GPU) are deliberately absent -- the embedder is
|
||||||
|
# ~930 ms/frame on this hardware, so a 77 s clip at 5 fps would be six minutes
|
||||||
|
# of inference alone.
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unit-tests:
|
||||||
|
runs-on: linux/amd64
|
||||||
|
name: Build and run the GPU-free suite
|
||||||
|
|
||||||
|
# Pinned by tag, never `latest`, so rebuilding the image cannot silently
|
||||||
|
# change what a previous green build meant. Bumping the dependency set means
|
||||||
|
# bumping the tag in scripts/ci/build_builder_image.sh AND here, in one
|
||||||
|
# commit -- see that script's header.
|
||||||
|
container:
|
||||||
|
image: gitea.tourolle.paris/dtourolle/sae-builder-cpu:v1
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# KPN is a submodule and the pipeline does not build without it.
|
||||||
|
#
|
||||||
|
# NOTE: this checks out the commit this repo PINS, which is the whole
|
||||||
|
# point and is also the first thing this job will disagree with a
|
||||||
|
# developer about. A local KPN working copy that is ahead of
|
||||||
|
# origin/master builds and passes here while CI builds something else
|
||||||
|
# entirely; the AR-004 evidence in docs/requirements.md was gathered
|
||||||
|
# that way. If this job fails on tests that pass locally, check
|
||||||
|
# `git -C external/KPN log origin/master..HEAD` before suspecting the
|
||||||
|
# tests.
|
||||||
|
# LFS is deliberately NOT fetched: SAE_MODELS_DIR is baked into the
|
||||||
|
# binary as a path string and nothing in T1/T2 opens a model file, so
|
||||||
|
# pulling ~hundreds of MB of ONNX would cost the job everything and
|
||||||
|
# buy it nothing.
|
||||||
|
submodules: recursive
|
||||||
|
lfs: false
|
||||||
|
|
||||||
|
- name: Assert the builder image is the pinned one
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
echo "builder=$SAE_BUILDER version=$SAE_BUILDER_VERSION"
|
||||||
|
echo "ort=$SAE_ORT_VERSION opencv=$SAE_OPENCV_VERSION"
|
||||||
|
# The image reports its own tag. A mismatch means the `container:`
|
||||||
|
# line above and the image that actually landed disagree, which is
|
||||||
|
# exactly the drift the pinning exists to prevent -- so it fails the
|
||||||
|
# job rather than building against an unknown toolchain.
|
||||||
|
[ "$SAE_BUILDER_VERSION" = "v1" ] || {
|
||||||
|
echo "image reports version '$SAE_BUILDER_VERSION', workflow pins v1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Fetch replay fixtures
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
# bash, not sh: the script declares #!/bin/bash and uses `set -o
|
||||||
|
# pipefail` and arrays, which dash does not have.
|
||||||
|
run: bash scripts/artifacts/pull_artifacts.sh replay-fixtures latest
|
||||||
|
|
||||||
|
# pull_artifacts.sh warns and continues when a package version is missing,
|
||||||
|
# which is right for a developer pulling one artifact of several and wrong
|
||||||
|
# here. A T2 test whose fixture never arrived must not look like a pass:
|
||||||
|
# the dumps are the entire input to the replay tier, and VR-002's claim is
|
||||||
|
# that replay drives the real nodes over real data.
|
||||||
|
- name: Verify the fixtures actually arrived
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
missing=0
|
||||||
|
for f in tests/fixtures/dumps/superhero.h5; do
|
||||||
|
if [ -s "$f" ]; then
|
||||||
|
echo " ok: $f ($(wc -c < "$f") bytes)"
|
||||||
|
else
|
||||||
|
echo " MISSING: $f" >&2
|
||||||
|
missing=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$missing" -ne 0 ]; then
|
||||||
|
echo "" >&2
|
||||||
|
echo "Replay fixtures are absent, so the T2 tier cannot run." >&2
|
||||||
|
echo "They are not in git (tests/fixtures/dumps/.gitignore) -- they" >&2
|
||||||
|
echo "live in the Gitea generic package registry and are pulled by" >&2
|
||||||
|
echo "the step above, which needs GITEA_TOKEN to resolve 'latest'." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
# SAE_GEMM_BACKEND defaults to ROCM and the auto-detect prefers a GPU
|
||||||
|
# backend where it finds one; CPU is stated explicitly so this job
|
||||||
|
# cannot start depending on what happens to be installed on the runner.
|
||||||
|
# The CPU kernel is OpenBLAS in this image (tests/CMakeLists.txt fails
|
||||||
|
# the configure if it is not), so the suite exercises the kernel the
|
||||||
|
# CPU release actually ships.
|
||||||
|
cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DSAE_BUILD_TESTS=ON \
|
||||||
|
-DSAE_GEMM_BACKEND=CPU
|
||||||
|
|
||||||
|
- name: Build the test suite
|
||||||
|
run: cmake --build build --target sae_tests --parallel
|
||||||
|
|
||||||
|
- name: Run the tests
|
||||||
|
run: ctest --test-dir build --output-on-failure
|
||||||
|
|
||||||
|
- name: Save test output
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: unit-test-results
|
||||||
|
path: build/Testing/
|
||||||
|
retention-days: 30
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# Build
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
cmake-build-*/
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
*.cmake
|
||||||
|
Makefile
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# Compiled objects
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.json
|
||||||
|
# Exception: small, curated result summaries backing specific numbers quoted
|
||||||
|
# in docs/ (cross-model held-out scores, per-film training breakdown, gallery
|
||||||
|
# coverage). Regenerate with scripts/docs/run_holdout_all_models.py and
|
||||||
|
# scripts/docs/gallery_coverage_per_film.py.
|
||||||
|
!docs_data/*.json
|
||||||
|
# Exception: test fixtures are inputs, not build output. The audio golden
|
||||||
|
# vector (IR-005) is shared verbatim with the jRay plugin repo, so it has to be
|
||||||
|
# tracked. Regenerate the media with tests/fixtures/audio/make_fixture.py.
|
||||||
|
!tests/fixtures/**
|
||||||
|
# Video files
|
||||||
|
*.mp4
|
||||||
|
*.mkv
|
||||||
|
*.avi
|
||||||
|
*.mov
|
||||||
|
|
||||||
|
# ONNX models in models/ are tracked via Git LFS (see .gitattributes).
|
||||||
|
# Any stray ONNX elsewhere is generated/downloaded and not tracked.
|
||||||
|
external/*.onnx
|
||||||
|
|
||||||
|
# Generated TensorRT engines (rebuilt by ORT / scripts/build_trt_engines.sh)
|
||||||
|
trt_cache/
|
||||||
|
|
||||||
|
# ORT pre-optimized model cache (generated on first run, provider-specific)
|
||||||
|
ort_cache/
|
||||||
|
|
||||||
|
# Gallery files (generated — HDF5 only, see src/gallery/gallery_store.cpp).
|
||||||
|
# Legacy JSON galleries from before that switch are also excluded.
|
||||||
|
gallery.json
|
||||||
|
gallery_*.json
|
||||||
|
gallery.h5
|
||||||
|
gallery_*.h5
|
||||||
|
|
||||||
|
# Calibration cache (generated alongside a gallery, per-embedder)
|
||||||
|
*.calib_cache.csv
|
||||||
|
*.calib_cache.png
|
||||||
|
|
||||||
|
# Cameo detection run outputs (generated by scripts/cameo_*.py)
|
||||||
|
cameo_progress.txt
|
||||||
|
cameo_report.txt
|
||||||
|
|
||||||
|
# Analysis plot outputs (scene-gap histograms / KDEs, etc.)
|
||||||
|
scene_gap_*.png
|
||||||
|
|
||||||
|
# Per-frame debug images
|
||||||
|
images/
|
||||||
|
|
||||||
|
# Annotations output
|
||||||
|
annotations.json
|
||||||
|
*_annotations.json
|
||||||
|
|
||||||
|
# MovieNet evaluation data
|
||||||
|
movienet-ps/
|
||||||
|
|
||||||
|
# Eval probe images (data, regenerable)
|
||||||
|
eval/probe/
|
||||||
|
|
||||||
|
# Local reference repos kept for inspiration (each has its own .git)
|
||||||
|
inspiration/
|
||||||
|
|
||||||
|
# experiments/ has its own nested .gitignore for HDF5 galleries/dumps/X-Ray
|
||||||
|
# corpus (all pushed/pulled via scripts/artifacts/{push,pull}_artifacts.sh to
|
||||||
|
# the Gitea generic package registry instead of committed).
|
||||||
|
# Exception to the blanket *.json rule above: the committed placeholder for
|
||||||
|
# experiments/file-lut.json (see experiments/.gitignore).
|
||||||
|
!experiments/file-lut.template.json
|
||||||
|
|
||||||
|
# Site build output (mkdocs build). Rendered site is deployed to a
|
||||||
|
# gitea-pages branch, never committed to a working branch.
|
||||||
|
site/
|
||||||
|
docs_site/
|
||||||
|
|
||||||
|
# Images staged into docs/ from the artifact registry at build time
|
||||||
|
# (scripts/docs/build_site.sh) — not committed, pulled fresh on each build.
|
||||||
|
# Exception: pipeline_topology.svg is small and hand-authored (not pulled from
|
||||||
|
# anywhere) and the README references it directly, so it needs to render on a
|
||||||
|
# plain Gitea repo view too, not just the built Pages site. (A directory-level
|
||||||
|
# ignore can't be un-ignored file-by-file below it, so this must NOT blanket-
|
||||||
|
# ignore docs/assets/ itself — only its contents, minus the one exception.)
|
||||||
|
docs/assets/images/*
|
||||||
|
!docs/assets/images/pipeline_topology.svg
|
||||||
|
# These frames are referenced directly by README.md, which renders on the
|
||||||
|
# plain Gitea repo view — committed for the same reason as the SVG above.
|
||||||
|
!docs/assets/images/lovelace_perfect_second.jpg
|
||||||
|
!docs/assets/images/valerian_screen_call.jpg
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Local secrets (API keys — never commit)
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Editor / OS
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
.claude/settings.local.json
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.venv-rocm/
|
||||||
|
!models/scene_boundary_xgb.json
|
||||||
|
experiments/dump_review/
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[submodule "external/KPN"]
|
||||||
|
path = external/KPN
|
||||||
|
url = https://gitea.tourolle.paris/dtourolle/KPN.git
|
||||||
|
branch = master
|
||||||
|
[submodule "jray-project"]
|
||||||
|
path = scripts/vendor/jray-project
|
||||||
|
url = git@gitea.tourolle.paris:dtourolle/jray-project.git
|
||||||
@@ -1,713 +0,0 @@
|
|||||||
|
|
||||||
<!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="icon" href="/dtourolle/scene-actor-extraction/assets/images/favicon.png">
|
|
||||||
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.7">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<title>scene-actor-extraction</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/dtourolle/scene-actor-extraction/assets/stylesheets/main.ec1eaa64.min.css">
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/dtourolle/scene-actor-extraction/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="/dtourolle/scene-actor-extraction/stylesheets/extra.css">
|
|
||||||
|
|
||||||
<script>__md_scope=new URL("/dtourolle/scene-actor-extraction/",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">
|
|
||||||
|
|
||||||
</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="/dtourolle/scene-actor-extraction/." 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">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</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="/dtourolle/scene-actor-extraction/." class="md-tabs__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Home
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-tabs__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/methodology/" class="md-tabs__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
How We Score Against X-Ray
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-tabs__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/best-model/" class="md-tabs__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Findings
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-tabs__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/model-bakeoff/" class="md-tabs__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Full Experiment Log
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-tabs__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/service-conversion/" 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="/dtourolle/scene-actor-extraction/." 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="/dtourolle/scene-actor-extraction/." class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
Home
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-nav__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/methodology/" class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
How We Score Against X-Ray
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-nav__item md-nav__item--nested">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
|
|
||||||
|
|
||||||
|
|
||||||
<label class="md-nav__link" for="__nav_3" id="__nav_3_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_3_label" aria-expanded="false">
|
|
||||||
<label class="md-nav__title" for="__nav_3">
|
|
||||||
<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="/dtourolle/scene-actor-extraction/best-model/" class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
Best Model
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-nav__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/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="/dtourolle/scene-actor-extraction/pose-expansion/" class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
Pose Expansion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-nav__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/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="/dtourolle/scene-actor-extraction/model-bakeoff/" class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
Full Experiment Log
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<li class="md-nav__item">
|
|
||||||
<a href="/dtourolle/scene-actor-extraction/service-conversion/" class="md-nav__link">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span class="md-ellipsis">
|
|
||||||
|
|
||||||
|
|
||||||
Service Conversion (proposal)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
|
||||||
</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">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="md-content" data-md-component="content">
|
|
||||||
|
|
||||||
<article class="md-content__inner md-typeset">
|
|
||||||
|
|
||||||
<h1>404 - Not found</h1>
|
|
||||||
|
|
||||||
</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">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<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": "/dtourolle/scene-actor-extraction/", "features": ["navigation.tabs", "navigation.sections", "navigation.top", "navigation.footer", "content.code.copy", "content.code.annotate"], "search": "/dtourolle/scene-actor-extraction/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="/dtourolle/scene-actor-extraction/assets/javascripts/bundle.d7400e89.min.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -0,0 +1,441 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
project(scene_actor_extraction VERSION 0.1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# ── Dependencies ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# KPN++ (pipeline backbone)
|
||||||
|
set(KPN_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(KPN_BUILD_PYTHON OFF CACHE BOOL "" FORCE)
|
||||||
|
set(KPN_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
option(SAE_WEB_DEBUG "Enable KPN web debug UI (localhost:9090)" OFF)
|
||||||
|
if(SAE_WEB_DEBUG)
|
||||||
|
set(KPN_WEB_DEBUG ON CACHE BOOL "" FORCE)
|
||||||
|
endif()
|
||||||
|
add_subdirectory(external/KPN)
|
||||||
|
|
||||||
|
# OpenCV (video decode, image ops, DNN inference, face detection)
|
||||||
|
# Accept 4 or 5: the APIs used here are stable across both, and distros have
|
||||||
|
# begun shipping 5.x as the default (Arch/CachyOS). find_package's version
|
||||||
|
# argument is a minimum, but OpenCV's config rejects a 5.x install when 4 is
|
||||||
|
# requested, so probe for 5 first and fall back to 4.
|
||||||
|
find_package(OpenCV 5 QUIET COMPONENTS
|
||||||
|
core imgproc imgcodecs videoio dnn objdetect highgui)
|
||||||
|
if(NOT OpenCV_FOUND)
|
||||||
|
find_package(OpenCV 4 REQUIRED COMPONENTS
|
||||||
|
core imgproc imgcodecs videoio dnn objdetect highgui)
|
||||||
|
endif()
|
||||||
|
message(STATUS "OpenCV: ${OpenCV_VERSION}")
|
||||||
|
|
||||||
|
# ── Model paths ───────────────────────────────────────────────────────────────
|
||||||
|
# Defined early so the backend object libraries below can embed it.
|
||||||
|
set(SAE_MODELS_DIR "${CMAKE_SOURCE_DIR}/models"
|
||||||
|
CACHE PATH "Directory containing ONNX model files")
|
||||||
|
|
||||||
|
# ── Backend selection ─────────────────────────────────────────────────────────
|
||||||
|
# Two independent compile-time axes. The core application is agnostic to both:
|
||||||
|
# only the matching backend .cpp (in src/backends/) is compiled, and the backend
|
||||||
|
# headers (onnxruntime / NvInfer.h / cublas / rocblas) never reach core TUs.
|
||||||
|
#
|
||||||
|
# SAE_INFERENCE_BACKEND ORT → SCRFD + ArcFace via ONNX Runtime (.onnx models)
|
||||||
|
# TRT → SCRFD + ArcFace via raw TensorRT (.engine files)
|
||||||
|
# SAE_GEMM_BACKEND ROCM → gallery similarity GEMM via rocBLAS / HIP
|
||||||
|
# CUDA → gallery similarity GEMM via cuBLAS / CUDA
|
||||||
|
# CPU → portable reference GEMM (no GPU; CI / testing)
|
||||||
|
set(SAE_INFERENCE_BACKEND "ORT" CACHE STRING "Inference backend: ORT | TRT")
|
||||||
|
set(SAE_GEMM_BACKEND "ROCM" CACHE STRING "Gallery GEMM backend: ROCM | CUDA | CPU")
|
||||||
|
set_property(CACHE SAE_INFERENCE_BACKEND PROPERTY STRINGS ORT TRT)
|
||||||
|
set_property(CACHE SAE_GEMM_BACKEND PROPERTY STRINGS ROCM CUDA CPU)
|
||||||
|
|
||||||
|
# Enable the ORT TensorRT/CUDA execution providers inside the ORT inference
|
||||||
|
# backend (only meaningful when ORT was built with the TensorRT EP). Off by
|
||||||
|
# default so ROCm/CPU builds don't reference unavailable EPs.
|
||||||
|
option(SAE_ORT_TRT_EP "ORT backend: enable TensorRT/CUDA execution providers" OFF)
|
||||||
|
|
||||||
|
# AR-026/AR-027: the CPU GEMM path is backed by OpenBLAS, and its absence is a
|
||||||
|
# configure error rather than a silent downgrade to the scalar loop. Declared at
|
||||||
|
# top level because the unit-test target compiles the CPU kernel regardless of
|
||||||
|
# which backend the main build selected, and both must make the same choice.
|
||||||
|
option(SAE_ALLOW_SCALAR_GEMM
|
||||||
|
"Permit the scalar-loop GEMM fallback when OpenBLAS is absent" OFF)
|
||||||
|
|
||||||
|
# Back-compat: a legacy -DSAE_WITH_TRT=ON/OFF seeds the new vars (ON⇒TRT+CUDA,
|
||||||
|
# OFF⇒ORT+ROCM) unless the user set them explicitly.
|
||||||
|
if(DEFINED SAE_WITH_TRT)
|
||||||
|
if(SAE_WITH_TRT)
|
||||||
|
set(SAE_INFERENCE_BACKEND "TRT" CACHE STRING "" FORCE)
|
||||||
|
set(SAE_GEMM_BACKEND "CUDA" CACHE STRING "" FORCE)
|
||||||
|
else()
|
||||||
|
set(SAE_INFERENCE_BACKEND "ORT" CACHE STRING "" FORCE)
|
||||||
|
set(SAE_GEMM_BACKEND "ROCM" CACHE STRING "" FORCE)
|
||||||
|
endif()
|
||||||
|
message(STATUS "SAE_WITH_TRT=${SAE_WITH_TRT} (legacy) → "
|
||||||
|
"SAE_INFERENCE_BACKEND=${SAE_INFERENCE_BACKEND} "
|
||||||
|
"SAE_GEMM_BACKEND=${SAE_GEMM_BACKEND}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT SAE_INFERENCE_BACKEND MATCHES "^(ORT|TRT)$")
|
||||||
|
message(FATAL_ERROR "SAE_INFERENCE_BACKEND must be ORT or TRT (got '${SAE_INFERENCE_BACKEND}')")
|
||||||
|
endif()
|
||||||
|
if(NOT SAE_GEMM_BACKEND MATCHES "^(ROCM|CUDA|CPU)$")
|
||||||
|
message(FATAL_ERROR "SAE_GEMM_BACKEND must be ROCM, CUDA or CPU (got '${SAE_GEMM_BACKEND}')")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# CUDA runtime is needed by both TRT inference and CUDA GEMM — find it once.
|
||||||
|
function(sae_find_cudart)
|
||||||
|
if(TARGET cudart_dep)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
find_library(CUDART_LIB cudart
|
||||||
|
HINTS /opt/cuda/lib64 /usr/local/cuda/lib64 /usr/lib)
|
||||||
|
find_path(CUDART_INCLUDE cuda_runtime_api.h
|
||||||
|
HINTS /opt/cuda/targets/x86_64-linux/include /opt/cuda/include
|
||||||
|
/usr/local/cuda/include /usr/include)
|
||||||
|
if(NOT (CUDART_LIB AND CUDART_INCLUDE))
|
||||||
|
message(FATAL_ERROR "CUDA runtime not found (cudart=${CUDART_LIB} headers=${CUDART_INCLUDE}).")
|
||||||
|
endif()
|
||||||
|
add_library(cudart_dep INTERFACE)
|
||||||
|
target_include_directories(cudart_dep INTERFACE "${CUDART_INCLUDE}")
|
||||||
|
target_link_libraries(cudart_dep INTERFACE "${CUDART_LIB}")
|
||||||
|
set_property(GLOBAL PROPERTY sae_cudart_found TRUE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# ── Inference backend dependency: builds the `inference_backend` object lib ────
|
||||||
|
if(SAE_INFERENCE_BACKEND STREQUAL "ORT")
|
||||||
|
find_library(ORT_LIB onnxruntime REQUIRED
|
||||||
|
HINTS /usr/lib64/rocm/lib /usr/lib /usr/local/lib)
|
||||||
|
find_path(ORT_INCLUDE onnxruntime_cxx_api.h
|
||||||
|
PATH_SUFFIXES onnxruntime
|
||||||
|
HINTS /usr/lib64/rocm/include/onnxruntime /usr/include/onnxruntime /usr/local/include/onnxruntime
|
||||||
|
/usr/lib64/rocm/include /usr/include /usr/local/include
|
||||||
|
REQUIRED)
|
||||||
|
# The include directive is <onnxruntime/onnxruntime_cxx_api.h>, so we need the
|
||||||
|
# parent of the onnxruntime/ subdirectory on the include path.
|
||||||
|
get_filename_component(ORT_INCLUDE_PARENT "${ORT_INCLUDE}" DIRECTORY)
|
||||||
|
if(NOT EXISTS "${ORT_INCLUDE_PARENT}/onnxruntime")
|
||||||
|
set(ORT_INCLUDE_PARENT "${ORT_INCLUDE}")
|
||||||
|
endif()
|
||||||
|
message(STATUS "Inference backend: ORT (${ORT_LIB} headers: ${ORT_INCLUDE_PARENT})")
|
||||||
|
|
||||||
|
add_library(inference_backend OBJECT src/backends/ort_backend.cpp)
|
||||||
|
set_target_properties(inference_backend PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(inference_backend PRIVATE src "${ORT_INCLUDE_PARENT}")
|
||||||
|
target_link_libraries(inference_backend PRIVATE ${OpenCV_LIBS} "${ORT_LIB}")
|
||||||
|
target_compile_definitions(inference_backend PRIVATE
|
||||||
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}"
|
||||||
|
$<$<BOOL:${SAE_ORT_TRT_EP}>:SAE_ORT_WITH_TRT_EP>)
|
||||||
|
else() # TRT
|
||||||
|
find_library(NVINFER_LIB nvinfer
|
||||||
|
HINTS /usr/lib /usr/local/lib /opt/tensorrt/lib)
|
||||||
|
find_path(NVINFER_INCLUDE NvInfer.h
|
||||||
|
HINTS /usr/include /usr/local/include /opt/tensorrt/include)
|
||||||
|
if(NOT (NVINFER_LIB AND NVINFER_INCLUDE))
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"TensorRT not found (nvinfer=${NVINFER_LIB} headers=${NVINFER_INCLUDE}). "
|
||||||
|
"Pass -DSAE_INFERENCE_BACKEND=ORT to load .onnx models without TensorRT.")
|
||||||
|
endif()
|
||||||
|
sae_find_cudart()
|
||||||
|
message(STATUS "Inference backend: TRT (${NVINFER_LIB})")
|
||||||
|
|
||||||
|
add_library(inference_backend OBJECT src/backends/trt_backend.cpp)
|
||||||
|
set_target_properties(inference_backend PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(inference_backend PRIVATE src "${NVINFER_INCLUDE}")
|
||||||
|
target_link_libraries(inference_backend PRIVATE
|
||||||
|
${OpenCV_LIBS} "${NVINFER_LIB}" cudart_dep)
|
||||||
|
target_compile_definitions(inference_backend PRIVATE
|
||||||
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── GEMM backend dependency: builds the `gemm_backend` object lib ──────────────
|
||||||
|
if(SAE_GEMM_BACKEND STREQUAL "CPU")
|
||||||
|
# Portable reference GEMM: no GPU libraries, no headers. Used for CI and as
|
||||||
|
# the correctness oracle for the CUDA/ROCm backends.
|
||||||
|
message(STATUS "GEMM backend: CPU (portable reference, no GPU)")
|
||||||
|
|
||||||
|
add_library(gemm_backend OBJECT src/backends/gemm_backend.cpp)
|
||||||
|
set_target_properties(gemm_backend PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(gemm_backend PRIVATE src)
|
||||||
|
target_compile_definitions(gemm_backend PRIVATE SAE_GEMM_CPU)
|
||||||
|
|
||||||
|
# AR-026/AR-027: the CPU path is backed by OpenBLAS, and that is REQUIRED
|
||||||
|
# rather than opportunistic. The CPU backend is what CI (no GPU) and the cpu
|
||||||
|
# builder image actually run, so a silent fall back to the scalar loop means
|
||||||
|
# AR-027 is measured — or worse, believed — on a path no release uses. A
|
||||||
|
# missing dependency should stop the build and name itself, not degrade into
|
||||||
|
# a slower answer nobody notices.
|
||||||
|
#
|
||||||
|
# The scalar loop survives as the correctness oracle the two backends are
|
||||||
|
# diffed against; -DSAE_ALLOW_SCALAR_GEMM=ON is how you ask for it, which
|
||||||
|
# keeps that an explicit, visible choice.
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
if(PkgConfig_FOUND)
|
||||||
|
pkg_check_modules(OPENBLAS QUIET openblas)
|
||||||
|
endif()
|
||||||
|
if(OPENBLAS_FOUND)
|
||||||
|
message(STATUS "GEMM backend: CPU + OpenBLAS ${OPENBLAS_VERSION}")
|
||||||
|
target_compile_definitions(gemm_backend PRIVATE SAE_GEMM_CBLAS)
|
||||||
|
target_include_directories(gemm_backend PRIVATE ${OPENBLAS_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(gemm_backend PRIVATE ${OPENBLAS_LINK_LIBRARIES})
|
||||||
|
elseif(SAE_ALLOW_SCALAR_GEMM)
|
||||||
|
message(WARNING "GEMM backend: CPU scalar fallback (SAE_ALLOW_SCALAR_GEMM=ON) — "
|
||||||
|
"correct, but slow on a large gallery. Do not measure AR-027 here.")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"OpenBLAS not found, and the CPU GEMM backend requires it (AR-026/AR-027).\n"
|
||||||
|
" Install it: Fedora dnf install openblas-devel\n"
|
||||||
|
" Arch pacman -S openblas\n"
|
||||||
|
" Debian apt install libopenblas-dev\n"
|
||||||
|
" Or build the scalar fallback deliberately: -DSAE_ALLOW_SCALAR_GEMM=ON")
|
||||||
|
endif()
|
||||||
|
elseif(SAE_GEMM_BACKEND STREQUAL "CUDA")
|
||||||
|
find_library(CUBLAS_LIB cublas
|
||||||
|
HINTS /opt/cuda/targets/x86_64-linux/lib /opt/cuda/lib64
|
||||||
|
/usr/local/cuda/lib64 /usr/lib)
|
||||||
|
if(NOT CUBLAS_LIB)
|
||||||
|
message(FATAL_ERROR "cuBLAS not found (cublas=${CUBLAS_LIB}).")
|
||||||
|
endif()
|
||||||
|
sae_find_cudart()
|
||||||
|
message(STATUS "GEMM backend: CUDA (${CUBLAS_LIB})")
|
||||||
|
|
||||||
|
add_library(gemm_backend OBJECT src/backends/gemm_backend.cpp)
|
||||||
|
set_target_properties(gemm_backend PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(gemm_backend PRIVATE src)
|
||||||
|
target_link_libraries(gemm_backend PRIVATE "${CUBLAS_LIB}" cudart_dep)
|
||||||
|
target_compile_definitions(gemm_backend PRIVATE SAE_GEMM_CUDA)
|
||||||
|
else() # ROCM
|
||||||
|
find_library(ROCBLAS_LIB rocblas
|
||||||
|
HINTS /usr/lib64/rocm/lib /usr/lib64 /usr/local/lib)
|
||||||
|
find_path(ROCBLAS_INCLUDE rocblas/rocblas.h
|
||||||
|
HINTS /usr/lib64/rocm/include /usr/include /usr/local/include)
|
||||||
|
find_library(HIP_LIB amdhip64
|
||||||
|
HINTS /usr/lib64/rocm/lib /usr/lib64 /usr/local/lib)
|
||||||
|
find_path(HIP_INCLUDE hip/hip_runtime_api.h
|
||||||
|
HINTS /usr/lib64/rocm/include /usr/include /usr/local/include)
|
||||||
|
if(NOT (ROCBLAS_LIB AND ROCBLAS_INCLUDE AND HIP_LIB AND HIP_INCLUDE))
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"rocBLAS or HIP runtime not found "
|
||||||
|
"(rocblas=${ROCBLAS_LIB} headers=${ROCBLAS_INCLUDE} "
|
||||||
|
"hip=${HIP_LIB} headers=${HIP_INCLUDE}). "
|
||||||
|
"Install rocblas-devel and hip-devel (or pass -DSAE_GEMM_BACKEND=CUDA).")
|
||||||
|
endif()
|
||||||
|
message(STATUS "GEMM backend: ROCM (${ROCBLAS_LIB})")
|
||||||
|
|
||||||
|
add_library(gemm_backend OBJECT src/backends/gemm_backend.cpp)
|
||||||
|
set_target_properties(gemm_backend PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(gemm_backend PRIVATE src "${ROCBLAS_INCLUDE}" "${HIP_INCLUDE}")
|
||||||
|
target_link_libraries(gemm_backend PRIVATE "${ROCBLAS_LIB}" "${HIP_LIB}")
|
||||||
|
# HIP headers require the platform to be declared explicitly when compiled with g++.
|
||||||
|
target_compile_definitions(gemm_backend PRIVATE SAE_GEMM_ROCM __HIP_PLATFORM_AMD__)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# FFmpeg (hwaccel video decode: CUDA/VAAPI, runtime-detected + swscale colour
|
||||||
|
# conversion). Hwaccel support is built into libavcodec/libavutil; no extra
|
||||||
|
# libraries are needed here.
|
||||||
|
# libswresample is the audio side of the same dependency — downmix + resample
|
||||||
|
# for the audio signature (IR-004, src/audio_signature.cpp). Not a new project
|
||||||
|
# dependency: it ships with the libav* set already required above.
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(AVFORMAT REQUIRED libavformat)
|
||||||
|
pkg_check_modules(AVCODEC REQUIRED libavcodec)
|
||||||
|
pkg_check_modules(AVUTIL REQUIRED libavutil)
|
||||||
|
pkg_check_modules(SWSCALE REQUIRED libswscale)
|
||||||
|
pkg_check_modules(SWRESAMPLE REQUIRED libswresample)
|
||||||
|
|
||||||
|
add_library(ffmpeg_libs INTERFACE)
|
||||||
|
target_compile_options(ffmpeg_libs INTERFACE
|
||||||
|
${AVFORMAT_CFLAGS_OTHER} ${AVCODEC_CFLAGS_OTHER}
|
||||||
|
${AVUTIL_CFLAGS_OTHER} ${SWSCALE_CFLAGS_OTHER}
|
||||||
|
${SWRESAMPLE_CFLAGS_OTHER})
|
||||||
|
target_include_directories(ffmpeg_libs INTERFACE
|
||||||
|
${AVFORMAT_INCLUDE_DIRS} ${AVCODEC_INCLUDE_DIRS}
|
||||||
|
${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS}
|
||||||
|
${SWRESAMPLE_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(ffmpeg_libs INTERFACE
|
||||||
|
${AVFORMAT_LIBRARIES} ${AVCODEC_LIBRARIES}
|
||||||
|
${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES}
|
||||||
|
${SWRESAMPLE_LIBRARIES})
|
||||||
|
message(STATUS "FFmpeg: avformat=${AVFORMAT_VERSION} avcodec=${AVCODEC_VERSION} "
|
||||||
|
"swresample=${SWRESAMPLE_VERSION}")
|
||||||
|
|
||||||
|
# nlohmann/json (gallery + output serialisation)
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
nlohmann_json
|
||||||
|
GIT_REPOSITORY https://github.com/nlohmann/json.git
|
||||||
|
GIT_TAG v3.11.3
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(nlohmann_json)
|
||||||
|
|
||||||
|
# nanobind (Python bindings for the sae_embed module)
|
||||||
|
find_package(Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)
|
||||||
|
FetchContent_Declare(
|
||||||
|
nanobind
|
||||||
|
GIT_REPOSITORY https://github.com/wjakob/nanobind.git
|
||||||
|
GIT_TAG v2.4.0
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(nanobind)
|
||||||
|
|
||||||
|
# XGBoost (learned scene-boundary detector for flood-fill presence). Fetched and
|
||||||
|
# built from source so we get both the C API header and a matching libxgboost,
|
||||||
|
# reproducibly — the pip wheel ships the .so but no header. Heavy first build, so
|
||||||
|
# it is opt-in; the scene-boundary node is compiled only when SAE_SCENE_XGB is on.
|
||||||
|
option(SAE_SCENE_XGB "Build the XGBoost scene-boundary detector node" ON)
|
||||||
|
if(SAE_SCENE_XGB)
|
||||||
|
set(BUILD_STATIC_LIB ON CACHE BOOL "" FORCE) # link xgboost statically
|
||||||
|
set(USE_OPENMP ON CACHE BOOL "" FORCE)
|
||||||
|
FetchContent_Declare(
|
||||||
|
xgboost
|
||||||
|
GIT_REPOSITORY https://github.com/dmlc/xgboost.git
|
||||||
|
GIT_TAG v2.1.1
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
GIT_SUBMODULES_RECURSE TRUE
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(xgboost)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── Model paths ───────────────────────────────────────────────────────────────
|
||||||
|
set(SAE_MODELS_DIR "${CMAKE_SOURCE_DIR}/models"
|
||||||
|
CACHE PATH "Directory containing ONNX model files")
|
||||||
|
|
||||||
|
# ── Shared library: gallery store + compiled-in backends ──────────────────────
|
||||||
|
# The backend object libraries carry their own ORT/TRT/CUDA/ROCm linkage and
|
||||||
|
# headers; sae_gallery re-exports those object files so every binary that links
|
||||||
|
# sae_gallery gets the chosen backend without ever seeing its headers.
|
||||||
|
# HDF5 (C++) — gallery fast-load path + embedding dump. Found here so sae_gallery
|
||||||
|
# (gallery_store.cpp) can link it; scene_analyze/dump_embeddings reuse the same vars.
|
||||||
|
find_package(HDF5 REQUIRED COMPONENTS CXX)
|
||||||
|
|
||||||
|
add_library(sae_gallery STATIC
|
||||||
|
src/gallery/gallery_store.cpp
|
||||||
|
src/gallery/gallery_builder.cpp
|
||||||
|
src/audio_signature.cpp # IR-004 — content-derived audio signature
|
||||||
|
src/gallery/embedder_stamp.cpp # GR-004 — gallery/embedder binding
|
||||||
|
)
|
||||||
|
set_target_properties(sae_gallery PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_include_directories(sae_gallery PUBLIC src ${HDF5_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(sae_gallery PUBLIC
|
||||||
|
kpn
|
||||||
|
${OpenCV_LIBS}
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
inference_backend
|
||||||
|
gemm_backend
|
||||||
|
ffmpeg_libs
|
||||||
|
${HDF5_CXX_LIBRARIES}
|
||||||
|
)
|
||||||
|
target_compile_definitions(sae_gallery PUBLIC
|
||||||
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ── embed_faces — image → embedding JSON (used by gallery builder scripts) ────
|
||||||
|
add_executable(embed_faces src/embed_faces.cpp)
|
||||||
|
target_link_libraries(embed_faces PRIVATE sae_gallery)
|
||||||
|
|
||||||
|
# ── sae_embed — Python module: load SCRFD+ArcFace once, embed many images ───
|
||||||
|
nanobind_add_module(sae_embed src/python_bindings.cpp)
|
||||||
|
target_link_libraries(sae_embed PRIVATE sae_gallery)
|
||||||
|
|
||||||
|
# ── sae_kpn — Python module: run the real downstream nodes over dumped embeddings ─
|
||||||
|
# Assembles face_tracker/identity_matcher/frame_annotation in a Python-driven KPN
|
||||||
|
# network (KPN_BUILD_PYTHON is enabled per-TU inside the .cpp). Powers the
|
||||||
|
# threshold-sweep optimizer in scripts/optimizer/.
|
||||||
|
#
|
||||||
|
# TRACES: VR-011 | PR-002
|
||||||
|
# ON again. It was OFF for one commit because it had not compiled since the
|
||||||
|
# AR-007/AR-008 tracker redesign -- the binding built FaceTrackerFunc from a
|
||||||
|
# Config alone, and the tracker had required a registry and a calibration since.
|
||||||
|
# VR-011 replaced the three per-node factories with one `add_pipeline` that
|
||||||
|
# builds the chain in main.cpp's order, which is the only order that satisfies
|
||||||
|
# those dependencies, so the failure mode cannot recur from Python.
|
||||||
|
option(SAE_BUILD_KPN_BINDINGS "Build the sae_kpn Python module" ON)
|
||||||
|
if(SAE_BUILD_KPN_BINDINGS)
|
||||||
|
nanobind_add_module(sae_kpn src/kpn_bindings.cpp)
|
||||||
|
target_link_libraries(sae_kpn PRIVATE sae_gallery)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── sae_audio — Python module: the v1 audio signature (IR-004) ────────────────
|
||||||
|
# Compiles audio_signature.cpp directly and links only FFmpeg, rather than
|
||||||
|
# linking sae_gallery: the signature needs no model, no OpenCV and no HDF5, and
|
||||||
|
# a module that dragged all three in would make `import sae_audio` depend on a
|
||||||
|
# GPU-capable build of a repo whose audio path is pure CPU DSP. tests/ compiles
|
||||||
|
# the same source the same way, for the same reason.
|
||||||
|
nanobind_add_module(sae_audio src/audio_bindings.cpp src/audio_signature.cpp)
|
||||||
|
target_include_directories(sae_audio PRIVATE src)
|
||||||
|
target_link_libraries(sae_audio PRIVATE ffmpeg_libs)
|
||||||
|
|
||||||
|
# HDF5 already found above (before sae_gallery); vars HDF5_CXX_LIBRARIES / _INCLUDE_DIRS
|
||||||
|
# are reused by scene_analyze / dump_embeddings below.
|
||||||
|
|
||||||
|
# The learned scene-boundary detector is compiled into the sink (result_sink →
|
||||||
|
# xgb_scene_boundary + audio_logpsd) when SAE_SCENE_XGB is on, so the analysis
|
||||||
|
# binaries need xgboost + FFTW + ffmpeg and the define. Found once here.
|
||||||
|
if(SAE_SCENE_XGB)
|
||||||
|
find_library(FFTW3_LIB fftw3 REQUIRED)
|
||||||
|
set(SAE_SCENE_LIBS xgboost ${FFTW3_LIB} ffmpeg_libs)
|
||||||
|
set(SAE_SCENE_DEFS SAE_SCENE_XGB)
|
||||||
|
else()
|
||||||
|
set(SAE_SCENE_LIBS "")
|
||||||
|
set(SAE_SCENE_DEFS "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── analyze — main analysis binary ───────────────────────────────────────────
|
||||||
|
add_executable(scene_analyze src/main.cpp)
|
||||||
|
target_link_libraries(scene_analyze PRIVATE sae_gallery ${HDF5_CXX_LIBRARIES} ${SAE_SCENE_LIBS})
|
||||||
|
target_include_directories(scene_analyze PRIVATE ${HDF5_INCLUDE_DIRS})
|
||||||
|
target_compile_definitions(scene_analyze PRIVATE ${SAE_SCENE_DEFS})
|
||||||
|
|
||||||
|
# ── xgb_boundary_parity — prove C++ scene-boundary inference matches Python ───
|
||||||
|
if(SAE_SCENE_XGB)
|
||||||
|
add_executable(xgb_boundary_parity src/tools/xgb_boundary_parity.cpp)
|
||||||
|
target_include_directories(xgb_boundary_parity PRIVATE src ${HDF5_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(xgb_boundary_parity PRIVATE
|
||||||
|
xgboost ${HDF5_CXX_LIBRARIES} ${FFTW3_LIB} ffmpeg_libs)
|
||||||
|
|
||||||
|
# Dumps the C++ feature matrix so training uses the exact inference features.
|
||||||
|
add_executable(scene_features_dump src/tools/scene_features_dump.cpp)
|
||||||
|
target_include_directories(scene_features_dump PRIVATE src ${HDF5_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(scene_features_dump PRIVATE
|
||||||
|
xgboost ${HDF5_CXX_LIBRARIES} ${FFTW3_LIB} ffmpeg_libs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── analyze_debug — same binary with debug frame/crop output ─────────────────
|
||||||
|
add_executable(scene_analyze_debug src/main.cpp)
|
||||||
|
target_link_libraries(scene_analyze_debug PRIVATE sae_gallery ${HDF5_CXX_LIBRARIES} ${SAE_SCENE_LIBS})
|
||||||
|
target_include_directories(scene_analyze_debug PRIVATE ${HDF5_INCLUDE_DIRS})
|
||||||
|
target_compile_definitions(scene_analyze_debug PRIVATE SAE_DEBUG=1 ${SAE_SCENE_DEFS})
|
||||||
|
|
||||||
|
# ── dump_embeddings — standalone embedding dumper, NO gallery/matcher ─────────
|
||||||
|
# Front-half only (decode→detect→align→embed→HDF5) for the optimizer replay corpus
|
||||||
|
# and model bake-off. Skips gallery load + calibration (~24s/run faster).
|
||||||
|
add_executable(dump_embeddings src/dump_embeddings.cpp)
|
||||||
|
target_link_libraries(dump_embeddings PRIVATE sae_gallery ${HDF5_CXX_LIBRARIES})
|
||||||
|
target_include_directories(dump_embeddings PRIVATE ${HDF5_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# ── scene_preview — live annotated display while analysing ───────────────────
|
||||||
|
add_executable(scene_preview src/scene_preview.cpp)
|
||||||
|
target_link_libraries(scene_preview PRIVATE sae_gallery)
|
||||||
|
|
||||||
|
# ── build_gallery — offline gallery construction tool ────────────────────────
|
||||||
|
add_executable(build_gallery src/build_gallery.cpp)
|
||||||
|
target_link_libraries(build_gallery PRIVATE sae_gallery)
|
||||||
|
|
||||||
|
# ── Optional: web debug UI for pipeline introspection ────────────────────────
|
||||||
|
if(SAE_WEB_DEBUG)
|
||||||
|
kpn_target_enable_web_debug(scene_analyze)
|
||||||
|
kpn_target_enable_web_debug(scene_analyze_debug)
|
||||||
|
kpn_target_enable_web_debug(scene_preview)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ── Tests ─────────────────────────────────────────────────────────────────────
|
||||||
|
option(SAE_BUILD_TESTS "Build unit tests (GPU-free)" OFF)
|
||||||
|
if(SAE_BUILD_TESTS)
|
||||||
|
enable_testing()
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "OpenCV ${OpenCV_VERSION} found")
|
||||||
|
message(STATUS "Models dir: ${SAE_MODELS_DIR}")
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
# sae-builder-cpu — the CI build image
|
||||||
|
#
|
||||||
|
# TRACES: DP-007 | PR-004
|
||||||
|
#
|
||||||
|
# Build/push: scripts/ci/build_builder_image.sh --push
|
||||||
|
# Consumed by: .gitea/workflows/unit-tests.yml (pinned by tag, never :latest)
|
||||||
|
# Docs: docs/ci-image.md
|
||||||
|
#
|
||||||
|
# This is the CPU corner of the DP-008 builder matrix and the DP-007 CI image at
|
||||||
|
# the same time — one artifact, two uses. The CUDA and ROCm siblings differ only
|
||||||
|
# in the accelerator stack layered on top of this dependency set.
|
||||||
|
#
|
||||||
|
# CI runs on an Intel N100 with no discrete GPU. Everything here is chosen so
|
||||||
|
# that `-DSAE_INFERENCE_BACKEND=ORT -DSAE_GEMM_BACKEND=CPU -DSAE_BUILD_TESTS=ON`
|
||||||
|
# configures, builds and runs without a GPU, without a model, and without
|
||||||
|
# reaching GitHub.
|
||||||
|
|
||||||
|
# ─── Base image ──────────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Chosen for the OLDEST glibc to be supported, not for recency. A binary built
|
||||||
|
# in a container runs against the *host's* glibc; glibc is backward compatible
|
||||||
|
# but not forward, so the build base sets the floor for every machine DP-008's
|
||||||
|
# binaries can ever run on. Building on a newer base than the oldest supported
|
||||||
|
# host produces the classic `GLIBC_2.xx not found` failure at load time.
|
||||||
|
#
|
||||||
|
# Debian 12 "bookworm" = glibc 2.36 (Aug 2022). What that floor covers:
|
||||||
|
#
|
||||||
|
# Distro glibc Covered?
|
||||||
|
# Arch / CachyOS (rolling) 2.41+ yes
|
||||||
|
# Fedora 37 and later 2.36+ yes ← DP-005's targets are Fedora+Arch
|
||||||
|
# Debian 12 / 13 2.36+ yes
|
||||||
|
# Ubuntu 24.04 LTS 2.39 yes
|
||||||
|
# Ubuntu 22.04 LTS 2.35 NO
|
||||||
|
# RHEL / Rocky / Alma 9 2.34 NO
|
||||||
|
# Debian 11 2.31 NO
|
||||||
|
#
|
||||||
|
# The three misses are accepted deliberately: DP-005 puts Debian/Ubuntu out of
|
||||||
|
# installer scope and names Fedora + Arch as the supported distros, and every
|
||||||
|
# supported Fedora is 2.36 or newer. Going lower costs the toolchain rather than
|
||||||
|
# buying reach — Debian 11 ships GCC 10 (incomplete C++20) and Python 3.9, which
|
||||||
|
# has no `tomllib` and therefore cannot read the traceability gate's
|
||||||
|
# traceability.toml.
|
||||||
|
#
|
||||||
|
# Escape hatch, recorded now so it is not rediscovered under pressure: if the
|
||||||
|
# floor must drop to glibc 2.28 (RHEL 8 / manylinux_2_28 — the same baseline the
|
||||||
|
# ONNX Runtime and PyTorch wheels target), the move is a Rocky 8 base plus
|
||||||
|
# gcc-toolset-13, and OpenCV/FFmpeg/HDF5 all leave apt for source or
|
||||||
|
# EPEL/RPM Fusion. That is a different image, not a flag on this one.
|
||||||
|
#
|
||||||
|
# Not a glibc problem but worth stating: the binaries this image produces also
|
||||||
|
# link OpenCV, FFmpeg and HDF5 shared objects by soname. Making a *portable*
|
||||||
|
# release binary (DP-008) is a separate question from the glibc floor, and is
|
||||||
|
# answered by static linking or bundling, not by the base image.
|
||||||
|
FROM debian:12-slim
|
||||||
|
|
||||||
|
# Pins. Every version this image installs from source is an ARG so a rebuild is
|
||||||
|
# a one-line diff and `docker history` records what a given tag actually holds.
|
||||||
|
#
|
||||||
|
# ORT 1.28.0 and OpenCV 5.0.0 match the developer machine, so CI and local
|
||||||
|
# builds exercise the same libraries rather than merely similar ones.
|
||||||
|
# Catch2 / nlohmann_json / nanobind match the FetchContent pins in
|
||||||
|
# CMakeLists.txt:248 and tests/CMakeLists.txt:12 exactly — a vendored copy at a
|
||||||
|
# different version would be a silent divergence, not a convenience.
|
||||||
|
ARG ORT_VERSION=1.28.0
|
||||||
|
ARG OPENCV_VERSION=5.0.0
|
||||||
|
ARG CATCH2_VERSION=v3.5.3
|
||||||
|
ARG NLOHMANN_JSON_VERSION=v3.11.3
|
||||||
|
ARG NANOBIND_VERSION=v2.4.0
|
||||||
|
|
||||||
|
# Stamped so a build can prove which image it ran in, and so a green tick can be
|
||||||
|
# traced back to a specific dependency set. See the "Confirm the builder image"
|
||||||
|
# step in .gitea/workflows/unit-tests.yml.
|
||||||
|
ARG IMAGE_TAG=dev
|
||||||
|
ENV SAE_BUILDER=cpu \
|
||||||
|
SAE_BUILDER_VERSION=${IMAGE_TAG} \
|
||||||
|
SAE_ORT_VERSION=${ORT_VERSION} \
|
||||||
|
SAE_OPENCV_VERSION=${OPENCV_VERSION} \
|
||||||
|
DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# ─── System dependencies ─────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# One layer, ordered by why it is here rather than alphabetically.
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
# Toolchain. bookworm's default gcc is 12.2 — enough for the C++20 the
|
||||||
|
# project sets unconditionally (CMakeLists.txt:4). cmake is 3.25, above the
|
||||||
|
# 3.21 minimum. Ninja because the N100 has four cores and every second of
|
||||||
|
# build scheduling shows.
|
||||||
|
build-essential \
|
||||||
|
cmake \
|
||||||
|
ninja-build \
|
||||||
|
pkg-config \
|
||||||
|
git \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
# Gitea's act_runner executes JS actions (actions/checkout, upload-artifact)
|
||||||
|
# with the `node` found *inside* the container. Without this the job cannot
|
||||||
|
# even check the repository out. Same reason as the kpnpp-builder image.
|
||||||
|
nodejs \
|
||||||
|
# HDF5 with the C++ API: galleries are HDF5-native and it is also the VR-001
|
||||||
|
# dump format. find_package(HDF5 COMPONENTS CXX) at CMakeLists.txt:273.
|
||||||
|
libhdf5-dev \
|
||||||
|
# FFmpeg decode. swresample is on this list deliberately: the audio
|
||||||
|
# signature (IR-004) downmixes to mono and resamples to 11025 Hz, and
|
||||||
|
# tests/test_audio_signature.cpp decodes the golden FLAC fixture, so the
|
||||||
|
# test build needs it as much as the main build does.
|
||||||
|
libavformat-dev \
|
||||||
|
libavcodec-dev \
|
||||||
|
libavutil-dev \
|
||||||
|
libswscale-dev \
|
||||||
|
libswresample-dev \
|
||||||
|
# OpenBLAS — required here, not optional. CI has no GPU, so SAE_GEMM_BACKEND
|
||||||
|
# =CPU is the only path it ever exercises, and without OpenBLAS the CPU GEMM
|
||||||
|
# falls back to a scalar loop that does not scale against a library-sized
|
||||||
|
# gallery (AR-027). The build only *warns* when it is missing so a developer
|
||||||
|
# without it still gets a working tree; the image must never be that case.
|
||||||
|
# Both the main build (CMakeLists.txt:162) and the test target
|
||||||
|
# (tests/CMakeLists.txt:42) discover it through pkg-config `openblas`.
|
||||||
|
libopenblas-dev \
|
||||||
|
# Python: the build itself needs the interpreter and headers
|
||||||
|
# (find_package(Python COMPONENTS Interpreter Development.Module) at
|
||||||
|
# CMakeLists.txt:254, for the nanobind modules). numpy/h5py/scipy are for
|
||||||
|
# the Python-side tooling — fixture generation, replay, validation scripts.
|
||||||
|
# From apt rather than pip: bookworm marks the environment externally
|
||||||
|
# managed (PEP 668), and apt's h5py is already linked against the same
|
||||||
|
# libhdf5 installed above. bookworm's python3 is 3.11, which has tomllib —
|
||||||
|
# the traceability gate needs it to read traceability.toml.
|
||||||
|
python3 \
|
||||||
|
python3-dev \
|
||||||
|
python3-numpy \
|
||||||
|
python3-h5py \
|
||||||
|
python3-scipy \
|
||||||
|
# Image codecs for the OpenCV build below. Without these OpenCV silently
|
||||||
|
# builds an imgcodecs that cannot read a JPEG, which fails at run time in a
|
||||||
|
# gallery build rather than at compile time here.
|
||||||
|
libjpeg62-turbo-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libtiff-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libopenjp2-7-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Fail the image build, not the CI run, if OpenBLAS or swresample are not
|
||||||
|
# discoverable the way CMakeLists.txt discovers them. An image that ships
|
||||||
|
# libopenblas but no openblas.pc would compile the scalar fallback in silence.
|
||||||
|
RUN set -eux; \
|
||||||
|
pkg-config --exists openblas; \
|
||||||
|
echo "openblas $(pkg-config --modversion openblas)"; \
|
||||||
|
pkg-config --exists libswresample; \
|
||||||
|
echo "swresample $(pkg-config --modversion libswresample)"
|
||||||
|
|
||||||
|
# ─── ONNX Runtime, CPU provider only ─────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# The official prebuilt linux-x64 tarball is the CPU build: no CUDA, no
|
||||||
|
# TensorRT, no ROCm execution providers. That is the whole requirement here —
|
||||||
|
# excluding the GPU providers is not a size optimisation, it is the point.
|
||||||
|
#
|
||||||
|
# Verified against the 1.28.0 tarball: the shared object's highest versioned
|
||||||
|
# symbol requirement is GLIBC_2.27 / GLIBCXX_3.4.21, well under this base's
|
||||||
|
# 2.36, so ORT does not raise the floor set above.
|
||||||
|
#
|
||||||
|
# Installed to /usr/local/{lib,include/onnxruntime} because CMakeLists.txt
|
||||||
|
# includes <onnxruntime/onnxruntime_cxx_api.h> and needs the *parent* of that
|
||||||
|
# directory on the include path (CMakeLists.txt:108-113).
|
||||||
|
#
|
||||||
|
# CI never calls a model — the embedder measures ~930 ms/frame on this CPU
|
||||||
|
# provider — so ORT is present to satisfy the link, not to run inference.
|
||||||
|
RUN set -eux; \
|
||||||
|
curl -fsSL -o /tmp/ort.tgz \
|
||||||
|
"https://github.com/microsoft/onnxruntime/releases/download/v${ORT_VERSION}/onnxruntime-linux-x64-${ORT_VERSION}.tgz"; \
|
||||||
|
mkdir -p /tmp/ort; \
|
||||||
|
tar -xzf /tmp/ort.tgz -C /tmp/ort --strip-components=1; \
|
||||||
|
cp -a /tmp/ort/lib/libonnxruntime.so* /usr/local/lib/; \
|
||||||
|
mkdir -p /usr/local/include/onnxruntime; \
|
||||||
|
cp -a /tmp/ort/include/. /usr/local/include/onnxruntime/; \
|
||||||
|
ldconfig; \
|
||||||
|
rm -rf /tmp/ort /tmp/ort.tgz; \
|
||||||
|
test -f /usr/local/include/onnxruntime/onnxruntime_cxx_api.h
|
||||||
|
|
||||||
|
# ─── OpenCV 5, from source ───────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# This is the reason the image is prebuilt at all. CMakeLists.txt:25 probes for
|
||||||
|
# OpenCV 5 first and falls back to 4; the branch targets 5, which no Debian
|
||||||
|
# release ships (bookworm has 4.6), and building it inside every CI run would
|
||||||
|
# dominate the run on an N100.
|
||||||
|
#
|
||||||
|
# BUILD_LIST is exactly the seven components find_package asks for
|
||||||
|
# (CMakeLists.txt:25-29) — OpenCV resolves their internal dependencies itself.
|
||||||
|
# Everything else is off: tests, samples, Java/Python bindings, and the apps.
|
||||||
|
#
|
||||||
|
# No GUI backend. highgui still builds (find_package REQUIREs the component) but
|
||||||
|
# with a stub — CI never calls imshow, and pulling GTK/Qt into a headless build
|
||||||
|
# image buys nothing. scene_preview is a developer tool, not a CI target.
|
||||||
|
#
|
||||||
|
# CUDA/cuDNN explicitly off: DP-007 excludes the GPU stack outright.
|
||||||
|
#
|
||||||
|
# The source tree and build tree are removed in the same layer, so the ~3 GB of
|
||||||
|
# intermediates cost nothing in the published image.
|
||||||
|
RUN set -eux; \
|
||||||
|
curl -fsSL -o /tmp/opencv.tar.gz \
|
||||||
|
"https://github.com/opencv/opencv/archive/refs/tags/${OPENCV_VERSION}.tar.gz"; \
|
||||||
|
mkdir -p /tmp/opencv-src; \
|
||||||
|
tar -xzf /tmp/opencv.tar.gz -C /tmp/opencv-src --strip-components=1; \
|
||||||
|
cmake -S /tmp/opencv-src -B /tmp/opencv-build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||||
|
-DBUILD_LIST=core,imgproc,imgcodecs,videoio,dnn,objdetect,highgui \
|
||||||
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
|
-DBUILD_TESTS=OFF \
|
||||||
|
-DBUILD_PERF_TESTS=OFF \
|
||||||
|
-DBUILD_EXAMPLES=OFF \
|
||||||
|
-DBUILD_DOCS=OFF \
|
||||||
|
-DBUILD_opencv_apps=OFF \
|
||||||
|
-DBUILD_JAVA=OFF \
|
||||||
|
-DBUILD_opencv_python3=OFF \
|
||||||
|
-DWITH_FFMPEG=ON \
|
||||||
|
-DWITH_GTK=OFF \
|
||||||
|
-DWITH_QT=OFF \
|
||||||
|
-DWITH_OPENGL=OFF \
|
||||||
|
-DWITH_CUDA=OFF \
|
||||||
|
-DWITH_CUDNN=OFF \
|
||||||
|
-DOPENCV_GENERATE_PKGCONFIG=ON \
|
||||||
|
-DCMAKE_INSTALL_RPATH=/usr/local/lib; \
|
||||||
|
cmake --build /tmp/opencv-build --parallel; \
|
||||||
|
cmake --install /tmp/opencv-build; \
|
||||||
|
ldconfig; \
|
||||||
|
rm -rf /tmp/opencv-src /tmp/opencv-build /tmp/opencv.tar.gz
|
||||||
|
|
||||||
|
# ─── Vendored dependencies: Catch2, nlohmann/json, nanobind ──────────────────
|
||||||
|
#
|
||||||
|
# All three are FetchContent'ed by the build today, which makes every CI run
|
||||||
|
# depend on GitHub being reachable — a network outage would present as a code
|
||||||
|
# failure. Baking them in removes that dependency entirely.
|
||||||
|
#
|
||||||
|
# Catch2 is *installed*, so tests/CMakeLists.txt:6 `find_package(Catch2 3 QUIET)`
|
||||||
|
# succeeds and the FetchContent fallback is never reached. Its source is kept as
|
||||||
|
# well so the override below can cover the case where find_package somehow does
|
||||||
|
# not fire.
|
||||||
|
#
|
||||||
|
# nanobind must be cloned with submodules: its `ext/robin_map` is a git
|
||||||
|
# submodule, and a GitHub source tarball does not contain it. This is the one
|
||||||
|
# dependency where "download the tarball" produces a tree that configures and
|
||||||
|
# then fails to compile.
|
||||||
|
RUN set -eux; \
|
||||||
|
mkdir -p /opt/vendor; \
|
||||||
|
git clone --depth 1 --branch "${NLOHMANN_JSON_VERSION}" \
|
||||||
|
https://github.com/nlohmann/json.git /opt/vendor/nlohmann_json; \
|
||||||
|
git clone --depth 1 --branch "${NANOBIND_VERSION}" --recurse-submodules \
|
||||||
|
https://github.com/wjakob/nanobind.git /opt/vendor/nanobind; \
|
||||||
|
git clone --depth 1 --branch "${CATCH2_VERSION}" \
|
||||||
|
https://github.com/catchorg/Catch2.git /opt/vendor/Catch2; \
|
||||||
|
cmake -S /opt/vendor/Catch2 -B /tmp/catch2-build -G Ninja \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr/local \
|
||||||
|
-DBUILD_TESTING=OFF; \
|
||||||
|
cmake --build /tmp/catch2-build --parallel; \
|
||||||
|
cmake --install /tmp/catch2-build; \
|
||||||
|
rm -rf /tmp/catch2-build; \
|
||||||
|
find /opt/vendor -maxdepth 2 -name .git -exec rm -rf {} +; \
|
||||||
|
ldconfig
|
||||||
|
|
||||||
|
# The initial-cache script the build is configured with. It lives in the image,
|
||||||
|
# not in the workflow, so the vendor paths have exactly one owner: move a
|
||||||
|
# directory here and no consumer needs editing.
|
||||||
|
#
|
||||||
|
# FETCHCONTENT_FULLY_DISCONNECTED=ON is the load-bearing line. With it, any
|
||||||
|
# FetchContent dependency that is *not* covered by an override above is a hard
|
||||||
|
# configure error instead of a silent download — so "this build does not touch
|
||||||
|
# GitHub" is enforced by the build system rather than asserted in a comment.
|
||||||
|
RUN set -eux; \
|
||||||
|
printf '%s\n' \
|
||||||
|
'# Baked into sae-builder-cpu. Use with: cmake -C /opt/vendor/vendored-deps.cmake ...' \
|
||||||
|
'# TRACES: DP-007' \
|
||||||
|
'set(FETCHCONTENT_SOURCE_DIR_NLOHMANN_JSON "/opt/vendor/nlohmann_json" CACHE PATH "vendored in the CI image")' \
|
||||||
|
'set(FETCHCONTENT_SOURCE_DIR_NANOBIND "/opt/vendor/nanobind" CACHE PATH "vendored in the CI image")' \
|
||||||
|
'set(FETCHCONTENT_SOURCE_DIR_CATCH2 "/opt/vendor/Catch2" CACHE PATH "vendored in the CI image")' \
|
||||||
|
'set(FETCHCONTENT_FULLY_DISCONNECTED ON CACHE BOOL "no CI build may fetch from the network")' \
|
||||||
|
> /opt/vendor/vendored-deps.cmake; \
|
||||||
|
cat /opt/vendor/vendored-deps.cmake
|
||||||
|
|
||||||
|
# ─── Self-check ──────────────────────────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# Run the project's own dependency discovery — the same find_package and
|
||||||
|
# pkg_check_modules calls CMakeLists.txt makes — against this image, at image
|
||||||
|
# build time. An image that cannot satisfy them should fail here, loudly, once,
|
||||||
|
# rather than in every CI run that pulls it.
|
||||||
|
#
|
||||||
|
# Deliberately not a build of the project: the image must be buildable without
|
||||||
|
# the repository, and the repository's own configure step is what CI is for.
|
||||||
|
RUN set -eux; \
|
||||||
|
mkdir -p /tmp/selfcheck; \
|
||||||
|
printf '%s\n' \
|
||||||
|
'cmake_minimum_required(VERSION 3.21)' \
|
||||||
|
'project(sae_image_selfcheck LANGUAGES CXX)' \
|
||||||
|
'set(CMAKE_CXX_STANDARD 20)' \
|
||||||
|
'set(CMAKE_CXX_STANDARD_REQUIRED ON)' \
|
||||||
|
'find_package(OpenCV 5 REQUIRED COMPONENTS core imgproc imgcodecs videoio dnn objdetect highgui)' \
|
||||||
|
'message(STATUS "OpenCV ${OpenCV_VERSION}")' \
|
||||||
|
'find_package(HDF5 REQUIRED COMPONENTS CXX)' \
|
||||||
|
'message(STATUS "HDF5 ${HDF5_VERSION}")' \
|
||||||
|
'find_package(Catch2 3 REQUIRED)' \
|
||||||
|
'message(STATUS "Catch2 ${Catch2_VERSION}")' \
|
||||||
|
'find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development.Module)' \
|
||||||
|
'find_package(PkgConfig REQUIRED)' \
|
||||||
|
'pkg_check_modules(AVFORMAT REQUIRED libavformat)' \
|
||||||
|
'pkg_check_modules(AVCODEC REQUIRED libavcodec)' \
|
||||||
|
'pkg_check_modules(AVUTIL REQUIRED libavutil)' \
|
||||||
|
'pkg_check_modules(SWSCALE REQUIRED libswscale)' \
|
||||||
|
'pkg_check_modules(SWRESAMPLE REQUIRED libswresample)' \
|
||||||
|
'pkg_check_modules(OPENBLAS REQUIRED openblas)' \
|
||||||
|
'find_library(ORT_LIB onnxruntime REQUIRED HINTS /usr/lib /usr/local/lib)' \
|
||||||
|
'find_path(ORT_INCLUDE onnxruntime_cxx_api.h PATH_SUFFIXES onnxruntime' \
|
||||||
|
' HINTS /usr/include/onnxruntime /usr/local/include/onnxruntime /usr/local/include REQUIRED)' \
|
||||||
|
'message(STATUS "ORT ${ORT_LIB} / ${ORT_INCLUDE}")' \
|
||||||
|
> /tmp/selfcheck/CMakeLists.txt; \
|
||||||
|
cmake -S /tmp/selfcheck -B /tmp/selfcheck/build -G Ninja; \
|
||||||
|
rm -rf /tmp/selfcheck
|
||||||
|
|
||||||
|
# Python-side tooling the fixture and validation scripts import. Checked here so
|
||||||
|
# a missing wheel is an image failure rather than a mid-run traceback.
|
||||||
|
RUN python3 -c "import numpy, h5py, scipy; print('numpy', numpy.__version__, 'h5py', h5py.__version__, 'scipy', scipy.__version__)"
|
||||||
|
|
||||||
|
# ─── What is deliberately NOT here ───────────────────────────────────────────
|
||||||
|
#
|
||||||
|
# CUDA, TensorRT, ROCm, and the ORT GPU execution providers
|
||||||
|
# No GPU to use them. They belong to the sae-builder-cuda and
|
||||||
|
# sae-builder-rocm siblings (DP-008).
|
||||||
|
#
|
||||||
|
# The ONNX models
|
||||||
|
# Seven files, ~725 MB, in Git LFS. T1/T2 tests are model-free by design
|
||||||
|
# (tests/CMakeLists.txt:1-4), so the CI image needs none of them, and
|
||||||
|
# baking them in would inflate the image roughly tenfold to serve the T3
|
||||||
|
# smoke tests alone. Those pull the model they need via LFS in a separate
|
||||||
|
# job. The CI workflow checks out with LFS off for the same reason.
|
||||||
|
#
|
||||||
|
# The repository
|
||||||
|
# Nothing from the source tree is COPYed in. The image is a toolchain, and
|
||||||
|
# a toolchain that embeds the code it builds has to be rebuilt whenever the
|
||||||
|
# code changes — which is exactly the per-run cost this image exists to
|
||||||
|
# avoid.
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Duncan Tourolle
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
NOTE ON MODELS AND THIRD-PARTY COMPONENTS
|
||||||
|
|
||||||
|
The MIT license above applies only to the source code in this repository. It
|
||||||
|
does NOT cover:
|
||||||
|
|
||||||
|
* Machine-learning model weights (the ONNX files in models/). These weights
|
||||||
|
are the property of their respective authors and are governed by their own
|
||||||
|
licenses, not by the MIT license above. The models — including the
|
||||||
|
InsightFace "buffalo" packs (ArcFace / SCRFD), YuNet, and LVFace — are
|
||||||
|
redistributed here for convenience under those upstream licenses. Several,
|
||||||
|
notably the InsightFace models, are licensed for NON-COMMERCIAL RESEARCH
|
||||||
|
USE ONLY. You are responsible for reviewing and complying with each model's
|
||||||
|
license before use.
|
||||||
|
|
||||||
|
* Third-party libraries this software links against (OpenCV, ONNX Runtime,
|
||||||
|
FFmpeg, TensorRT/CUDA, nlohmann/json, nanobind, and others), each of which
|
||||||
|
carries its own license.
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
# Scene Actor Extraction
|
||||||
|
|
||||||
|
Identifies actors in movie files and produces X-ray-style scene annotations compatible with [Jellyfin](https://jellyfin.org/). Built on a KPN++ pipeline with ArcFace/LVFace embeddings and a tracked-identity matcher.
|
||||||
|
|
||||||
|
**67.4% macro-F1 against Amazon X-Ray ground truth**, on 5 films never seen by
|
||||||
|
the optimizer (89.7% P / 65.4% R training-set; see the generalization-gap
|
||||||
|
discussion in the [deep dive](https://pages.tourolle.paris/dtourolle/scene-actor-extraction/lvface-deep-dive/)).
|
||||||
|
Full benchmark write-up, model comparison, and failure-mode analysis:
|
||||||
|
**https://pages.tourolle.paris/dtourolle/scene-actor-extraction/**
|
||||||
|
|
||||||
|

|
||||||
|
*A perfect X-Ray second on a held-out film (never used for threshold tuning):
|
||||||
|
every visible face named at 100%, the background extra honestly left unnamed,
|
||||||
|
and the two credited cast without a visible face correctly carried as present
|
||||||
|
off-screen. Bottom panels show the per-second verdict against Amazon X-Ray
|
||||||
|
(green = correct, orange = wrong, blue = missed).*
|
||||||
|
|
||||||
|
It also doesn't care whether the face is in the room:
|
||||||
|
|
||||||
|

|
||||||
|
*Herbie Hancock at 98% — as a face on a screen inside the movie, under a
|
||||||
|
sci-fi HUD overlay.*
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
1. **Build a gallery** — download actor headshots from TMDB/IMDB, embed them with ArcFace or LVFace (`build_gallery` / `scripts/make_gallery.py`).
|
||||||
|
2. **Analyze a movie** — `scene_analyze` decodes frames at configurable FPS, detects faces (SCRFD), tracks them across cuts, matches identities against the gallery using calibrated similarity, and writes time-window JSON.
|
||||||
|
3. **Output** — minimal mode produces Jellyfin-ready actor name + time-window JSON; standard mode adds per-frame bbox, similarity, and track data.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
| Dependency | Role |
|
||||||
|
|---|---|
|
||||||
|
| KPN++ | Pipeline backbone (nodes, networks) |
|
||||||
|
| OpenCV 4 | Video decode, image ops, DNN inference |
|
||||||
|
| ONNX Runtime | SCRFD face detector (dynamic shape nodes unsupported by cv::dnn) |
|
||||||
|
| TensorRT + CUDA runtime + cuBLAS | Optional TRT engines for SCRFD/ArcFace (`--detector-engine`/`--arcface-engine`); identity_matcher's GPU gallery scan |
|
||||||
|
| FFmpeg (libav*) | NVDEC hardware video decode + colour conversion |
|
||||||
|
| nlohmann/json | JSON I/O |
|
||||||
|
| nanobind | Python bindings for `sae_embed` |
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build -j$(nproc)
|
||||||
|
```
|
||||||
|
|
||||||
|
This also builds `sae_embed`, a Python module (via nanobind) that loads the
|
||||||
|
SCRFD detector and ArcFace embedder once and exposes a reusable `embed()`
|
||||||
|
method. The gallery-builder scripts (`make_gallery.py`,
|
||||||
|
`make_jellyfin_gallery.py`, `movienet_eval.py`) import it directly — there is
|
||||||
|
no subprocess fallback, so if it's missing they exit with a build instruction:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build --target sae_embed
|
||||||
|
```
|
||||||
|
|
||||||
|
Optional flags:
|
||||||
|
|
||||||
|
| Flag | Default | Effect |
|
||||||
|
|---|---|---|
|
||||||
|
| `-DSAE_WEB_DEBUG=ON` | OFF | Enables KPN web debug UI at `localhost:9090` |
|
||||||
|
|
||||||
|
## Models
|
||||||
|
|
||||||
|
The ONNX model weights live in `models/` (tracked via Git LFS):
|
||||||
|
- `LVFace-B_Glint360K.onnx` — LVFace embedder (ViT backbone, ICCV 2025), the default
|
||||||
|
(best F1 in the rep4 model bake-off, see `docs/rep4-optimizer-results.md`)
|
||||||
|
- `arcface_w600k_r50.onnx` — ArcFace embedder, previous default
|
||||||
|
- `arcface_w600k_mbf.onnx`, `arcface_r18.onnx` — lighter ArcFace alternatives
|
||||||
|
- `face_detection_yunet_2023mar.onnx` — YuNet face detector
|
||||||
|
- `scrfd_500m_bnkps.onnx` — SCRFD face detector
|
||||||
|
|
||||||
|
### LVFace
|
||||||
|
|
||||||
|
[LVFace](https://github.com/bytedance/LVFace) is a Vision-Transformer face
|
||||||
|
recognition model. The `LVFace-B_Glint360K.onnx` export shares ArcFace's I/O
|
||||||
|
contract (112×112 aligned BGR crop → L2-normalised 512-d embedding) and its
|
||||||
|
`(x − 127.5)/128` input scaling, so it slots straight into the existing embedder
|
||||||
|
— just point `--arcface-model` at it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/scene_analyze --arcface-model models/LVFace-B_Glint360K.onnx \
|
||||||
|
--gallery gallery.h5 --movie movie.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Important:** embeddings from different recognition models are not
|
||||||
|
> interchangeable. A gallery (and its calibration cache) must be built with the
|
||||||
|
> **same** embedder used for analysis — rebuild the gallery with
|
||||||
|
> `--arcface models/LVFace-B_Glint360K.onnx` before analysing with LVFace.
|
||||||
|
|
||||||
|
If they are missing (e.g. LFS not fetched), re-download them with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/download_models.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Model licensing:** the model weights carry their own licenses, separate
|
||||||
|
> from this project's MIT license, and are redistributed here under those
|
||||||
|
> upstream terms. Several — notably the InsightFace "buffalo" models (ArcFace /
|
||||||
|
> SCRFD) — are licensed for **non-commercial research use only**. Review and
|
||||||
|
> comply with each model's license before use.
|
||||||
|
|
||||||
|
## Binaries
|
||||||
|
|
||||||
|
| Binary | Description |
|
||||||
|
|---|---|
|
||||||
|
| `scene_analyze` | Main analysis pipeline, writes JSON output |
|
||||||
|
| `scene_analyze_debug` | Same as above + per-frame annotated JPEGs (`SAE_DEBUG=1`) |
|
||||||
|
| `scene_preview` | Live OpenCV display window while analysing |
|
||||||
|
| `build_gallery` | Offline gallery builder from a directory of images |
|
||||||
|
| `embed_faces` | CLI: image(s) → embedding JSON, used by gallery-builder scripts |
|
||||||
|
| `sae_embed` | Python module (nanobind) used by gallery-builder scripts — loads SCRFD+ArcFace once |
|
||||||
|
|
||||||
|
### `scene_analyze`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/scene_analyze --gallery gallery.h5 --movie movie.mp4 [options]
|
||||||
|
```
|
||||||
|
|
||||||
|
Key options:
|
||||||
|
|
||||||
|
| Flag | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `--fps` | 1 | Frames per second to sample (5–10 recommended for tracking) |
|
||||||
|
| `--prob-threshold` | 0.5 | Minimum calibrated match probability |
|
||||||
|
| `--match-threshold` | — | Raw cosine similarity threshold (fallback) |
|
||||||
|
| `--extinction` | 5s | How long a track persists after last detection |
|
||||||
|
| `--track-alpha` | — | IoU vs. embedding weight in Hungarian assignment |
|
||||||
|
| `--track-min-iou` | — | Minimum IoU gate for spatial assignment |
|
||||||
|
| `--track-max-embed` | — | Maximum embedding distance gate |
|
||||||
|
| `--track-max-missing` | — | Frames a track survives without a detection |
|
||||||
|
|
||||||
|
### Gallery builders
|
||||||
|
|
||||||
|
**Per-movie (TMDB):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/make_gallery.py --tmdb-key <TMDB_KEY> --movie-id <TMDB_ID> --output gallery.h5
|
||||||
|
```
|
||||||
|
|
||||||
|
Fetches cast images from TMDB and embeds them via `sae_embed`.
|
||||||
|
|
||||||
|
**Whole-library (Jellyfin):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/make_jellyfin_gallery.py \
|
||||||
|
--jellyfin-url http://jellyfin.local:8096 \
|
||||||
|
--api-key <API_KEY> \
|
||||||
|
--output gallery.h5
|
||||||
|
```
|
||||||
|
|
||||||
|
Scans every Movie/Series in Jellyfin, collects the unique cast across the
|
||||||
|
whole library, downloads each actor's headshot directly from Jellyfin (no
|
||||||
|
TMDB key needed), and embeds them via `sae_embed` into one global
|
||||||
|
gallery.h5. Since `identity_matcher` scores faces against the entire
|
||||||
|
gallery, `scene_analyze` can then recognise any actor from your library in
|
||||||
|
any film — not just the cast listed for that one title. Pass `--merge` on
|
||||||
|
later runs to only embed actors newly added to the library. Pass
|
||||||
|
`--tmdb-key` to fall back to TMDB profile images for actors with no usable
|
||||||
|
image cached in Jellyfin.
|
||||||
|
|
||||||
|
Jellyfin/TMDB lookups and image downloads for different actors run
|
||||||
|
concurrently (`--workers`, default 8). Embedding is GPU-bound, so it's
|
||||||
|
gated separately via `--embed-concurrency` (default 1) — only that many
|
||||||
|
embed calls run at once while other actors' downloads continue in the
|
||||||
|
background.
|
||||||
|
|
||||||
|
To restrict a single-title run to that title's credited cast (faster, fewer
|
||||||
|
look-alike mismatches), filter the global gallery first:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/filter_gallery.py \
|
||||||
|
--gallery gallery.h5 \
|
||||||
|
--jellyfin-url http://jellyfin.local:8096 \
|
||||||
|
--api-key <API_KEY> \
|
||||||
|
--title "The Matrix" \
|
||||||
|
--output gallery_matrix.h5
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running directly from Jellyfin
|
||||||
|
|
||||||
|
`scripts/run_from_jellyfin.py` resolves a title to its media file via the
|
||||||
|
Jellyfin API, filters the gallery to that title's cast, and runs
|
||||||
|
`scene_analyze` in one step. Requires this tool to run on a host that shares
|
||||||
|
Jellyfin's media mount (it uses the item's on-disk `Path`, not a stream URL):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/run_from_jellyfin.py \
|
||||||
|
--jellyfin-url http://jellyfin.local:8096 \
|
||||||
|
--api-key <API_KEY> \
|
||||||
|
--title "The Matrix" \
|
||||||
|
--gallery gallery.h5 \
|
||||||
|
-- --fps 5 --verbosity 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Anything after `--` is passed through to `scene_analyze` unchanged. Pass
|
||||||
|
`--no-filter` to use the gallery as-is (skip per-title cast filtering), or
|
||||||
|
`--item-id` instead of `--title` to skip the search.
|
||||||
|
|
||||||
|
After a successful run, the output JSON is pushed to the [JRay Jellyfin
|
||||||
|
plugin](https://gitea.tourolle.paris/dtourolle/jRay)'s Truth endpoint
|
||||||
|
(`PUT /Plugins/JRay/Items/{itemId}/Truth`) so
|
||||||
|
Jellyfin picks it up immediately, using `--api-key` (must be an
|
||||||
|
**Administrator** key for the push to succeed). Pass `--no-push` to skip
|
||||||
|
this and only write `--output` locally (e.g. for local debugging).
|
||||||
|
|
||||||
|
### Worker mode
|
||||||
|
|
||||||
|
Pass `--worker` instead of `--item-id`/`--title` to run this as an extraction
|
||||||
|
worker: it polls the JRay plugin's `GET /Plugins/JRay/Tasks/Pending` endpoint
|
||||||
|
for a random batch of items with no truth data yet, processes each one, and
|
||||||
|
pushes the result back. The endpoint's sampling spreads work across the
|
||||||
|
backlog without any server-side task tracking, so any number of workers can
|
||||||
|
poll the same library concurrently.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/run_from_jellyfin.py \
|
||||||
|
--jellyfin-url http://jellyfin.local:8096 \
|
||||||
|
--api-key <ADMIN_API_KEY> \
|
||||||
|
--gallery whole_gallery.h5 \
|
||||||
|
--worker \
|
||||||
|
-- --fps 5
|
||||||
|
```
|
||||||
|
|
||||||
|
- `--poll-limit` — batch size requested from `Tasks/Pending` (default 10, max 100)
|
||||||
|
- `--poll-interval` — seconds to sleep between polls when the backlog is empty (default 60)
|
||||||
|
- `--once` — process a single batch and exit instead of looping forever
|
||||||
|
|
||||||
|
A failure on one item (bad path, push rejected, etc.) is logged and the
|
||||||
|
worker moves on to the next item rather than exiting.
|
||||||
|
|
||||||
|
## Output format
|
||||||
|
|
||||||
|
**Minimal** (default) — Jellyfin-ready:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{ "actor": "Name", "start": 12.0, "end": 45.5 }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Standard** — per-frame detail with bounding boxes, similarity scores, and track IDs.
|
||||||
|
|
||||||
|
## Evaluation
|
||||||
|
|
||||||
|
Scripts in `eval/` and `scripts/movienet_*.py` support benchmarking against the MovieNet dataset.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The source code in this repository is licensed under the [MIT License](LICENSE).
|
||||||
|
|
||||||
|
The MIT license covers **only the code**. The model weights in `models/` (see
|
||||||
|
[Models](#models)) are redistributed under their own licenses — several for
|
||||||
|
non-commercial research use only. Third-party libraries this software links
|
||||||
|
against (OpenCV, ONNX Runtime, FFmpeg, TensorRT/CUDA, nlohmann/json, nanobind,
|
||||||
|
and others) likewise carry their own licenses.
|
||||||
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 165 KiB |
@@ -1,18 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Lunr languages, `Danish` language
|
|
||||||
* https://github.com/MihaiValentin/lunr-languages
|
|
||||||
*
|
|
||||||
* Copyright 2014, Mihai Valentin
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
/*!
|
|
||||||
* based on
|
|
||||||
* Snowball JavaScript Library v0.3
|
|
||||||
* http://code.google.com/p/urim/
|
|
||||||
* http://snowball.tartarus.org/
|
|
||||||
*
|
|
||||||
* Copyright 2010, Oleg Mazko
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
|
|
||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){var r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){function e(){var e,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d<a&&(d=a)}}function n(){var e,r;if(f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del();break;case 2:f.in_grouping_b(p,97,229)&&f.slice_del()}}function t(){var e,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}function s(){var e,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case 1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case 2:f.slice_from("løs")}}function o(){var e;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}var a,d,u,c=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],l=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=new i;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var r=f.cursor;return e(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n<p.length;n++)r?a.push(new e.Token(p[n],{position:[f,p[n].length],index:a.length})):a.push(p[n]),f+=p[n].length;l=c+1}return a},e.ja.stemmer=function(){return function(e){return e}}(),e.Pipeline.registerFunction(e.ja.stemmer,"stemmer-ja"),e.ja.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.ja.trimmer=e.trimmerSupport.generateTrimmer(e.ja.wordCharacters),e.Pipeline.registerFunction(e.ja.trimmer,"trimmer-ja"),e.ja.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.ja.stopWordFilter,"stopWordFilter-ja"),e.jp=e.ja,e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.Pipeline.registerFunction(e.jp.trimmer,"trimmer-jp"),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
module.exports=require("./lunr.ja");
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.kn=function(){this.pipeline.reset(),this.pipeline.add(e.kn.trimmer,e.kn.stopWordFilter,e.kn.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.kn.stemmer))},e.kn.wordCharacters="ಀ-಄ಅ-ಔಕ-ಹಾ-ೌ಼-ಽೕ-ೖೝ-ೞೠ-ೡೢ-ೣ೦-೯ೱ-ೳ",e.kn.trimmer=e.trimmerSupport.generateTrimmer(e.kn.wordCharacters),e.Pipeline.registerFunction(e.kn.trimmer,"trimmer-kn"),e.kn.stopWordFilter=e.generateStopWordFilter("ಮತ್ತು ಈ ಒಂದು ರಲ್ಲಿ ಹಾಗೂ ಎಂದು ಅಥವಾ ಇದು ರ ಅವರು ಎಂಬ ಮೇಲೆ ಅವರ ತನ್ನ ಆದರೆ ತಮ್ಮ ನಂತರ ಮೂಲಕ ಹೆಚ್ಚು ನ ಆ ಕೆಲವು ಅನೇಕ ಎರಡು ಹಾಗು ಪ್ರಮುಖ ಇದನ್ನು ಇದರ ಸುಮಾರು ಅದರ ಅದು ಮೊದಲ ಬಗ್ಗೆ ನಲ್ಲಿ ರಂದು ಇತರ ಅತ್ಯಂತ ಹೆಚ್ಚಿನ ಸಹ ಸಾಮಾನ್ಯವಾಗಿ ನೇ ಹಲವಾರು ಹೊಸ ದಿ ಕಡಿಮೆ ಯಾವುದೇ ಹೊಂದಿದೆ ದೊಡ್ಡ ಅನ್ನು ಇವರು ಪ್ರಕಾರ ಇದೆ ಮಾತ್ರ ಕೂಡ ಇಲ್ಲಿ ಎಲ್ಲಾ ವಿವಿಧ ಅದನ್ನು ಹಲವು ರಿಂದ ಕೇವಲ ದ ದಕ್ಷಿಣ ಗೆ ಅವನ ಅತಿ ನೆಯ ಬಹಳ ಕೆಲಸ ಎಲ್ಲ ಪ್ರತಿ ಇತ್ಯಾದಿ ಇವು ಬೇರೆ ಹೀಗೆ ನಡುವೆ ಇದಕ್ಕೆ ಎಸ್ ಇವರ ಮೊದಲು ಶ್ರೀ ಮಾಡುವ ಇದರಲ್ಲಿ ರೀತಿಯ ಮಾಡಿದ ಕಾಲ ಅಲ್ಲಿ ಮಾಡಲು ಅದೇ ಈಗ ಅವು ಗಳು ಎ ಎಂಬುದು ಅವನು ಅಂದರೆ ಅವರಿಗೆ ಇರುವ ವಿಶೇಷ ಮುಂದೆ ಅವುಗಳ ಮುಂತಾದ ಮೂಲ ಬಿ ಮೀ ಒಂದೇ ಇನ್ನೂ ಹೆಚ್ಚಾಗಿ ಮಾಡಿ ಅವರನ್ನು ಇದೇ ಯ ರೀತಿಯಲ್ಲಿ ಜೊತೆ ಅದರಲ್ಲಿ ಮಾಡಿದರು ನಡೆದ ಆಗ ಮತ್ತೆ ಪೂರ್ವ ಆತ ಬಂದ ಯಾವ ಒಟ್ಟು ಇತರೆ ಹಿಂದೆ ಪ್ರಮಾಣದ ಗಳನ್ನು ಕುರಿತು ಯು ಆದ್ದರಿಂದ ಅಲ್ಲದೆ ನಗರದ ಮೇಲಿನ ಏಕೆಂದರೆ ರಷ್ಟು ಎಂಬುದನ್ನು ಬಾರಿ ಎಂದರೆ ಹಿಂದಿನ ಆದರೂ ಆದ ಸಂಬಂಧಿಸಿದ ಮತ್ತೊಂದು ಸಿ ಆತನ ".split(" ")),e.kn.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.kn.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var n=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(n).split("|")},e.Pipeline.registerFunction(e.kn.stemmer,"stemmer-kn"),e.Pipeline.registerFunction(e.kn.stopWordFilter,"stopWordFilter-kn")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var t=Array.prototype.slice.call(arguments),i=t.join("-"),r="",n=[],s=[],p=0;p<t.length;++p)"en"==t[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[t[p]].wordCharacters,e[t[p]].stopWordFilter&&n.unshift(e[t[p]].stopWordFilter),e[t[p]].stemmer&&(n.push(e[t[p]].stemmer),s.push(e[t[p]].stemmer)));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+i),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Lunr languages, `Norwegian` language
|
|
||||||
* https://github.com/MihaiValentin/lunr-languages
|
|
||||||
*
|
|
||||||
* Copyright 2014, Mihai Valentin
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
/*!
|
|
||||||
* based on
|
|
||||||
* Snowball JavaScript Library v0.3
|
|
||||||
* http://code.google.com/p/urim/
|
|
||||||
* http://snowball.tartarus.org/
|
|
||||||
*
|
|
||||||
* Copyright 2010, Oleg Mazko
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
|
|
||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){function e(){var e,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a<s&&(a=s)}}function i(){var e,r,n;if(w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case 3:w.slice_from("er")}}function t(){var e,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}function o(){var e,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}var s,a,m=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],u=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sa=function(){this.pipeline.reset(),this.pipeline.add(e.sa.trimmer,e.sa.stopWordFilter,e.sa.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sa.stemmer))},e.sa.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿ꣠-꣱ꣲ-ꣷ꣸-ꣻ꣼-ꣽꣾ-ꣿᆰ0-ᆰ9",e.sa.trimmer=e.trimmerSupport.generateTrimmer(e.sa.wordCharacters),e.Pipeline.registerFunction(e.sa.trimmer,"trimmer-sa"),e.sa.stopWordFilter=e.generateStopWordFilter('तथा अयम् एकम् इत्यस्मिन् तथा तत् वा अयम् इत्यस्य ते आहूत उपरि तेषाम् किन्तु तेषाम् तदा इत्यनेन अधिकः इत्यस्य तत् केचन बहवः द्वि तथा महत्वपूर्णः अयम् अस्य विषये अयं अस्ति तत् प्रथमः विषये इत्युपरि इत्युपरि इतर अधिकतमः अधिकः अपि सामान्यतया ठ इतरेतर नूतनम् द न्यूनम् कश्चित् वा विशालः द सः अस्ति तदनुसारम् तत्र अस्ति केवलम् अपि अत्र सर्वे विविधाः तत् बहवः यतः इदानीम् द दक्षिण इत्यस्मै तस्य उपरि नथ अतीव कार्यम् सर्वे एकैकम् इत्यादि। एते सन्ति उत इत्थम् मध्ये एतदर्थं . स कस्य प्रथमः श्री. करोति अस्मिन् प्रकारः निर्मिता कालः तत्र कर्तुं समान अधुना ते सन्ति स एकः अस्ति सः अर्थात् तेषां कृते . स्थितम् विशेषः अग्रिम तेषाम् समान स्रोतः ख म समान इदानीमपि अधिकतया करोतु ते समान इत्यस्य वीथी सह यस्मिन् कृतवान् धृतः तदा पुनः पूर्वं सः आगतः किम् कुल इतर पुरा मात्रा स विषये उ अतएव अपि नगरस्य उपरि यतः प्रतिशतं कतरः कालः साधनानि भूत तथापि जात सम्बन्धि अन्यत् ग अतः अस्माकं स्वकीयाः अस्माकं इदानीं अन्तः इत्यादयः भवन्तः इत्यादयः एते एताः तस्य अस्य इदम् एते तेषां तेषां तेषां तान् तेषां तेषां तेषां समानः सः एकः च तादृशाः बहवः अन्ये च वदन्ति यत् कियत् कस्मै कस्मै यस्मै यस्मै यस्मै यस्मै न अतिनीचः किन्तु प्रथमं सम्पूर्णतया ततः चिरकालानन्तरं पुस्तकं सम्पूर्णतया अन्तः किन्तु अत्र वा इह इव श्रद्धाय अवशिष्यते परन्तु अन्ये वर्गाः सन्ति ते सन्ति शक्नुवन्ति सर्वे मिलित्वा सर्वे एकत्र"'.split(" ")),e.sa.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.sa.tokenizer=function(t){if(!arguments.length||null==t||void 0==t)return[];if(Array.isArray(t))return t.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var i=t.toString().toLowerCase().replace(/^\s+/,"");return r.cut(i).split("|")},e.Pipeline.registerFunction(e.sa.stemmer,"stemmer-sa"),e.Pipeline.registerFunction(e.sa.stopWordFilter,"stopWordFilter-sa")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(e-=i,!(t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=_.s_size-1-l;m>=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Lunr languages, `Swedish` language
|
|
||||||
* https://github.com/MihaiValentin/lunr-languages
|
|
||||||
*
|
|
||||||
* Copyright 2014, Mihai Valentin
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
/*!
|
|
||||||
* based on
|
|
||||||
* Snowball JavaScript Library v0.3
|
|
||||||
* http://code.google.com/p/urim/
|
|
||||||
* http://snowball.tartarus.org/
|
|
||||||
*
|
|
||||||
* Copyright 2010, Oleg Mazko
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*/
|
|
||||||
|
|
||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o<a&&(o=a)}}function t(){var e,r=w.limit_backward;if(w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="-உஊ-ஏஐ-ஙச-ட-னப-யர-ஹ-ிீ-ொ-ௐ---௩௪-௯௰-௹௺-a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[-]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("@node-rs/jieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 為 以 于 於 上 他 而 后 後 之 来 來 及 了 因 下 可 到 由 这 這 与 與 也 此 但 并 並 个 個 其 已 无 無 小 我 们 們 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 當 从 從 得 打 凡 儿 兒 尔 爾 该 該 各 给 給 跟 和 何 还 還 即 几 幾 既 看 据 據 距 靠 啦 另 么 麽 每 嘛 拿 哪 您 凭 憑 且 却 卻 让 讓 仍 啥 如 若 使 谁 誰 虽 雖 随 隨 同 所 她 哇 嗡 往 些 向 沿 哟 喲 用 咱 则 則 怎 曾 至 致 着 著 诸 諸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}});
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
/**
|
|
||||||
* export the module via AMD, CommonJS or as a browser global
|
|
||||||
* Export code from https://github.com/umdjs/umd/blob/master/returnExports.js
|
|
||||||
*/
|
|
||||||
;(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module.
|
|
||||||
define(factory)
|
|
||||||
} else if (typeof exports === 'object') {
|
|
||||||
/**
|
|
||||||
* Node. Does not work with strict CommonJS, but
|
|
||||||
* only CommonJS-like environments that support module.exports,
|
|
||||||
* like Node.
|
|
||||||
*/
|
|
||||||
module.exports = factory()
|
|
||||||
} else {
|
|
||||||
// Browser globals (root is window)
|
|
||||||
factory()(root.lunr);
|
|
||||||
}
|
|
||||||
}(this, function () {
|
|
||||||
/**
|
|
||||||
* Just return a value to define the module export.
|
|
||||||
* This example returns an object, but the module
|
|
||||||
* can return a function as the exported value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return function(lunr) {
|
|
||||||
// TinySegmenter 0.1 -- Super compact Japanese tokenizer in Javascript
|
|
||||||
// (c) 2008 Taku Kudo <taku@chasen.org>
|
|
||||||
// TinySegmenter is freely distributable under the terms of a new BSD licence.
|
|
||||||
// For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt
|
|
||||||
|
|
||||||
function TinySegmenter() {
|
|
||||||
var patterns = {
|
|
||||||
"[一二三四五六七八九十百千万億兆]":"M",
|
|
||||||
"[一-龠々〆ヵヶ]":"H",
|
|
||||||
"[ぁ-ん]":"I",
|
|
||||||
"[ァ-ヴーア-ン゙ー]":"K",
|
|
||||||
"[a-zA-Za-zA-Z]":"A",
|
|
||||||
"[0-90-9]":"N"
|
|
||||||
}
|
|
||||||
this.chartype_ = [];
|
|
||||||
for (var i in patterns) {
|
|
||||||
var regexp = new RegExp(i);
|
|
||||||
this.chartype_.push([regexp, patterns[i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.BIAS__ = -332
|
|
||||||
this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378};
|
|
||||||
this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920};
|
|
||||||
this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266};
|
|
||||||
this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352};
|
|
||||||
this.BP2__ = {"BO":60,"OO":-1762};
|
|
||||||
this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965};
|
|
||||||
this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146};
|
|
||||||
this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699};
|
|
||||||
this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973};
|
|
||||||
this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682};
|
|
||||||
this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669};
|
|
||||||
this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990};
|
|
||||||
this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832};
|
|
||||||
this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649};
|
|
||||||
this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393};
|
|
||||||
this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841};
|
|
||||||
this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68};
|
|
||||||
this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591};
|
|
||||||
this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685};
|
|
||||||
this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156};
|
|
||||||
this.TW1__ = {"につい":-4681,"東京都":2026};
|
|
||||||
this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216};
|
|
||||||
this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287};
|
|
||||||
this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865};
|
|
||||||
this.UC1__ = {"A":484,"K":93,"M":645,"O":-505};
|
|
||||||
this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646};
|
|
||||||
this.UC3__ = {"A":-1370,"I":2311};
|
|
||||||
this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646};
|
|
||||||
this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831};
|
|
||||||
this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387};
|
|
||||||
this.UP1__ = {"O":-214};
|
|
||||||
this.UP2__ = {"B":69,"O":935};
|
|
||||||
this.UP3__ = {"B":189};
|
|
||||||
this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422};
|
|
||||||
this.UQ2__ = {"BH":216,"BI":113,"OK":1759};
|
|
||||||
this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212};
|
|
||||||
this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135};
|
|
||||||
this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568};
|
|
||||||
this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278};
|
|
||||||
this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637};
|
|
||||||
this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343};
|
|
||||||
this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496};
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
TinySegmenter.prototype.ctype_ = function(str) {
|
|
||||||
for (var i in this.chartype_) {
|
|
||||||
if (str.match(this.chartype_[i][0])) {
|
|
||||||
return this.chartype_[i][1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "O";
|
|
||||||
}
|
|
||||||
|
|
||||||
TinySegmenter.prototype.ts_ = function(v) {
|
|
||||||
if (v) { return v; }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
TinySegmenter.prototype.segment = function(input) {
|
|
||||||
if (input == null || input == undefined || input == "") {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
var result = [];
|
|
||||||
var seg = ["B3","B2","B1"];
|
|
||||||
var ctype = ["O","O","O"];
|
|
||||||
var o = input.split("");
|
|
||||||
for (i = 0; i < o.length; ++i) {
|
|
||||||
seg.push(o[i]);
|
|
||||||
ctype.push(this.ctype_(o[i]))
|
|
||||||
}
|
|
||||||
seg.push("E1");
|
|
||||||
seg.push("E2");
|
|
||||||
seg.push("E3");
|
|
||||||
ctype.push("O");
|
|
||||||
ctype.push("O");
|
|
||||||
ctype.push("O");
|
|
||||||
var word = seg[3];
|
|
||||||
var p1 = "U";
|
|
||||||
var p2 = "U";
|
|
||||||
var p3 = "U";
|
|
||||||
for (var i = 4; i < seg.length - 3; ++i) {
|
|
||||||
var score = this.BIAS__;
|
|
||||||
var w1 = seg[i-3];
|
|
||||||
var w2 = seg[i-2];
|
|
||||||
var w3 = seg[i-1];
|
|
||||||
var w4 = seg[i];
|
|
||||||
var w5 = seg[i+1];
|
|
||||||
var w6 = seg[i+2];
|
|
||||||
var c1 = ctype[i-3];
|
|
||||||
var c2 = ctype[i-2];
|
|
||||||
var c3 = ctype[i-1];
|
|
||||||
var c4 = ctype[i];
|
|
||||||
var c5 = ctype[i+1];
|
|
||||||
var c6 = ctype[i+2];
|
|
||||||
score += this.ts_(this.UP1__[p1]);
|
|
||||||
score += this.ts_(this.UP2__[p2]);
|
|
||||||
score += this.ts_(this.UP3__[p3]);
|
|
||||||
score += this.ts_(this.BP1__[p1 + p2]);
|
|
||||||
score += this.ts_(this.BP2__[p2 + p3]);
|
|
||||||
score += this.ts_(this.UW1__[w1]);
|
|
||||||
score += this.ts_(this.UW2__[w2]);
|
|
||||||
score += this.ts_(this.UW3__[w3]);
|
|
||||||
score += this.ts_(this.UW4__[w4]);
|
|
||||||
score += this.ts_(this.UW5__[w5]);
|
|
||||||
score += this.ts_(this.UW6__[w6]);
|
|
||||||
score += this.ts_(this.BW1__[w2 + w3]);
|
|
||||||
score += this.ts_(this.BW2__[w3 + w4]);
|
|
||||||
score += this.ts_(this.BW3__[w4 + w5]);
|
|
||||||
score += this.ts_(this.TW1__[w1 + w2 + w3]);
|
|
||||||
score += this.ts_(this.TW2__[w2 + w3 + w4]);
|
|
||||||
score += this.ts_(this.TW3__[w3 + w4 + w5]);
|
|
||||||
score += this.ts_(this.TW4__[w4 + w5 + w6]);
|
|
||||||
score += this.ts_(this.UC1__[c1]);
|
|
||||||
score += this.ts_(this.UC2__[c2]);
|
|
||||||
score += this.ts_(this.UC3__[c3]);
|
|
||||||
score += this.ts_(this.UC4__[c4]);
|
|
||||||
score += this.ts_(this.UC5__[c5]);
|
|
||||||
score += this.ts_(this.UC6__[c6]);
|
|
||||||
score += this.ts_(this.BC1__[c2 + c3]);
|
|
||||||
score += this.ts_(this.BC2__[c3 + c4]);
|
|
||||||
score += this.ts_(this.BC3__[c4 + c5]);
|
|
||||||
score += this.ts_(this.TC1__[c1 + c2 + c3]);
|
|
||||||
score += this.ts_(this.TC2__[c2 + c3 + c4]);
|
|
||||||
score += this.ts_(this.TC3__[c3 + c4 + c5]);
|
|
||||||
score += this.ts_(this.TC4__[c4 + c5 + c6]);
|
|
||||||
// score += this.ts_(this.TC5__[c4 + c5 + c6]);
|
|
||||||
score += this.ts_(this.UQ1__[p1 + c1]);
|
|
||||||
score += this.ts_(this.UQ2__[p2 + c2]);
|
|
||||||
score += this.ts_(this.UQ3__[p3 + c3]);
|
|
||||||
score += this.ts_(this.BQ1__[p2 + c2 + c3]);
|
|
||||||
score += this.ts_(this.BQ2__[p2 + c3 + c4]);
|
|
||||||
score += this.ts_(this.BQ3__[p3 + c2 + c3]);
|
|
||||||
score += this.ts_(this.BQ4__[p3 + c3 + c4]);
|
|
||||||
score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]);
|
|
||||||
score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]);
|
|
||||||
score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]);
|
|
||||||
score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]);
|
|
||||||
var p = "O";
|
|
||||||
if (score > 0) {
|
|
||||||
result.push(word);
|
|
||||||
word = "";
|
|
||||||
p = "B";
|
|
||||||
}
|
|
||||||
p1 = p2;
|
|
||||||
p2 = p3;
|
|
||||||
p3 = p;
|
|
||||||
word += seg[i];
|
|
||||||
}
|
|
||||||
result.push(word);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
lunr.TinySegmenter = TinySegmenter;
|
|
||||||
};
|
|
||||||
|
|
||||||
}));
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":3,"sources":["src/templates/assets/stylesheets/palette/_scheme.scss","../../../../src/templates/assets/stylesheets/palette.scss","src/templates/assets/stylesheets/palette/_accent.scss","src/templates/assets/stylesheets/palette/_primary.scss","src/templates/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAME,sDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,mDAAA,CACA,gDAAA,CACA,yDAAA,CACA,4DAAA,CAGA,0BAAA,CACA,mCAAA,CAGA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,iCAAA,CAGA,yDAAA,CACA,iEAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,uDAAA,CAGA,8DAAA,CAKA,8DAAA,CAKA,0DAAA,CAzEA,iBCiBF,CD6DE,kHAEE,YC3DJ,CDkFE,yDACE,4BChFJ,CD+EE,2DACE,4BC7EJ,CD4EE,gEACE,4BC1EJ,CDyEE,2DACE,4BCvEJ,CDsEE,yDACE,4BCpEJ,CDmEE,0DACE,4BCjEJ,CDgEE,gEACE,4BC9DJ,CD6DE,0DACE,4BC3DJ,CD0DE,2OACE,4BC/CJ,CDsDA,+FAGE,iCCpDF,CACF,CCjDE,2BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD6CN,CCvDE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDoDN,CC9DE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD2DN,CCrEE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDkEN,CC5EE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDyEN,CCnFE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDgFN,CC1FE,kCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDuFN,CCjGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD8FN,CCxGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDqGN,CC/GE,6BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD4GN,CCtHE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDmHN,CC7HE,4BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD6HN,CCpIE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDoIN,CC3IE,6BACE,yBAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD2IN,CClJE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDkJN,CCzJE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDsJN,CE3JE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwJN,CEnKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgKN,CE3KE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwKN,CEnLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgLN,CE3LE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwLN,CEnME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgMN,CE3ME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwMN,CEnNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgNN,CE3NE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwNN,CEnOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgON,CE3OE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwON,CEnPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFmPN,CE3PE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCF2PN,CEnQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFmQN,CE3QE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCF2QN,CEnRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFgRN,CE3RE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFwRN,CEnSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BF4RN,CE5SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BFqSN,CEtRE,sEACE,4BFyRJ,CE1RE,+DACE,4BF6RJ,CE9RE,iEACE,4BFiSJ,CElSE,gEACE,4BFqSJ,CEtSE,iEACE,4BFySJ,CEhSA,8BACE,mDAAA,CACA,4DAAA,CACA,0DAAA,CACA,oDAAA,CACA,2DAAA,CAGA,4BFiSF,CE9RE,yCACE,+BFgSJ,CE7RI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCFiSN,CG7MI,mCD1EA,+CACE,8CF0RJ,CEvRI,qDACE,8CFyRN,CEpRE,iEACE,mCFsRJ,CACF,CGxNI,sCDvDA,uCACE,oCFkRJ,CACF,CEzQA,8BACE,kDAAA,CACA,4DAAA,CACA,wDAAA,CACA,oDAAA,CACA,6DAAA,CAGA,4BF0QF,CEvQE,yCACE,+BFyQJ,CEtQI,kDAEE,0CAAA,CACA,sCAAA,CAFA,mCF0QN,CEnQE,yCACE,6CFqQJ,CG9NI,0CDhCA,8CACE,gDFiQJ,CACF,CGnOI,0CDvBA,iFACE,6CF6PJ,CACF,CG3PI,sCDKA,uCACE,6CFyPJ,CACF","file":"palette.css"}
|
|
||||||
|
After Width: | Height: | Size: 404 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 252 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 268 KiB |
|
After Width: | Height: | Size: 268 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 447 KiB |