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:
2026-07-22 09:23:05 +07:00
parent e0b849fdf2
commit 022fbb3351
6 changed files with 385 additions and 44 deletions
+93 -7
View File
@@ -3056,6 +3056,9 @@ const App = () => {
isRunning: false,
});
const [aiPrompt, setAiPrompt] = useState('');
const [promptHistory, setPromptHistory] = useState([]);
const [promptHistIdx, setPromptHistIdx] = useState(-1);
const promptHistRef = useRef([]);
const [aiProvider, setAiProvider] = useState('OpenAI');
const [aiModel, setAiModel] = useState('GPT-4o');
const [aiActionLog, setAiActionLog] = useState([]);
@@ -6993,10 +6996,13 @@ const App = () => {
dawContext,
tools: window.AIGateway.DEFAULT_TOOLS
});
if (result.textResponse) {
setAiActionLog(prev => [...prev, { type: 'status', text: ` AI: ${result.textResponse}`, time: Date.now() }]);
const hasText = !!result.textResponse;
const hasCalls = result.functionCalls && result.functionCalls.length > 0;
if (hasText) {
setAiActionLog(prev => [...prev, { type: 'status', 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', text: ` Gọi lệnh: ${fc.name}(${JSON.stringify(fc.arguments)})`, time: Date.now() }]);
const cmdName = fc.name.toUpperCase();
@@ -7007,9 +7013,14 @@ const App = () => {
} catch (cmdErr) {
setAiActionLog(prev => [...prev, { type: 'error', text: `${fc.name}: ${cmdErr.message}`, 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.`, time: Date.now() }]);
setAiPrompt('');
setTimeout(() => lucide.createIcons(), 200);
@@ -7179,12 +7190,19 @@ 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, error: 'Track not found' };
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;
@@ -7286,15 +7304,83 @@ const App = () => {
}
return { success: false, 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));
return { success: true, bpm: bpmVal };
},
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 };
return { success: true, time: parseFloat(time.toFixed(3)) };
},
addMarker: (args) => {
const trackId = args.track_id || selectedTrackId;