feat: initial commit for MediaGen AI project
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { GeneratedMedia } from '../models/openrouter.models';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class StorageService {
|
||||
private readonly ACTIVE_PROVIDER = 'ai_active_provider';
|
||||
private readonly API_KEY_OPENROUTER = 'openrouter_api_key';
|
||||
private readonly API_KEY_REPLICATE = 'replicate_api_key';
|
||||
private readonly SELECTED_MODEL = 'openrouter_selected_model';
|
||||
private readonly MEDIA_HISTORY = 'openrouter_media_history';
|
||||
|
||||
private readonly DEFAULT_ENV_API_KEY = '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';
|
||||
|
||||
// Cache in-memory per preservare i dataURL dei video ed audio per la sessione corrente
|
||||
private urlCache = new Map<string, string>();
|
||||
|
||||
getActiveProvider(): 'openrouter' | 'replicate' {
|
||||
const p = localStorage.getItem(this.ACTIVE_PROVIDER);
|
||||
return (p === 'replicate') ? 'replicate' : 'openrouter';
|
||||
}
|
||||
|
||||
setActiveProvider(provider: 'openrouter' | 'replicate'): void {
|
||||
localStorage.setItem(this.ACTIVE_PROVIDER, provider);
|
||||
}
|
||||
|
||||
getApiKey(provider?: 'openrouter' | 'replicate'): string {
|
||||
const p = provider || this.getActiveProvider();
|
||||
if (p === 'replicate') {
|
||||
return localStorage.getItem(this.API_KEY_REPLICATE) || '';
|
||||
}
|
||||
return localStorage.getItem(this.API_KEY_OPENROUTER) || this.DEFAULT_ENV_API_KEY;
|
||||
}
|
||||
|
||||
setApiKey(key: string, provider?: 'openrouter' | 'replicate'): void {
|
||||
const p = provider || this.getActiveProvider();
|
||||
if (p === 'replicate') {
|
||||
localStorage.setItem(this.API_KEY_REPLICATE, key.trim());
|
||||
} else {
|
||||
localStorage.setItem(this.API_KEY_OPENROUTER, key.trim());
|
||||
}
|
||||
}
|
||||
|
||||
private readonly REPLICATE_BUDGET = 'replicate_initial_budget';
|
||||
private readonly REPLICATE_USAGE = 'replicate_total_usage';
|
||||
|
||||
getReplicateBudget(): number {
|
||||
const val = localStorage.getItem(this.REPLICATE_BUDGET);
|
||||
return val !== null ? parseFloat(val) : 11.72; // Credito rimanente Replicate
|
||||
}
|
||||
|
||||
setReplicateBudget(budget: number): void {
|
||||
localStorage.setItem(this.REPLICATE_BUDGET, Math.max(0, budget).toString());
|
||||
}
|
||||
|
||||
getReplicateUsage(): number {
|
||||
const val = localStorage.getItem(this.REPLICATE_USAGE);
|
||||
return val ? parseFloat(val) || 0 : 0.07;
|
||||
}
|
||||
|
||||
getReplicateRemainingCredits(): number {
|
||||
const currentRemaining = localStorage.getItem('replicate_remaining_credits');
|
||||
if (currentRemaining !== null) {
|
||||
return Math.max(0, parseFloat(currentRemaining) || 0);
|
||||
}
|
||||
const budget = this.getReplicateBudget();
|
||||
return Math.max(0, budget);
|
||||
}
|
||||
|
||||
setReplicateRemainingCredits(credits: number): void {
|
||||
localStorage.setItem('replicate_remaining_credits', Math.max(0, credits).toString());
|
||||
}
|
||||
|
||||
addReplicateUsage(amount: number): number {
|
||||
const currentUsage = this.getReplicateUsage();
|
||||
const updatedUsage = Math.max(0, currentUsage + amount);
|
||||
localStorage.setItem(this.REPLICATE_USAGE, updatedUsage.toString());
|
||||
|
||||
// Scala direttamente dai crediti rimanenti Replicate
|
||||
const currentRemaining = this.getReplicateRemainingCredits();
|
||||
const updatedRemaining = Math.max(0, currentRemaining - amount);
|
||||
this.setReplicateRemainingCredits(updatedRemaining);
|
||||
|
||||
return updatedUsage;
|
||||
}
|
||||
|
||||
getSelectedModel(): string {
|
||||
return localStorage.getItem(this.SELECTED_MODEL) || 'recraft-ai/recraft-v3';
|
||||
}
|
||||
|
||||
setSelectedModel(model: string): void {
|
||||
localStorage.setItem(this.SELECTED_MODEL, model);
|
||||
}
|
||||
|
||||
getHistory(): GeneratedMedia[] {
|
||||
try {
|
||||
const data = localStorage.getItem(this.MEDIA_HISTORY);
|
||||
const rawList: GeneratedMedia[] = data ? JSON.parse(data) : [];
|
||||
return rawList.map(item => {
|
||||
let costDisplay = item.costDisplay;
|
||||
// Fix per eventuali elementi salvati precedentemente con il tempo in secondi invece del costo in dollari
|
||||
if (costDisplay) {
|
||||
const numMatch = costDisplay.match(/[\d.]+/);
|
||||
if (numMatch && parseFloat(numMatch[0]) > 20) {
|
||||
// Era il tempo di predict in secondi (es. 129s) invece del costo reale
|
||||
const durationEst = 5;
|
||||
costDisplay = `$${(0.067 * durationEst).toFixed(4)}`;
|
||||
}
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
costDisplay: costDisplay || '$0.3350',
|
||||
url: item.url || this.urlCache.get(item.id) || ''
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn('Impossibile leggere lo storico da localStorage', e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
saveMediaItem(item: GeneratedMedia): void {
|
||||
if (item.id && item.url) {
|
||||
this.urlCache.set(item.id, item.url);
|
||||
}
|
||||
|
||||
let history = this.getHistory();
|
||||
|
||||
// Per evitare di superare i 5MB di quota di localStorage, rimuovi la stringa base64 se supera i 50KB nello storage su disco
|
||||
const cleanItem = { ...item };
|
||||
if (cleanItem.url && cleanItem.url.startsWith('data:') && cleanItem.url.length > 50000) {
|
||||
cleanItem.url = '';
|
||||
}
|
||||
|
||||
history.unshift(cleanItem);
|
||||
|
||||
if (history.length > 15) {
|
||||
history = history.slice(0, 15);
|
||||
}
|
||||
|
||||
this.persistHistory(history);
|
||||
}
|
||||
|
||||
private persistHistory(history: GeneratedMedia[]): void {
|
||||
let list = history.map(item => {
|
||||
if (item.url && item.url.startsWith('data:') && item.url.length > 50000) {
|
||||
return { ...item, url: '' };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
while (list.length > 0) {
|
||||
try {
|
||||
localStorage.setItem(this.MEDIA_HISTORY, JSON.stringify(list));
|
||||
return;
|
||||
} catch (e) {
|
||||
list = list.map(item => (item.url && item.url.startsWith('data:') ? { ...item, url: '' } : item));
|
||||
list.pop();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
localStorage.removeItem(this.MEDIA_HISTORY);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
clearHistory(): void {
|
||||
this.urlCache.clear();
|
||||
try {
|
||||
localStorage.removeItem(this.MEDIA_HISTORY);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
deleteItem(id: string): void {
|
||||
this.urlCache.delete(id);
|
||||
const history = this.getHistory().filter(item => item.id !== id);
|
||||
this.persistHistory(history);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user