add midi tracks to webUI

This commit is contained in:
josc146 2023-12-10 23:08:44 +08:00
parent 9b7b651ef9
commit e48f39375e
4 changed files with 48 additions and 28 deletions

View File

@ -18,7 +18,7 @@ import {
} from '@fluentui/react-icons'; } from '@fluentui/react-icons';
import { Button, Card, DialogTrigger, Slider, Text, Tooltip } from '@fluentui/react-components'; import { Button, Card, DialogTrigger, Slider, Text, Tooltip } from '@fluentui/react-components';
import { useWindowSize } from 'usehooks-ts'; import { useWindowSize } from 'usehooks-ts';
import commonStore from '../../stores/commonStore'; import commonStore, { ModelStatus } from '../../stores/commonStore';
import classnames from 'classnames'; import classnames from 'classnames';
import { import {
InstrumentType, InstrumentType,
@ -420,6 +420,7 @@ const AudiotrackEditor: FC<{ setPrompt: (prompt: string) => void }> = observer((
<div key={track.id} className="flex gap-2 pb-1 border-b"> <div key={track.id} className="flex gap-2 pb-1 border-b">
<div className="flex gap-1 border-r h-7"> <div className="flex gap-1 border-r h-7">
<ToolTipButton desc={commonStore.recordingTrackId === track.id ? t('Stop') : t('Record')} <ToolTipButton desc={commonStore.recordingTrackId === track.id ? t('Stop') : t('Record')}
disabled={commonStore.platform === 'web'}
icon={commonStore.recordingTrackId === track.id ? <Stop16Filled /> : <Record16Regular />} icon={commonStore.recordingTrackId === track.id ? <Stop16Filled /> : <Record16Regular />}
size="small" shape="circular" appearance="subtle" size="small" shape="circular" appearance="subtle"
onClick={() => { onClick={() => {
@ -481,6 +482,7 @@ const AudiotrackEditor: FC<{ setPrompt: (prompt: string) => void }> = observer((
<div className="flex gap-1"> <div className="flex gap-1">
<Button icon={<Add16Regular />} size="small" shape="circular" <Button icon={<Add16Regular />} size="small" shape="circular"
appearance="subtle" appearance="subtle"
disabled={commonStore.platform === 'web'}
onClick={() => { onClick={() => {
commonStore.setTracks([...commonStore.tracks, { commonStore.setTracks([...commonStore.tracks, {
id: uuid(), id: uuid(),
@ -496,11 +498,20 @@ const AudiotrackEditor: FC<{ setPrompt: (prompt: string) => void }> = observer((
<Button icon={<ArrowUpload16Regular />} size="small" shape="circular" <Button icon={<ArrowUpload16Regular />} size="small" shape="circular"
appearance="subtle" appearance="subtle"
onClick={() => { onClick={() => {
if (commonStore.status.status === ModelStatus.Offline && !commonStore.settings.apiUrl && commonStore.platform !== 'web') {
toast(t('Please click the button in the top right corner to start the model'), { type: 'warning' });
return;
}
OpenOpenFileDialog('*.mid').then(async filePath => { OpenOpenFileDialog('*.mid').then(async filePath => {
if (!filePath) if (!filePath)
return; return;
const blob = await fetch(absPathAsset(filePath)).then(r => r.blob()); let blob: Blob;
if (commonStore.platform === 'web')
blob = (filePath as unknown as { blob: Blob }).blob;
else
blob = await fetch(absPathAsset(filePath)).then(r => r.blob());
const bodyForm = new FormData(); const bodyForm = new FormData();
bodyForm.append('file_data', blob); bodyForm.append('file_data', blob);
fetch(getServerRoot(commonStore.getCurrentModelConfig().apiParameters.apiPort) + '/midi-to-text', { fetch(getServerRoot(commonStore.getCurrentModelConfig().apiParameters.apiPort) + '/midi-to-text', {

View File

@ -567,7 +567,7 @@ const ChatPanel: FC = observer(() => {
const setUploading = () => commonStore.setAttachmentUploading(true); const setUploading = () => commonStore.setAttachmentUploading(true);
// actually, status of web platform is always Offline // actually, status of web platform is always Offline
if (commonStore.platform === 'web' || commonStore.status.status === ModelStatus.Offline || currentConfig.modelParameters.device === 'WebGPU') { if (commonStore.platform === 'web' || commonStore.status.status === ModelStatus.Offline || currentConfig.modelParameters.device === 'WebGPU') {
webOpenOpenFileDialog({ filterPattern, fnStartLoading: setUploading }).then(webReturn => { webOpenOpenFileDialog(filterPattern, setUploading).then(webReturn => {
if (webReturn.content) if (webReturn.content)
commonStore.setCurrentTempAttachment( commonStore.setCurrentTempAttachment(
{ {

View File

@ -250,32 +250,36 @@ const CompositionPanel: FC = observer(() => {
}} /> }} />
} /> } />
<div className="grow" /> <div className="grow" />
<Checkbox className="select-none" {
size="large" label={t('Use Local Sound Font')} checked={params.useLocalSoundFont} commonStore.platform !== 'web' &&
onChange={async (_, data) => { <Checkbox className="select-none"
if (data.checked) { size="large" label={t('Use Local Sound Font')} checked={params.useLocalSoundFont}
if (!await FileExists('assets/sound-font/accordion/instrument.json')) { onChange={async (_, data) => {
toast(t('Failed to load local sound font, please check if the files exist - assets/sound-font'), if (data.checked) {
{ type: 'warning' }); if (!await FileExists('assets/sound-font/accordion/instrument.json')) {
return; toast(t('Failed to load local sound font, please check if the files exist - assets/sound-font'),
{ type: 'warning' });
return;
}
} }
} setParams({
setParams({ useLocalSoundFont: data.checked as boolean
useLocalSoundFont: data.checked as boolean });
}); setSoundFont();
setSoundFont(); }} />
}} /> }
<Checkbox className="select-none" <Checkbox className="select-none"
size="large" label={t('Auto Play At The End')} checked={params.autoPlay} onChange={(_, data) => { size="large" label={t('Auto Play At The End')} checked={params.autoPlay} onChange={(_, data) => {
setParams({ setParams({
autoPlay: data.checked as boolean autoPlay: data.checked as boolean
}); });
}} /> }} />
{commonStore.platform !== 'web' && <Labeled flex breakline label={t('MIDI Input')}
<Labeled flex breakline label={t('MIDI Input')} desc={t('Select the MIDI input device to be used.')}
desc={t('Select the MIDI input device to be used.')} content={
content={ <div className="flex flex-col gap-1">
<div className="flex flex-col gap-1"> {
commonStore.platform !== 'web' &&
<Dropdown style={{ minWidth: 0 }} <Dropdown style={{ minWidth: 0 }}
value={(commonStore.activeMidiDeviceIndex === -1 || !(commonStore.activeMidiDeviceIndex in commonStore.midiPorts)) value={(commonStore.activeMidiDeviceIndex === -1 || !(commonStore.activeMidiDeviceIndex in commonStore.midiPorts))
? t('None')! ? t('None')!
@ -299,10 +303,10 @@ const CompositionPanel: FC = observer(() => {
<Option key={i} value={i.toString()}>{p.name}</Option>) <Option key={i} value={i.toString()}>{p.name}</Option>)
} }
</Dropdown> </Dropdown>
<AudiotrackButton setPrompt={setPrompt} /> }
</div> <AudiotrackButton setPrompt={setPrompt} />
} /> </div>
} } />
</div> </div>
<div className="flex justify-between gap-2"> <div className="flex justify-between gap-2">
<ToolTipButton desc={t('Regenerate')} icon={<ArrowSync20Regular />} onClick={() => { <ToolTipButton desc={t('Regenerate')} icon={<ArrowSync20Regular />} onClick={() => {

View File

@ -1,12 +1,17 @@
import { getDocument, GlobalWorkerOptions, PDFDocumentProxy } from 'pdfjs-dist'; import { getDocument, GlobalWorkerOptions, PDFDocumentProxy } from 'pdfjs-dist';
import { TextItem } from 'pdfjs-dist/types/src/display/api'; import { TextItem } from 'pdfjs-dist/types/src/display/api';
export function webOpenOpenFileDialog({ filterPattern, fnStartLoading }: { filterPattern: string, fnStartLoading: Function | null }): Promise<{ blob: Blob, content?: string }> { export function webOpenOpenFileDialog(filterPattern: string, fnStartLoading: Function | undefined): Promise<{
blob: Blob,
content?: string
}> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const input = document.createElement('input'); const input = document.createElement('input');
input.type = 'file'; input.type = 'file';
input.accept = filterPattern input.accept = filterPattern
.replaceAll('*.txt', 'text/plain') .replaceAll('*.txt', 'text/plain')
.replace('*.midi', 'audio/midi')
.replace('*.mid', 'audio/midi')
.replaceAll('*.', 'application/') .replaceAll('*.', 'application/')
.replaceAll(';', ','); .replaceAll(';', ',');
@ -15,7 +20,7 @@ export function webOpenOpenFileDialog({ filterPattern, fnStartLoading }: { filte
const file: Blob = e.target?.files[0]; const file: Blob = e.target?.files[0];
if (fnStartLoading && typeof fnStartLoading === 'function') if (fnStartLoading && typeof fnStartLoading === 'function')
fnStartLoading(); fnStartLoading();
if (!GlobalWorkerOptions.workerSrc) if (!GlobalWorkerOptions.workerSrc && file.type === 'application/pdf')
// @ts-ignore // @ts-ignore
GlobalWorkerOptions.workerSrc = await import('pdfjs-dist/build/pdf.worker.min.mjs'); GlobalWorkerOptions.workerSrc = await import('pdfjs-dist/build/pdf.worker.min.mjs');
if (file.type === 'text/plain') { if (file.type === 'text/plain') {