Skip to content

Commit a583196

Browse files
authored
Merge pull request #221 from scribear/feature/whisper-dropdown-model-buttons-An
feat(whisper): settings gear dialog with state to show which model is on use
2 parents e30d75b + 39716cd commit a583196

3 files changed

Lines changed: 77 additions & 65 deletions

File tree

src/components/navbars/topbar/api/WhisperSettings.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default function WhisperSettings() {
2424
const dispatch = useDispatch();
2525
const selected = useSelector(selectSelectedModel);
2626

27-
// normalize current selection to 'tiny' | 'base' | undefined
27+
// Normalize current selection to 'tiny' | 'base' | undefined
2828
const selectedKey: ModelKey | undefined = React.useMemo(() => {
2929
if (typeof selected === 'string') {
3030
return selected === 'tiny' || selected === 'base' ? selected : undefined;
@@ -40,19 +40,19 @@ export default function WhisperSettings() {
4040
const closePopup = () => setAnchorEl(null);
4141

4242
const pick = (which: ModelKey) => {
43-
// keep existing flags your loader watches
43+
// Keep flags if your loader watches them
4444
sessionStorage.setItem('isDownloadTiny', (which === 'tiny').toString());
4545
sessionStorage.setItem('isDownloadBase', (which === 'base').toString());
4646

47-
// update redux
47+
// Update redux
4848
dispatch({ type: 'SET_SELECTED_MODEL', payload: which as any });
4949

5050
closePopup();
5151
};
5252

5353
return (
5454
<>
55-
{/* Right-side gear, same pattern as Azure/ScribeAR Server */}
55+
{/* Right-side gear (same pattern as Azure/ScribeAR Server) */}
5656
<IconButton onClick={showPopup}>
5757
<SettingsIcon />
5858
</IconButton>

src/components/navbars/topbar/api/pickApi.tsx

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,45 @@ import {
1717
import {
1818
CancelIcon,
1919
CheckCircleIcon,
20-
Collapse,
2120
DoNotDisturbOnIcon,
2221
ErrorIcon,
23-
ExpandLess,
24-
ExpandMore,
25-
IconButton,
2622
ListItemButton,
2723
ListItemIcon,
2824
ListItemText,
2925
ThemeProvider,
3026
createTheme,
27+
Chip,
3128
} from '../../../../muiImports';
3229
import { ListItem } from '@mui/material';
3330

3431
import AzureSettings from './AzureSettings';
3532
import StreamTextSettings from './StreamTextSettings';
3633
import ScribearServerSettings from './ScribearServerSettings';
3734
import PlaybackSettings from './PlaybackSettings';
38-
import WhisperSettings from './WhisperSettings'; // <-- use settings-gear dialog for Whisper
35+
import WhisperSettings from './WhisperSettings';
3936

4037
import swal from 'sweetalert';
4138
import { testAzureTranslRecog } from '../../../api/azure/azureTranslRecog';
39+
import { selectSelectedModel } from '../../../../react-redux&middleware/redux/reducers/modelSelectionReducers';
40+
41+
// helper to normalize selected model to 'tiny' | 'base' | undefined
42+
function getSelectedModelKey(selected: unknown): 'tiny' | 'base' | undefined {
43+
if (typeof selected === 'string') {
44+
return selected === 'tiny' || selected === 'base' ? selected : undefined;
45+
}
46+
if (selected && typeof selected === 'object' && 'key' in (selected as any)) {
47+
const k = (selected as any).key;
48+
return k === 'tiny' || k === 'base' ? k : undefined;
49+
}
50+
return undefined;
51+
}
4252

4353
const currTheme = createTheme({
4454
palette: {
4555
primary: { main: '#ffffff' },
4656
success: { main: '#4caf50' },
4757
warning: { main: '#f44336' },
48-
error: { main: '#C8C224' },
58+
error: { main: '#C8C224' },
4959
},
5060
});
5161

@@ -84,13 +94,20 @@ export default function PickApi() {
8494
const dispatch = useDispatch();
8595
const myTheme = currTheme;
8696

97+
// ✅ hooks INSIDE the component
8798
const apiStatus = useSelector((state: RootState) => state.APIStatusReducer as ApiStatus);
8899
const controlStatus = useSelector((state: RootState) => state.ControlReducer as ControlStatus);
89100
const azureStatus = useSelector((state: RootState) => state.AzureReducer as AzureStatus);
90101
const streamTextStatus = useSelector((state: RootState) => state.StreamTextReducer as StreamTextStatus);
91102
const scribearServerStatus = useSelector((state: RootState) => state.ScribearServerReducer as ScribearServerStatus);
92103
const playbackStatus = useSelector((state: RootState) => state.PlaybackReducer as PlaybackStatus);
93104

105+
const selectedModel = useSelector(selectSelectedModel as any);
106+
const selectedModelKey = React.useMemo(
107+
() => getSelectedModelKey(selectedModel),
108+
[selectedModel]
109+
);
110+
94111
const [state, setState] = React.useState({
95112
showAzureDropdown: false,
96113
showWhisperDropdown: false,
@@ -102,22 +119,14 @@ export default function PickApi() {
102119
testAzureTranslRecog(controlStatus, azureStatus)
103120
.then(() => {
104121
localStorage.setItem('azureStatus', JSON.stringify(azureStatus));
105-
106122
copyStatus.currentApi = API.AZURE_TRANSLATION;
107123
copyStatus.azureTranslStatus = STATUS.TRANSCRIBING;
108124
copyStatus.webspeechStatus = STATUS.AVAILABLE;
109125
copyStatus.azureConvoStatus = STATUS.AVAILABLE;
110126
copyStatus.whisperStatus = STATUS.AVAILABLE;
111127
copyStatus.streamTextStatus = STATUS.AVAILABLE;
112128
copyStatus.playbackStatus = STATUS.AVAILABLE;
113-
114-
swal({
115-
title: 'Success!',
116-
text: 'Switching to Microsoft Azure',
117-
icon: 'success',
118-
timer: 1500,
119-
});
120-
129+
swal({ title: 'Success!', text: 'Switching to Microsoft Azure', icon: 'success', timer: 1500 });
121130
dispatch({ type: 'CHANGE_API_STATUS', payload: copyStatus });
122131
})
123132
.catch((error) => {
@@ -129,28 +138,12 @@ export default function PickApi() {
129138
});
130139
};
131140

132-
const switchToStreamText = (event: React.KeyboardEvent | React.MouseEvent) => {
133-
localStorage.setItem('streamTextStatus', JSON.stringify(streamTextStatus));
134-
return toggleDrawer('streamTextStatus', API.STREAM_TEXT, false)(event);
135-
};
136-
137-
const switchToScribearServer = (event: React.KeyboardEvent | React.MouseEvent) => {
138-
localStorage.setItem('scribearServerStatus', JSON.stringify(scribearServerStatus));
139-
return toggleDrawer('scribearServerStatus', API.SCRIBEAR_SERVER, false)(event);
140-
};
141-
142-
const switchToPlayback = (event: React.KeyboardEvent | React.MouseEvent) => {
143-
localStorage.setItem('playbackStatus', JSON.stringify(playbackStatus));
144-
return toggleDrawer('playbackStatus', API.PLAYBACK, false)(event);
145-
};
146-
147141
const toggleDrawer =
148142
(apiStat: string, api: ApiType, isArrow: boolean) =>
149143
(_event: React.KeyboardEvent | React.MouseEvent) => {
150144
if (apiStatus.currentApi !== api) {
151145
if (!isArrow) {
152-
const copyStatus = { ...apiStatus };
153-
copyStatus.currentApi = api;
146+
const copyStatus = { ...apiStatus, currentApi: api };
154147

155148
// reset all
156149
copyStatus.azureTranslStatus = STATUS.AVAILABLE;
@@ -163,31 +156,21 @@ export default function PickApi() {
163156

164157
let apiName = '';
165158
if (api === API.AZURE_TRANSLATION) {
166-
apiName = 'Microsoft Azure';
167-
copyStatus.azureTranslStatus = STATUS.TRANSCRIBING;
159+
apiName = 'Microsoft Azure'; copyStatus.azureTranslStatus = STATUS.TRANSCRIBING;
168160
} else if (api === API.WHISPER) {
169-
apiName = 'Whisper';
170-
copyStatus.whisperStatus = STATUS.TRANSCRIBING;
161+
apiName = 'Whisper'; copyStatus.whisperStatus = STATUS.TRANSCRIBING;
171162
} else if (api === API.WEBSPEECH) {
172-
copyStatus.webspeechStatus = STATUS.TRANSCRIBING;
163+
copyStatus.webspeechStatus = STATUS.TRANSCRIBING;
173164
} else if (api === API.STREAM_TEXT) {
174-
apiName = 'StreamText';
175-
copyStatus.streamTextStatus = STATUS.TRANSCRIBING;
165+
apiName = 'StreamText'; copyStatus.streamTextStatus = STATUS.TRANSCRIBING;
176166
} else if (api === API.SCRIBEAR_SERVER) {
177-
apiName = 'ScribeAR Server';
178-
copyStatus.scribearServerStatus = STATUS.TRANSCRIBING;
167+
apiName = 'ScribeAR Server'; copyStatus.scribearServerStatus = STATUS.TRANSCRIBING;
179168
} else if (api === API.PLAYBACK) {
180-
apiName = 'Playback';
181-
copyStatus.playbackStatus = STATUS.TRANSCRIBING;
169+
apiName = 'Playback'; copyStatus.playbackStatus = STATUS.TRANSCRIBING;
182170
}
183171

184172
dispatch({ type: 'CHANGE_API_STATUS', payload: copyStatus });
185-
swal({
186-
title: 'Success!',
187-
text: 'Switching to ' + apiName,
188-
icon: 'success',
189-
timer: 2500,
190-
});
173+
swal({ title: 'Success!', text: 'Switching to ' + apiName, icon: 'success', timer: 2500 });
191174
} else {
192175
setState((s) => ({ ...s, [apiStat]: !s[apiStat] }));
193176
}
@@ -196,17 +179,34 @@ export default function PickApi() {
196179
}
197180
};
198181

182+
const switchToStreamText = (e: React.KeyboardEvent | React.MouseEvent) => {
183+
localStorage.setItem('streamTextStatus', JSON.stringify(streamTextStatus));
184+
return toggleDrawer('streamTextStatus', API.STREAM_TEXT, false)(e);
185+
};
186+
187+
const switchToScribearServer = (e: React.KeyboardEvent | React.MouseEvent) => {
188+
localStorage.setItem('scribearServerStatus', JSON.stringify(scribearServerStatus));
189+
return toggleDrawer('scribearServerStatus', API.SCRIBEAR_SERVER, false)(e);
190+
};
191+
192+
const switchToPlayback = (e: React.KeyboardEvent | React.MouseEvent) => {
193+
localStorage.setItem('playbackStatus', JSON.stringify(playbackStatus));
194+
return toggleDrawer('playbackStatus', API.PLAYBACK, false)(e);
195+
};
196+
199197
return (
200198
<div>
201199
{/* Webspeech */}
202-
<ListItemButton onClick={toggleDrawer('webspeechStatus', API.WEBSPEECH, false)}>
203-
<ThemeProvider theme={myTheme}>
204-
<ListItemIcon>
205-
<IconStatus {...{ currentApi: apiStatus.webspeechStatus }} />
206-
</ListItemIcon>
207-
</ThemeProvider>
208-
<ListItemText primary="Webspeech" />
209-
</ListItemButton>
200+
<ListItem disableGutters>
201+
<ListItemButton onClick={toggleDrawer('webspeechStatus', API.WEBSPEECH, false)}>
202+
<ThemeProvider theme={myTheme}>
203+
<ListItemIcon>
204+
<IconStatus {...{ currentApi: apiStatus.webspeechStatus }} />
205+
</ListItemIcon>
206+
</ThemeProvider>
207+
<ListItemText primary="Webspeech" />
208+
</ListItemButton>
209+
</ListItem>
210210

211211
{/* Microsoft Azure */}
212212
<ListItem>
@@ -252,7 +252,7 @@ export default function PickApi() {
252252
<StreamTextSettings />
253253
</ListItem>
254254

255-
{/* Whisper (now matches others: button + gear on the right) */}
255+
{/* Whisper (button + gear; inline chip shows selected model) */}
256256
<ListItem>
257257
<ListItemButton
258258
disableGutters
@@ -261,7 +261,17 @@ export default function PickApi() {
261261
<ListItemIcon>
262262
<IconStatus {...{ currentApi: apiStatus.whisperStatus }} />
263263
</ListItemIcon>
264-
<ListItemText primary="Whisper" />
264+
265+
<ListItemText
266+
primary={
267+
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
268+
<span>Whisper</span>
269+
{selectedModelKey && (
270+
<Chip size="small" variant="outlined" label={selectedModelKey.toUpperCase()} />
271+
)}
272+
</span>
273+
}
274+
/>
265275
</ListItemButton>
266276
<WhisperSettings />
267277
</ListItem>

src/muiImports.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import FormatColorTextIcon from '@mui/icons-material/FormatColorText';
5555
import Autocomplete from '@mui/material/Autocomplete';
5656
import { Switch } from '@mui/material';
5757
import MemoryIcon from '@mui/icons-material/Memory';
58+
import Chip from '@mui/material/Chip';
5859
export {
5960
createTheme,
6061
Autocomplete,
@@ -114,5 +115,6 @@ export {
114115
FormatColorTextIcon,
115116
ArchitectureIcon,
116117
Switch,
117-
MemoryIcon
118-
}
118+
MemoryIcon,
119+
Chip
120+
}

0 commit comments

Comments
 (0)