Rewrite frontend as single self-contained HTML file — all CSS/JS inline, no external files to fail loading
This commit is contained in:
8
dist/providers/tts/elevenLabsTTSProvider.d.ts
vendored
Normal file
8
dist/providers/tts/elevenLabsTTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
export declare class ElevenLabsTTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private axiosInstance;
|
||||
private lastRequestId;
|
||||
constructor(config: TTSProviderConfig);
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
}
|
||||
79
dist/providers/tts/elevenLabsTTSProvider.js
vendored
Normal file
79
dist/providers/tts/elevenLabsTTSProvider.js
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ElevenLabsTTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
class ElevenLabsTTSProvider {
|
||||
constructor(config) {
|
||||
this.lastRequestId = null;
|
||||
this.config = config;
|
||||
this.axiosInstance = axios_1.default.create({
|
||||
baseURL: 'https://api.elevenlabs.io/v1',
|
||||
headers: {
|
||||
'xi-api-key': config.apiKey,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
}
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
const voice = options.voice || this.config.voice || 'JBFqnCBsd6RMkjVDRZzb';
|
||||
const model = options.model || this.config.model || 'eleven_multilingual_v2';
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
const requestBody = {
|
||||
text,
|
||||
model_id: model,
|
||||
voice_settings: {
|
||||
stability: 0.5,
|
||||
similarity_boost: 0.75,
|
||||
speed: speedFactor,
|
||||
use_speaker_boost: true
|
||||
}
|
||||
};
|
||||
if (this.lastRequestId) {
|
||||
requestBody.previous_request_ids = [this.lastRequestId];
|
||||
}
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
const response = await this.axiosInstance.post(`/text-to-speech/${voice}`, requestBody, {
|
||||
params: { output_format: 'mp3_44100_128' },
|
||||
responseType: 'arraybuffer'
|
||||
});
|
||||
this.lastRequestId = response.headers['request-id'] || null;
|
||||
const audioBuffer = Buffer.from(response.data);
|
||||
fs_1.default.writeFileSync(tempOutputPath, audioBuffer);
|
||||
const cost = text.length;
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
if (error.response) {
|
||||
console.error(`ElevenLabs TTS error (${error.response.status}):`, Buffer.from(error.response.data).toString());
|
||||
}
|
||||
else {
|
||||
console.error('ElevenLabs TTS error:', error.message);
|
||||
}
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ElevenLabsTTSProvider = ElevenLabsTTSProvider;
|
||||
//# sourceMappingURL=elevenLabsTTSProvider.js.map
|
||||
1
dist/providers/tts/elevenLabsTTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/elevenLabsTTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"elevenLabsTTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/elevenLabsTTSProvider.ts"],"names":[],"mappings":"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"}
|
||||
8
dist/providers/tts/googleCloudTTSProvider.d.ts
vendored
Normal file
8
dist/providers/tts/googleCloudTTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
export declare class GoogleCloudTTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private client;
|
||||
constructor(config: TTSProviderConfig);
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
private extractLanguageCode;
|
||||
}
|
||||
80
dist/providers/tts/googleCloudTTSProvider.js
vendored
Normal file
80
dist/providers/tts/googleCloudTTSProvider.js
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GoogleCloudTTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const text_to_speech_1 = require("@google-cloud/text-to-speech");
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
class GoogleCloudTTSProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
const clientConfig = {
|
||||
apiKey: config.apiKey,
|
||||
fallback: true
|
||||
};
|
||||
if (config.keyFilename) {
|
||||
clientConfig.keyFilename = config.keyFilename;
|
||||
}
|
||||
this.client = new text_to_speech_1.TextToSpeechClient(clientConfig);
|
||||
}
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
const voice = options.voice || this.config.voice || 'en-US-Chirp-HD-F';
|
||||
const model = options.model || this.config.model || 'chirp-hd';
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
const request = {
|
||||
input: { text },
|
||||
voice: {
|
||||
languageCode: this.extractLanguageCode(voice),
|
||||
name: voice
|
||||
},
|
||||
audioConfig: {
|
||||
audioEncoding: 'MP3',
|
||||
speakingRate: speedFactor
|
||||
}
|
||||
};
|
||||
const [response] = await this.client.synthesizeSpeech(request);
|
||||
if (!response.audioContent) {
|
||||
throw new Error('No audio content returned from Google Cloud TTS');
|
||||
}
|
||||
const audioBuffer = response.audioContent instanceof Uint8Array
|
||||
? Buffer.from(response.audioContent)
|
||||
: Buffer.from(response.audioContent);
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
fs_1.default.writeFileSync(tempOutputPath, audioBuffer);
|
||||
const cost = text.length;
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Google Cloud TTS error:', error.message);
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
extractLanguageCode(voiceName) {
|
||||
const parts = voiceName.split('-');
|
||||
if (parts.length >= 2) {
|
||||
return `${parts[0]}-${parts[1]}`;
|
||||
}
|
||||
return 'en-US';
|
||||
}
|
||||
}
|
||||
exports.GoogleCloudTTSProvider = GoogleCloudTTSProvider;
|
||||
//# sourceMappingURL=googleCloudTTSProvider.js.map
|
||||
1
dist/providers/tts/googleCloudTTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/googleCloudTTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"googleCloudTTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/googleCloudTTSProvider.ts"],"names":[],"mappings":"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"}
|
||||
4
dist/providers/tts/index.d.ts
vendored
Normal file
4
dist/providers/tts/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './ttsProviderFactory';
|
||||
export * from './openAITTSProvider';
|
||||
export * from './elevenLabsTTSProvider';
|
||||
export * from './googleCloudTTSProvider';
|
||||
21
dist/providers/tts/index.js
vendored
Normal file
21
dist/providers/tts/index.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./ttsProviderFactory"), exports);
|
||||
__exportStar(require("./openAITTSProvider"), exports);
|
||||
__exportStar(require("./elevenLabsTTSProvider"), exports);
|
||||
__exportStar(require("./googleCloudTTSProvider"), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
dist/providers/tts/index.js.map
vendored
Normal file
1
dist/providers/tts/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/tts/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,sDAAoC;AACpC,0DAAwC;AACxC,2DAAyC"}
|
||||
17
dist/providers/tts/openAITTSProvider.d.ts
vendored
Normal file
17
dist/providers/tts/openAITTSProvider.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { TTSProvider, TTSProviderConfig, TTSOptions, TTSResult } from '../../interfaces';
|
||||
/**
|
||||
* OpenAI TTS Provider Implementation
|
||||
*/
|
||||
export declare class OpenAITTSProvider implements TTSProvider {
|
||||
private config;
|
||||
private openai;
|
||||
constructor(config: TTSProviderConfig);
|
||||
/**
|
||||
* Convert text to speech
|
||||
* @param text - Text to convert to speech
|
||||
* @param outputPath - Output path for the audio file
|
||||
* @param options - Additional options
|
||||
* @returns Duration of the generated audio in seconds and cost
|
||||
*/
|
||||
textToSpeech(text: string, outputPath: string, options?: TTSOptions): Promise<TTSResult>;
|
||||
}
|
||||
75
dist/providers/tts/openAITTSProvider.js
vendored
Normal file
75
dist/providers/tts/openAITTSProvider.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OpenAITTSProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const child_process_1 = require("child_process");
|
||||
const openai_1 = require("openai");
|
||||
const mediaUtils_1 = require("../../utils/mediaUtils");
|
||||
/**
|
||||
* OpenAI TTS Provider Implementation
|
||||
*/
|
||||
class OpenAITTSProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.openai = new openai_1.OpenAI({
|
||||
apiKey: config.apiKey,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Convert text to speech
|
||||
* @param text - Text to convert to speech
|
||||
* @param outputPath - Output path for the audio file
|
||||
* @param options - Additional options
|
||||
* @returns Duration of the generated audio in seconds and cost
|
||||
*/
|
||||
async textToSpeech(text, outputPath, options = {}) {
|
||||
try {
|
||||
// Get the options, with defaults from config
|
||||
const voice = options.voice || this.config.voice;
|
||||
const model = options.model || this.config.model;
|
||||
const speedFactor = options.speedFactor || 1.0;
|
||||
// Generate the initial TTS output
|
||||
const tempOutputPath = outputPath.replace(/\.\w+$/, '_temp$&');
|
||||
const mp3 = await this.openai.audio.speech.create({
|
||||
model: model,
|
||||
voice: voice,
|
||||
input: text,
|
||||
...(options.instructions ? { instructions: options.instructions } : {})
|
||||
});
|
||||
// Cost calculation is based on character count
|
||||
const cost = text.length;
|
||||
const buffer = Buffer.from(await mp3.arrayBuffer());
|
||||
fs_1.default.writeFileSync(tempOutputPath, buffer);
|
||||
// Speed up the audio using FFmpeg if needed
|
||||
if (speedFactor !== 1.0) {
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -i "${tempOutputPath}" -filter:a "atempo=${speedFactor}" -c:a libmp3lame -q:a 2 "${outputPath}" -y`);
|
||||
// Clean up temporary file
|
||||
fs_1.default.unlinkSync(tempOutputPath);
|
||||
}
|
||||
else {
|
||||
// Just use the file as is
|
||||
fs_1.default.renameSync(tempOutputPath, outputPath);
|
||||
}
|
||||
// Get actual audio duration for accurate timing
|
||||
const audioDuration = (0, mediaUtils_1.getAudioDuration)(outputPath);
|
||||
return {
|
||||
duration: audioDuration,
|
||||
cost: cost
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error generating speech:", error);
|
||||
// Create a silent audio file if TTS fails
|
||||
(0, child_process_1.execSync)(`ffmpeg -v error -f lavfi -i anullsrc=r=24000:cl=mono -t 1 -q:a 9 -acodec libmp3lame "${outputPath}" -y`);
|
||||
return {
|
||||
duration: 1,
|
||||
cost: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.OpenAITTSProvider = OpenAITTSProvider;
|
||||
//# sourceMappingURL=openAITTSProvider.js.map
|
||||
1
dist/providers/tts/openAITTSProvider.js.map
vendored
Normal file
1
dist/providers/tts/openAITTSProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"openAITTSProvider.js","sourceRoot":"","sources":["../../../src/providers/tts/openAITTSProvider.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,iDAAyC;AACzC,mCAAgC;AAEhC,uDAA0D;AAE1D;;GAEG;AACH,MAAa,iBAAiB;IAI5B,YAAY,MAAyB;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,CAAC;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAChB,IAAY,EACZ,UAAkB,EAClB,UAAsB,EAAE;QAExB,IAAI,CAAC;YACH,6CAA6C;YAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACjD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;YAE/C,kCAAkC;YAClC,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAE/D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;gBAChD,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,KAAY;gBACnB,KAAK,EAAE,IAAI;gBACX,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACxE,CAAC,CAAC;YAEH,+CAA+C;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;YAEzB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YACpD,YAAE,CAAC,aAAa,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;YAEzC,4CAA4C;YAC5C,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;gBACxB,IAAA,wBAAQ,EAAC,uBAAuB,cAAc,uBAAuB,WAAW,6BAA6B,UAAU,MAAM,CAAC,CAAC;gBAC/H,0BAA0B;gBAC1B,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,0BAA0B;gBAC1B,YAAE,CAAC,UAAU,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;YAC5C,CAAC;YAED,gDAAgD;YAChD,MAAM,aAAa,GAAG,IAAA,6BAAgB,EAAC,UAAU,CAAC,CAAC;YAEnD,OAAO;gBACL,QAAQ,EAAE,aAAa;gBACvB,IAAI,EAAE,IAAI;aACX,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,0CAA0C;YAC1C,IAAA,wBAAQ,EAAC,wFAAwF,UAAU,MAAM,CAAC,CAAC;YACnH,OAAO;gBACL,QAAQ,EAAE,CAAC;gBACX,IAAI,EAAE,CAAC;aACR,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AAxED,8CAwEC"}
|
||||
8
dist/providers/tts/ttsProviderFactory.d.ts
vendored
Normal file
8
dist/providers/tts/ttsProviderFactory.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { TTSProvider } from '../../interfaces';
|
||||
import { Config } from '../../config/config';
|
||||
/**
|
||||
* Factory for creating TTS providers
|
||||
*/
|
||||
export declare class TTSProviderFactory {
|
||||
static getProvider(config: Config): TTSProvider;
|
||||
}
|
||||
31
dist/providers/tts/ttsProviderFactory.js
vendored
Normal file
31
dist/providers/tts/ttsProviderFactory.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TTSProviderFactory = void 0;
|
||||
const openAITTSProvider_1 = require("./openAITTSProvider");
|
||||
const elevenLabsTTSProvider_1 = require("./elevenLabsTTSProvider");
|
||||
const googleCloudTTSProvider_1 = require("./googleCloudTTSProvider");
|
||||
/**
|
||||
* Factory for creating TTS providers
|
||||
*/
|
||||
class TTSProviderFactory {
|
||||
static getProvider(config) {
|
||||
const providerName = config.ttsProvider;
|
||||
const providerConfig = config.ttsProviders[providerName];
|
||||
if (!providerConfig) {
|
||||
throw new Error(`TTS provider "${providerName}" not configured.`);
|
||||
}
|
||||
switch (providerName) {
|
||||
case 'openai':
|
||||
return new openAITTSProvider_1.OpenAITTSProvider(providerConfig);
|
||||
case 'elevenlabs':
|
||||
return new elevenLabsTTSProvider_1.ElevenLabsTTSProvider(providerConfig);
|
||||
case 'google':
|
||||
return new googleCloudTTSProvider_1.GoogleCloudTTSProvider(providerConfig);
|
||||
// Add other providers here
|
||||
default:
|
||||
throw new Error(`TTS provider "${providerName}" not implemented.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.TTSProviderFactory = TTSProviderFactory;
|
||||
//# sourceMappingURL=ttsProviderFactory.js.map
|
||||
1
dist/providers/tts/ttsProviderFactory.js.map
vendored
Normal file
1
dist/providers/tts/ttsProviderFactory.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ttsProviderFactory.js","sourceRoot":"","sources":["../../../src/providers/tts/ttsProviderFactory.ts"],"names":[],"mappings":";;;AAEA,2DAAwD;AACxD,mEAAgE;AAChE,qEAAkE;AAElE;;GAEG;AACH,MAAa,kBAAkB;IAC7B,MAAM,CAAC,WAAW,CAAC,MAAc;QAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC;QACxC,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAEzD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,iBAAiB,YAAY,mBAAmB,CAAC,CAAC;QACpE,CAAC;QAED,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,QAAQ;gBACX,OAAO,IAAI,qCAAiB,CAAC,cAAc,CAAC,CAAC;YAC/C,KAAK,YAAY;gBACf,OAAO,IAAI,6CAAqB,CAAC,cAAc,CAAC,CAAC;YACnD,KAAK,QAAQ;gBACX,OAAO,IAAI,+CAAsB,CAAC,cAAc,CAAC,CAAC;YACpD,2BAA2B;YAC3B;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,YAAY,oBAAoB,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;CACF;AArBD,gDAqBC"}
|
||||
33
dist/providers/vision/geminiVisionProvider.d.ts
vendored
Normal file
33
dist/providers/vision/geminiVisionProvider.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { VisionProvider, VisionProviderConfig, VisionResult, BatchContext } from '../../interfaces';
|
||||
/**
|
||||
* Google Gemini Vision Provider Implementation
|
||||
*/
|
||||
export declare class GeminiVisionProvider implements VisionProvider {
|
||||
private config;
|
||||
private genAI;
|
||||
private model;
|
||||
constructor(config: VisionProviderConfig);
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeImage(imagePath: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Compare two images and describe the differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
compareImages(image1Path: string, image2Path: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeBatch(imagePaths: string[], lastBatchContext: BatchContext, prompt: string): Promise<VisionResult>;
|
||||
}
|
||||
162
dist/providers/vision/geminiVisionProvider.js
vendored
Normal file
162
dist/providers/vision/geminiVisionProvider.js
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GeminiVisionProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const generative_ai_1 = require("@google/generative-ai");
|
||||
/**
|
||||
* Google Gemini Vision Provider Implementation
|
||||
*/
|
||||
class GeminiVisionProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.genAI = new generative_ai_1.GoogleGenerativeAI(config.apiKey);
|
||||
this.model = this.genAI.getGenerativeModel({ model: config.model });
|
||||
}
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeImage(imagePath, prompt) {
|
||||
try {
|
||||
const imageData = fs_1.default.readFileSync(imagePath);
|
||||
const mimeType = 'image/jpeg'; // Assuming JPEG, could be detected based on file extension
|
||||
// Create a file part for the image
|
||||
const imagePart = {
|
||||
inlineData: {
|
||||
data: imageData.toString('base64'),
|
||||
mimeType
|
||||
}
|
||||
};
|
||||
// Generate content using Gemini
|
||||
const result = await this.model.generateContent([prompt, imagePart]);
|
||||
const response = await result.response;
|
||||
const text = response.text();
|
||||
// Gemini doesn't provide token usage information in the same way as OpenAI
|
||||
// We'll estimate based on prompt length and response length
|
||||
const inputTokens = Math.ceil(prompt.length / 4) + 1000; // rough estimate for image
|
||||
const outputTokens = Math.ceil(text.length / 4);
|
||||
return {
|
||||
description: text,
|
||||
usage: {
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
totalTokens: inputTokens + outputTokens
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error describing image with Gemini:", error);
|
||||
return {
|
||||
description: "Unable to describe this image.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compare two images and describe the differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async compareImages(image1Path, image2Path, prompt) {
|
||||
try {
|
||||
const image1Data = fs_1.default.readFileSync(image1Path);
|
||||
const image2Data = fs_1.default.readFileSync(image2Path);
|
||||
const mimeType = 'image/jpeg'; // Assuming JPEG, could be detected based on file extension
|
||||
// Create file parts for both images
|
||||
const image1Part = {
|
||||
inlineData: {
|
||||
data: image1Data.toString('base64'),
|
||||
mimeType
|
||||
}
|
||||
};
|
||||
const image2Part = {
|
||||
inlineData: {
|
||||
data: image2Data.toString('base64'),
|
||||
mimeType
|
||||
}
|
||||
};
|
||||
// Generate content using Gemini with both images
|
||||
const result = await this.model.generateContent([prompt, image1Part, image2Part]);
|
||||
const response = await result.response;
|
||||
const text = response.text();
|
||||
// Estimate token usage
|
||||
const inputTokens = Math.ceil(prompt.length / 4) + 2000; // rough estimate for two images
|
||||
const outputTokens = Math.ceil(text.length / 4);
|
||||
return {
|
||||
description: text,
|
||||
usage: {
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
totalTokens: inputTokens + outputTokens
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error comparing images with Gemini:", error);
|
||||
return {
|
||||
description: "Unable to describe the differences between these images.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeBatch(imagePaths, lastBatchContext, prompt) {
|
||||
try {
|
||||
// Create a prompt that includes context from the last batch if available
|
||||
let contextualPrompt = prompt;
|
||||
if (lastBatchContext && lastBatchContext.lastDescription) {
|
||||
contextualPrompt = `Previous batch summary: ${lastBatchContext.lastDescription}\n\n${prompt}`;
|
||||
}
|
||||
// Create content parts array starting with the prompt
|
||||
const contentParts = [contextualPrompt];
|
||||
// Add all images to the content parts
|
||||
for (const imagePath of imagePaths) {
|
||||
const imageData = fs_1.default.readFileSync(imagePath);
|
||||
const mimeType = 'image/jpeg'; // Assuming JPEG, could be detected based on file extension
|
||||
contentParts.push({
|
||||
inlineData: {
|
||||
data: imageData.toString('base64'),
|
||||
mimeType
|
||||
}
|
||||
});
|
||||
}
|
||||
// Generate content using Gemini with all images
|
||||
const result = await this.model.generateContent(contentParts);
|
||||
const response = await result.response;
|
||||
const text = response.text();
|
||||
// Estimate token usage
|
||||
const inputTokens = Math.ceil(contextualPrompt.length / 4) + (1000 * imagePaths.length); // rough estimate
|
||||
const outputTokens = Math.ceil(text.length / 4);
|
||||
return {
|
||||
description: text,
|
||||
usage: {
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
totalTokens: inputTokens + outputTokens
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error describing batch of images with Gemini:", error);
|
||||
return {
|
||||
description: "Unable to describe this batch of images.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.GeminiVisionProvider = GeminiVisionProvider;
|
||||
//# sourceMappingURL=geminiVisionProvider.js.map
|
||||
1
dist/providers/vision/geminiVisionProvider.js.map
vendored
Normal file
1
dist/providers/vision/geminiVisionProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"geminiVisionProvider.js","sourceRoot":"","sources":["../../../src/providers/vision/geminiVisionProvider.ts"],"names":[],"mappings":"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"}
|
||||
5
dist/providers/vision/index.d.ts
vendored
Normal file
5
dist/providers/vision/index.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './visionProviderFactory';
|
||||
export * from './openAIVisionProvider';
|
||||
export * from './geminiVisionProvider';
|
||||
export * from './ollamaVisionProvider';
|
||||
export * from './openRouterVisionProvider';
|
||||
22
dist/providers/vision/index.js
vendored
Normal file
22
dist/providers/vision/index.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./visionProviderFactory"), exports);
|
||||
__exportStar(require("./openAIVisionProvider"), exports);
|
||||
__exportStar(require("./geminiVisionProvider"), exports);
|
||||
__exportStar(require("./ollamaVisionProvider"), exports);
|
||||
__exportStar(require("./openRouterVisionProvider"), exports);
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
dist/providers/vision/index.js.map
vendored
Normal file
1
dist/providers/vision/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/vision/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAwC;AACxC,yDAAuC;AACvC,yDAAuC;AACvC,yDAAuC;AACvC,6DAA2C"}
|
||||
33
dist/providers/vision/ollamaVisionProvider.d.ts
vendored
Normal file
33
dist/providers/vision/ollamaVisionProvider.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { VisionProvider, VisionProviderConfig, VisionResult, BatchContext } from '../../interfaces';
|
||||
/**
|
||||
* Ollama Vision Provider Implementation
|
||||
* See: https://github.com/ollama/ollama/blob/main/docs/api.md
|
||||
*/
|
||||
export declare class OllamaVisionProvider implements VisionProvider {
|
||||
private config;
|
||||
private axiosInstance;
|
||||
constructor(config: VisionProviderConfig);
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeImage(imagePath: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Compare two images and describe differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
compareImages(image1Path: string, image2Path: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch (optional)
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeBatch(imagePaths: string[], lastBatchContext: BatchContext, prompt: string): Promise<VisionResult>;
|
||||
}
|
||||
141
dist/providers/vision/ollamaVisionProvider.js
vendored
Normal file
141
dist/providers/vision/ollamaVisionProvider.js
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OllamaVisionProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
/**
|
||||
* Ollama Vision Provider Implementation
|
||||
* See: https://github.com/ollama/ollama/blob/main/docs/api.md
|
||||
*/
|
||||
class OllamaVisionProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.axiosInstance = axios_1.default.create({
|
||||
baseURL: config.baseUrl || "http://localhost:11434",
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeImage(imagePath, prompt) {
|
||||
try {
|
||||
const imageData = fs_1.default.readFileSync(imagePath);
|
||||
const base64Image = imageData.toString('base64');
|
||||
const response = await this.axiosInstance.post('/api/generate', {
|
||||
model: this.config.model,
|
||||
prompt: prompt,
|
||||
images: [base64Image],
|
||||
stream: false,
|
||||
options: {
|
||||
max_tokens: this.config.maxTokens || 300,
|
||||
temperature: 0.1
|
||||
}
|
||||
});
|
||||
const combinedText = response.data.response || "";
|
||||
return {
|
||||
description: combinedText.trim(),
|
||||
usage: {
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
totalTokens: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Ollama describeImage error:", error);
|
||||
return {
|
||||
description: "Unable to describe this image.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compare two images and describe differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async compareImages(image1Path, image2Path, prompt) {
|
||||
try {
|
||||
const image1Data = fs_1.default.readFileSync(image1Path).toString('base64');
|
||||
const image2Data = fs_1.default.readFileSync(image2Path).toString('base64');
|
||||
const response = await this.axiosInstance.post('/api/generate', {
|
||||
model: this.config.model,
|
||||
prompt: prompt,
|
||||
images: [image1Data, image2Data],
|
||||
stream: false,
|
||||
options: {
|
||||
max_tokens: this.config.maxTokens || 300,
|
||||
temperature: 0.2
|
||||
}
|
||||
});
|
||||
const combinedText = response.data.response || "";
|
||||
return {
|
||||
description: combinedText.trim(),
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Ollama compareImages error:", error);
|
||||
return {
|
||||
description: "Unable to describe the differences.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch (optional)
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeBatch(imagePaths, lastBatchContext, prompt) {
|
||||
try {
|
||||
let userPrompt = prompt;
|
||||
// If there's context, prepend it. This helps maintain a storyline across batches.
|
||||
if (lastBatchContext && lastBatchContext.lastDescription) {
|
||||
userPrompt = `Previous batch summary: ${lastBatchContext.lastDescription}\n\n${prompt}`;
|
||||
}
|
||||
// Convert images to base64
|
||||
const imagesBase64 = imagePaths.map(fp => {
|
||||
const imageData = fs_1.default.readFileSync(fp);
|
||||
return imageData.toString('base64');
|
||||
});
|
||||
const response = await this.axiosInstance.post('/api/generate', {
|
||||
model: this.config.model,
|
||||
prompt: userPrompt,
|
||||
images: imagesBase64,
|
||||
stream: false,
|
||||
options: {
|
||||
max_tokens: this.config.maxTokens || 300,
|
||||
temperature: 0.2
|
||||
}
|
||||
}, {
|
||||
timeout: 120000 // Timeout in milliseconds, e.g., 5000 ms = 5 seconds
|
||||
});
|
||||
const combinedText = response.data.response || "";
|
||||
return {
|
||||
description: combinedText.trim(),
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Ollama describeBatch error:", error);
|
||||
return {
|
||||
description: "Unable to describe this batch of images.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.OllamaVisionProvider = OllamaVisionProvider;
|
||||
//# sourceMappingURL=ollamaVisionProvider.js.map
|
||||
1
dist/providers/vision/ollamaVisionProvider.js.map
vendored
Normal file
1
dist/providers/vision/ollamaVisionProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ollamaVisionProvider.js","sourceRoot":"","sources":["../../../src/providers/vision/ollamaVisionProvider.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,kDAA6C;AAG7C;;;GAGG;AACH,MAAa,oBAAoB;IAI/B,YAAY,MAA4B;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,eAAK,CAAC,MAAM,CAAC;YAChC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,wBAAwB;YACnD,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB,EAAE,MAAc;QACnD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAEjD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE;gBAC9D,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBACxB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,CAAC,WAAW,CAAC;gBACrB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG;oBACxC,WAAW,EAAE,GAAG;iBACjB;aACF,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YAClD,OAAO;gBACL,WAAW,EAAE,YAAY,CAAC,IAAI,EAAE;gBAChC,KAAK,EAAE;oBACL,WAAW,EAAE,CAAC;oBACd,YAAY,EAAE,CAAC;oBACf,WAAW,EAAE,CAAC;iBACf;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,OAAO;gBACL,WAAW,EAAE,gCAAgC;gBAC7C,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,aAAa,CAAC,UAAkB,EAAE,UAAkB,EAAE,MAAc;QACxE,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAClE,MAAM,UAAU,GAAG,YAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAElE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE;gBAC9D,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBACxB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;gBAChC,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG;oBACxC,WAAW,EAAE,GAAG;iBACjB;aACF,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YAClD,OAAO;gBACL,WAAW,EAAE,YAAY,CAAC,IAAI,EAAE;gBAChC,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,OAAO;gBACL,WAAW,EAAE,qCAAqC;gBAClD,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,aAAa,CACjB,UAAoB,EACpB,gBAA8B,EAC9B,MAAc;QAEd,IAAI,CAAC;YACH,IAAI,UAAU,GAAG,MAAM,CAAC;YAExB,kFAAkF;YAClF,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,eAAe,EAAE,CAAC;gBACzD,UAAU,GAAG,2BAA2B,gBAAgB,CAAC,eAAe,OAAO,MAAM,EAAE,CAAC;YAC1F,CAAC;YAED,2BAA2B;YAC3B,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBACvC,MAAM,SAAS,GAAG,YAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;gBACtC,OAAO,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE;gBAC9D,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;gBACxB,MAAM,EAAE,UAAU;gBAClB,MAAM,EAAE,YAAY;gBACpB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE;oBACP,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG;oBACxC,WAAW,EAAE,GAAG;iBACjB;aACF,EAAE;gBACD,OAAO,EAAE,MAAM,CAAC,qDAAqD;aACtE,CAAC,CAAC;YAEH,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;YAElD,OAAO;gBACL,WAAW,EAAE,YAAY,CAAC,IAAI,EAAE;gBAChC,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACpD,OAAO;gBACL,WAAW,EAAE,0CAA0C;gBACvD,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA9ID,oDA8IC"}
|
||||
32
dist/providers/vision/openAIVisionProvider.d.ts
vendored
Normal file
32
dist/providers/vision/openAIVisionProvider.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { VisionProvider, VisionProviderConfig, VisionResult, BatchContext } from '../../interfaces';
|
||||
/**
|
||||
* OpenAI Vision Provider Implementation
|
||||
*/
|
||||
export declare class OpenAIVisionProvider implements VisionProvider {
|
||||
private config;
|
||||
private openai;
|
||||
constructor(config: VisionProviderConfig);
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeImage(imagePath: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Compare two images and describe the differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
compareImages(image1Path: string, image2Path: string, prompt: string): Promise<VisionResult>;
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
describeBatch(imagePaths: string[], lastBatchContext: BatchContext, prompt: string): Promise<VisionResult>;
|
||||
}
|
||||
182
dist/providers/vision/openAIVisionProvider.js
vendored
Normal file
182
dist/providers/vision/openAIVisionProvider.js
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OpenAIVisionProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const openai_1 = require("openai");
|
||||
/**
|
||||
* OpenAI Vision Provider Implementation
|
||||
*/
|
||||
class OpenAIVisionProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.openai = new openai_1.OpenAI({
|
||||
apiKey: config.apiKey,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Describe a single image
|
||||
* @param imagePath - Path to the image file
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeImage(imagePath, prompt) {
|
||||
try {
|
||||
const imageData = fs_1.default.readFileSync(imagePath);
|
||||
const base64Image = imageData.toString('base64');
|
||||
const response = await this.openai.chat.completions.create({
|
||||
model: this.config.model,
|
||||
temperature: 0.1,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: prompt },
|
||||
{
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64Image}`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_completion_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
return {
|
||||
description: response.choices[0].message.content?.trim() || "No description generated.",
|
||||
usage: {
|
||||
inputTokens: response.usage?.prompt_tokens || 0,
|
||||
outputTokens: response.usage?.completion_tokens || 0,
|
||||
totalTokens: response.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error describing image:", error);
|
||||
return {
|
||||
description: "Unable to describe this image.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compare two images and describe the differences
|
||||
* @param image1Path - Path to the first image
|
||||
* @param image2Path - Path to the second image
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async compareImages(image1Path, image2Path, prompt) {
|
||||
try {
|
||||
const image1Data = fs_1.default.readFileSync(image1Path);
|
||||
const image2Data = fs_1.default.readFileSync(image2Path);
|
||||
const base64Image1 = image1Data.toString('base64');
|
||||
const base64Image2 = image2Data.toString('base64');
|
||||
const response = await this.openai.chat.completions.create({
|
||||
model: this.config.model,
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: prompt },
|
||||
{
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64Image1}`
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64Image2}`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_completion_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
return {
|
||||
description: response.choices[0].message.content?.trim() || "No description generated.",
|
||||
usage: {
|
||||
inputTokens: response.usage?.prompt_tokens || 0,
|
||||
outputTokens: response.usage?.completion_tokens || 0,
|
||||
totalTokens: response.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error comparing images:", error);
|
||||
return {
|
||||
description: "Unable to describe the differences between these images.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Describe a batch of images
|
||||
* @param imagePaths - Array of paths to the images
|
||||
* @param lastBatchContext - Context from the previous batch
|
||||
* @param prompt - Prompt for the AI
|
||||
* @returns Description and usage stats
|
||||
*/
|
||||
async describeBatch(imagePaths, lastBatchContext, prompt) {
|
||||
try {
|
||||
// Convert images to base64
|
||||
const imagesBase64 = imagePaths.map(fp => {
|
||||
const imageData = fs_1.default.readFileSync(fp);
|
||||
return imageData.toString('base64');
|
||||
});
|
||||
// Build the messages array for the chat completion
|
||||
const messages = [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: prompt }
|
||||
]
|
||||
}
|
||||
];
|
||||
// If we have some text context from the last batch, inject that as well
|
||||
if (lastBatchContext && lastBatchContext.lastDescription) {
|
||||
messages.unshift({
|
||||
role: "system",
|
||||
content: `Previous batch summary: ${lastBatchContext.lastDescription}`
|
||||
});
|
||||
}
|
||||
// Append each image in the new batch
|
||||
imagesBase64.forEach(base64 => {
|
||||
messages[messages.length - 1].content.push({
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64}`
|
||||
}
|
||||
});
|
||||
});
|
||||
const response = await this.openai.chat.completions.create({
|
||||
model: this.config.model,
|
||||
messages,
|
||||
max_completion_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
return {
|
||||
description: response.choices[0].message.content?.trim() || "No description generated.",
|
||||
usage: {
|
||||
inputTokens: response.usage?.prompt_tokens || 0,
|
||||
outputTokens: response.usage?.completion_tokens || 0,
|
||||
totalTokens: response.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Error describing batch of images:", error);
|
||||
return {
|
||||
description: "Unable to describe this batch of images.",
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.OpenAIVisionProvider = OpenAIVisionProvider;
|
||||
//# sourceMappingURL=openAIVisionProvider.js.map
|
||||
1
dist/providers/vision/openAIVisionProvider.js.map
vendored
Normal file
1
dist/providers/vision/openAIVisionProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"openAIVisionProvider.js","sourceRoot":"","sources":["../../../src/providers/vision/openAIVisionProvider.ts"],"names":[],"mappings":"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"}
|
||||
9
dist/providers/vision/openRouterVisionProvider.d.ts
vendored
Normal file
9
dist/providers/vision/openRouterVisionProvider.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { VisionProvider, VisionProviderConfig, VisionResult, BatchContext } from '../../interfaces';
|
||||
export declare class OpenRouterVisionProvider implements VisionProvider {
|
||||
private config;
|
||||
private axiosInstance;
|
||||
constructor(config: VisionProviderConfig);
|
||||
describeImage(imagePath: string, prompt: string): Promise<VisionResult>;
|
||||
compareImages(image1Path: string, image2Path: string, prompt: string): Promise<VisionResult>;
|
||||
describeBatch(imagePaths: string[], lastBatchContext: BatchContext, prompt: string): Promise<VisionResult>;
|
||||
}
|
||||
161
dist/providers/vision/openRouterVisionProvider.js
vendored
Normal file
161
dist/providers/vision/openRouterVisionProvider.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OpenRouterVisionProvider = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
class OpenRouterVisionProvider {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.axiosInstance = axios_1.default.create({
|
||||
baseURL: config.baseUrl || 'https://openrouter.ai/api/v1',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${config.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'HTTP-Referer': 'https://github.com/anomalyco/aidio-description',
|
||||
'X-Title': 'Aidio Description Generator'
|
||||
}
|
||||
});
|
||||
}
|
||||
async describeImage(imagePath, prompt) {
|
||||
try {
|
||||
const imageData = fs_1.default.readFileSync(imagePath);
|
||||
const base64Image = imageData.toString('base64');
|
||||
const response = await this.axiosInstance.post('/chat/completions', {
|
||||
model: this.config.model,
|
||||
temperature: 0.1,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: prompt },
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64Image}`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
const data = response.data;
|
||||
return {
|
||||
description: data.choices?.[0]?.message?.content?.trim() || 'No description generated.',
|
||||
usage: {
|
||||
inputTokens: data.usage?.prompt_tokens || 0,
|
||||
outputTokens: data.usage?.completion_tokens || 0,
|
||||
totalTokens: data.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('OpenRouter describeImage error:', error.response?.data || error.message);
|
||||
return {
|
||||
description: 'Unable to describe this image.',
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
async compareImages(image1Path, image2Path, prompt) {
|
||||
try {
|
||||
const image1Data = fs_1.default.readFileSync(image1Path);
|
||||
const image2Data = fs_1.default.readFileSync(image2Path);
|
||||
const base64Image1 = image1Data.toString('base64');
|
||||
const base64Image2 = image2Data.toString('base64');
|
||||
const response = await this.axiosInstance.post('/chat/completions', {
|
||||
model: this.config.model,
|
||||
temperature: 0.1,
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: prompt },
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: { url: `data:image/jpeg;base64,${base64Image1}` }
|
||||
},
|
||||
{
|
||||
type: 'image_url',
|
||||
image_url: { url: `data:image/jpeg;base64,${base64Image2}` }
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
const data = response.data;
|
||||
return {
|
||||
description: data.choices?.[0]?.message?.content?.trim() || 'No description generated.',
|
||||
usage: {
|
||||
inputTokens: data.usage?.prompt_tokens || 0,
|
||||
outputTokens: data.usage?.completion_tokens || 0,
|
||||
totalTokens: data.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('OpenRouter compareImages error:', error.response?.data || error.message);
|
||||
return {
|
||||
description: 'Unable to describe the differences between these images.',
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
async describeBatch(imagePaths, lastBatchContext, prompt) {
|
||||
try {
|
||||
const imagesBase64 = imagePaths.map(fp => {
|
||||
const imageData = fs_1.default.readFileSync(fp);
|
||||
return imageData.toString('base64');
|
||||
});
|
||||
const messages = [
|
||||
{
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: prompt }
|
||||
]
|
||||
}
|
||||
];
|
||||
if (lastBatchContext && lastBatchContext.lastDescription) {
|
||||
messages.unshift({
|
||||
role: 'system',
|
||||
content: `Previous batch summary: ${lastBatchContext.lastDescription}`
|
||||
});
|
||||
}
|
||||
imagesBase64.forEach(base64 => {
|
||||
messages[messages.length - 1].content.push({
|
||||
type: 'image_url',
|
||||
image_url: {
|
||||
url: `data:image/jpeg;base64,${base64}`
|
||||
}
|
||||
});
|
||||
});
|
||||
const response = await this.axiosInstance.post('/chat/completions', {
|
||||
model: this.config.model,
|
||||
messages,
|
||||
max_tokens: this.config.maxTokens || 300
|
||||
});
|
||||
const data = response.data;
|
||||
return {
|
||||
description: data.choices?.[0]?.message?.content?.trim() || 'No description generated.',
|
||||
usage: {
|
||||
inputTokens: data.usage?.prompt_tokens || 0,
|
||||
outputTokens: data.usage?.completion_tokens || 0,
|
||||
totalTokens: data.usage?.total_tokens || 0
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
console.error('OpenRouter describeBatch error:', error.response?.data || error.message);
|
||||
return {
|
||||
description: 'Unable to describe this batch of images.',
|
||||
usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.OpenRouterVisionProvider = OpenRouterVisionProvider;
|
||||
//# sourceMappingURL=openRouterVisionProvider.js.map
|
||||
1
dist/providers/vision/openRouterVisionProvider.js.map
vendored
Normal file
1
dist/providers/vision/openRouterVisionProvider.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"openRouterVisionProvider.js","sourceRoot":"","sources":["../../../src/providers/vision/openRouterVisionProvider.ts"],"names":[],"mappings":"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"}
|
||||
8
dist/providers/vision/visionProviderFactory.d.ts
vendored
Normal file
8
dist/providers/vision/visionProviderFactory.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { VisionProvider } from '../../interfaces';
|
||||
import { Config } from '../../config/config';
|
||||
/**
|
||||
* Factory for creating vision AI providers
|
||||
*/
|
||||
export declare class VisionProviderFactory {
|
||||
static getProvider(config: Config): VisionProvider;
|
||||
}
|
||||
34
dist/providers/vision/visionProviderFactory.js
vendored
Normal file
34
dist/providers/vision/visionProviderFactory.js
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.VisionProviderFactory = void 0;
|
||||
const openAIVisionProvider_1 = require("./openAIVisionProvider");
|
||||
const geminiVisionProvider_1 = require("./geminiVisionProvider");
|
||||
const ollamaVisionProvider_1 = require("./ollamaVisionProvider");
|
||||
const openRouterVisionProvider_1 = require("./openRouterVisionProvider");
|
||||
/**
|
||||
* Factory for creating vision AI providers
|
||||
*/
|
||||
class VisionProviderFactory {
|
||||
static getProvider(config) {
|
||||
const providerName = config.visionProvider;
|
||||
const providerConfig = config.visionProviders[providerName];
|
||||
if (!providerConfig) {
|
||||
throw new Error(`Vision provider "${providerName}" not configured.`);
|
||||
}
|
||||
switch (providerName) {
|
||||
case 'openai':
|
||||
return new openAIVisionProvider_1.OpenAIVisionProvider(providerConfig);
|
||||
case 'gemini':
|
||||
return new geminiVisionProvider_1.GeminiVisionProvider(providerConfig);
|
||||
case "ollama":
|
||||
return new ollamaVisionProvider_1.OllamaVisionProvider(providerConfig);
|
||||
case 'openrouter':
|
||||
return new openRouterVisionProvider_1.OpenRouterVisionProvider(providerConfig);
|
||||
// Add other providers here
|
||||
default:
|
||||
throw new Error(`Vision provider "${providerName}" not implemented.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.VisionProviderFactory = VisionProviderFactory;
|
||||
//# sourceMappingURL=visionProviderFactory.js.map
|
||||
1
dist/providers/vision/visionProviderFactory.js.map
vendored
Normal file
1
dist/providers/vision/visionProviderFactory.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"visionProviderFactory.js","sourceRoot":"","sources":["../../../src/providers/vision/visionProviderFactory.ts"],"names":[],"mappings":";;;AAEA,iEAA8D;AAC9D,iEAA8D;AAC9D,iEAA8D;AAC9D,yEAAsE;AAEtE;;GAEG;AACH,MAAa,qBAAqB;IAChC,MAAM,CAAC,WAAW,CAAC,MAAc;QAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC;QAC3C,MAAM,cAAc,GAAG,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QAE5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,oBAAoB,YAAY,mBAAmB,CAAC,CAAC;QACvE,CAAC;QAED,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,QAAQ;gBACX,OAAO,IAAI,2CAAoB,CAAC,cAAc,CAAC,CAAC;YAClD,KAAK,QAAQ;gBACX,OAAO,IAAI,2CAAoB,CAAC,cAAc,CAAC,CAAC;YAClD,KAAK,QAAQ;gBACX,OAAO,IAAI,2CAAoB,CAAC,cAAc,CAAC,CAAC;YAClD,KAAK,YAAY;gBACf,OAAO,IAAI,mDAAwB,CAAC,cAAc,CAAC,CAAC;YACtD,2BAA2B;YAC3B;gBACE,MAAM,IAAI,KAAK,CAAC,oBAAoB,YAAY,oBAAoB,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;CACF;AAvBD,sDAuBC"}
|
||||
Reference in New Issue
Block a user