Spaces:
Sleeping
Sleeping
File size: 3,934 Bytes
6678fa1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /**
* HuggingFace Spaces API Client
*
* Calls the ML API hosted on HuggingFace Spaces instead of local Python.
* This enables deployment on platforms without Python support.
*
* Set HF_SPACES_URL environment variable to your Space URL:
* HF_SPACES_URL=https://username-space-name.hf.space
*/
import FormData from 'form-data';
import fs from 'fs';
import path from 'path';
const HF_SPACES_URL = process.env.HF_SPACES_URL;
export function isHfSpacesEnabled(): boolean {
return !!HF_SPACES_URL;
}
export function getSpacesUrl(): string | undefined {
return HF_SPACES_URL;
}
interface EmbeddingResult {
success: boolean;
embedding?: number[];
dimension?: number;
error?: string;
}
interface ChunkResult {
success: boolean;
total_duration?: number;
chunk_count?: number;
chunks?: Array<{
start_time: number;
end_time: number;
embedding: number[];
}>;
error?: string;
}
interface SearchResult {
matches: Array<{
score: number;
trackId: string;
title: string;
artist: string;
distinctiveness?: number;
}>;
mean_similarity?: number;
}
/**
* Extract MERT embedding via HuggingFace Spaces API
*/
export async function extractEmbedding(audioPath: string): Promise<EmbeddingResult> {
if (!HF_SPACES_URL) {
return { success: false, error: "HF_SPACES_URL not configured" };
}
try {
const formData = new FormData();
formData.append('audio_file', fs.createReadStream(audioPath));
const response = await fetch(`${HF_SPACES_URL}/api/extract_embedding`, {
method: 'POST',
body: formData as any,
});
const text = await response.text();
return JSON.parse(text);
} catch (error) {
return { success: false, error: String(error) };
}
}
/**
* Extract chunk embeddings via HuggingFace Spaces API
*/
export async function extractChunks(
audioPath: string,
chunkDuration: number = 10.0,
overlap: number = 5.0
): Promise<ChunkResult> {
if (!HF_SPACES_URL) {
return { success: false, error: "HF_SPACES_URL not configured" };
}
try {
const formData = new FormData();
formData.append('audio_file', fs.createReadStream(audioPath));
formData.append('chunk_duration', String(chunkDuration));
formData.append('overlap', String(overlap));
const response = await fetch(`${HF_SPACES_URL}/api/extract_chunks`, {
method: 'POST',
body: formData as any,
});
const text = await response.text();
return JSON.parse(text);
} catch (error) {
return { success: false, error: String(error) };
}
}
/**
* Search for similar tracks via HuggingFace Spaces API
*/
export async function searchSimilar(
queryEmbedding: number[],
indexData: { entries: Array<{ trackId: string; title: string; artist: string; embedding: number[] }> },
k: number = 5
): Promise<SearchResult> {
if (!HF_SPACES_URL) {
return { matches: [] };
}
try {
const formData = new FormData();
formData.append('query_embedding_json', JSON.stringify(queryEmbedding));
formData.append('index_json', JSON.stringify(indexData));
formData.append('k', String(k));
const response = await fetch(`${HF_SPACES_URL}/api/search`, {
method: 'POST',
body: formData as any,
});
const text = await response.text();
return JSON.parse(text);
} catch (error) {
return { matches: [] };
}
}
/**
* Check if HuggingFace Spaces API is healthy
*/
export async function checkHealth(): Promise<{ ok: boolean; details?: any }> {
if (!HF_SPACES_URL) {
return { ok: false, details: { error: "HF_SPACES_URL not configured" } };
}
try {
const response = await fetch(`${HF_SPACES_URL}/api/health`, {
method: 'POST',
});
const text = await response.text();
const data = JSON.parse(text);
return { ok: data.status === 'ok', details: data };
} catch (error) {
return { ok: false, details: { error: String(error) } };
}
}
|