Rewrite frontend as single self-contained HTML file — all CSS/JS inline, no external files to fail loading
This commit is contained in:
32
dist/config/config.d.ts
vendored
Normal file
32
dist/config/config.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { VisionProviderConfig, TTSProviderConfig } from '../interfaces';
|
||||
export interface Config {
|
||||
captureIntervalSeconds: number;
|
||||
contextWindowSize: number;
|
||||
defaultPrompt: string;
|
||||
changePrompt: string;
|
||||
batchPrompt: string;
|
||||
visionProvider: string;
|
||||
visionModel: string;
|
||||
visionProviders: {
|
||||
[key: string]: VisionProviderConfig;
|
||||
};
|
||||
ttsProvider: string;
|
||||
ttsVoice: string;
|
||||
ttsSpeedFactor: number;
|
||||
ttsInstructions?: string;
|
||||
ttsProviders: {
|
||||
[key: string]: TTSProviderConfig;
|
||||
};
|
||||
outputDir: string;
|
||||
tempDir: string;
|
||||
batchTimeMode: boolean;
|
||||
batchWindowDuration: number;
|
||||
framesInBatch: number;
|
||||
}
|
||||
/**
|
||||
* Get default configuration options.
|
||||
* Uses a function so that process.env is read at call time
|
||||
* (after dotenv has been loaded), not at module import time.
|
||||
*/
|
||||
export declare function getDefaultConfig(): Config;
|
||||
export declare const defaultConfig: Config;
|
||||
77
dist/config/config.js
vendored
Normal file
77
dist/config/config.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.defaultConfig = void 0;
|
||||
exports.getDefaultConfig = getDefaultConfig;
|
||||
/**
|
||||
* Get default configuration options.
|
||||
* Uses a function so that process.env is read at call time
|
||||
* (after dotenv has been loaded), not at module import time.
|
||||
*/
|
||||
function getDefaultConfig() {
|
||||
return {
|
||||
captureIntervalSeconds: 10,
|
||||
contextWindowSize: 5,
|
||||
defaultPrompt: "Describe this frame from a video in 1-2 sentences for someone who cannot see it. Focus on key visual elements. Avoid using terms like 'in this frame', simply describe the actual frame. Keep sentences short and concise, as this will be used to generate an audio track which is overlayed on the video.",
|
||||
changePrompt: "Describe what has changed between these frames in 1-2 sentences for someone who cannot see the video. Focus on significant visual changes only. Avoid talking about meta information such as 'in this frame', or 'the significant change is', and merely describe the actual change taking place. Only describe the changes relevant to the last frame. The previous frames are attached for you to build context and build situational awareness. Keep it short and concise, as your text will be used to generate audio description tracks to be played with the video.",
|
||||
batchPrompt: "Describe the sequence of frames in this batch over time for someone who cannot see it. Focus on what happens, changes, or stands out visually during these seconds. Keep it to 1-3 concise sentences, avoiding words like 'in these frames'—just describe what's happening. Use context from the previous batch if relevant. Keep sentences short and concise. Avoid speculation or overly verbose or unnecessary sentences. Try not to use nested sentences and keep sentences short to help flow. This will be used for audio description and mixed back in with the video file later, so we need to maintain consistency and quick pacing. Avoid using phrases such as 'as evidenced by' or 'suggesting'. Only focus on describing the visual scene. Do not repeat information given in the previous prompt, and focus only on what has changed since that description. Avoid talking about the scene or sequence, simply focus on the action within these frames. The listener knows that this is a video, so we do not need to remind them. Also avoid overusing phrases such as 'the scene shifts', the shifting or perspective change should be evident from the description of the sequence itself.",
|
||||
// Vision AI settings
|
||||
visionProvider: "openai",
|
||||
visionModel: "gpt-5.4-mini",
|
||||
visionProviders: {
|
||||
openai: {
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
model: "gpt-5.4-mini",
|
||||
maxTokens: 300
|
||||
},
|
||||
gemini: {
|
||||
apiKey: process.env.GOOGLE_API_KEY,
|
||||
model: "gemini-2.0-flash",
|
||||
maxTokens: 300
|
||||
},
|
||||
ollama: {
|
||||
baseUrl: "http://localhost:11434",
|
||||
model: "gemma3:12b",
|
||||
maxTokens: 3000
|
||||
},
|
||||
openrouter: {
|
||||
apiKey: process.env.OPENROUTER_API_KEY,
|
||||
model: "anthropic/claude-sonnet-4.5",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
maxTokens: 300
|
||||
}
|
||||
},
|
||||
// TTS settings
|
||||
ttsProvider: "openai",
|
||||
ttsVoice: "alloy",
|
||||
ttsSpeedFactor: 1.5,
|
||||
ttsInstructions: "Speak in a calm, narrating tone suitable for audio descriptions. Keep a steady pace and clear enunciation.",
|
||||
ttsProviders: {
|
||||
openai: {
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
model: "gpt-4o-mini-tts",
|
||||
voice: "shimmer"
|
||||
},
|
||||
elevenlabs: {
|
||||
apiKey: process.env.ELEVENLABS_API_KEY,
|
||||
model: "eleven_multilingual_v2",
|
||||
voice: "JBFqnCBsd6RMkjVDRZzb"
|
||||
},
|
||||
google: {
|
||||
apiKey: process.env.GOOGLE_CLOUD_TTS_KEY,
|
||||
keyFilename: process.env.GOOGLE_CLOUD_TTS_KEYFILE,
|
||||
model: "chirp-hd",
|
||||
voice: "en-US-Chirp-HD-F"
|
||||
}
|
||||
},
|
||||
// Video processing settings
|
||||
outputDir: "./desc/output/",
|
||||
tempDir: "./desc/tmp/",
|
||||
batchTimeMode: true,
|
||||
batchWindowDuration: 15,
|
||||
framesInBatch: 10,
|
||||
};
|
||||
}
|
||||
// Keep a static export alias for backward compatibility
|
||||
// (but callers should prefer getDefaultConfig() for correct env loading)
|
||||
exports.defaultConfig = getDefaultConfig();
|
||||
//# sourceMappingURL=config.js.map
|
||||
1
dist/config/config.js.map
vendored
Normal file
1
dist/config/config.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config/config.ts"],"names":[],"mappings":";;;AAsCA,4CAkEC;AAvED;;;;GAIG;AACH,SAAgB,gBAAgB;IAC9B,OAAO;QACL,sBAAsB,EAAE,EAAE;QAC1B,iBAAiB,EAAE,CAAC;QACpB,aAAa,EAAE,6SAA6S;QAC5T,YAAY,EAAE,2iBAA2iB;QACzjB,WAAW,EAAE,6oCAA6oC;QAE1pC,qBAAqB;QACrB,cAAc,EAAE,QAAQ;QACxB,WAAW,EAAE,cAAc;QAC3B,eAAe,EAAE;YACf,MAAM,EAAE;gBACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;gBAClC,KAAK,EAAE,cAAc;gBACrB,SAAS,EAAE,GAAG;aACf;YACD,MAAM,EAAE;gBACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;gBAClC,KAAK,EAAE,kBAAkB;gBACzB,SAAS,EAAE,GAAG;aACf;YACD,MAAM,EAAE;gBACN,OAAO,EAAE,wBAAwB;gBACjC,KAAK,EAAE,YAAY;gBACnB,SAAS,EAAE,IAAI;aAChB;YACD,UAAU,EAAE;gBACV,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;gBACtC,KAAK,EAAE,6BAA6B;gBACpC,OAAO,EAAE,8BAA8B;gBACvC,SAAS,EAAE,GAAG;aACf;SACF;QAED,eAAe;QACf,WAAW,EAAE,QAAQ;QACrB,QAAQ,EAAE,OAAO;QACjB,cAAc,EAAE,GAAG;QACnB,eAAe,EAAE,4GAA4G;QAC7H,YAAY,EAAE;YACZ,MAAM,EAAE;gBACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;gBAClC,KAAK,EAAE,iBAAiB;gBACxB,KAAK,EAAE,SAAS;aACjB;YACD,UAAU,EAAE;gBACV,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;gBACtC,KAAK,EAAE,wBAAwB;gBAC/B,KAAK,EAAE,sBAAsB;aAC9B;YACD,MAAM,EAAE;gBACN,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;gBACxC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBACjD,KAAK,EAAE,UAAU;gBACjB,KAAK,EAAE,kBAAkB;aAC1B;SACF;QAED,4BAA4B;QAC5B,SAAS,EAAE,gBAAgB;QAC3B,OAAO,EAAE,aAAa;QACtB,aAAa,EAAE,IAAI;QACnB,mBAAmB,EAAE,EAAE;QACvB,aAAa,EAAE,EAAE;KAClB,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,yEAAyE;AAC5D,QAAA,aAAa,GAAG,gBAAgB,EAAE,CAAC"}
|
||||
2
dist/config/index.d.ts
vendored
Normal file
2
dist/config/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { Config, getDefaultConfig, defaultConfig } from './config';
|
||||
export { createStats, printStats } from './stats';
|
||||
10
dist/config/index.js
vendored
Normal file
10
dist/config/index.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.printStats = exports.createStats = exports.defaultConfig = exports.getDefaultConfig = void 0;
|
||||
var config_1 = require("./config");
|
||||
Object.defineProperty(exports, "getDefaultConfig", { enumerable: true, get: function () { return config_1.getDefaultConfig; } });
|
||||
Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return config_1.defaultConfig; } });
|
||||
var stats_1 = require("./stats");
|
||||
Object.defineProperty(exports, "createStats", { enumerable: true, get: function () { return stats_1.createStats; } });
|
||||
Object.defineProperty(exports, "printStats", { enumerable: true, get: function () { return stats_1.printStats; } });
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
dist/config/index.js.map
vendored
Normal file
1
dist/config/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":";;;AAAA,mCAAmE;AAAlD,0GAAA,gBAAgB,OAAA;AAAE,uGAAA,aAAa,OAAA;AAChD,iCAAkD;AAAzC,oGAAA,WAAW,OAAA;AAAE,mGAAA,UAAU,OAAA"}
|
||||
9
dist/config/stats.d.ts
vendored
Normal file
9
dist/config/stats.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Stats } from '../interfaces';
|
||||
import { Config } from './config';
|
||||
export declare const createStats: () => Stats;
|
||||
/**
|
||||
* Print out statistics
|
||||
* @param stats - Statistics object
|
||||
* @param settings - Configuration settings
|
||||
*/
|
||||
export declare function printStats(stats: Stats, settings: Config): void;
|
||||
72
dist/config/stats.js
vendored
Normal file
72
dist/config/stats.js
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createStats = void 0;
|
||||
exports.printStats = printStats;
|
||||
// Initialize stats object
|
||||
const createStats = () => ({
|
||||
totalFrames: 0,
|
||||
totalBatches: 0,
|
||||
totalVisionInputCost: 0,
|
||||
totalVisionOutputCost: 0,
|
||||
totalTTSCost: 0,
|
||||
totalCost: 0
|
||||
});
|
||||
exports.createStats = createStats;
|
||||
// Pricing constants (as of March 2025)
|
||||
const pricing = {
|
||||
vision: {
|
||||
openai: {
|
||||
'gpt-4o': {
|
||||
input: 0.0025,
|
||||
output: 0.01
|
||||
}
|
||||
},
|
||||
gemini: {
|
||||
'gemini-pro-vision': {
|
||||
input: 0.0025,
|
||||
output: 0.0025
|
||||
}
|
||||
}
|
||||
},
|
||||
tts: {
|
||||
openai: {
|
||||
'tts-1': 0.015,
|
||||
'tts-1-hd': 0.030
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Print out statistics
|
||||
* @param stats - Statistics object
|
||||
* @param settings - Configuration settings
|
||||
*/
|
||||
function printStats(stats, settings) {
|
||||
// Get the pricing for the selected providers
|
||||
const visionProvider = settings.visionProvider;
|
||||
const visionModel = settings.visionProviders[visionProvider].model;
|
||||
const ttsProvider = settings.ttsProvider;
|
||||
const ttsModel = settings.ttsProviders[ttsProvider].model;
|
||||
// Check if the pricing data exists
|
||||
const visionPricing = pricing.vision[visionProvider]?.[visionModel];
|
||||
const ttsPricing = pricing.tts[ttsProvider]?.[ttsModel];
|
||||
if (!visionPricing) {
|
||||
console.warn(`Warning: No pricing data for vision provider "${visionProvider}" and model "${visionModel}".`);
|
||||
}
|
||||
if (!ttsPricing) {
|
||||
console.warn(`Warning: No pricing data for TTS provider "${ttsProvider}" and model "${ttsModel}".`);
|
||||
}
|
||||
// Calculate prices using available pricing data
|
||||
const visionInputCost = visionPricing ? (stats.totalVisionInputCost * visionPricing.input / 1000) : 0;
|
||||
const visionOutputCost = visionPricing ? (stats.totalVisionOutputCost * visionPricing.output / 1000) : 0;
|
||||
const ttsCost = ttsPricing ? (stats.totalTTSCost * ttsPricing / 1000) : 0;
|
||||
const totalCost = visionInputCost + visionOutputCost + ttsCost;
|
||||
// Print out the stats
|
||||
console.log('\n=== STATISTICS ===');
|
||||
console.log(`Vision provider: ${visionProvider}, Model: ${visionModel}`);
|
||||
console.log(`TTS provider: ${ttsProvider}, Model: ${ttsModel}`);
|
||||
console.log(`Total vision input cost: ${visionInputCost.toFixed(4)}`);
|
||||
console.log(`Total vision output cost: ${visionOutputCost.toFixed(4)}`);
|
||||
console.log(`Total TTS cost: ${ttsCost.toFixed(4)}`);
|
||||
console.log(`Total cost: ${totalCost.toFixed(4)}`);
|
||||
}
|
||||
//# sourceMappingURL=stats.js.map
|
||||
1
dist/config/stats.js.map
vendored
Normal file
1
dist/config/stats.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/config/stats.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user