fix: đã sửa lỗi AI gửi prompt và thêm các tool để AI thực hiện
This commit is contained in:
@@ -7004,14 +7004,21 @@ const App = () => {
|
||||
dawContext,
|
||||
tools: window.AIGateway.DEFAULT_TOOLS
|
||||
});
|
||||
if (result.textResponse) {
|
||||
const hasText = !!result.textResponse;
|
||||
const hasCalls = result.functionCalls && result.functionCalls.length > 0;
|
||||
if (hasText) {
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'status',
|
||||
text: ` AI: ${result.textResponse}`,
|
||||
text: ` AI: ${result.textResponse.slice(0, 500)}`,
|
||||
time: Date.now()
|
||||
}]);
|
||||
}
|
||||
if (result.functionCalls && result.functionCalls.length > 0) {
|
||||
if (hasCalls) {
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'info',
|
||||
text: ` Gọi ${result.functionCalls.length} lệnh...`,
|
||||
time: Date.now()
|
||||
}]);
|
||||
for (const fc of result.functionCalls) {
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'info',
|
||||
@@ -7034,9 +7041,22 @@ const App = () => {
|
||||
time: Date.now()
|
||||
}]);
|
||||
}
|
||||
} else {
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'error',
|
||||
text: ` ❌ ${fc.name}: DAWCommandDispatcher not available`,
|
||||
time: Date.now()
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasText && !hasCalls) {
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'error',
|
||||
text: ` AI không trả về lệnh hoặc text. Kiểm tra provider/model có hỗ trợ function calling.`,
|
||||
time: Date.now()
|
||||
}]);
|
||||
}
|
||||
setAiActionLog(prev => [...prev, {
|
||||
type: 'status',
|
||||
text: ` Hoàn tất.`,
|
||||
@@ -7224,7 +7244,9 @@ const App = () => {
|
||||
},
|
||||
addClip: args => {
|
||||
const trackId = args.track_id || selectedTrackId;
|
||||
const startTime = args.start_time || args.start_bar ? args.start_bar * (60 / parseInt(bpm || 120)) * 4 : currentTime;
|
||||
const barDur = 60 / parseInt(bpm || 120) * 4;
|
||||
let startTime;
|
||||
if (args.start_time !== undefined && args.start_time !== null) startTime = args.start_time;else if (args.start_bar !== undefined && args.start_bar !== null) startTime = args.start_bar * barDur;else startTime = currentTime;
|
||||
const track = tracks.find(t => t.id === trackId);
|
||||
if (!track) return {
|
||||
success: false,
|
||||
@@ -7232,7 +7254,8 @@ const App = () => {
|
||||
};
|
||||
const ctx = getAudioContext();
|
||||
const sr = 44100;
|
||||
const duration = args.duration_seconds || args.length_bars ? args.length_bars * (60 / parseInt(bpm || 120)) * 4 : 2;
|
||||
let duration;
|
||||
if (args.duration_seconds !== undefined && args.duration_seconds !== null) duration = args.duration_seconds;else if (args.length_bars !== undefined && args.length_bars !== null) duration = args.length_bars * barDur;else duration = 2;
|
||||
const buffer = ctx.createBuffer(1, Math.floor(sr * duration), sr);
|
||||
const data = buffer.getChannelData(0);
|
||||
for (let i = 0; i < data.length; i++) data[i] = 0;
|
||||
@@ -7395,6 +7418,89 @@ const App = () => {
|
||||
error: `Unknown action: ${action}`
|
||||
};
|
||||
},
|
||||
renameTrack: args => {
|
||||
const tid = args.track_id || selectedTrackId;
|
||||
const name = args.name;
|
||||
if (!tid) return {
|
||||
success: false,
|
||||
error: 'No track_id provided'
|
||||
};
|
||||
if (!name) return {
|
||||
success: false,
|
||||
error: 'No name provided'
|
||||
};
|
||||
updateTrackName(tid, name);
|
||||
return {
|
||||
success: true,
|
||||
trackId: tid,
|
||||
name
|
||||
};
|
||||
},
|
||||
setSelection: args => {
|
||||
const barDur = 60 / parseInt(bpm || 120) * 4;
|
||||
let start, end;
|
||||
if (args.start_time !== undefined && args.start_time !== null) start = args.start_time;else if (args.start_bar !== undefined && args.start_bar !== null) start = args.start_bar * barDur;else start = currentTime;
|
||||
if (args.end_time !== undefined && args.end_time !== null) end = args.end_time;else if (args.length_bars !== undefined && args.length_bars !== null) end = start + args.length_bars * barDur;else if (args.end_bar !== undefined && args.end_bar !== null) end = args.end_bar * barDur;else end = start + barDur;
|
||||
clearLocalSelection();
|
||||
setSelectionMode('global');
|
||||
setSelectionStart(start);
|
||||
setSelectionEnd(end);
|
||||
return {
|
||||
success: true,
|
||||
start: parseFloat(start.toFixed(3)),
|
||||
end: parseFloat(end.toFixed(3)),
|
||||
length: parseFloat((end - start).toFixed(3))
|
||||
};
|
||||
},
|
||||
scanTrack: args => {
|
||||
const tid = args.track_id || selectedTrackId;
|
||||
const track = tracks.find(t => t.id === tid);
|
||||
if (!track) return {
|
||||
success: false,
|
||||
error: 'Track not found'
|
||||
};
|
||||
if (!track.buffer) return {
|
||||
success: false,
|
||||
error: 'Track has no audio buffer. Load audio first.'
|
||||
};
|
||||
const buffer = track.buffer;
|
||||
const data = buffer.getChannelData(0);
|
||||
const sr = buffer.sampleRate;
|
||||
const channels = buffer.numberOfChannels;
|
||||
const duration = buffer.duration;
|
||||
const totalSamples = buffer.length;
|
||||
const windowSize = Math.min(sr * 3, data.length);
|
||||
let detectedBPM = 0;
|
||||
if (windowSize > sr) {
|
||||
let maxCorr = 0;
|
||||
for (let lag = Math.floor(sr * 0.3); lag <= Math.floor(sr * 2.0); lag++) {
|
||||
let corr = 0;
|
||||
const step = 4;
|
||||
for (let i = 0; i < windowSize && i + lag < data.length; i += step) corr += data[i] * data[i + lag];
|
||||
corr /= windowSize / step;
|
||||
if (corr > maxCorr) {
|
||||
maxCorr = corr;
|
||||
detectedBPM = 60 / (lag / sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
detectedBPM = Math.round(Math.min(300, Math.max(30, detectedBPM)));
|
||||
const bitDepth = 16;
|
||||
const bitrate = Math.round(sr * channels * bitDepth / 1000);
|
||||
return {
|
||||
success: true,
|
||||
trackId: tid,
|
||||
trackName: track.name,
|
||||
bpm: detectedBPM,
|
||||
sampleRate: sr,
|
||||
channels,
|
||||
duration: parseFloat(duration.toFixed(3)),
|
||||
totalSamples,
|
||||
bitDepth,
|
||||
bitrateKbps: bitrate,
|
||||
hasAudio: true
|
||||
};
|
||||
},
|
||||
setBpm: args => {
|
||||
const bpmVal = args.bpm || args.tempo || 120;
|
||||
setBpm(String(bpmVal));
|
||||
@@ -7404,11 +7510,13 @@ const App = () => {
|
||||
};
|
||||
},
|
||||
setPlayhead: args => {
|
||||
const time = args.time ?? args.position ?? 0;
|
||||
const barDur = 60 / parseInt(bpm || 120) * 4;
|
||||
let time;
|
||||
if (args.time !== undefined && args.time !== null) time = args.time;else if (args.bar !== undefined && args.bar !== null) time = args.bar * barDur;else time = 0;
|
||||
handlePlayheadSet(time);
|
||||
return {
|
||||
success: true,
|
||||
time
|
||||
time: parseFloat(time.toFixed(3))
|
||||
};
|
||||
},
|
||||
addMarker: args => {
|
||||
|
||||
Reference in New Issue
Block a user