bundle pytorch model
This commit is contained in:
parent
fad0d49776
commit
381daeeac9
@ -1,3 +1,5 @@
|
||||
!dist/vibeui.pt
|
||||
|
||||
runs
|
||||
requirements.txt
|
||||
venv
|
||||
|
@ -19,6 +19,9 @@ RUN apt-get update -y && \
|
||||
# Install IPFS Kubo
|
||||
COPY --from=ipfs/kubo:v0.36.0 /usr/local/bin/ipfs /usr/local/bin/ipfs
|
||||
|
||||
# Include the vibeui pytorch model
|
||||
COPY ./dist/vibeui.pt /app/dist/vibeui.pt
|
||||
|
||||
# Copy and install dependencies
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install --ignore-scripts=false --foreground-scripts --verbose
|
||||
|
@ -8,7 +8,7 @@ dotenvx.config({ path: ['../../.env.development'] })
|
||||
|
||||
const EnvSchema = z.object({
|
||||
NODE_ENV: z.enum(['development', 'production', 'test']),
|
||||
VENV: z.string(),
|
||||
VENV: z.string().default('/app/venv'),
|
||||
PORT: z.coerce.number().default(3000),
|
||||
DATABASE_URL: z.string().url(),
|
||||
ORIGIN: z.string(),
|
||||
|
@ -4,51 +4,15 @@ import { withAccelerate } from "@prisma/extension-accelerate";
|
||||
import { getOrDownloadAsset } from "../utils/cache";
|
||||
import { env } from "../config/env";
|
||||
import { getS3Client, uploadFile } from "../utils/s3";
|
||||
import { nanoid } from "nanoid";
|
||||
import { existsSync, rmSync } from "node:fs";
|
||||
import { join, basename, extname } from "node:path";
|
||||
import { readFile, writeFile, readdir } from 'node:fs/promises';
|
||||
import yaml from 'js-yaml';
|
||||
import { getNanoSpawn } from "../utils/nanoSpawn";
|
||||
import which from "which";
|
||||
import * as ort from 'onnxruntime-node';
|
||||
import { inference, loadDataYaml } from "../utils/vibeui";
|
||||
import { ffprobe } from "../utils/vibeui";
|
||||
import { inference } from "../utils/vibeui";
|
||||
import { preparePython } from "../utils/python";
|
||||
import { generateActions2, buildFunscript } from "../utils/funscripts";
|
||||
import { buildFunscript } from "../utils/funscripts";
|
||||
|
||||
|
||||
interface Payload {
|
||||
vodId: string;
|
||||
}
|
||||
|
||||
// interface Detection {
|
||||
// startFrame: number;
|
||||
// endFrame: number;
|
||||
// className: string;
|
||||
// }
|
||||
|
||||
// interface DataYaml {
|
||||
// path: string;
|
||||
// train: string;
|
||||
// val: string;
|
||||
// names: Record<string, string>;
|
||||
// }
|
||||
|
||||
// interface FunscriptAction {
|
||||
// at: number;
|
||||
// pos: number;
|
||||
// }
|
||||
|
||||
// interface Funscript {
|
||||
// version: string;
|
||||
// actions: FunscriptAction[];
|
||||
// }
|
||||
|
||||
|
||||
// interface ClassPositionMap {
|
||||
// [className: string]: number | 'pattern';
|
||||
// }
|
||||
|
||||
|
||||
const prisma = new PrismaClient().$extends(withAccelerate());
|
||||
@ -63,206 +27,6 @@ function assertPayload(payload: any): asserts payload is Payload {
|
||||
|
||||
|
||||
|
||||
// export async function buildFunscript(
|
||||
// helpers: Helpers,
|
||||
// predictionOutput: string,
|
||||
// videoPath: string
|
||||
// ): Promise<string> {
|
||||
// const labelDir = join(predictionOutput, 'labels');
|
||||
// const yamlPath = join(predictionOutput, 'data.yaml');
|
||||
// const outputPath = join(process.env.CACHE_ROOT ?? '/tmp', `${nanoid()}.funscript`);
|
||||
// helpers.logger.info('Starting Funscript generation');
|
||||
|
||||
// try {
|
||||
|
||||
// const data = await loadDataYaml(join(env.VIBEUI_DIR, 'data.yaml'))
|
||||
// const classPositionMap = await loadClassPositionMap(data, helpers);
|
||||
// const { fps, totalFrames } = await loadVideoMetadata(videoPath, helpers);
|
||||
// const detectionSegments = await processLabelFiles(labelDir, helpers, data);
|
||||
// const totalDurationMs = Math.floor((totalFrames / fps) * 1000);
|
||||
// const actions = generateActions2(totalDurationMs, fps, detectionSegments, classPositionMap);
|
||||
// await writeFunscript(outputPath, actions, helpers);
|
||||
|
||||
// return outputPath;
|
||||
// } catch (error) {
|
||||
// helpers.logger.error(`Error generating Funscript: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// async function loadClassPositionMap(data: DataYaml, helpers: Helpers): Promise<ClassPositionMap> {
|
||||
// try {
|
||||
|
||||
// if (
|
||||
// !data ||
|
||||
// typeof data !== 'object' ||
|
||||
// !('names' in data) ||
|
||||
// typeof data.names !== 'object' ||
|
||||
// data.names === null ||
|
||||
// Object.keys(data.names).length === 0
|
||||
// ) {
|
||||
// throw new Error('Invalid data.yaml: "names" field is missing, not an object, or empty');
|
||||
// }
|
||||
|
||||
// const positionMap: ClassPositionMap = {
|
||||
// ControlledByTipper: 50,
|
||||
// ControlledByTipperHigh: 80,
|
||||
// ControlledByTipperLow: 20,
|
||||
// ControlledByTipperMedium: 50,
|
||||
// ControlledByTipperUltrahigh: 95,
|
||||
// Ring1: 30,
|
||||
// Ring2: 40,
|
||||
// Ring3: 50,
|
||||
// Ring4: 60,
|
||||
// Earthquake: 'pattern',
|
||||
// Fireworks: 'pattern',
|
||||
// Pulse: 'pattern',
|
||||
// Wave: 'pattern',
|
||||
// Pause: 0,
|
||||
// RandomTime: 70,
|
||||
// HighLevel: 80,
|
||||
// LowLevel: 20,
|
||||
// MediumLevel: 50,
|
||||
// UltraHighLevel: 95
|
||||
// };
|
||||
|
||||
// const names = Object.values(data.names);
|
||||
// for (const name of names) {
|
||||
// if (typeof name !== 'string' || name.trim() === '') {
|
||||
// helpers.logger.info(`Skipping invalid class name: ${name}`);
|
||||
// continue;
|
||||
// }
|
||||
// if (!(name in positionMap)) {
|
||||
// helpers.logger.info(`No position mapping for class "${name}", defaulting to 0`);
|
||||
// positionMap[name] = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// helpers.logger.info(`Loaded class position map: ${JSON.stringify(positionMap)}`);
|
||||
// return positionMap;
|
||||
// } catch (error) {
|
||||
// helpers.logger.error(`Error loading data.yaml: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
|
||||
// function generatePatternPositions(startMs: number, durationMs: number, className: string, fps: number): FunscriptAction[] {
|
||||
// const actions: FunscriptAction[] = [];
|
||||
// const frameDurationMs = 1000 / fps;
|
||||
// const totalFrames = Math.floor(durationMs / frameDurationMs);
|
||||
// const intervalMs = 100;
|
||||
|
||||
// for (let timeMs = 0; timeMs < durationMs; timeMs += intervalMs) {
|
||||
// const progress = timeMs / durationMs;
|
||||
// let pos = 0;
|
||||
|
||||
// switch (className) {
|
||||
// case 'Pulse':
|
||||
// pos = Math.round(50 * Math.sin(progress * 2 * Math.PI));
|
||||
// break;
|
||||
// case 'Wave':
|
||||
// pos = Math.round(50 + 50 * Math.sin(progress * 2 * Math.PI));
|
||||
// break;
|
||||
// case 'Fireworks':
|
||||
// pos = Math.random() > 0.5 ? 80 : 0;
|
||||
// break;
|
||||
// case 'Earthquake':
|
||||
// pos = Math.round(90 * Math.sin(progress * 4 * Math.PI) + (Math.random() - 0.5) * 10);
|
||||
// pos = Math.max(0, Math.min(90, pos));
|
||||
// break;
|
||||
// }
|
||||
|
||||
// actions.push({ at: startMs + timeMs, pos });
|
||||
// }
|
||||
|
||||
// return actions;
|
||||
// }
|
||||
|
||||
// async function loadVideoMetadata(videoPath: string, helpers: Helpers) {
|
||||
// const { fps, frames: totalFrames } = await ffprobe(videoPath);
|
||||
// helpers.logger.info(`Video metadata: fps=${fps}, frames=${totalFrames}`);
|
||||
// return { fps, totalFrames };
|
||||
// }
|
||||
|
||||
|
||||
// async function processLabelFiles(labelDir: string, helpers: Helpers, data: DataYaml): Promise<Detection[]> {
|
||||
// const labelFiles = (await readdir(labelDir)).filter(file => file.endsWith('.txt'));
|
||||
// const detections: Map<number, Detection[]> = new Map();
|
||||
// const names = data.names;
|
||||
|
||||
// for (const file of labelFiles) {
|
||||
// const match = file.match(/(\d+)\.txt$/);
|
||||
// if (!match) {
|
||||
// helpers.logger.info(`Skipping invalid filename: ${file}`);
|
||||
// continue;
|
||||
// }
|
||||
// const frameIndex = parseInt(match[1], 10);
|
||||
// if (isNaN(frameIndex)) {
|
||||
// helpers.logger.info(`Skipping invalid frame index from filename: ${file}`);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// const content = await readFile(join(labelDir, file), 'utf8');
|
||||
// const lines = content.trim().split('\n');
|
||||
// const frameDetections: Detection[] = [];
|
||||
// let maxConfidence = 0;
|
||||
// let selectedClassIndex = -1;
|
||||
|
||||
// for (const line of lines) {
|
||||
// const parts = line.trim().split(/\s+/);
|
||||
// if (parts.length < 6) continue;
|
||||
|
||||
// const classIndex = parseInt(parts[0], 10);
|
||||
// const confidence = parseFloat(parts[5]);
|
||||
// if (isNaN(classIndex) || isNaN(confidence)) continue;
|
||||
|
||||
// if (confidence >= 0.7 && confidence > maxConfidence) {
|
||||
// maxConfidence = confidence;
|
||||
// selectedClassIndex = classIndex;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (maxConfidence > 0) {
|
||||
// const className = (data.names as Record<string, string>)[selectedClassIndex.toString()];
|
||||
// if (className) {
|
||||
// frameDetections.push({ startFrame: frameIndex, endFrame: frameIndex, className });
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (frameDetections.length > 0) {
|
||||
// detections.set(frameIndex, frameDetections);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Merge overlapping detections into continuous segments
|
||||
// const detectionSegments: Detection[] = [];
|
||||
// let currentDetection: Detection | null = null;
|
||||
|
||||
// for (const [frameIndex, frameDetections] of detections.entries()) {
|
||||
// for (const detection of frameDetections) {
|
||||
// if (!currentDetection || currentDetection.className !== detection.className) {
|
||||
// if (currentDetection) detectionSegments.push(currentDetection);
|
||||
// currentDetection = { ...detection, endFrame: frameIndex };
|
||||
// } else {
|
||||
// currentDetection.endFrame = frameIndex;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (currentDetection) detectionSegments.push(currentDetection);
|
||||
|
||||
// return detectionSegments;
|
||||
// }
|
||||
|
||||
|
||||
// async function writeFunscript(outputPath: string, actions: FunscriptAction[], helpers: Helpers) {
|
||||
// const funscript: Funscript = { version: '1.0', actions };
|
||||
// await writeFile(outputPath, JSON.stringify(funscript, null, 2));
|
||||
// helpers.logger.info(`Funscript generated: ${outputPath} (${actions.length} actions)`);
|
||||
// }
|
||||
|
||||
|
||||
const createFunscript: Task = async (payload: any, helpers: Helpers) => {
|
||||
assertPayload(payload);
|
||||
const { vodId } = payload;
|
||||
|
Loading…
x
Reference in New Issue
Block a user