lightning-pose-app 1.8.1a1__py3-none-any.whl → 1.8.1a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lightning_pose_app-1.8.1a1.dist-info → lightning_pose_app-1.8.1a2.dist-info}/METADATA +1 -1
- lightning_pose_app-1.8.1a2.dist-info/RECORD +20 -0
- litpose_app/main.py +15 -5
- litpose_app/ngdist/ng_app/3rdpartylicenses.txt +11 -11
- litpose_app/ngdist/ng_app/app.component-IZ5OUDH2.css.map +7 -0
- litpose_app/ngdist/ng_app/index.html +11 -2
- litpose_app/ngdist/ng_app/{main-QMBNNDJG.js → main-WFYIUX2C.js} +849 -525
- litpose_app/ngdist/ng_app/main-WFYIUX2C.js.map +1 -0
- litpose_app/ngdist/ng_app/project-settings.component-BXKZMYM3.css.map +7 -0
- litpose_app/ngdist/ng_app/{styles-JT3DWFJR.css → styles-AJ6NQDUD.css} +376 -19
- litpose_app/ngdist/ng_app/styles-AJ6NQDUD.css.map +7 -0
- litpose_app/ngdist/ng_app/viewer-page.component-KIYG73MW.css.map +7 -0
- litpose_app/super_rglob.py +18 -6
- lightning_pose_app-1.8.1a1.dist-info/RECORD +0 -17
- litpose_app/ngdist/ng_app/main-QMBNNDJG.js.map +0 -1
- litpose_app/ngdist/ng_app/styles-JT3DWFJR.css.map +0 -7
- {lightning_pose_app-1.8.1a1.dist-info → lightning_pose_app-1.8.1a2.dist-info}/WHEEL +0 -0
|
@@ -7892,6 +7892,10 @@ var OutputEmitterRef = class {
|
|
|
7892
7892
|
}
|
|
7893
7893
|
}
|
|
7894
7894
|
};
|
|
7895
|
+
function output(opts) {
|
|
7896
|
+
ngDevMode && assertInInjectionContext(output);
|
|
7897
|
+
return new OutputEmitterRef();
|
|
7898
|
+
}
|
|
7895
7899
|
function inputFunction(initialValue, opts) {
|
|
7896
7900
|
ngDevMode && assertInInjectionContext(input);
|
|
7897
7901
|
return createInputSignal(initialValue, opts);
|
|
@@ -20793,13 +20797,13 @@ function listenToOutput(tNode, lView, directiveIndex, lookupName, eventName, lis
|
|
|
20793
20797
|
const tView = lView[TVIEW];
|
|
20794
20798
|
const def = tView.data[directiveIndex];
|
|
20795
20799
|
const propertyName = def.outputs[lookupName];
|
|
20796
|
-
const
|
|
20797
|
-
if (ngDevMode && !isOutputSubscribable(
|
|
20800
|
+
const output2 = instance[propertyName];
|
|
20801
|
+
if (ngDevMode && !isOutputSubscribable(output2)) {
|
|
20798
20802
|
throw new Error(`@Output ${propertyName} not initialized in '${instance.constructor.name}'.`);
|
|
20799
20803
|
}
|
|
20800
20804
|
const tCleanup = tView.firstCreatePass ? getOrCreateTViewCleanup(tView) : null;
|
|
20801
20805
|
const lCleanup = getOrCreateLViewCleanup(lView);
|
|
20802
|
-
const subscription =
|
|
20806
|
+
const subscription = output2.subscribe(listenerFn);
|
|
20803
20807
|
const idx = lCleanup.length;
|
|
20804
20808
|
lCleanup.push(listenerFn, subscription);
|
|
20805
20809
|
tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1));
|
|
@@ -39894,6 +39898,423 @@ function provideRouterInitializer() {
|
|
|
39894
39898
|
// node_modules/@angular/router/fesm2022/router.mjs
|
|
39895
39899
|
var VERSION4 = new Version("19.2.11");
|
|
39896
39900
|
|
|
39901
|
+
// src/app/rpc.service.ts
|
|
39902
|
+
var RpcService = class _RpcService {
|
|
39903
|
+
http = inject(HttpClient);
|
|
39904
|
+
call(method, params) {
|
|
39905
|
+
const observable2 = this.http.post(`/app/v0/rpc/${method}`, params ?? null, {
|
|
39906
|
+
headers: { "Content-type": "application/json" }
|
|
39907
|
+
});
|
|
39908
|
+
return firstValueFrom(observable2);
|
|
39909
|
+
}
|
|
39910
|
+
static \u0275fac = function RpcService_Factory(__ngFactoryType__) {
|
|
39911
|
+
return new (__ngFactoryType__ || _RpcService)();
|
|
39912
|
+
};
|
|
39913
|
+
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _RpcService, factory: _RpcService.\u0275fac, providedIn: "root" });
|
|
39914
|
+
};
|
|
39915
|
+
(() => {
|
|
39916
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RpcService, [{
|
|
39917
|
+
type: Injectable,
|
|
39918
|
+
args: [{
|
|
39919
|
+
providedIn: "root"
|
|
39920
|
+
}]
|
|
39921
|
+
}], null, null);
|
|
39922
|
+
})();
|
|
39923
|
+
|
|
39924
|
+
// src/app/project-info.ts
|
|
39925
|
+
var ProjectInfo = class {
|
|
39926
|
+
// absolute path on server filesystem
|
|
39927
|
+
data_dir;
|
|
39928
|
+
// absolute path on server filesystem
|
|
39929
|
+
model_dir;
|
|
39930
|
+
views;
|
|
39931
|
+
constructor(projectInfo) {
|
|
39932
|
+
this.data_dir = String(projectInfo.data_dir);
|
|
39933
|
+
this.model_dir = String(projectInfo.model_dir);
|
|
39934
|
+
this.views = projectInfo.views ?? [];
|
|
39935
|
+
}
|
|
39936
|
+
};
|
|
39937
|
+
|
|
39938
|
+
// node_modules/@angular/core/fesm2022/rxjs-interop.mjs
|
|
39939
|
+
function takeUntilDestroyed(destroyRef) {
|
|
39940
|
+
if (!destroyRef) {
|
|
39941
|
+
assertInInjectionContext(takeUntilDestroyed);
|
|
39942
|
+
destroyRef = inject(DestroyRef);
|
|
39943
|
+
}
|
|
39944
|
+
const destroyed$ = new Observable((observer) => {
|
|
39945
|
+
const unregisterFn = destroyRef.onDestroy(observer.next.bind(observer));
|
|
39946
|
+
return unregisterFn;
|
|
39947
|
+
});
|
|
39948
|
+
return (source) => {
|
|
39949
|
+
return source.pipe(takeUntil(destroyed$));
|
|
39950
|
+
};
|
|
39951
|
+
}
|
|
39952
|
+
function toSignal(source, options) {
|
|
39953
|
+
typeof ngDevMode !== "undefined" && ngDevMode && assertNotInReactiveContext(toSignal, "Invoking `toSignal` causes new subscriptions every time. Consider moving `toSignal` outside of the reactive context and read the signal value where needed.");
|
|
39954
|
+
const requiresCleanup = !options?.manualCleanup;
|
|
39955
|
+
requiresCleanup && !options?.injector && assertInInjectionContext(toSignal);
|
|
39956
|
+
const cleanupRef = requiresCleanup ? options?.injector?.get(DestroyRef) ?? inject(DestroyRef) : null;
|
|
39957
|
+
const equal = makeToSignalEqual(options?.equal);
|
|
39958
|
+
let state;
|
|
39959
|
+
if (options?.requireSync) {
|
|
39960
|
+
state = signal({
|
|
39961
|
+
kind: 0
|
|
39962
|
+
/* StateKind.NoValue */
|
|
39963
|
+
}, {
|
|
39964
|
+
equal
|
|
39965
|
+
});
|
|
39966
|
+
} else {
|
|
39967
|
+
state = signal({
|
|
39968
|
+
kind: 1,
|
|
39969
|
+
value: options?.initialValue
|
|
39970
|
+
}, {
|
|
39971
|
+
equal
|
|
39972
|
+
});
|
|
39973
|
+
}
|
|
39974
|
+
const sub = source.subscribe({
|
|
39975
|
+
next: (value) => state.set({
|
|
39976
|
+
kind: 1,
|
|
39977
|
+
value
|
|
39978
|
+
}),
|
|
39979
|
+
error: (error) => {
|
|
39980
|
+
if (options?.rejectErrors) {
|
|
39981
|
+
throw error;
|
|
39982
|
+
}
|
|
39983
|
+
state.set({
|
|
39984
|
+
kind: 2,
|
|
39985
|
+
error
|
|
39986
|
+
});
|
|
39987
|
+
}
|
|
39988
|
+
// Completion of the Observable is meaningless to the signal. Signals don't have a concept of
|
|
39989
|
+
// "complete".
|
|
39990
|
+
});
|
|
39991
|
+
if (options?.requireSync && state().kind === 0) {
|
|
39992
|
+
throw new RuntimeError(601, (typeof ngDevMode === "undefined" || ngDevMode) && "`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.");
|
|
39993
|
+
}
|
|
39994
|
+
cleanupRef?.onDestroy(sub.unsubscribe.bind(sub));
|
|
39995
|
+
return computed(() => {
|
|
39996
|
+
const current = state();
|
|
39997
|
+
switch (current.kind) {
|
|
39998
|
+
case 1:
|
|
39999
|
+
return current.value;
|
|
40000
|
+
case 2:
|
|
40001
|
+
throw current.error;
|
|
40002
|
+
case 0:
|
|
40003
|
+
throw new RuntimeError(601, (typeof ngDevMode === "undefined" || ngDevMode) && "`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.");
|
|
40004
|
+
}
|
|
40005
|
+
}, {
|
|
40006
|
+
equal: options?.equal
|
|
40007
|
+
});
|
|
40008
|
+
}
|
|
40009
|
+
function makeToSignalEqual(userEquality = Object.is) {
|
|
40010
|
+
return (a, b) => a.kind === 1 && b.kind === 1 && userEquality(a.value, b.value);
|
|
40011
|
+
}
|
|
40012
|
+
|
|
40013
|
+
// src/app/project-info.service.ts
|
|
40014
|
+
var ProjectInfoService = class _ProjectInfoService {
|
|
40015
|
+
rpc = inject(RpcService);
|
|
40016
|
+
// undefined means not yet requested
|
|
40017
|
+
// null means requested and not present
|
|
40018
|
+
_projectInfo = void 0;
|
|
40019
|
+
async loadProjectInfo() {
|
|
40020
|
+
const response = await this.rpc.call("getProjectInfo");
|
|
40021
|
+
this._projectInfo = response.projectInfo ? new ProjectInfo(response.projectInfo) : null;
|
|
40022
|
+
this.setAllViews(this._projectInfo?.views ?? []);
|
|
40023
|
+
}
|
|
40024
|
+
get projectInfo() {
|
|
40025
|
+
return this._projectInfo;
|
|
40026
|
+
}
|
|
40027
|
+
async setProjectInfo(projectInfo) {
|
|
40028
|
+
await this.rpc.call("setProjectInfo", { projectInfo });
|
|
40029
|
+
window.location.reload();
|
|
40030
|
+
}
|
|
40031
|
+
// Newer style of models.
|
|
40032
|
+
_allViews = new BehaviorSubject([]);
|
|
40033
|
+
allViews$ = this._allViews.asObservable().pipe(distinctUntilChanged());
|
|
40034
|
+
allViews = toSignal(this.allViews$, { requireSync: true });
|
|
40035
|
+
setAllViews(views) {
|
|
40036
|
+
this._allViews.next(views.concat(["unknown"]));
|
|
40037
|
+
}
|
|
40038
|
+
_allKeypoints = new BehaviorSubject([]);
|
|
40039
|
+
allKeypoints$ = this._allKeypoints.asObservable().pipe(distinctUntilChanged());
|
|
40040
|
+
allKeypoints = toSignal(this.allKeypoints$, { requireSync: true });
|
|
40041
|
+
setAllKeypoints(keypoints) {
|
|
40042
|
+
this._allKeypoints.next(keypoints);
|
|
40043
|
+
}
|
|
40044
|
+
_allModels = new BehaviorSubject([]);
|
|
40045
|
+
allModels$ = this._allModels.asObservable().pipe(distinctUntilChanged());
|
|
40046
|
+
allModels = toSignal(this.allModels$, { requireSync: true });
|
|
40047
|
+
setAllModels(models) {
|
|
40048
|
+
this._allModels.next(models);
|
|
40049
|
+
}
|
|
40050
|
+
static \u0275fac = function ProjectInfoService_Factory(__ngFactoryType__) {
|
|
40051
|
+
return new (__ngFactoryType__ || _ProjectInfoService)();
|
|
40052
|
+
};
|
|
40053
|
+
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _ProjectInfoService, factory: _ProjectInfoService.\u0275fac, providedIn: "root" });
|
|
40054
|
+
};
|
|
40055
|
+
(() => {
|
|
40056
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ProjectInfoService, [{
|
|
40057
|
+
type: Injectable,
|
|
40058
|
+
args: [{
|
|
40059
|
+
providedIn: "root"
|
|
40060
|
+
}]
|
|
40061
|
+
}], null, null);
|
|
40062
|
+
})();
|
|
40063
|
+
|
|
40064
|
+
// src/app/csv-parser.service.ts
|
|
40065
|
+
var import_ndarray = __toESM(require_ndarray());
|
|
40066
|
+
var import_papaparse = __toESM(require_papaparse_min());
|
|
40067
|
+
var CsvParserService = class _CsvParserService {
|
|
40068
|
+
/**
|
|
40069
|
+
* Parses a CSV string from pose estimation into a 3D array (ndarray-like structure)
|
|
40070
|
+
* using the PapaParse library.
|
|
40071
|
+
* The output shape is (number of frames, number of bodyparts, 2 for x/y coordinates).
|
|
40072
|
+
*
|
|
40073
|
+
* @param csvString The CSV data as a string.
|
|
40074
|
+
* @returns A 3D array of numbers: number[][][].
|
|
40075
|
+
* Returns an empty array if the CSV is malformed, has no data, or PapaParse fails.
|
|
40076
|
+
*/
|
|
40077
|
+
getBodyParts(csvString) {
|
|
40078
|
+
const parseOutput = import_papaparse.default.parse(csvString.trim(), {
|
|
40079
|
+
dynamicTyping: false,
|
|
40080
|
+
skipEmptyLines: true
|
|
40081
|
+
});
|
|
40082
|
+
if (parseOutput.errors.length > 0) {
|
|
40083
|
+
console.error("PapaParse errors:", parseOutput.errors);
|
|
40084
|
+
return [];
|
|
40085
|
+
}
|
|
40086
|
+
const allRows = parseOutput.data;
|
|
40087
|
+
if (allRows.length < 4) {
|
|
40088
|
+
console.error("CSV must have at least 3 header lines and 1 data line.");
|
|
40089
|
+
return [];
|
|
40090
|
+
}
|
|
40091
|
+
const bodypartsHeader = allRows[1];
|
|
40092
|
+
if (!bodypartsHeader || bodypartsHeader.length <= 1 || (bodypartsHeader.length - 1) % 3 !== 0) {
|
|
40093
|
+
console.error("Malformed bodyparts header line (line 2 of CSV).", bodypartsHeader);
|
|
40094
|
+
return [];
|
|
40095
|
+
}
|
|
40096
|
+
return bodypartsHeader.filter((_element, index) => {
|
|
40097
|
+
return (index - 1) % 3 === 0 && index >= 1;
|
|
40098
|
+
});
|
|
40099
|
+
}
|
|
40100
|
+
parsePredictionFile(csvString) {
|
|
40101
|
+
const parseOutput = import_papaparse.default.parse(csvString.trim(), {
|
|
40102
|
+
dynamicTyping: false,
|
|
40103
|
+
skipEmptyLines: true
|
|
40104
|
+
});
|
|
40105
|
+
if (parseOutput.errors.length > 0) {
|
|
40106
|
+
console.error("PapaParse errors:", parseOutput.errors);
|
|
40107
|
+
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
40108
|
+
}
|
|
40109
|
+
const allRows = parseOutput.data;
|
|
40110
|
+
if (allRows.length < 4) {
|
|
40111
|
+
console.error("CSV must have at least 3 header lines and 1 data line.");
|
|
40112
|
+
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
40113
|
+
}
|
|
40114
|
+
const bodypartsHeader = allRows[1];
|
|
40115
|
+
if (!bodypartsHeader || bodypartsHeader.length <= 1 || (bodypartsHeader.length - 1) % 3 !== 0) {
|
|
40116
|
+
console.error("Malformed bodyparts header line (line 2 of CSV).", bodypartsHeader);
|
|
40117
|
+
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
40118
|
+
}
|
|
40119
|
+
const numBodyParts = (bodypartsHeader.length - 1) / 3;
|
|
40120
|
+
const coordsHeader = allRows[2];
|
|
40121
|
+
if (!coordsHeader || coordsHeader.length !== bodypartsHeader.length) {
|
|
40122
|
+
console.error("Coordinate header (line 3 of CSV) length mismatch with bodyparts header.");
|
|
40123
|
+
return (0, import_ndarray.default)(new Float64Array(0), [
|
|
40124
|
+
0,
|
|
40125
|
+
numBodyParts > 0 ? numBodyParts : 0,
|
|
40126
|
+
2
|
|
40127
|
+
]);
|
|
40128
|
+
}
|
|
40129
|
+
const dataRowsOnly = allRows.slice(3);
|
|
40130
|
+
const numFrames = dataRowsOnly.length;
|
|
40131
|
+
if (numFrames === 0 || numBodyParts === 0) {
|
|
40132
|
+
return (0, import_ndarray.default)(new Float64Array(0), [numFrames, numBodyParts, 2]);
|
|
40133
|
+
}
|
|
40134
|
+
const flatData = new Float64Array(numFrames * numBodyParts * 2);
|
|
40135
|
+
let flatIndex = 0;
|
|
40136
|
+
for (let rowIndex = 0; rowIndex < numFrames; rowIndex++) {
|
|
40137
|
+
const values = dataRowsOnly[rowIndex];
|
|
40138
|
+
if (values.length < 1 + numBodyParts * 3) {
|
|
40139
|
+
console.warn(`Skipping malformed data row ${rowIndex + 4} (not enough columns): "${values.slice(0, 5).join(",")}..."`);
|
|
40140
|
+
for (let i = 0; i < numBodyParts; i++) {
|
|
40141
|
+
flatData[flatIndex++] = NaN;
|
|
40142
|
+
flatData[flatIndex++] = NaN;
|
|
40143
|
+
}
|
|
40144
|
+
continue;
|
|
40145
|
+
}
|
|
40146
|
+
for (let bodyPartIdx = 0; bodyPartIdx < numBodyParts; bodyPartIdx++) {
|
|
40147
|
+
const xDataIndex = 1 + bodyPartIdx * 3;
|
|
40148
|
+
const yDataIndex = 1 + bodyPartIdx * 3 + 1;
|
|
40149
|
+
if (xDataIndex >= values.length || yDataIndex >= values.length) {
|
|
40150
|
+
console.warn(`Skipping body part ${bodyPartIdx} in data row ${rowIndex + 4} due to insufficient data.`);
|
|
40151
|
+
flatData[flatIndex++] = NaN;
|
|
40152
|
+
flatData[flatIndex++] = NaN;
|
|
40153
|
+
continue;
|
|
40154
|
+
}
|
|
40155
|
+
const xString = values[xDataIndex];
|
|
40156
|
+
const yString = values[yDataIndex];
|
|
40157
|
+
const x = parseFloat(xString);
|
|
40158
|
+
const y = parseFloat(yString);
|
|
40159
|
+
if (isNaN(x) || isNaN(y)) {
|
|
40160
|
+
console.warn(`Could not parse x or y as number for body part ${bodyPartIdx} in data row ${rowIndex + 4}. Values: x='${xString}', y='${yString}'.`);
|
|
40161
|
+
flatData[flatIndex++] = NaN;
|
|
40162
|
+
flatData[flatIndex++] = NaN;
|
|
40163
|
+
} else {
|
|
40164
|
+
flatData[flatIndex++] = x;
|
|
40165
|
+
flatData[flatIndex++] = y;
|
|
40166
|
+
}
|
|
40167
|
+
}
|
|
40168
|
+
}
|
|
40169
|
+
return (0, import_ndarray.default)(flatData, [numFrames, numBodyParts, 2]);
|
|
40170
|
+
}
|
|
40171
|
+
static \u0275fac = function CsvParserService_Factory(__ngFactoryType__) {
|
|
40172
|
+
return new (__ngFactoryType__ || _CsvParserService)();
|
|
40173
|
+
};
|
|
40174
|
+
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _CsvParserService, factory: _CsvParserService.\u0275fac, providedIn: "root" });
|
|
40175
|
+
};
|
|
40176
|
+
(() => {
|
|
40177
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CsvParserService, [{
|
|
40178
|
+
type: Injectable,
|
|
40179
|
+
args: [{
|
|
40180
|
+
providedIn: "root"
|
|
40181
|
+
}]
|
|
40182
|
+
}], null, null);
|
|
40183
|
+
})();
|
|
40184
|
+
|
|
40185
|
+
// src/app/session.service.ts
|
|
40186
|
+
var SessionService = class _SessionService {
|
|
40187
|
+
rpc = inject(RpcService);
|
|
40188
|
+
httpClient = inject(HttpClient);
|
|
40189
|
+
predictionFiles = [];
|
|
40190
|
+
projectInfoService = inject(ProjectInfoService);
|
|
40191
|
+
csvParser = inject(CsvParserService);
|
|
40192
|
+
_allSessions = new BehaviorSubject([]);
|
|
40193
|
+
allSessions$ = this._allSessions.asObservable();
|
|
40194
|
+
allSessions = toSignal(this.allSessions$, { requireSync: true });
|
|
40195
|
+
async loadSessions() {
|
|
40196
|
+
const projectInfo = this.projectInfoService.projectInfo;
|
|
40197
|
+
const response = await this.rpc.call("rglob", {
|
|
40198
|
+
baseDir: projectInfo.data_dir,
|
|
40199
|
+
pattern: "**/*.fine.mp4",
|
|
40200
|
+
//temporary
|
|
40201
|
+
noDirs: true
|
|
40202
|
+
});
|
|
40203
|
+
const mp4Files = response.entries.filter((entry) => entry.type === "file").map((entry) => entry.path);
|
|
40204
|
+
const sessions = this.groupVideoFilesIntoSessions(mp4Files, this.projectInfoService.projectInfo.views);
|
|
40205
|
+
return this._allSessions.next(sessions);
|
|
40206
|
+
}
|
|
40207
|
+
async loadPredictionIndex() {
|
|
40208
|
+
const projectInfo = this.projectInfoService.projectInfo;
|
|
40209
|
+
const response = await this.rpc.call("rglob", {
|
|
40210
|
+
baseDir: projectInfo.model_dir,
|
|
40211
|
+
pattern: "**/video_preds/**/*.csv",
|
|
40212
|
+
noDirs: true
|
|
40213
|
+
});
|
|
40214
|
+
this.predictionFiles = response.entries.filter((entry) => {
|
|
40215
|
+
if (entry.type !== "file")
|
|
40216
|
+
return false;
|
|
40217
|
+
if (entry.path.endsWith("_bbox.csv"))
|
|
40218
|
+
return false;
|
|
40219
|
+
if (entry.path.endsWith("_error.csv"))
|
|
40220
|
+
return false;
|
|
40221
|
+
if (entry.path.endsWith("_loss.csv"))
|
|
40222
|
+
return false;
|
|
40223
|
+
if (entry.path.endsWith("_norm.csv"))
|
|
40224
|
+
return false;
|
|
40225
|
+
return true;
|
|
40226
|
+
}).map((entry) => {
|
|
40227
|
+
let match2 = entry.path.match(/(.+)\/video_preds\/([^/]+)\.mp4\/predictions\.csv/);
|
|
40228
|
+
if (!match2) {
|
|
40229
|
+
match2 = entry.path.match(/(.+)\/video_preds\/([^/]+)\.csv/);
|
|
40230
|
+
}
|
|
40231
|
+
if (!match2)
|
|
40232
|
+
return null;
|
|
40233
|
+
const modelKey = match2[1];
|
|
40234
|
+
const sessionView = match2[2];
|
|
40235
|
+
const viewName = this.projectInfoService.allViews().find((v) => sessionView.includes(v));
|
|
40236
|
+
if (!viewName)
|
|
40237
|
+
return null;
|
|
40238
|
+
const sessionKey = sessionView.replace(viewName, "*");
|
|
40239
|
+
return {
|
|
40240
|
+
path: entry.path,
|
|
40241
|
+
modelKey,
|
|
40242
|
+
sessionKey,
|
|
40243
|
+
viewName
|
|
40244
|
+
};
|
|
40245
|
+
}).filter((entry) => entry != null);
|
|
40246
|
+
this.initModels();
|
|
40247
|
+
await this.initKeypoints();
|
|
40248
|
+
}
|
|
40249
|
+
initModels() {
|
|
40250
|
+
const uniqueModels = new Set(this.predictionFiles.map((pfile) => pfile.modelKey).filter((x) => x));
|
|
40251
|
+
this.projectInfoService.setAllModels(Array.from(uniqueModels).sort());
|
|
40252
|
+
}
|
|
40253
|
+
async initKeypoints() {
|
|
40254
|
+
if (this.predictionFiles.length === 0)
|
|
40255
|
+
return;
|
|
40256
|
+
const csvFile = await this.getPredictionFile(this.predictionFiles[0]);
|
|
40257
|
+
if (!csvFile)
|
|
40258
|
+
return;
|
|
40259
|
+
const allKeypoints = this.csvParser.getBodyParts(csvFile);
|
|
40260
|
+
this.projectInfoService.setAllKeypoints(allKeypoints);
|
|
40261
|
+
}
|
|
40262
|
+
getPredictionFilesForSession(sessionKey) {
|
|
40263
|
+
const predictionFiles = this.predictionFiles.filter((p) => p.sessionKey === sessionKey || p.sessionKey === sessionKey.replace(/\.fine$/, ""));
|
|
40264
|
+
return predictionFiles;
|
|
40265
|
+
}
|
|
40266
|
+
async getPredictionFile(pfile) {
|
|
40267
|
+
const modelDir = this.projectInfoService.projectInfo?.model_dir;
|
|
40268
|
+
const src = "/app/v0/files/" + modelDir + "/" + pfile.path;
|
|
40269
|
+
return await firstValueFrom(this.httpClient.get(src, { responseType: "text" }).pipe(catchError((error) => {
|
|
40270
|
+
if (error.status === 404) {
|
|
40271
|
+
return [null];
|
|
40272
|
+
}
|
|
40273
|
+
throw error;
|
|
40274
|
+
})));
|
|
40275
|
+
}
|
|
40276
|
+
async ffprobe(file) {
|
|
40277
|
+
const response = await this.rpc.call("ffprobe", {
|
|
40278
|
+
path: file
|
|
40279
|
+
});
|
|
40280
|
+
return response;
|
|
40281
|
+
}
|
|
40282
|
+
groupVideoFilesIntoSessions(filenames, views) {
|
|
40283
|
+
const sessionKeyToItsViewFiles = /* @__PURE__ */ new Map();
|
|
40284
|
+
for (const filename of filenames) {
|
|
40285
|
+
let viewName = views.find((v) => filename.includes(v));
|
|
40286
|
+
if (!viewName) {
|
|
40287
|
+
viewName = "unknown";
|
|
40288
|
+
}
|
|
40289
|
+
const sessionKey = viewName == "unknown" ? filename : filename.replace(viewName, "*");
|
|
40290
|
+
if (!sessionKeyToItsViewFiles.has(sessionKey)) {
|
|
40291
|
+
sessionKeyToItsViewFiles.set(sessionKey, []);
|
|
40292
|
+
}
|
|
40293
|
+
const projectInfo = this.projectInfoService.projectInfo;
|
|
40294
|
+
sessionKeyToItsViewFiles.get(sessionKey).push({
|
|
40295
|
+
viewName,
|
|
40296
|
+
videoPath: projectInfo.data_dir + "/" + filename
|
|
40297
|
+
});
|
|
40298
|
+
}
|
|
40299
|
+
return Array.from(sessionKeyToItsViewFiles.entries()).map(([key, sessionViews]) => ({
|
|
40300
|
+
key: key.replace(/\.mp4$/, ""),
|
|
40301
|
+
views: sessionViews
|
|
40302
|
+
}));
|
|
40303
|
+
}
|
|
40304
|
+
static \u0275fac = function SessionService_Factory(__ngFactoryType__) {
|
|
40305
|
+
return new (__ngFactoryType__ || _SessionService)();
|
|
40306
|
+
};
|
|
40307
|
+
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _SessionService, factory: _SessionService.\u0275fac, providedIn: "root" });
|
|
40308
|
+
};
|
|
40309
|
+
(() => {
|
|
40310
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(SessionService, [{
|
|
40311
|
+
type: Injectable,
|
|
40312
|
+
args: [{
|
|
40313
|
+
providedIn: "root"
|
|
40314
|
+
}]
|
|
40315
|
+
}], null, null);
|
|
40316
|
+
})();
|
|
40317
|
+
|
|
39897
40318
|
// node_modules/@angular/cdk/fesm2022/boolean-property-DaaVhX5A.mjs
|
|
39898
40319
|
function coerceBooleanProperty(value) {
|
|
39899
40320
|
return value != null && `${value}` !== "false";
|
|
@@ -40880,12 +41301,12 @@ var BreakpointObserver = class _BreakpointObserver {
|
|
|
40880
41301
|
query,
|
|
40881
41302
|
matches
|
|
40882
41303
|
})), takeUntil(this._destroySubject));
|
|
40883
|
-
const
|
|
41304
|
+
const output2 = {
|
|
40884
41305
|
observable: queryObservable,
|
|
40885
41306
|
mql
|
|
40886
41307
|
};
|
|
40887
|
-
this._queries.set(query,
|
|
40888
|
-
return
|
|
41308
|
+
this._queries.set(query, output2);
|
|
41309
|
+
return output2;
|
|
40889
41310
|
}
|
|
40890
41311
|
static \u0275fac = function BreakpointObserver_Factory(__ngFactoryType__) {
|
|
40891
41312
|
return new (__ngFactoryType__ || _BreakpointObserver)();
|
|
@@ -52946,14 +53367,14 @@ var ViewportRuler = class _ViewportRuler {
|
|
|
52946
53367
|
if (!this._viewportSize) {
|
|
52947
53368
|
this._updateViewportSize();
|
|
52948
53369
|
}
|
|
52949
|
-
const
|
|
53370
|
+
const output2 = {
|
|
52950
53371
|
width: this._viewportSize.width,
|
|
52951
53372
|
height: this._viewportSize.height
|
|
52952
53373
|
};
|
|
52953
53374
|
if (!this._platform.isBrowser) {
|
|
52954
53375
|
this._viewportSize = null;
|
|
52955
53376
|
}
|
|
52956
|
-
return
|
|
53377
|
+
return output2;
|
|
52957
53378
|
}
|
|
52958
53379
|
/** Gets a DOMRect for the viewport's bounds. */
|
|
52959
53380
|
getViewportRect() {
|
|
@@ -53892,399 +54313,6 @@ var ScrollingModule = class _ScrollingModule {
|
|
|
53892
54313
|
}], null, null);
|
|
53893
54314
|
})();
|
|
53894
54315
|
|
|
53895
|
-
// node_modules/@angular/core/fesm2022/rxjs-interop.mjs
|
|
53896
|
-
function takeUntilDestroyed(destroyRef) {
|
|
53897
|
-
if (!destroyRef) {
|
|
53898
|
-
assertInInjectionContext(takeUntilDestroyed);
|
|
53899
|
-
destroyRef = inject(DestroyRef);
|
|
53900
|
-
}
|
|
53901
|
-
const destroyed$ = new Observable((observer) => {
|
|
53902
|
-
const unregisterFn = destroyRef.onDestroy(observer.next.bind(observer));
|
|
53903
|
-
return unregisterFn;
|
|
53904
|
-
});
|
|
53905
|
-
return (source) => {
|
|
53906
|
-
return source.pipe(takeUntil(destroyed$));
|
|
53907
|
-
};
|
|
53908
|
-
}
|
|
53909
|
-
function toSignal(source, options) {
|
|
53910
|
-
typeof ngDevMode !== "undefined" && ngDevMode && assertNotInReactiveContext(toSignal, "Invoking `toSignal` causes new subscriptions every time. Consider moving `toSignal` outside of the reactive context and read the signal value where needed.");
|
|
53911
|
-
const requiresCleanup = !options?.manualCleanup;
|
|
53912
|
-
requiresCleanup && !options?.injector && assertInInjectionContext(toSignal);
|
|
53913
|
-
const cleanupRef = requiresCleanup ? options?.injector?.get(DestroyRef) ?? inject(DestroyRef) : null;
|
|
53914
|
-
const equal = makeToSignalEqual(options?.equal);
|
|
53915
|
-
let state;
|
|
53916
|
-
if (options?.requireSync) {
|
|
53917
|
-
state = signal({
|
|
53918
|
-
kind: 0
|
|
53919
|
-
/* StateKind.NoValue */
|
|
53920
|
-
}, {
|
|
53921
|
-
equal
|
|
53922
|
-
});
|
|
53923
|
-
} else {
|
|
53924
|
-
state = signal({
|
|
53925
|
-
kind: 1,
|
|
53926
|
-
value: options?.initialValue
|
|
53927
|
-
}, {
|
|
53928
|
-
equal
|
|
53929
|
-
});
|
|
53930
|
-
}
|
|
53931
|
-
const sub = source.subscribe({
|
|
53932
|
-
next: (value) => state.set({
|
|
53933
|
-
kind: 1,
|
|
53934
|
-
value
|
|
53935
|
-
}),
|
|
53936
|
-
error: (error) => {
|
|
53937
|
-
if (options?.rejectErrors) {
|
|
53938
|
-
throw error;
|
|
53939
|
-
}
|
|
53940
|
-
state.set({
|
|
53941
|
-
kind: 2,
|
|
53942
|
-
error
|
|
53943
|
-
});
|
|
53944
|
-
}
|
|
53945
|
-
// Completion of the Observable is meaningless to the signal. Signals don't have a concept of
|
|
53946
|
-
// "complete".
|
|
53947
|
-
});
|
|
53948
|
-
if (options?.requireSync && state().kind === 0) {
|
|
53949
|
-
throw new RuntimeError(601, (typeof ngDevMode === "undefined" || ngDevMode) && "`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.");
|
|
53950
|
-
}
|
|
53951
|
-
cleanupRef?.onDestroy(sub.unsubscribe.bind(sub));
|
|
53952
|
-
return computed(() => {
|
|
53953
|
-
const current = state();
|
|
53954
|
-
switch (current.kind) {
|
|
53955
|
-
case 1:
|
|
53956
|
-
return current.value;
|
|
53957
|
-
case 2:
|
|
53958
|
-
throw current.error;
|
|
53959
|
-
case 0:
|
|
53960
|
-
throw new RuntimeError(601, (typeof ngDevMode === "undefined" || ngDevMode) && "`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.");
|
|
53961
|
-
}
|
|
53962
|
-
}, {
|
|
53963
|
-
equal: options?.equal
|
|
53964
|
-
});
|
|
53965
|
-
}
|
|
53966
|
-
function makeToSignalEqual(userEquality = Object.is) {
|
|
53967
|
-
return (a, b) => a.kind === 1 && b.kind === 1 && userEquality(a.value, b.value);
|
|
53968
|
-
}
|
|
53969
|
-
|
|
53970
|
-
// src/app/rpc.service.ts
|
|
53971
|
-
var RpcService = class _RpcService {
|
|
53972
|
-
http = inject(HttpClient);
|
|
53973
|
-
call(method, params) {
|
|
53974
|
-
const observable2 = this.http.post(`/app/v0/rpc/${method}`, params ?? null, {
|
|
53975
|
-
headers: { "Content-type": "application/json" }
|
|
53976
|
-
});
|
|
53977
|
-
return firstValueFrom(observable2);
|
|
53978
|
-
}
|
|
53979
|
-
static \u0275fac = function RpcService_Factory(__ngFactoryType__) {
|
|
53980
|
-
return new (__ngFactoryType__ || _RpcService)();
|
|
53981
|
-
};
|
|
53982
|
-
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _RpcService, factory: _RpcService.\u0275fac, providedIn: "root" });
|
|
53983
|
-
};
|
|
53984
|
-
(() => {
|
|
53985
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(RpcService, [{
|
|
53986
|
-
type: Injectable,
|
|
53987
|
-
args: [{
|
|
53988
|
-
providedIn: "root"
|
|
53989
|
-
}]
|
|
53990
|
-
}], null, null);
|
|
53991
|
-
})();
|
|
53992
|
-
|
|
53993
|
-
// src/app/project-info.service.ts
|
|
53994
|
-
var ProjectInfoService = class _ProjectInfoService {
|
|
53995
|
-
rpc = inject(RpcService);
|
|
53996
|
-
// inits to undefined, set to null if no project exists.
|
|
53997
|
-
_projectInfo = void 0;
|
|
53998
|
-
async loadProjectInfo() {
|
|
53999
|
-
const response = await this.rpc.call("getProjectInfo");
|
|
54000
|
-
this._projectInfo = response.projectInfo;
|
|
54001
|
-
this.setAllViews(response.projectInfo.views);
|
|
54002
|
-
}
|
|
54003
|
-
get projectInfo() {
|
|
54004
|
-
return this._projectInfo;
|
|
54005
|
-
}
|
|
54006
|
-
async setProjectInfo(projectInfo) {
|
|
54007
|
-
await this.rpc.call("setProjectInfo", { projectInfo });
|
|
54008
|
-
}
|
|
54009
|
-
// Newer style of models.
|
|
54010
|
-
_allViews = new BehaviorSubject([]);
|
|
54011
|
-
allViews$ = this._allViews.asObservable().pipe(distinctUntilChanged());
|
|
54012
|
-
allViews = toSignal(this.allViews$, { requireSync: true });
|
|
54013
|
-
setAllViews(views) {
|
|
54014
|
-
this._allViews.next(views);
|
|
54015
|
-
}
|
|
54016
|
-
_allKeypoints = new BehaviorSubject([]);
|
|
54017
|
-
allKeypoints$ = this._allKeypoints.asObservable().pipe(distinctUntilChanged());
|
|
54018
|
-
allKeypoints = toSignal(this.allKeypoints$, { requireSync: true });
|
|
54019
|
-
setAllKeypoints(keypoints) {
|
|
54020
|
-
this._allKeypoints.next(keypoints);
|
|
54021
|
-
}
|
|
54022
|
-
_allModels = new BehaviorSubject([]);
|
|
54023
|
-
allModels$ = this._allModels.asObservable().pipe(distinctUntilChanged());
|
|
54024
|
-
allModels = toSignal(this.allModels$, { requireSync: true });
|
|
54025
|
-
setAllModels(models) {
|
|
54026
|
-
this._allModels.next(models);
|
|
54027
|
-
}
|
|
54028
|
-
static \u0275fac = function ProjectInfoService_Factory(__ngFactoryType__) {
|
|
54029
|
-
return new (__ngFactoryType__ || _ProjectInfoService)();
|
|
54030
|
-
};
|
|
54031
|
-
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _ProjectInfoService, factory: _ProjectInfoService.\u0275fac, providedIn: "root" });
|
|
54032
|
-
};
|
|
54033
|
-
(() => {
|
|
54034
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ProjectInfoService, [{
|
|
54035
|
-
type: Injectable,
|
|
54036
|
-
args: [{
|
|
54037
|
-
providedIn: "root"
|
|
54038
|
-
}]
|
|
54039
|
-
}], null, null);
|
|
54040
|
-
})();
|
|
54041
|
-
|
|
54042
|
-
// src/app/csv-parser.service.ts
|
|
54043
|
-
var import_ndarray = __toESM(require_ndarray());
|
|
54044
|
-
var import_papaparse = __toESM(require_papaparse_min());
|
|
54045
|
-
var CsvParserService = class _CsvParserService {
|
|
54046
|
-
/**
|
|
54047
|
-
* Parses a CSV string from pose estimation into a 3D array (ndarray-like structure)
|
|
54048
|
-
* using the PapaParse library.
|
|
54049
|
-
* The output shape is (number of frames, number of bodyparts, 2 for x/y coordinates).
|
|
54050
|
-
*
|
|
54051
|
-
* @param csvString The CSV data as a string.
|
|
54052
|
-
* @returns A 3D array of numbers: number[][][].
|
|
54053
|
-
* Returns an empty array if the CSV is malformed, has no data, or PapaParse fails.
|
|
54054
|
-
*/
|
|
54055
|
-
getBodyParts(csvString) {
|
|
54056
|
-
const parseOutput = import_papaparse.default.parse(csvString.trim(), {
|
|
54057
|
-
dynamicTyping: false,
|
|
54058
|
-
skipEmptyLines: true
|
|
54059
|
-
});
|
|
54060
|
-
if (parseOutput.errors.length > 0) {
|
|
54061
|
-
console.error("PapaParse errors:", parseOutput.errors);
|
|
54062
|
-
return [];
|
|
54063
|
-
}
|
|
54064
|
-
const allRows = parseOutput.data;
|
|
54065
|
-
if (allRows.length < 4) {
|
|
54066
|
-
console.error("CSV must have at least 3 header lines and 1 data line.");
|
|
54067
|
-
return [];
|
|
54068
|
-
}
|
|
54069
|
-
const bodypartsHeader = allRows[1];
|
|
54070
|
-
if (!bodypartsHeader || bodypartsHeader.length <= 1 || (bodypartsHeader.length - 1) % 3 !== 0) {
|
|
54071
|
-
console.error("Malformed bodyparts header line (line 2 of CSV).", bodypartsHeader);
|
|
54072
|
-
return [];
|
|
54073
|
-
}
|
|
54074
|
-
return bodypartsHeader.filter((_element, index) => {
|
|
54075
|
-
return (index - 1) % 3 === 0 && index >= 1;
|
|
54076
|
-
});
|
|
54077
|
-
}
|
|
54078
|
-
parsePredictionFile(csvString) {
|
|
54079
|
-
const parseOutput = import_papaparse.default.parse(csvString.trim(), {
|
|
54080
|
-
dynamicTyping: false,
|
|
54081
|
-
skipEmptyLines: true
|
|
54082
|
-
});
|
|
54083
|
-
if (parseOutput.errors.length > 0) {
|
|
54084
|
-
console.error("PapaParse errors:", parseOutput.errors);
|
|
54085
|
-
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
54086
|
-
}
|
|
54087
|
-
const allRows = parseOutput.data;
|
|
54088
|
-
if (allRows.length < 4) {
|
|
54089
|
-
console.error("CSV must have at least 3 header lines and 1 data line.");
|
|
54090
|
-
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
54091
|
-
}
|
|
54092
|
-
const bodypartsHeader = allRows[1];
|
|
54093
|
-
if (!bodypartsHeader || bodypartsHeader.length <= 1 || (bodypartsHeader.length - 1) % 3 !== 0) {
|
|
54094
|
-
console.error("Malformed bodyparts header line (line 2 of CSV).", bodypartsHeader);
|
|
54095
|
-
return (0, import_ndarray.default)(new Float64Array(0), [0, 0, 2]);
|
|
54096
|
-
}
|
|
54097
|
-
const numBodyParts = (bodypartsHeader.length - 1) / 3;
|
|
54098
|
-
const coordsHeader = allRows[2];
|
|
54099
|
-
if (!coordsHeader || coordsHeader.length !== bodypartsHeader.length) {
|
|
54100
|
-
console.error("Coordinate header (line 3 of CSV) length mismatch with bodyparts header.");
|
|
54101
|
-
return (0, import_ndarray.default)(new Float64Array(0), [
|
|
54102
|
-
0,
|
|
54103
|
-
numBodyParts > 0 ? numBodyParts : 0,
|
|
54104
|
-
2
|
|
54105
|
-
]);
|
|
54106
|
-
}
|
|
54107
|
-
const dataRowsOnly = allRows.slice(3);
|
|
54108
|
-
const numFrames = dataRowsOnly.length;
|
|
54109
|
-
if (numFrames === 0 || numBodyParts === 0) {
|
|
54110
|
-
return (0, import_ndarray.default)(new Float64Array(0), [numFrames, numBodyParts, 2]);
|
|
54111
|
-
}
|
|
54112
|
-
const flatData = new Float64Array(numFrames * numBodyParts * 2);
|
|
54113
|
-
let flatIndex = 0;
|
|
54114
|
-
for (let rowIndex = 0; rowIndex < numFrames; rowIndex++) {
|
|
54115
|
-
const values = dataRowsOnly[rowIndex];
|
|
54116
|
-
if (values.length < 1 + numBodyParts * 3) {
|
|
54117
|
-
console.warn(`Skipping malformed data row ${rowIndex + 4} (not enough columns): "${values.slice(0, 5).join(",")}..."`);
|
|
54118
|
-
for (let i = 0; i < numBodyParts; i++) {
|
|
54119
|
-
flatData[flatIndex++] = NaN;
|
|
54120
|
-
flatData[flatIndex++] = NaN;
|
|
54121
|
-
}
|
|
54122
|
-
continue;
|
|
54123
|
-
}
|
|
54124
|
-
for (let bodyPartIdx = 0; bodyPartIdx < numBodyParts; bodyPartIdx++) {
|
|
54125
|
-
const xDataIndex = 1 + bodyPartIdx * 3;
|
|
54126
|
-
const yDataIndex = 1 + bodyPartIdx * 3 + 1;
|
|
54127
|
-
if (xDataIndex >= values.length || yDataIndex >= values.length) {
|
|
54128
|
-
console.warn(`Skipping body part ${bodyPartIdx} in data row ${rowIndex + 4} due to insufficient data.`);
|
|
54129
|
-
flatData[flatIndex++] = NaN;
|
|
54130
|
-
flatData[flatIndex++] = NaN;
|
|
54131
|
-
continue;
|
|
54132
|
-
}
|
|
54133
|
-
const xString = values[xDataIndex];
|
|
54134
|
-
const yString = values[yDataIndex];
|
|
54135
|
-
const x = parseFloat(xString);
|
|
54136
|
-
const y = parseFloat(yString);
|
|
54137
|
-
if (isNaN(x) || isNaN(y)) {
|
|
54138
|
-
console.warn(`Could not parse x or y as number for body part ${bodyPartIdx} in data row ${rowIndex + 4}. Values: x='${xString}', y='${yString}'.`);
|
|
54139
|
-
flatData[flatIndex++] = NaN;
|
|
54140
|
-
flatData[flatIndex++] = NaN;
|
|
54141
|
-
} else {
|
|
54142
|
-
flatData[flatIndex++] = x;
|
|
54143
|
-
flatData[flatIndex++] = y;
|
|
54144
|
-
}
|
|
54145
|
-
}
|
|
54146
|
-
}
|
|
54147
|
-
return (0, import_ndarray.default)(flatData, [numFrames, numBodyParts, 2]);
|
|
54148
|
-
}
|
|
54149
|
-
static \u0275fac = function CsvParserService_Factory(__ngFactoryType__) {
|
|
54150
|
-
return new (__ngFactoryType__ || _CsvParserService)();
|
|
54151
|
-
};
|
|
54152
|
-
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _CsvParserService, factory: _CsvParserService.\u0275fac, providedIn: "root" });
|
|
54153
|
-
};
|
|
54154
|
-
(() => {
|
|
54155
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(CsvParserService, [{
|
|
54156
|
-
type: Injectable,
|
|
54157
|
-
args: [{
|
|
54158
|
-
providedIn: "root"
|
|
54159
|
-
}]
|
|
54160
|
-
}], null, null);
|
|
54161
|
-
})();
|
|
54162
|
-
|
|
54163
|
-
// src/app/session.service.ts
|
|
54164
|
-
var SessionService = class _SessionService {
|
|
54165
|
-
rpc = inject(RpcService);
|
|
54166
|
-
httpClient = inject(HttpClient);
|
|
54167
|
-
allSessions = new BehaviorSubject([]);
|
|
54168
|
-
predictionFiles = [];
|
|
54169
|
-
projectInfoService = inject(ProjectInfoService);
|
|
54170
|
-
csvParser = inject(CsvParserService);
|
|
54171
|
-
getAllSessions() {
|
|
54172
|
-
return this.allSessions.asObservable();
|
|
54173
|
-
}
|
|
54174
|
-
async loadSessions() {
|
|
54175
|
-
const projectInfo = this.projectInfoService.projectInfo;
|
|
54176
|
-
const response = await this.rpc.call("rglob", {
|
|
54177
|
-
baseDir: projectInfo.data_dir,
|
|
54178
|
-
pattern: "**/*.fine.mp4",
|
|
54179
|
-
//temporary
|
|
54180
|
-
noDirs: true
|
|
54181
|
-
});
|
|
54182
|
-
const mp4Files = response.entries.filter((entry) => entry.type === "file").map((entry) => entry.path);
|
|
54183
|
-
const sessions = getUniqueSessionTemplates(mp4Files, this.projectInfoService.projectInfo.views).map((templateName) => {
|
|
54184
|
-
return { key: templateName.replace(/\.mp4$/, "") };
|
|
54185
|
-
});
|
|
54186
|
-
return this.allSessions.next(sessions);
|
|
54187
|
-
}
|
|
54188
|
-
async loadPredictionIndex() {
|
|
54189
|
-
const projectInfo = this.projectInfoService.projectInfo;
|
|
54190
|
-
const response = await this.rpc.call("rglob", {
|
|
54191
|
-
baseDir: projectInfo.model_dir,
|
|
54192
|
-
pattern: "**/video_preds/**/*.csv",
|
|
54193
|
-
noDirs: true
|
|
54194
|
-
});
|
|
54195
|
-
this.predictionFiles = response.entries.filter((entry) => {
|
|
54196
|
-
if (entry.type !== "file")
|
|
54197
|
-
return false;
|
|
54198
|
-
if (entry.path.endsWith("_bbox.csv"))
|
|
54199
|
-
return false;
|
|
54200
|
-
if (entry.path.endsWith("_error.csv"))
|
|
54201
|
-
return false;
|
|
54202
|
-
if (entry.path.endsWith("_loss.csv"))
|
|
54203
|
-
return false;
|
|
54204
|
-
if (entry.path.endsWith("_norm.csv"))
|
|
54205
|
-
return false;
|
|
54206
|
-
return true;
|
|
54207
|
-
}).map((entry) => {
|
|
54208
|
-
let match2 = entry.path.match(/(.+)\/video_preds\/([^/]+)\.mp4\/predictions\.csv/);
|
|
54209
|
-
if (!match2) {
|
|
54210
|
-
match2 = entry.path.match(/(.+)\/video_preds\/([^/]+)\.csv/);
|
|
54211
|
-
}
|
|
54212
|
-
if (!match2)
|
|
54213
|
-
return null;
|
|
54214
|
-
const modelKey = match2[1];
|
|
54215
|
-
const sessionView = match2[2];
|
|
54216
|
-
const viewName = this.projectInfoService.allViews().find((v) => sessionView.includes(v));
|
|
54217
|
-
if (!viewName)
|
|
54218
|
-
return null;
|
|
54219
|
-
const sessionKey = sessionView.replace(viewName, "*");
|
|
54220
|
-
return {
|
|
54221
|
-
path: entry.path,
|
|
54222
|
-
modelKey,
|
|
54223
|
-
sessionKey,
|
|
54224
|
-
viewName
|
|
54225
|
-
};
|
|
54226
|
-
}).filter((entry) => entry != null);
|
|
54227
|
-
this.initModels();
|
|
54228
|
-
await this.initKeypoints();
|
|
54229
|
-
}
|
|
54230
|
-
initModels() {
|
|
54231
|
-
const uniqueModels = new Set(this.predictionFiles.map((pfile) => pfile.modelKey).filter((x) => x));
|
|
54232
|
-
this.projectInfoService.setAllModels(Array.from(uniqueModels).sort());
|
|
54233
|
-
}
|
|
54234
|
-
async initKeypoints() {
|
|
54235
|
-
if (this.predictionFiles.length === 0)
|
|
54236
|
-
return;
|
|
54237
|
-
const csvFile = await this.getPredictionFile(this.predictionFiles[0]);
|
|
54238
|
-
if (!csvFile)
|
|
54239
|
-
return;
|
|
54240
|
-
const allKeypoints = this.csvParser.getBodyParts(csvFile);
|
|
54241
|
-
this.projectInfoService.setAllKeypoints(allKeypoints);
|
|
54242
|
-
}
|
|
54243
|
-
getPredictionFilesForSession(sessionKey) {
|
|
54244
|
-
const predictionFiles = this.predictionFiles.filter((p) => p.sessionKey === sessionKey || p.sessionKey === sessionKey.replace(/\.fine$/, ""));
|
|
54245
|
-
return predictionFiles;
|
|
54246
|
-
}
|
|
54247
|
-
async getPredictionFile(pfile) {
|
|
54248
|
-
const modelDir = this.projectInfoService.projectInfo?.model_dir;
|
|
54249
|
-
const src = "/app/v0/files/" + modelDir + "/" + pfile.path;
|
|
54250
|
-
return await firstValueFrom(this.httpClient.get(src, { responseType: "text" }).pipe(catchError((error) => {
|
|
54251
|
-
if (error.status === 404) {
|
|
54252
|
-
return [null];
|
|
54253
|
-
}
|
|
54254
|
-
throw error;
|
|
54255
|
-
})));
|
|
54256
|
-
}
|
|
54257
|
-
async ffprobe(file) {
|
|
54258
|
-
const response = await this.rpc.call("ffprobe", {
|
|
54259
|
-
path: file
|
|
54260
|
-
});
|
|
54261
|
-
return response;
|
|
54262
|
-
}
|
|
54263
|
-
static \u0275fac = function SessionService_Factory(__ngFactoryType__) {
|
|
54264
|
-
return new (__ngFactoryType__ || _SessionService)();
|
|
54265
|
-
};
|
|
54266
|
-
static \u0275prov = /* @__PURE__ */ \u0275\u0275defineInjectable({ token: _SessionService, factory: _SessionService.\u0275fac, providedIn: "root" });
|
|
54267
|
-
};
|
|
54268
|
-
(() => {
|
|
54269
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(SessionService, [{
|
|
54270
|
-
type: Injectable,
|
|
54271
|
-
args: [{
|
|
54272
|
-
providedIn: "root"
|
|
54273
|
-
}]
|
|
54274
|
-
}], null, null);
|
|
54275
|
-
})();
|
|
54276
|
-
function getUniqueSessionTemplates(filenames, views) {
|
|
54277
|
-
const sessionTemplates = /* @__PURE__ */ new Set();
|
|
54278
|
-
for (const filename of filenames) {
|
|
54279
|
-
const viewName = views.find((v) => filename.includes(v));
|
|
54280
|
-
const sessionTemplate = viewName ? filename.replace(viewName, "*") : filename;
|
|
54281
|
-
if (!sessionTemplates.has(sessionTemplate)) {
|
|
54282
|
-
sessionTemplates.add(sessionTemplate);
|
|
54283
|
-
}
|
|
54284
|
-
}
|
|
54285
|
-
return Array.from(sessionTemplates);
|
|
54286
|
-
}
|
|
54287
|
-
|
|
54288
54316
|
// src/app/viewer/viewer-left-panel/viewer-sessions-panel.component.ts
|
|
54289
54317
|
var _c03 = (a0) => ["/viewer", a0];
|
|
54290
54318
|
var _forTrack0 = ($index, $item) => $item.key;
|
|
@@ -54303,19 +54331,11 @@ function ViewerSessionsPanelComponent_For_16_Template(rf, ctx) {
|
|
|
54303
54331
|
}
|
|
54304
54332
|
}
|
|
54305
54333
|
var ViewerSessionsPanelComponent = class _ViewerSessionsPanelComponent {
|
|
54306
|
-
sessionService;
|
|
54307
|
-
sessions;
|
|
54308
|
-
constructor(sessionService) {
|
|
54309
|
-
this.sessionService = sessionService;
|
|
54310
|
-
this.sessions = toSignal(this.sessionService.getAllSessions(), {
|
|
54311
|
-
requireSync: true
|
|
54312
|
-
});
|
|
54313
|
-
}
|
|
54314
|
-
selectedSession = input(null);
|
|
54334
|
+
sessionService = inject(SessionService);
|
|
54315
54335
|
static \u0275fac = function ViewerSessionsPanelComponent_Factory(__ngFactoryType__) {
|
|
54316
|
-
return new (__ngFactoryType__ || _ViewerSessionsPanelComponent)(
|
|
54336
|
+
return new (__ngFactoryType__ || _ViewerSessionsPanelComponent)();
|
|
54317
54337
|
};
|
|
54318
|
-
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerSessionsPanelComponent, selectors: [["app-sessions-panel"]],
|
|
54338
|
+
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerSessionsPanelComponent, selectors: [["app-sessions-panel"]], decls: 17, vars: 0, consts: [[1, "flex", "justify-between"], [1, "px-2"], [1, "dropdown", "dropdown-end"], [1, "btn", "btn-xs", "btn-ghost"], [1, "material-icons", "text-base!"], ["tabindex", "0", 1, "dropdown-content", "menu", "menu-sm", "bg-base-100", "z-40", "w-52", "p-2", "shadow-sm"], [1, "panel-content", "inset-shadow-xs", "inset-shadow-black/30"], [1, "overflow-x-auto"], ["tabindex", "0", "role", "listbox", 1, "w-fit", "relative"], ["routerLinkActive", "bg-sky-700", 1, "text-nowrap"], ["role", "option", 1, "p-1", "block", "hover:bg-base-content/10", "rounded-sm", 3, "routerLink"]], template: function ViewerSessionsPanelComponent_Template(rf, ctx) {
|
|
54319
54339
|
if (rf & 1) {
|
|
54320
54340
|
\u0275\u0275elementStart(0, "div", 0)(1, "h1", 1);
|
|
54321
54341
|
\u0275\u0275text(2, "Sessions");
|
|
@@ -54332,7 +54352,7 @@ var ViewerSessionsPanelComponent = class _ViewerSessionsPanelComponent {
|
|
|
54332
54352
|
}
|
|
54333
54353
|
if (rf & 2) {
|
|
54334
54354
|
\u0275\u0275advance(15);
|
|
54335
|
-
\u0275\u0275repeater(ctx.
|
|
54355
|
+
\u0275\u0275repeater(ctx.sessionService.allSessions());
|
|
54336
54356
|
}
|
|
54337
54357
|
}, dependencies: [RouterLink, RouterLinkActive, MatListModule, ScrollingModule], encapsulation: 2, changeDetection: 0 });
|
|
54338
54358
|
};
|
|
@@ -54361,10 +54381,11 @@ var ViewerSessionsPanelComponent = class _ViewerSessionsPanelComponent {
|
|
|
54361
54381
|
<div class="panel-content inset-shadow-xs inset-shadow-black/30">
|
|
54362
54382
|
<!--panel content-->
|
|
54363
54383
|
<div class="overflow-x-auto">
|
|
54364
|
-
<ul class="w-fit relative">
|
|
54365
|
-
@for (session of
|
|
54384
|
+
<ul class="w-fit relative" tabindex="0" role="listbox">
|
|
54385
|
+
@for (session of sessionService.allSessions(); track session.key) {
|
|
54366
54386
|
<li class="text-nowrap" routerLinkActive="bg-sky-700">
|
|
54367
54387
|
<a
|
|
54388
|
+
role="option"
|
|
54368
54389
|
class="p-1 block hover:bg-base-content/10 rounded-sm"
|
|
54369
54390
|
[routerLink]="['/viewer', session.key]"
|
|
54370
54391
|
>
|
|
@@ -54376,10 +54397,10 @@ var ViewerSessionsPanelComponent = class _ViewerSessionsPanelComponent {
|
|
|
54376
54397
|
</div>
|
|
54377
54398
|
</div>
|
|
54378
54399
|
` }]
|
|
54379
|
-
}],
|
|
54400
|
+
}], null, null);
|
|
54380
54401
|
})();
|
|
54381
54402
|
(() => {
|
|
54382
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerSessionsPanelComponent, { className: "ViewerSessionsPanelComponent", filePath: "src/app/viewer/viewer-left-panel/viewer-sessions-panel.component.ts", lineNumber:
|
|
54403
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerSessionsPanelComponent, { className: "ViewerSessionsPanelComponent", filePath: "src/app/viewer/viewer-left-panel/viewer-sessions-panel.component.ts", lineNumber: 24 });
|
|
54383
54404
|
})();
|
|
54384
54405
|
|
|
54385
54406
|
// src/app/view-settings.model.ts
|
|
@@ -58971,13 +58992,6 @@ function ViewerCenterPanelComponent_For_3_Template(rf, ctx) {
|
|
|
58971
58992
|
\u0275\u0275property("labelerMode", false)("keypointModels", w_r1.keypoints());
|
|
58972
58993
|
}
|
|
58973
58994
|
}
|
|
58974
|
-
function ViewerCenterPanelComponent_ForEmpty_4_Template(rf, ctx) {
|
|
58975
|
-
if (rf & 1) {
|
|
58976
|
-
\u0275\u0275elementStart(0, "p");
|
|
58977
|
-
\u0275\u0275text(1, "Loading...");
|
|
58978
|
-
\u0275\u0275elementEnd();
|
|
58979
|
-
}
|
|
58980
|
-
}
|
|
58981
58995
|
var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
58982
58996
|
sessionKey = signal(null);
|
|
58983
58997
|
csvParser = inject(CsvParserService);
|
|
@@ -58999,26 +59013,32 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
|
58999
59013
|
const sessionKey = this.sessionKey();
|
|
59000
59014
|
if (!sessionKey)
|
|
59001
59015
|
return;
|
|
59002
|
-
this.
|
|
59003
|
-
|
|
59004
|
-
|
|
59005
|
-
|
|
59006
|
-
|
|
59007
|
-
|
|
59008
|
-
|
|
59009
|
-
|
|
59010
|
-
|
|
59011
|
-
|
|
59012
|
-
|
|
59013
|
-
|
|
59016
|
+
const session = this.sessionService.allSessions().find((session2) => session2.key === sessionKey);
|
|
59017
|
+
if (!session)
|
|
59018
|
+
return;
|
|
59019
|
+
this.widgetModels.set(
|
|
59020
|
+
//this.projectInfoService.allViews().flatMap((view) => {
|
|
59021
|
+
session.views.flatMap((sessionView) => {
|
|
59022
|
+
const keypointModels = this.projectInfoService.allModels().flatMap((modelKey) => {
|
|
59023
|
+
const predictions = this.predictions.get(new Pair(sessionView.viewName, modelKey).toMapKey());
|
|
59024
|
+
if (predictions) {
|
|
59025
|
+
return this.projectInfoService.allKeypoints().map((k) => this.buildKeypoint(k, predictions, modelKey));
|
|
59026
|
+
} else {
|
|
59027
|
+
return [];
|
|
59028
|
+
}
|
|
59029
|
+
});
|
|
59030
|
+
const widget = this.buildWidget(sessionView, keypointModels);
|
|
59031
|
+
return widget;
|
|
59032
|
+
})
|
|
59033
|
+
);
|
|
59014
59034
|
}
|
|
59015
|
-
buildWidget(
|
|
59035
|
+
buildWidget(sessionView, allKeypoints) {
|
|
59016
59036
|
const filteredKeypoints = computed(() => {
|
|
59017
59037
|
return allKeypoints.filter((k) => this.viewSettings.modelsShown().includes(k.modelKey) && this.viewSettings.keypointsShown().includes(k.name));
|
|
59018
59038
|
});
|
|
59019
59039
|
return {
|
|
59020
|
-
id:
|
|
59021
|
-
videoSrc: this.getVideoSrc(
|
|
59040
|
+
id: sessionView.viewName,
|
|
59041
|
+
videoSrc: this.getVideoSrc(sessionView),
|
|
59022
59042
|
keypoints: filteredKeypoints
|
|
59023
59043
|
};
|
|
59024
59044
|
}
|
|
@@ -59055,8 +59075,8 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
|
59055
59075
|
const dataDir = this.projectInfoService.projectInfo?.data_dir;
|
|
59056
59076
|
return dataDir + "/" + sessionKey.replace(/\*/g, view) + ".mp4";
|
|
59057
59077
|
}
|
|
59058
|
-
getVideoSrc(
|
|
59059
|
-
return "/app/v0/files/" +
|
|
59078
|
+
getVideoSrc(sessionView) {
|
|
59079
|
+
return "/app/v0/files/" + sessionView.videoPath;
|
|
59060
59080
|
}
|
|
59061
59081
|
async loadSession(sessionKey) {
|
|
59062
59082
|
this.sessionKey.set(sessionKey);
|
|
@@ -59071,7 +59091,7 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
|
59071
59091
|
this.loadPredictionFiles()
|
|
59072
59092
|
]);
|
|
59073
59093
|
this.loadingService.isLoading.set(false);
|
|
59074
|
-
this.buildWidgetModels();
|
|
59094
|
+
await this.buildWidgetModels();
|
|
59075
59095
|
}
|
|
59076
59096
|
async loadPredictionFiles() {
|
|
59077
59097
|
const sessionKey = this.sessionKey();
|
|
@@ -59108,12 +59128,12 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
|
59108
59128
|
static \u0275fac = function ViewerCenterPanelComponent_Factory(__ngFactoryType__) {
|
|
59109
59129
|
return new (__ngFactoryType__ || _ViewerCenterPanelComponent)();
|
|
59110
59130
|
};
|
|
59111
|
-
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerCenterPanelComponent, selectors: [["app-viewer-center-panel"]], inputs: { viewSettings: "viewSettings" }, decls:
|
|
59131
|
+
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ViewerCenterPanelComponent, selectors: [["app-viewer-center-panel"]], inputs: { viewSettings: "viewSettings" }, decls: 5, vars: 0, consts: [[1, "flex", "flex-col", "h-full"], [1, "video-tile", "w-full", "grow", "flex", "flex-wrap", "overflow-y-auto", "gap-4", "*:grow", "*:shrink-0", "*:max-w-xs", "justify-start", "content-start", "p-4"], [3, "src"], [3, "labelerMode", "keypointModels"]], template: function ViewerCenterPanelComponent_Template(rf, ctx) {
|
|
59112
59132
|
if (rf & 1) {
|
|
59113
59133
|
\u0275\u0275elementStart(0, "div", 0)(1, "div", 1);
|
|
59114
|
-
\u0275\u0275repeaterCreate(2, ViewerCenterPanelComponent_For_3_Template, 2, 3, "app-video-tile", 2, _forTrack03
|
|
59134
|
+
\u0275\u0275repeaterCreate(2, ViewerCenterPanelComponent_For_3_Template, 2, 3, "app-video-tile", 2, _forTrack03);
|
|
59115
59135
|
\u0275\u0275elementEnd();
|
|
59116
|
-
\u0275\u0275element(
|
|
59136
|
+
\u0275\u0275element(4, "app-video-player-controls");
|
|
59117
59137
|
\u0275\u0275elementEnd();
|
|
59118
59138
|
}
|
|
59119
59139
|
if (rf & 2) {
|
|
@@ -59133,13 +59153,13 @@ var ViewerCenterPanelComponent = class _ViewerCenterPanelComponent {
|
|
|
59133
59153
|
VideoPlayerControlsComponent,
|
|
59134
59154
|
VideoTileComponent,
|
|
59135
59155
|
KeypointContainerComponent
|
|
59136
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: '<div class="flex flex-col h-full">\n <!-- Video content area -->\n <div\n class="video-tile w-full grow flex flex-wrap overflow-y-auto gap-4 *:grow *:shrink-0 *:max-w-xs justify-start content-start p-4"\n >\n <!-- `track videosrc` makes the widget component get\n destroyed and recreated if videoSrc changes. Reactively\n changing videoSrc of an existing video does not work unfortunately. -->\n @for (w of filteredWidgetModels(); track w.videoSrc) {\n <!--@if (viewSettings.viewsShown().indexOf(w.id) >= 0) {-->\n <app-video-tile [src]="w.videoSrc">\n <app-keypoint-container\n [labelerMode]="false"\n [keypointModels]="w.keypoints()"\n ></app-keypoint-container>\n </app-video-tile>\n }
|
|
59156
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: '<div class="flex flex-col h-full">\n <!-- Video content area -->\n <div\n class="video-tile w-full grow flex flex-wrap overflow-y-auto gap-4 *:grow *:shrink-0 *:max-w-xs justify-start content-start p-4"\n >\n <!-- `track videosrc` makes the widget component get\n destroyed and recreated if videoSrc changes. Reactively\n changing videoSrc of an existing video does not work unfortunately. -->\n @for (w of filteredWidgetModels(); track w.videoSrc) {\n <!--@if (viewSettings.viewsShown().indexOf(w.id) >= 0) {-->\n <app-video-tile [src]="w.videoSrc">\n <app-keypoint-container\n [labelerMode]="false"\n [keypointModels]="w.keypoints()"\n ></app-keypoint-container>\n </app-video-tile>\n }\n </div>\n\n <app-video-player-controls></app-video-player-controls>\n</div>\n' }]
|
|
59137
59157
|
}], null, { viewSettings: [{
|
|
59138
59158
|
type: Input
|
|
59139
59159
|
}] });
|
|
59140
59160
|
})();
|
|
59141
59161
|
(() => {
|
|
59142
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerCenterPanelComponent, { className: "ViewerCenterPanelComponent", filePath: "src/app/viewer/viewer-center-panel/viewer-center-panel.component.ts", lineNumber:
|
|
59162
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ViewerCenterPanelComponent, { className: "ViewerCenterPanelComponent", filePath: "src/app/viewer/viewer-center-panel/viewer-center-panel.component.ts", lineNumber: 38 });
|
|
59143
59163
|
})();
|
|
59144
59164
|
|
|
59145
59165
|
// src/app/loading-bar/loading-bar.component.ts
|
|
@@ -59182,19 +59202,14 @@ var LoadingBarComponent = class _LoadingBarComponent {
|
|
|
59182
59202
|
|
|
59183
59203
|
// src/app/viewer/viewer-page/viewer-page.component.ts
|
|
59184
59204
|
var _c05 = (a0) => [a0];
|
|
59185
|
-
function
|
|
59186
|
-
if (rf & 1) {
|
|
59187
|
-
\u0275\u0275text(0, " Loading...\n");
|
|
59188
|
-
}
|
|
59189
|
-
}
|
|
59190
|
-
function ViewerPageComponent_Conditional_1_For_14_Template(rf, ctx) {
|
|
59205
|
+
function ViewerPageComponent_Conditional_0_For_14_Template(rf, ctx) {
|
|
59191
59206
|
if (rf & 1) {
|
|
59192
59207
|
const _r1 = \u0275\u0275getCurrentView();
|
|
59193
|
-
\u0275\u0275elementStart(0, "li",
|
|
59208
|
+
\u0275\u0275elementStart(0, "li", 10)(1, "span");
|
|
59194
59209
|
\u0275\u0275text(2);
|
|
59195
59210
|
\u0275\u0275elementEnd();
|
|
59196
|
-
\u0275\u0275elementStart(3, "input",
|
|
59197
|
-
\u0275\u0275listener("change", function
|
|
59211
|
+
\u0275\u0275elementStart(3, "input", 13);
|
|
59212
|
+
\u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_14_Template_input_change_3_listener($event) {
|
|
59198
59213
|
const cam_r2 = \u0275\u0275restoreView(_r1).$implicit;
|
|
59199
59214
|
const ctx_r2 = \u0275\u0275nextContext(2);
|
|
59200
59215
|
return \u0275\u0275resetView(ctx_r2.onViewCheckboxChange($event, cam_r2));
|
|
@@ -59210,14 +59225,14 @@ function ViewerPageComponent_Conditional_1_For_14_Template(rf, ctx) {
|
|
|
59210
59225
|
\u0275\u0275property("checked", ctx_r2.viewSelectionModel.isSelected(cam_r2));
|
|
59211
59226
|
}
|
|
59212
59227
|
}
|
|
59213
|
-
function
|
|
59228
|
+
function ViewerPageComponent_Conditional_0_For_22_Template(rf, ctx) {
|
|
59214
59229
|
if (rf & 1) {
|
|
59215
59230
|
const _r4 = \u0275\u0275getCurrentView();
|
|
59216
|
-
\u0275\u0275elementStart(0, "li",
|
|
59231
|
+
\u0275\u0275elementStart(0, "li", 10)(1, "span");
|
|
59217
59232
|
\u0275\u0275text(2);
|
|
59218
59233
|
\u0275\u0275elementEnd();
|
|
59219
|
-
\u0275\u0275elementStart(3, "input",
|
|
59220
|
-
\u0275\u0275listener("change", function
|
|
59234
|
+
\u0275\u0275elementStart(3, "input", 13);
|
|
59235
|
+
\u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_22_Template_input_change_3_listener($event) {
|
|
59221
59236
|
const kp_r5 = \u0275\u0275restoreView(_r4).$implicit;
|
|
59222
59237
|
const ctx_r2 = \u0275\u0275nextContext(2);
|
|
59223
59238
|
return \u0275\u0275resetView(ctx_r2.onKeypointCheckboxChange($event, kp_r5));
|
|
@@ -59233,9 +59248,9 @@ function ViewerPageComponent_Conditional_1_For_22_Template(rf, ctx) {
|
|
|
59233
59248
|
\u0275\u0275property("checked", ctx_r2.keypointSelectionModel.isSelected(kp_r5));
|
|
59234
59249
|
}
|
|
59235
59250
|
}
|
|
59236
|
-
function
|
|
59251
|
+
function ViewerPageComponent_Conditional_0_For_31_For_5_Template(rf, ctx) {
|
|
59237
59252
|
if (rf & 1) {
|
|
59238
|
-
\u0275\u0275elementStart(0, "option",
|
|
59253
|
+
\u0275\u0275elementStart(0, "option", 15);
|
|
59239
59254
|
\u0275\u0275text(1);
|
|
59240
59255
|
\u0275\u0275elementEnd();
|
|
59241
59256
|
}
|
|
@@ -59247,19 +59262,19 @@ function ViewerPageComponent_Conditional_1_For_31_For_5_Template(rf, ctx) {
|
|
|
59247
59262
|
\u0275\u0275textInterpolate1(" ", dropdownItem_r8, " ");
|
|
59248
59263
|
}
|
|
59249
59264
|
}
|
|
59250
|
-
function
|
|
59265
|
+
function ViewerPageComponent_Conditional_0_For_31_Template(rf, ctx) {
|
|
59251
59266
|
if (rf & 1) {
|
|
59252
59267
|
const _r6 = \u0275\u0275getCurrentView();
|
|
59253
59268
|
\u0275\u0275declareLet(0);
|
|
59254
|
-
\u0275\u0275elementStart(1, "li",
|
|
59255
|
-
\u0275\u0275listener("change", function
|
|
59269
|
+
\u0275\u0275elementStart(1, "li", 12)(2, "select", 14);
|
|
59270
|
+
\u0275\u0275listener("change", function ViewerPageComponent_Conditional_0_For_31_Template_select_change_2_listener($event) {
|
|
59256
59271
|
\u0275\u0275restoreView(_r6);
|
|
59257
59272
|
const modelIndex_r7 = \u0275\u0275readContextLet(0);
|
|
59258
59273
|
const ctx_r2 = \u0275\u0275nextContext(2);
|
|
59259
59274
|
return \u0275\u0275resetView(ctx_r2.onModelDropdownItemClick(modelIndex_r7, $event));
|
|
59260
59275
|
});
|
|
59261
59276
|
\u0275\u0275declareLet(3);
|
|
59262
|
-
\u0275\u0275repeaterCreate(4,
|
|
59277
|
+
\u0275\u0275repeaterCreate(4, ViewerPageComponent_Conditional_0_For_31_For_5_Template, 2, 2, "option", 15, \u0275\u0275repeaterTrackByIdentity);
|
|
59263
59278
|
\u0275\u0275elementEnd()();
|
|
59264
59279
|
}
|
|
59265
59280
|
if (rf & 2) {
|
|
@@ -59273,45 +59288,43 @@ function ViewerPageComponent_Conditional_1_For_31_Template(rf, ctx) {
|
|
|
59273
59288
|
\u0275\u0275repeater(options_r12);
|
|
59274
59289
|
}
|
|
59275
59290
|
}
|
|
59276
|
-
function
|
|
59291
|
+
function ViewerPageComponent_Conditional_0_Template(rf, ctx) {
|
|
59277
59292
|
if (rf & 1) {
|
|
59278
59293
|
\u0275\u0275elementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
|
|
59279
|
-
\u0275\u0275element(3, "app-sessions-panel"
|
|
59294
|
+
\u0275\u0275element(3, "app-sessions-panel");
|
|
59280
59295
|
\u0275\u0275elementEnd();
|
|
59281
|
-
\u0275\u0275element(4, "app-loading-bar",
|
|
59296
|
+
\u0275\u0275element(4, "app-loading-bar", 3);
|
|
59282
59297
|
\u0275\u0275elementEnd();
|
|
59283
|
-
\u0275\u0275element(5, "app-viewer-center-panel",
|
|
59284
|
-
\u0275\u0275elementStart(6, "div",
|
|
59298
|
+
\u0275\u0275element(5, "app-viewer-center-panel", 4);
|
|
59299
|
+
\u0275\u0275elementStart(6, "div", 5)(7, "div", 6)(8, "div", 7)(9, "h1", 8);
|
|
59285
59300
|
\u0275\u0275text(10, "Views");
|
|
59286
59301
|
\u0275\u0275elementEnd()();
|
|
59287
|
-
\u0275\u0275elementStart(11, "div",
|
|
59288
|
-
\u0275\u0275repeaterCreate(13,
|
|
59302
|
+
\u0275\u0275elementStart(11, "div", 9)(12, "ul");
|
|
59303
|
+
\u0275\u0275repeaterCreate(13, ViewerPageComponent_Conditional_0_For_14_Template, 4, 2, "li", 10, \u0275\u0275repeaterTrackByIdentity);
|
|
59289
59304
|
\u0275\u0275elementEnd()()();
|
|
59290
|
-
\u0275\u0275elementStart(15, "div",
|
|
59305
|
+
\u0275\u0275elementStart(15, "div", 6)(16, "div", 7)(17, "h1", 8);
|
|
59291
59306
|
\u0275\u0275text(18, "Keypoints");
|
|
59292
59307
|
\u0275\u0275elementEnd()();
|
|
59293
|
-
\u0275\u0275elementStart(19, "div",
|
|
59294
|
-
\u0275\u0275repeaterCreate(21,
|
|
59308
|
+
\u0275\u0275elementStart(19, "div", 9)(20, "ul");
|
|
59309
|
+
\u0275\u0275repeaterCreate(21, ViewerPageComponent_Conditional_0_For_22_Template, 4, 2, "li", 10, \u0275\u0275repeaterTrackByIdentity);
|
|
59295
59310
|
\u0275\u0275elementEnd()()();
|
|
59296
|
-
\u0275\u0275elementStart(23, "div",
|
|
59311
|
+
\u0275\u0275elementStart(23, "div", 6)(24, "div", 7)(25, "h1", 8);
|
|
59297
59312
|
\u0275\u0275text(26, "Models");
|
|
59298
59313
|
\u0275\u0275elementEnd()();
|
|
59299
|
-
\u0275\u0275elementStart(27, "div",
|
|
59314
|
+
\u0275\u0275elementStart(27, "div", 11)(28, "ul");
|
|
59300
59315
|
\u0275\u0275declareLet(29);
|
|
59301
|
-
\u0275\u0275repeaterCreate(30,
|
|
59316
|
+
\u0275\u0275repeaterCreate(30, ViewerPageComponent_Conditional_0_For_31_Template, 6, 7, "li", 12, \u0275\u0275repeaterTrackByIndex);
|
|
59302
59317
|
\u0275\u0275elementEnd()()()()();
|
|
59303
59318
|
}
|
|
59304
59319
|
if (rf & 2) {
|
|
59305
59320
|
const ctx_r2 = \u0275\u0275nextContext();
|
|
59306
|
-
\u0275\u0275advance(
|
|
59307
|
-
\u0275\u0275property("selectedSession", ctx_r2.selectedSession());
|
|
59308
|
-
\u0275\u0275advance(2);
|
|
59321
|
+
\u0275\u0275advance(5);
|
|
59309
59322
|
\u0275\u0275property("viewSettings", ctx_r2.viewSettings);
|
|
59310
59323
|
\u0275\u0275advance(8);
|
|
59311
59324
|
\u0275\u0275repeater(ctx_r2.allViews);
|
|
59312
59325
|
\u0275\u0275advance(8);
|
|
59313
59326
|
\u0275\u0275repeater(ctx_r2.projectInfoService.allKeypoints());
|
|
59314
|
-
const modelSelectors_r13 = ctx_r2.viewSettings.modelsShown().length < 2 ? ctx_r2.viewSettings.modelsShown().concat(\u0275\u0275pureFunction1(
|
|
59327
|
+
const modelSelectors_r13 = ctx_r2.viewSettings.modelsShown().length < 2 ? ctx_r2.viewSettings.modelsShown().concat(\u0275\u0275pureFunction1(1, _c05, ctx_r2.noneOption)) : ctx_r2.viewSettings.modelsShown();
|
|
59315
59328
|
\u0275\u0275advance(9);
|
|
59316
59329
|
\u0275\u0275repeater(modelSelectors_r13);
|
|
59317
59330
|
}
|
|
@@ -59344,10 +59357,8 @@ var ViewerPageComponent = class _ViewerPageComponent {
|
|
|
59344
59357
|
isIniting = signal(true);
|
|
59345
59358
|
async ngOnInit() {
|
|
59346
59359
|
this.loadingService.isLoading.set(true);
|
|
59347
|
-
this.loadingService.maxProgress.set(
|
|
59360
|
+
this.loadingService.maxProgress.set(2);
|
|
59348
59361
|
this.loadingService.progress.set(0);
|
|
59349
|
-
await this.projectInfoService.loadProjectInfo();
|
|
59350
|
-
this.loadingService.progress.update((x) => x + 1);
|
|
59351
59362
|
const p = this.sessionService.loadPredictionIndex();
|
|
59352
59363
|
const s = this.sessionService.loadSessions().then(() => {
|
|
59353
59364
|
this.loadingService.progress.update((x) => x + 1);
|
|
@@ -59384,16 +59395,6 @@ var ViewerPageComponent = class _ViewerPageComponent {
|
|
|
59384
59395
|
this.viewSettings.setKeypointsShown(this.keypointSelectionModel.selected);
|
|
59385
59396
|
});
|
|
59386
59397
|
}
|
|
59387
|
-
selectedSession = computed(() => {
|
|
59388
|
-
const sessionKey = this._sessionKey();
|
|
59389
|
-
if (!sessionKey) {
|
|
59390
|
-
return null;
|
|
59391
|
-
} else {
|
|
59392
|
-
return {
|
|
59393
|
-
key: sessionKey
|
|
59394
|
-
};
|
|
59395
|
-
}
|
|
59396
|
-
});
|
|
59397
59398
|
onKeypointCheckboxChange(event, keypointName) {
|
|
59398
59399
|
const target = event.target;
|
|
59399
59400
|
if (target.checked) {
|
|
@@ -59432,18 +59433,18 @@ var ViewerPageComponent = class _ViewerPageComponent {
|
|
|
59432
59433
|
if (rf & 2) {
|
|
59433
59434
|
\u0275\u0275queryAdvance();
|
|
59434
59435
|
}
|
|
59435
|
-
}, inputs: { sessionKey: "sessionKey" }, features: [\u0275\u0275ProvidersFeature([VideoPlayerState, ViewSettings])], decls:
|
|
59436
|
+
}, inputs: { sessionKey: "sessionKey" }, features: [\u0275\u0275ProvidersFeature([VideoPlayerState, ViewSettings])], decls: 1, vars: 1, consts: [[1, "grow", "flex", "flex-row", "items-stretch"], [1, "bg-base-200", "w-60", "xl:w-80", "flex", "flex-col", "justify-between", "shadow-lg"], [1, "p-4"], [1, "h-20", "p-4"], [1, "grow", "z-30", 3, "viewSettings"], [1, "shrink-0", "w-40", "xl:w-60", "h-full"], [1, "panel", "m-4"], [1, "panel-header"], [1, "px-2", "mb-1"], [1, "panel-content", "max-h-60", "overflow-y-auto"], [1, "p-1", "flex", "justify-between", "items-center"], [1, "panel-content", "max-h-60", "overflow-y-visible"], [1, "p-1", "w-full"], ["type", "checkbox", 1, "checkbox", "checkbox-xs", 3, "change", "checked"], [1, "select", "select-sm", "w-full", "flex-grow", 3, "change"], [3, "selected"]], template: function ViewerPageComponent_Template(rf, ctx) {
|
|
59436
59437
|
if (rf & 1) {
|
|
59437
|
-
\u0275\u0275template(0, ViewerPageComponent_Conditional_0_Template,
|
|
59438
|
+
\u0275\u0275template(0, ViewerPageComponent_Conditional_0_Template, 32, 3, "div", 0);
|
|
59438
59439
|
}
|
|
59439
59440
|
if (rf & 2) {
|
|
59440
|
-
\u0275\u0275conditional(ctx.isIniting() ? 0 : 1);
|
|
59441
|
+
\u0275\u0275conditional(!ctx.isIniting() ? 0 : -1);
|
|
59441
59442
|
}
|
|
59442
59443
|
}, dependencies: [
|
|
59443
59444
|
ViewerSessionsPanelComponent,
|
|
59444
59445
|
ViewerCenterPanelComponent,
|
|
59445
59446
|
LoadingBarComponent
|
|
59446
|
-
],
|
|
59447
|
+
], styles: ["\n\n[_nghost-%COMP%] {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KIYG73MW.css.map */"], changeDetection: 0 });
|
|
59447
59448
|
};
|
|
59448
59449
|
(() => {
|
|
59449
59450
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ViewerPageComponent, [{
|
|
@@ -59452,18 +59453,21 @@ var ViewerPageComponent = class _ViewerPageComponent {
|
|
|
59452
59453
|
ViewerSessionsPanelComponent,
|
|
59453
59454
|
ViewerCenterPanelComponent,
|
|
59454
59455
|
LoadingBarComponent
|
|
59455
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, providers: [VideoPlayerState, ViewSettings], template:
|
|
59456
|
-
|
|
59457
|
-
|
|
59458
|
-
|
|
59459
|
-
|
|
59460
|
-
|
|
59456
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, providers: [VideoPlayerState, ViewSettings], template: `<style>
|
|
59457
|
+
:host {
|
|
59458
|
+
flex-grow: 1;
|
|
59459
|
+
display: flex;
|
|
59460
|
+
}
|
|
59461
|
+
</style>
|
|
59462
|
+
|
|
59463
|
+
@if (!isIniting()) {
|
|
59464
|
+
<div class="grow flex flex-row items-stretch">
|
|
59461
59465
|
<!-- Left pane -->
|
|
59462
|
-
<div
|
|
59466
|
+
<div
|
|
59467
|
+
class="bg-base-200 w-60 xl:w-80 flex flex-col justify-between shadow-lg"
|
|
59468
|
+
>
|
|
59463
59469
|
<div class="p-4">
|
|
59464
|
-
<app-sessions-panel
|
|
59465
|
-
[selectedSession]="selectedSession()"
|
|
59466
|
-
></app-sessions-panel>
|
|
59470
|
+
<app-sessions-panel></app-sessions-panel>
|
|
59467
59471
|
</div>
|
|
59468
59472
|
<app-loading-bar class="h-20 p-4"></app-loading-bar>
|
|
59469
59473
|
</div>
|
|
@@ -59555,7 +59559,7 @@ var ViewerPageComponent = class _ViewerPageComponent {
|
|
|
59555
59559
|
</div>
|
|
59556
59560
|
</div>
|
|
59557
59561
|
}
|
|
59558
|
-
|
|
59562
|
+
`, styles: ["/* angular:styles/component:css;1fa15f7a0ae1b0259233282b2d49fb361834bf7fd726c58584c186240f9d8f04;/home/ksikka/lightning-pose/app/web_ui/src/app/viewer/viewer-page/viewer-page.component.html */\n:host {\n flex-grow: 1;\n display: flex;\n}\n/*# sourceMappingURL=/static/viewer-page.component-KIYG73MW.css.map */\n"] }]
|
|
59559
59563
|
}], () => [], { sessionKey: [{
|
|
59560
59564
|
type: Input
|
|
59561
59565
|
}] });
|
|
@@ -65999,36 +66003,356 @@ var appConfig = {
|
|
|
65999
66003
|
]
|
|
66000
66004
|
};
|
|
66001
66005
|
|
|
66006
|
+
// src/app/project-settings/project-settings.component.ts
|
|
66007
|
+
function ProjectSettingsComponent_Conditional_1_Template(rf, ctx) {
|
|
66008
|
+
if (rf & 1) {
|
|
66009
|
+
\u0275\u0275text(0, " Setup ");
|
|
66010
|
+
}
|
|
66011
|
+
}
|
|
66012
|
+
function ProjectSettingsComponent_Conditional_2_Template(rf, ctx) {
|
|
66013
|
+
if (rf & 1) {
|
|
66014
|
+
\u0275\u0275text(0, " Settings ");
|
|
66015
|
+
}
|
|
66016
|
+
}
|
|
66017
|
+
function ProjectSettingsComponent_Conditional_31_Template(rf, ctx) {
|
|
66018
|
+
if (rf & 1) {
|
|
66019
|
+
const _r1 = \u0275\u0275getCurrentView();
|
|
66020
|
+
\u0275\u0275elementStart(0, "button", 14);
|
|
66021
|
+
\u0275\u0275listener("click", function ProjectSettingsComponent_Conditional_31_Template_button_click_0_listener() {
|
|
66022
|
+
\u0275\u0275restoreView(_r1);
|
|
66023
|
+
const ctx_r1 = \u0275\u0275nextContext();
|
|
66024
|
+
return \u0275\u0275resetView(ctx_r1.done.emit(null));
|
|
66025
|
+
});
|
|
66026
|
+
\u0275\u0275text(1, " Cancel ");
|
|
66027
|
+
\u0275\u0275elementEnd();
|
|
66028
|
+
}
|
|
66029
|
+
}
|
|
66030
|
+
var ProjectSettingsComponent = class _ProjectSettingsComponent {
|
|
66031
|
+
done = output();
|
|
66032
|
+
setupMode = input(false);
|
|
66033
|
+
projectInfoForm;
|
|
66034
|
+
viewsInitialRows = signal(4);
|
|
66035
|
+
projectInfoService = inject(ProjectInfoService);
|
|
66036
|
+
fb = inject(FormBuilder);
|
|
66037
|
+
constructor() {
|
|
66038
|
+
this.projectInfoForm = this.fb.group({
|
|
66039
|
+
dataDir: [""],
|
|
66040
|
+
modelDir: [""],
|
|
66041
|
+
views: [""]
|
|
66042
|
+
});
|
|
66043
|
+
}
|
|
66044
|
+
ngOnInit() {
|
|
66045
|
+
const projectInfo = this.projectInfoService.projectInfo;
|
|
66046
|
+
if (projectInfo) {
|
|
66047
|
+
this.projectInfoForm.patchValue({
|
|
66048
|
+
dataDir: projectInfo.data_dir,
|
|
66049
|
+
modelDir: projectInfo.model_dir,
|
|
66050
|
+
views: projectInfo.views.join("\n")
|
|
66051
|
+
});
|
|
66052
|
+
this.viewsInitialRows.update((x) => Math.max(x, projectInfo.views.length));
|
|
66053
|
+
}
|
|
66054
|
+
}
|
|
66055
|
+
async onSaveClick() {
|
|
66056
|
+
const projectInfo = {};
|
|
66057
|
+
projectInfo.data_dir = this.projectInfoForm.get("dataDir")?.value ?? "";
|
|
66058
|
+
projectInfo.model_dir = this.projectInfoForm.get("modelDir")?.value ?? "";
|
|
66059
|
+
projectInfo.views = this.parseMultilineText(this.projectInfoForm.get("views")?.value ?? "");
|
|
66060
|
+
await this.projectInfoService.setProjectInfo(projectInfo);
|
|
66061
|
+
}
|
|
66062
|
+
parseMultilineText(text) {
|
|
66063
|
+
return text.split("\n").map((x) => x.trim()).filter((x) => Boolean(x));
|
|
66064
|
+
}
|
|
66065
|
+
get cameraViewPlaceholder() {
|
|
66066
|
+
return `view1
|
|
66067
|
+
view2
|
|
66068
|
+
...`;
|
|
66069
|
+
}
|
|
66070
|
+
static \u0275fac = function ProjectSettingsComponent_Factory(__ngFactoryType__) {
|
|
66071
|
+
return new (__ngFactoryType__ || _ProjectSettingsComponent)();
|
|
66072
|
+
};
|
|
66073
|
+
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _ProjectSettingsComponent, selectors: [["app-project-settings"]], inputs: { setupMode: [1, "setupMode"] }, outputs: { done: "done" }, decls: 34, vars: 6, consts: [[1, "text-xl", "font-bold"], [3, "formGroup"], [1, "fieldset", "my-6"], [1, "fieldset-legend", "text-md"], [1, "input", "w-full"], [1, "material-icons", "!text-sm", "opacity-50"], ["formControlName", "dataDir", "type", "text", "placeholder", "/", 1, "grow"], [1, "label"], [1, "fieldset", "my-4"], ["formControlName", "modelDir", "type", "text", "placeholder", "/", 1, "grow"], ["formControlName", "views", 1, "textarea", "w-full", 3, "rows", "placeholder"], [1, "modal-action"], [1, "btn", "btn-soft", "btn-secondary"], [1, "btn", "btn-soft", "btn-primary", 3, "click", "disabled"], [1, "btn", "btn-soft", "btn-secondary", 3, "click"]], template: function ProjectSettingsComponent_Template(rf, ctx) {
|
|
66074
|
+
if (rf & 1) {
|
|
66075
|
+
\u0275\u0275elementStart(0, "h3", 0);
|
|
66076
|
+
\u0275\u0275template(1, ProjectSettingsComponent_Conditional_1_Template, 1, 0)(2, ProjectSettingsComponent_Conditional_2_Template, 1, 0);
|
|
66077
|
+
\u0275\u0275elementEnd();
|
|
66078
|
+
\u0275\u0275elementStart(3, "form", 1)(4, "fieldset", 2)(5, "label", 3);
|
|
66079
|
+
\u0275\u0275text(6, "Data directory");
|
|
66080
|
+
\u0275\u0275elementEnd();
|
|
66081
|
+
\u0275\u0275elementStart(7, "div", 4)(8, "span", 5);
|
|
66082
|
+
\u0275\u0275text(9, "folder");
|
|
66083
|
+
\u0275\u0275elementEnd();
|
|
66084
|
+
\u0275\u0275element(10, "input", 6);
|
|
66085
|
+
\u0275\u0275elementEnd();
|
|
66086
|
+
\u0275\u0275elementStart(11, "p", 7);
|
|
66087
|
+
\u0275\u0275text(12, "Root of the data directory for the project.");
|
|
66088
|
+
\u0275\u0275elementEnd()();
|
|
66089
|
+
\u0275\u0275elementStart(13, "fieldset", 8)(14, "label", 3);
|
|
66090
|
+
\u0275\u0275text(15, "Model directory");
|
|
66091
|
+
\u0275\u0275elementEnd();
|
|
66092
|
+
\u0275\u0275elementStart(16, "div", 4)(17, "span", 5);
|
|
66093
|
+
\u0275\u0275text(18, "folder");
|
|
66094
|
+
\u0275\u0275elementEnd();
|
|
66095
|
+
\u0275\u0275element(19, "input", 9);
|
|
66096
|
+
\u0275\u0275elementEnd();
|
|
66097
|
+
\u0275\u0275elementStart(20, "p", 7);
|
|
66098
|
+
\u0275\u0275text(21, "Root of the model directory for the project.");
|
|
66099
|
+
\u0275\u0275elementEnd()();
|
|
66100
|
+
\u0275\u0275elementStart(22, "fieldset", 8)(23, "label", 3);
|
|
66101
|
+
\u0275\u0275text(24, "Camera Views");
|
|
66102
|
+
\u0275\u0275elementEnd();
|
|
66103
|
+
\u0275\u0275element(25, "textarea", 10);
|
|
66104
|
+
\u0275\u0275elementStart(26, "p", 7);
|
|
66105
|
+
\u0275\u0275text(27, " Names of views embedded in video filenames.");
|
|
66106
|
+
\u0275\u0275element(28, "br");
|
|
66107
|
+
\u0275\u0275text(29, " Used to group files into sessions. ");
|
|
66108
|
+
\u0275\u0275elementEnd()();
|
|
66109
|
+
\u0275\u0275elementStart(30, "div", 11);
|
|
66110
|
+
\u0275\u0275template(31, ProjectSettingsComponent_Conditional_31_Template, 2, 0, "button", 12);
|
|
66111
|
+
\u0275\u0275elementStart(32, "button", 13);
|
|
66112
|
+
\u0275\u0275listener("click", function ProjectSettingsComponent_Template_button_click_32_listener() {
|
|
66113
|
+
return ctx.onSaveClick();
|
|
66114
|
+
});
|
|
66115
|
+
\u0275\u0275text(33, " Save ");
|
|
66116
|
+
\u0275\u0275elementEnd()()();
|
|
66117
|
+
}
|
|
66118
|
+
if (rf & 2) {
|
|
66119
|
+
\u0275\u0275advance();
|
|
66120
|
+
\u0275\u0275conditional(ctx.setupMode() ? 1 : 2);
|
|
66121
|
+
\u0275\u0275advance(2);
|
|
66122
|
+
\u0275\u0275property("formGroup", ctx.projectInfoForm);
|
|
66123
|
+
\u0275\u0275advance(22);
|
|
66124
|
+
\u0275\u0275property("rows", ctx.viewsInitialRows())("placeholder", ctx.cameraViewPlaceholder);
|
|
66125
|
+
\u0275\u0275advance(6);
|
|
66126
|
+
\u0275\u0275conditional(!ctx.setupMode() ? 31 : -1);
|
|
66127
|
+
\u0275\u0275advance();
|
|
66128
|
+
\u0275\u0275property("disabled", !ctx.projectInfoForm.dirty);
|
|
66129
|
+
}
|
|
66130
|
+
}, dependencies: [ReactiveFormsModule, \u0275NgNoValidate, DefaultValueAccessor, NgControlStatus, NgControlStatusGroup, FormGroupDirective, FormControlName], styles: ["\n\n[_ngcontent-%COMP%]::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-BXKZMYM3.css.map */"], changeDetection: 0 });
|
|
66131
|
+
};
|
|
66132
|
+
(() => {
|
|
66133
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ProjectSettingsComponent, [{
|
|
66134
|
+
type: Component,
|
|
66135
|
+
args: [{ selector: "app-project-settings", imports: [ReactiveFormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `<style>
|
|
66136
|
+
::placeholder {
|
|
66137
|
+
/** bring back the default style from daisy. dont know why it's getting overridden. */
|
|
66138
|
+
color: color-mix(in oklch, currentColor 50%, #0000) !important;
|
|
66139
|
+
}
|
|
66140
|
+
</style>
|
|
66141
|
+
|
|
66142
|
+
<h3 class="text-xl font-bold">
|
|
66143
|
+
@if (setupMode()) {
|
|
66144
|
+
Setup
|
|
66145
|
+
} @else {
|
|
66146
|
+
Settings
|
|
66147
|
+
}
|
|
66148
|
+
</h3>
|
|
66149
|
+
|
|
66150
|
+
<form [formGroup]="projectInfoForm">
|
|
66151
|
+
<fieldset class="fieldset my-6">
|
|
66152
|
+
<!-- We like the fieldset / fieldset-legend styles from daisy, but
|
|
66153
|
+
we're certainly not using it as intended. Daisy inputs
|
|
66154
|
+
have no other good way of putting the label on top.
|
|
66155
|
+
TODO fix properly. -->
|
|
66156
|
+
<label class="fieldset-legend text-md">Data directory</label>
|
|
66157
|
+
<div class="input w-full">
|
|
66158
|
+
<span class="material-icons !text-sm opacity-50">folder</span>
|
|
66159
|
+
<input
|
|
66160
|
+
formControlName="dataDir"
|
|
66161
|
+
type="text"
|
|
66162
|
+
class="grow"
|
|
66163
|
+
placeholder="/"
|
|
66164
|
+
/>
|
|
66165
|
+
</div>
|
|
66166
|
+
<p class="label">Root of the data directory for the project.</p>
|
|
66167
|
+
</fieldset>
|
|
66168
|
+
|
|
66169
|
+
<fieldset class="fieldset my-4">
|
|
66170
|
+
<label class="fieldset-legend text-md">Model directory</label>
|
|
66171
|
+
|
|
66172
|
+
<div class="input w-full">
|
|
66173
|
+
<span class="material-icons !text-sm opacity-50">folder</span>
|
|
66174
|
+
<input
|
|
66175
|
+
formControlName="modelDir"
|
|
66176
|
+
type="text"
|
|
66177
|
+
class="grow"
|
|
66178
|
+
placeholder="/"
|
|
66179
|
+
/>
|
|
66180
|
+
</div>
|
|
66181
|
+
<p class="label">Root of the model directory for the project.</p>
|
|
66182
|
+
</fieldset>
|
|
66183
|
+
|
|
66184
|
+
<fieldset class="fieldset my-4">
|
|
66185
|
+
<label class="fieldset-legend text-md">Camera Views</label>
|
|
66186
|
+
|
|
66187
|
+
<textarea
|
|
66188
|
+
class="textarea w-full"
|
|
66189
|
+
[rows]="viewsInitialRows()"
|
|
66190
|
+
[placeholder]="cameraViewPlaceholder"
|
|
66191
|
+
formControlName="views"
|
|
66192
|
+
></textarea>
|
|
66193
|
+
<p class="label">
|
|
66194
|
+
Names of views embedded in video filenames.<br />
|
|
66195
|
+
Used to group files into sessions.
|
|
66196
|
+
</p>
|
|
66197
|
+
</fieldset>
|
|
66198
|
+
|
|
66199
|
+
<div class="modal-action">
|
|
66200
|
+
@if (!setupMode()) {
|
|
66201
|
+
<button class="btn btn-soft btn-secondary" (click)="done.emit(null)">
|
|
66202
|
+
Cancel
|
|
66203
|
+
</button>
|
|
66204
|
+
}
|
|
66205
|
+
<button
|
|
66206
|
+
class="btn btn-soft btn-primary"
|
|
66207
|
+
(click)="onSaveClick()"
|
|
66208
|
+
[disabled]="!projectInfoForm.dirty"
|
|
66209
|
+
>
|
|
66210
|
+
Save
|
|
66211
|
+
</button>
|
|
66212
|
+
</div>
|
|
66213
|
+
</form>
|
|
66214
|
+
`, styles: ["/* angular:styles/component:css;5c3484fa86afc1ad339d983c727d8801928706c064dd49a4001f42c8eac3d364;/home/ksikka/lightning-pose/app/web_ui/src/app/project-settings/project-settings.component.html */\n::placeholder {\n color: color-mix(in oklch, currentColor 50%, #0000) !important;\n}\n/*# sourceMappingURL=/static/project-settings.component-BXKZMYM3.css.map */\n"] }]
|
|
66215
|
+
}], () => [], null);
|
|
66216
|
+
})();
|
|
66217
|
+
(() => {
|
|
66218
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(ProjectSettingsComponent, { className: "ProjectSettingsComponent", filePath: "src/app/project-settings/project-settings.component.ts", lineNumber: 21 });
|
|
66219
|
+
})();
|
|
66220
|
+
|
|
66002
66221
|
// src/app/app.component.ts
|
|
66222
|
+
var _c08 = ["settingsDialog"];
|
|
66223
|
+
function AppComponent_Conditional_18_Template(rf, ctx) {
|
|
66224
|
+
if (rf & 1) {
|
|
66225
|
+
\u0275\u0275element(0, "router-outlet");
|
|
66226
|
+
}
|
|
66227
|
+
}
|
|
66228
|
+
function AppComponent_Conditional_19_Template(rf, ctx) {
|
|
66229
|
+
if (rf & 1) {
|
|
66230
|
+
\u0275\u0275element(0, "app-project-settings", 12);
|
|
66231
|
+
}
|
|
66232
|
+
if (rf & 2) {
|
|
66233
|
+
\u0275\u0275property("setupMode", true);
|
|
66234
|
+
}
|
|
66235
|
+
}
|
|
66236
|
+
function AppComponent_Conditional_22_Template(rf, ctx) {
|
|
66237
|
+
if (rf & 1) {
|
|
66238
|
+
const _r2 = \u0275\u0275getCurrentView();
|
|
66239
|
+
\u0275\u0275elementStart(0, "app-project-settings", 14);
|
|
66240
|
+
\u0275\u0275listener("done", function AppComponent_Conditional_22_Template_app_project_settings_done_0_listener() {
|
|
66241
|
+
\u0275\u0275restoreView(_r2);
|
|
66242
|
+
const ctx_r2 = \u0275\u0275nextContext();
|
|
66243
|
+
return \u0275\u0275resetView(ctx_r2.settingsDialogOpen.set(false));
|
|
66244
|
+
});
|
|
66245
|
+
\u0275\u0275elementEnd();
|
|
66246
|
+
\u0275\u0275elementStart(1, "div", 15)(2, "button", 16);
|
|
66247
|
+
\u0275\u0275listener("click", function AppComponent_Conditional_22_Template_button_click_2_listener() {
|
|
66248
|
+
\u0275\u0275restoreView(_r2);
|
|
66249
|
+
const ctx_r2 = \u0275\u0275nextContext();
|
|
66250
|
+
return \u0275\u0275resetView(ctx_r2.settingsDialogOpen.set(false));
|
|
66251
|
+
});
|
|
66252
|
+
\u0275\u0275text(3, "close");
|
|
66253
|
+
\u0275\u0275elementEnd()();
|
|
66254
|
+
}
|
|
66255
|
+
}
|
|
66003
66256
|
var AppComponent = class _AppComponent {
|
|
66257
|
+
projectInfoService = inject(ProjectInfoService);
|
|
66258
|
+
// Whether the required initial setup has been done.
|
|
66259
|
+
// (Setting data directory, model directory, views).
|
|
66260
|
+
projectInfoRequestCompleted = signal(false);
|
|
66261
|
+
hasBeenSetup = signal(false);
|
|
66262
|
+
settingsDialog = viewChild.required("settingsDialog");
|
|
66263
|
+
settingsDialogOpen = signal(false);
|
|
66264
|
+
async ngOnInit() {
|
|
66265
|
+
await this.projectInfoService.loadProjectInfo();
|
|
66266
|
+
this.hasBeenSetup.set(Boolean(this.projectInfoService.projectInfo));
|
|
66267
|
+
this.projectInfoRequestCompleted.set(true);
|
|
66268
|
+
}
|
|
66269
|
+
constructor() {
|
|
66270
|
+
effect(() => {
|
|
66271
|
+
if (this.settingsDialogOpen()) {
|
|
66272
|
+
this.openSettingsDialog();
|
|
66273
|
+
} else {
|
|
66274
|
+
this.closeSettingsDialog();
|
|
66275
|
+
}
|
|
66276
|
+
});
|
|
66277
|
+
}
|
|
66278
|
+
openSettingsDialog() {
|
|
66279
|
+
const elementRef = this.settingsDialog();
|
|
66280
|
+
elementRef.nativeElement.showModal();
|
|
66281
|
+
}
|
|
66282
|
+
closeSettingsDialog() {
|
|
66283
|
+
const elementRef = this.settingsDialog();
|
|
66284
|
+
elementRef.nativeElement.close();
|
|
66285
|
+
}
|
|
66004
66286
|
static \u0275fac = function AppComponent_Factory(__ngFactoryType__) {
|
|
66005
66287
|
return new (__ngFactoryType__ || _AppComponent)();
|
|
66006
66288
|
};
|
|
66007
|
-
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _AppComponent, selectors: [["app-root"]],
|
|
66289
|
+
static \u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _AppComponent, selectors: [["app-root"]], viewQuery: function AppComponent_Query(rf, ctx) {
|
|
66008
66290
|
if (rf & 1) {
|
|
66009
|
-
\u0275\
|
|
66010
|
-
|
|
66011
|
-
|
|
66012
|
-
\u0275\
|
|
66013
|
-
|
|
66291
|
+
\u0275\u0275viewQuerySignal(ctx.settingsDialog, _c08, 5);
|
|
66292
|
+
}
|
|
66293
|
+
if (rf & 2) {
|
|
66294
|
+
\u0275\u0275queryAdvance();
|
|
66295
|
+
}
|
|
66296
|
+
}, decls: 23, vars: 4, consts: [["settingsDialog", ""], [1, "navbar", "bg-base-200", "shadow-lg"], [1, "navbar-start"], [1, "text-lg", "font-semibold"], [1, "navbar-center"], [1, "menu", "menu-horizontal", "p-0"], ["routerLink", "/viewer", "routerLinkActive", "menu-active", "ariaCurrentWhenActive", "page"], ["routerLink", "/labeler", "routerLinkActive", "menu-active", "ariaCurrentWhenActive", "page"], [1, "navbar-end"], ["tabindex", "0", 1, "btn", "btn-ghost", 3, "click", "keydown.enter"], [1, "material-icons"], [1, "flex-grow", "flex", "min-h-0"], [1, "w-lg", "mt-8", 3, "setupMode"], [1, "modal"], [1, "modal-box", 3, "done"], [1, "modal-backdrop"], [3, "click"]], template: function AppComponent_Template(rf, ctx) {
|
|
66297
|
+
if (rf & 1) {
|
|
66298
|
+
const _r1 = \u0275\u0275getCurrentView();
|
|
66299
|
+
\u0275\u0275elementStart(0, "header")(1, "nav", 1)(2, "div", 2)(3, "span", 3);
|
|
66300
|
+
\u0275\u0275text(4, "Lightning Pose");
|
|
66014
66301
|
\u0275\u0275elementEnd()();
|
|
66015
|
-
\u0275\u0275elementStart(7, "li")(8, "a",
|
|
66016
|
-
\u0275\u0275text(9, "
|
|
66302
|
+
\u0275\u0275elementStart(5, "div", 4)(6, "ul", 5)(7, "li")(8, "a", 6);
|
|
66303
|
+
\u0275\u0275text(9, "Viewer");
|
|
66304
|
+
\u0275\u0275elementEnd()();
|
|
66305
|
+
\u0275\u0275elementStart(10, "li")(11, "a", 7);
|
|
66306
|
+
\u0275\u0275text(12, "Labeler");
|
|
66017
66307
|
\u0275\u0275elementEnd()()()();
|
|
66018
|
-
\u0275\
|
|
66308
|
+
\u0275\u0275elementStart(13, "div", 8)(14, "button", 9);
|
|
66309
|
+
\u0275\u0275listener("click", function AppComponent_Template_button_click_14_listener() {
|
|
66310
|
+
\u0275\u0275restoreView(_r1);
|
|
66311
|
+
return \u0275\u0275resetView(ctx.settingsDialogOpen.set(true));
|
|
66312
|
+
})("keydown.enter", function AppComponent_Template_button_keydown_enter_14_listener() {
|
|
66313
|
+
\u0275\u0275restoreView(_r1);
|
|
66314
|
+
return \u0275\u0275resetView(ctx.settingsDialogOpen.set(true));
|
|
66315
|
+
});
|
|
66316
|
+
\u0275\u0275elementStart(15, "span", 10);
|
|
66317
|
+
\u0275\u0275text(16, "settings");
|
|
66318
|
+
\u0275\u0275elementEnd()()()()();
|
|
66319
|
+
\u0275\u0275elementStart(17, "main", 11);
|
|
66320
|
+
\u0275\u0275template(18, AppComponent_Conditional_18_Template, 1, 0, "router-outlet")(19, AppComponent_Conditional_19_Template, 1, 1, "app-project-settings", 12);
|
|
66321
|
+
\u0275\u0275elementEnd();
|
|
66322
|
+
\u0275\u0275elementStart(20, "dialog", 13, 0);
|
|
66323
|
+
\u0275\u0275template(22, AppComponent_Conditional_22_Template, 4, 0);
|
|
66324
|
+
\u0275\u0275elementEnd();
|
|
66325
|
+
}
|
|
66326
|
+
if (rf & 2) {
|
|
66327
|
+
\u0275\u0275advance(17);
|
|
66328
|
+
\u0275\u0275classProp("justify-center", !ctx.hasBeenSetup());
|
|
66329
|
+
\u0275\u0275advance();
|
|
66330
|
+
\u0275\u0275conditional(ctx.hasBeenSetup() ? 18 : 19);
|
|
66331
|
+
\u0275\u0275advance(4);
|
|
66332
|
+
\u0275\u0275conditional(ctx.settingsDialogOpen() ? 22 : -1);
|
|
66019
66333
|
}
|
|
66020
|
-
}, dependencies: [
|
|
66334
|
+
}, dependencies: [
|
|
66335
|
+
RouterOutlet,
|
|
66336
|
+
RouterLink,
|
|
66337
|
+
RouterLinkActive,
|
|
66338
|
+
ProjectSettingsComponent
|
|
66339
|
+
], styles: ["\n\n[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar[_ngcontent-%COMP%] {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-IZ5OUDH2.css.map */"], changeDetection: 0 });
|
|
66021
66340
|
};
|
|
66022
66341
|
(() => {
|
|
66023
66342
|
(typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(AppComponent, [{
|
|
66024
66343
|
type: Component,
|
|
66025
|
-
args: [{ selector: "app-root", imports: [
|
|
66026
|
-
|
|
66344
|
+
args: [{ selector: "app-root", imports: [
|
|
66345
|
+
RouterOutlet,
|
|
66346
|
+
RouterLink,
|
|
66347
|
+
RouterLinkActive,
|
|
66348
|
+
ProjectSettingsComponent
|
|
66349
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: '<style>\n :host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n }\n .navbar {\n min-height: 3rem; /* reduce from default of 4rem */\n }\n</style>\n<header>\n <nav class="navbar bg-base-200 shadow-lg">\n <div class="navbar-start">\n <span class="text-lg font-semibold">Lightning Pose</span>\n </div>\n\n <div class="navbar-center">\n <ul class="menu menu-horizontal p-0">\n <li>\n <a\n routerLink="/viewer"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Viewer</a\n >\n </li>\n <li>\n <a\n routerLink="/labeler"\n routerLinkActive="menu-active"\n ariaCurrentWhenActive="page"\n >Labeler</a\n >\n </li>\n </ul>\n </div>\n\n <div class="navbar-end">\n <button\n class="btn btn-ghost"\n tabindex="0"\n (click)="settingsDialogOpen.set(true)"\n (keydown.enter)="settingsDialogOpen.set(true)"\n >\n <span class="material-icons">settings</span>\n </button>\n </div>\n </nav>\n</header>\n\n<!-- Set min-height: 0 to allow it to shrink if its content is too large.\n Default min-height for flex items is auto. -->\n<main class="flex-grow flex min-h-0" [class.justify-center]="!hasBeenSetup()">\n @if (hasBeenSetup()) {\n <router-outlet />\n } @else {\n <app-project-settings\n [setupMode]="true"\n class="w-lg mt-8"\n ></app-project-settings>\n }\n</main>\n\n<!-- Settings dialog -->\n<dialog #settingsDialog class="modal">\n @if (settingsDialogOpen()) {\n <app-project-settings\n class="modal-box"\n (done)="settingsDialogOpen.set(false)"\n ></app-project-settings>\n\n <!-- Makes the dialog close when clicked from outside. -->\n <div class="modal-backdrop">\n <button (click)="settingsDialogOpen.set(false)">close</button>\n </div>\n }\n</dialog>\n', styles: ["/* angular:styles/component:css;22d8514f1dd5b50f33b3fb93fdb69668f78eeb349bd672e238e3ac9acfbbda19;/home/ksikka/lightning-pose/app/web_ui/src/app/app.component.html */\n:host {\n display: flex;\n flex-direction: column;\n height: 100vh;\n}\n.navbar {\n min-height: 3rem;\n}\n/*# sourceMappingURL=/static/app.component-IZ5OUDH2.css.map */\n"] }]
|
|
66350
|
+
}], () => [], null);
|
|
66027
66351
|
})();
|
|
66028
66352
|
(() => {
|
|
66029
|
-
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(AppComponent, { className: "AppComponent", filePath: "src/app/app.component.ts", lineNumber:
|
|
66353
|
+
(typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(AppComponent, { className: "AppComponent", filePath: "src/app/app.component.ts", lineNumber: 27 });
|
|
66030
66354
|
})();
|
|
66031
66355
|
|
|
66032
66356
|
// src/main.ts
|
|
66033
66357
|
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
|
|
66034
|
-
//# sourceMappingURL=main-
|
|
66358
|
+
//# sourceMappingURL=main-WFYIUX2C.js.map
|