Add batch API endpoints for cents calculation, client fetches cents from server
This commit is contained in:
parent
c6bb3a12ce
commit
8f332fac52
|
|
@ -581,13 +581,37 @@
|
||||||
// Load from Flask API - get chords and compute graphs client-side
|
// Load from Flask API - get chords and compute graphs client-side
|
||||||
async function loadAllGraphs() {
|
async function loadAllGraphs() {
|
||||||
try {
|
try {
|
||||||
|
// Step 1: Get raw chord data
|
||||||
const response = await fetch("/api/chords");
|
const response = await fetch("/api/chords");
|
||||||
if (!response.ok) throw new Error("API not available");
|
if (!response.ok) throw new Error("API not available");
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// Compute graphs from raw chord data client-side
|
// Step 2: Collect all fractions from all chords
|
||||||
|
const allFractions = [];
|
||||||
|
const chordFractions = []; // Track which fractions belong to which chord
|
||||||
|
|
||||||
|
for (const chord of data.chords) {
|
||||||
|
const fractions = [];
|
||||||
|
for (const pitch of chord) {
|
||||||
|
fractions.push(pitch.fraction || "1");
|
||||||
|
}
|
||||||
|
chordFractions.push(fractions);
|
||||||
|
allFractions.push(...fractions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Batch fetch cents from server (avoid N+1 problem)
|
||||||
|
const centsResponse = await fetch("/api/batch-calculate-cents", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: JSON.stringify({ fractions: allFractions })
|
||||||
|
});
|
||||||
|
const centsData = await centsResponse.json();
|
||||||
|
const allCents = centsData.results.map(r => r.cents);
|
||||||
|
|
||||||
|
// Step 4: Build graphs with cached cents values
|
||||||
|
let centsIndex = 0;
|
||||||
const graphs = data.chords.map((chord, index) => {
|
const graphs = data.chords.map((chord, index) => {
|
||||||
return calculateGraph(chord, index);
|
return calculateGraph(chord, index, () => allCents[centsIndex++]);
|
||||||
});
|
});
|
||||||
|
|
||||||
allGraphsData = {
|
allGraphsData = {
|
||||||
|
|
@ -611,18 +635,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute graph (nodes + edges) from raw chord data - client-side version
|
// Compute graph (nodes + edges) from raw chord data - using API for cents
|
||||||
function calculateGraph(chord, index) {
|
function calculateGraph(chord, index, getNextCent) {
|
||||||
if (!chord) return { nodes: [], edges: [] };
|
if (!chord) return { nodes: [], edges: [] };
|
||||||
|
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
const dims = [2, 3, 5, 7];
|
const dims = [2, 3, 5, 7];
|
||||||
|
|
||||||
// Calculate cents for each pitch
|
// Calculate cents for each pitch (fetched from server)
|
||||||
for (let i = 0; i < chord.length; i++) {
|
for (let i = 0; i < chord.length; i++) {
|
||||||
const pitch = chord[i];
|
const pitch = chord[i];
|
||||||
const fraction = parseFraction(pitch.fraction || "1");
|
const cents = getNextCent();
|
||||||
const cents = fraction > 0 ? 1200 * Math.log2(fraction) : 0;
|
|
||||||
|
|
||||||
nodes.push({
|
nodes.push({
|
||||||
id: i,
|
id: i,
|
||||||
|
|
@ -689,18 +712,6 @@
|
||||||
return { nodes, edges, index };
|
return { nodes, edges, index };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse fraction string to number
|
|
||||||
function parseFraction(fracStr) {
|
|
||||||
if (typeof fracStr === 'number') return fracStr;
|
|
||||||
if (!fracStr) return 1;
|
|
||||||
|
|
||||||
if (fracStr.includes('/')) {
|
|
||||||
const [num, den] = fracStr.split('/').map(Number);
|
|
||||||
return num / den;
|
|
||||||
}
|
|
||||||
return Number(fracStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update UI elements
|
// Update UI elements
|
||||||
function updateUI() {
|
function updateUI() {
|
||||||
hasPrev = currentIndex > 0;
|
hasPrev = currentIndex > 0;
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,45 @@ def load_file():
|
||||||
return jsonify({"error": f"Invalid JSON in: {filepath}"}), 400
|
return jsonify({"error": f"Invalid JSON in: {filepath}"}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/parse-fraction", methods=["POST"])
|
||||||
|
def parse_fraction_api():
|
||||||
|
"""Parse a fraction string to float."""
|
||||||
|
data = request.json
|
||||||
|
fraction = data.get("fraction", "1")
|
||||||
|
try:
|
||||||
|
value = parse_fraction(fraction)
|
||||||
|
return jsonify({"fraction": fraction, "value": value})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/calculate-cents", methods=["POST"])
|
||||||
|
def calculate_cents_api():
|
||||||
|
"""Calculate cents from fraction string."""
|
||||||
|
data = request.json
|
||||||
|
fraction = data.get("fraction", "1")
|
||||||
|
try:
|
||||||
|
cents = calculate_cents(fraction)
|
||||||
|
return jsonify({"fraction": fraction, "cents": cents})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/batch-calculate-cents", methods=["POST"])
|
||||||
|
def batch_calculate_cents_api():
|
||||||
|
"""Calculate cents for multiple fractions at once."""
|
||||||
|
data = request.json
|
||||||
|
fractions = data.get("fractions", [])
|
||||||
|
try:
|
||||||
|
results = []
|
||||||
|
for fraction in fractions:
|
||||||
|
cents = calculate_cents(fraction)
|
||||||
|
results.append({"fraction": fraction, "cents": cents})
|
||||||
|
return jsonify({"results": results})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 400
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Starting Path Navigator server...")
|
print("Starting Path Navigator server...")
|
||||||
print(f"Loading chords from: {get_chords_file()}")
|
print(f"Loading chords from: {get_chords_file()}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue