Skip to content

Commit 5f054f5

Browse files
committed
Merge branch 'main' of https://github.com/transformerlab/transformerlab-app into add/move-job-to-experiment
2 parents 862896f + 71b4f1f commit 5f054f5

File tree

18 files changed

+400
-115
lines changed

18 files changed

+400
-115
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ npm-debug.log.*
2828
*.css.d.ts
2929
*.sass.d.ts
3030
*.scss.d.ts
31+
32+
# IDEs
33+
# NOTE: Cursor automatically ignores files in .gitignore and a default list on their website
34+
# Override with ! prefix in .cursorignore.
35+
# https://docs.cursor.com/context/ignore-files#default-ignore-list
36+
.cursor/
37+
.cursorignore

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,40 +49,47 @@ Transformer Lab is proud to be supported by Mozilla through the <a href="https:/
4949

5050
## Features
5151

52+
5253
Transformer Lab allows you to:
5354

5455
- 💕 **One-click Download Hundreds of Popular Models**:
55-
- DeepSeek, Llama3, Qwen, Phi4, Gemma, Mistral, Mixtral, Command-R, and dozens more
56-
-**Download any LLM from Huggingface**
56+
- DeepSeek, Qwen, Gemma, Phi4, Llama, Mistral, Mixtral, Stable Diffusion, Flux, Command-R, and dozens more
57+
-**Download any LLM, VLM, or Diffusion model from Huggingface**
5758
- 🎶 **Finetune / Train Across Different Hardware**
5859
- Finetune using MLX on Apple Silicon
5960
- Finetune using Huggingface on GPU
61+
- Finetune Diffusion LoRAs on GPU
6062
- ⚖️ **RLHF and Preference Optimization**
6163
- DPO
6264
- ORPO
6365
- SIMPO
6466
- Reward Modeling
65-
- 💻 **Work with LLMs Across Operating Systems**:
67+
- 💻 **Work with Models Across Operating Systems**:
6668
- Windows App
6769
- MacOS App
6870
- Linux
6971
- 💬 **Chat with Models**
7072
- Chat
7173
- Completions
74+
- Visualize Model Architecture
75+
- Inspect activations & attention for each generated token
7276
- Preset (Templated) Prompts
7377
- Chat History
7478
- Tweak generation parameters
7579
- Batched Inference
7680
- Tool Use / Function Calling (in alpha)
7781
- 🚂 **Use Different Inference Engines**
7882
- MLX on Apple Silicon
79-
- Huggingface Transformers
83+
- FastChat
8084
- vLLM
8185
- Llama CPP
86+
- SGLang
87+
- 🖼️ **Support for Image Diffusion Models**
88+
- Run and experiment with image generation models (e.g., Stable Diffusion, Flux, etc.)
8289
- 🧑‍🎓 **Evaluate models**
8390
- 📖 **RAG (Retreival Augmented Generation)**
8491
- Drag and Drop File UI
85-
- Works on Apple MLX, Transformers, and other engines
92+
- Works on Apple MLX, FastChat, and other engines
8693
- 📓 **Build Datasets for Training**
8794
- Pull from hundreds of common datasets available on HuggingFace
8895
- Provide your own dataset using drag and drop
@@ -94,14 +101,14 @@ Transformer Lab allows you to:
94101
- 🔀 **Convert Models Across Platforms**
95102
- Convert from/to Huggingface, MLX, GGUF
96103
- 🔌 **Plugin Support**
97-
- Easily pull from a library of existing plugins
104+
- Easily install from a gallery of existing plugins
98105
- Write your own plugins to extend functionality
99106
- 🧑‍💻 **Embedded Monaco Code Editor**
100107
- Edit plugins and view what's happening behind the scenes
101108
- 📝 **Prompt Editing**
102109
- Easily edit System Messages or Prompt Templates
103110
- 📜 **Inference Logs**
104-
- While doing inference or RAG, view a log of the raw queries sent to the LLM
111+
- While doing inference or RAG, view a log of the raw queries sent to the model
105112

106113
And you can do the above, all through a simple cross-platform GUI.
107114

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"url": "https://github.com/dadmobile"
2626
}
2727
],
28-
"version": "0.20.3",
28+
"version": "0.20.7",
2929
"main": "./src/main/main.ts",
3030
"scripts": {
3131
"build": "concurrently \"npm run build:main\" \"npm run build:renderer\" \"npm run build:cloud\"",
@@ -267,7 +267,8 @@
267267
"x64"
268268
]
269269
}
270-
]
270+
],
271+
"publisherName": "Transformer Lab Inc."
271272
},
272273
"linux": {
273274
"target": [

release/app/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "transformerlab",
3-
"version": "0.20.3",
3+
"version": "0.20.7",
44
"description": "A tool to play with and train LLMs",
55
"license": "AGPL-3.0",
66
"author": {

src/renderer/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ function AppContent({
121121
flexDirection: 'row',
122122
justifyContent: 'space-between',
123123
height: '18px',
124+
lineHeight: '18px',
124125
}}
125126
>
126127
<div>&nbsp;</div>
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from 'react';
2+
import {
3+
Box,
4+
Typography,
5+
Card,
6+
CardContent,
7+
Stack,
8+
IconButton,
9+
} from '@mui/joy';
10+
import { Play, Pause, Volume2 } from 'lucide-react';
11+
12+
interface AudioPlayerProps {
13+
audioData: {
14+
audio_data_url: string;
15+
};
16+
metadata: {
17+
path?: string;
18+
duration?: number;
19+
};
20+
}
21+
22+
const AudioPlayer: React.FC<AudioPlayerProps> = ({ audioData, metadata }) => {
23+
const [isPlaying, setIsPlaying] = React.useState(false);
24+
const [audio] = React.useState(new Audio(audioData.audio_data_url));
25+
26+
const togglePlay = () => {
27+
if (isPlaying) {
28+
audio.pause();
29+
setIsPlaying(false);
30+
} else {
31+
audio.play();
32+
setIsPlaying(true);
33+
}
34+
};
35+
36+
// Handle audio ended event
37+
React.useEffect(() => {
38+
const handleEnded = () => setIsPlaying(false);
39+
audio.addEventListener('ended', handleEnded);
40+
return () => audio.removeEventListener('ended', handleEnded);
41+
}, [audio]);
42+
43+
return (
44+
<Card variant="outlined" sx={{ maxWidth: 400 }}>
45+
<CardContent>
46+
<Stack spacing={2}>
47+
{/* Audio Controls */}
48+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
49+
<IconButton
50+
size="sm"
51+
variant="solid"
52+
color="primary"
53+
onClick={togglePlay}
54+
>
55+
{isPlaying ? <Pause size={16} /> : <Play size={16} />}
56+
</IconButton>
57+
<Volume2 size={16} />
58+
<Typography level="body-sm">
59+
{metadata?.duration
60+
? `${metadata.duration.toFixed(1)}s`
61+
: 'Audio'}
62+
</Typography>
63+
</Box>
64+
65+
{/* File Path Only */}
66+
{metadata?.path && (
67+
<Box sx={{ fontSize: '0.75rem', color: 'text.secondary' }}>
68+
<div>
69+
<strong>File:</strong> {metadata.path}
70+
</div>
71+
</Box>
72+
)}
73+
</Stack>
74+
</CardContent>
75+
</Card>
76+
);
77+
};
78+
79+
export default AudioPlayer;

src/renderer/components/Data/DatasetPreviewWithTemplate.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import * as chatAPI from '../../lib/transformerlab-api-sdk';
1515
import { ChevronLeftIcon, ChevronRightIcon, Sheet } from 'lucide-react';
1616
import useSWR from 'swr';
1717
import { useAPI } from 'renderer/lib/transformerlab-api-sdk';
18+
import { useNotification } from '../Shared/NotificationSystem';
1819

1920
const fetcher = (url) =>
2021
fetch(url)
@@ -39,6 +40,7 @@ const DatasetTableWithTemplate = ({
3940
};
4041

4142
const shouldUseChatTemplate = !!modelName && !!chatColumn;
43+
const { addNotification } = useNotification();
4244

4345
const {
4446
data: result,
@@ -73,6 +75,12 @@ const DatasetTableWithTemplate = ({
7375
if (isLoading) {
7476
return <LinearProgress />;
7577
}
78+
if (result?.status === 'error') {
79+
addNotification({
80+
type: 'warning',
81+
message: result?.message,
82+
});
83+
}
7684
return '';
7785
}
7886
return (

src/renderer/components/Data/DatasetTable.tsx

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,40 @@ import { useEffect, useState } from 'react';
22
import {
33
Button,
44
Table,
5-
CircularProgress,
65
Box,
76
IconButton,
87
iconButtonClasses,
98
Alert,
109
Select,
1110
Option,
1211
FormControl,
13-
FormLabel,
14-
LinearProgress,
1512
Typography,
1613
Skeleton,
1714
Tooltip,
1815
} from '@mui/joy';
1916

20-
import * as chatAPI from '../../lib/transformerlab-api-sdk';
2117
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
2218
import useSWR from 'swr';
23-
const fetcher = (url) =>
19+
import * as chatAPI from '../../lib/transformerlab-api-sdk';
20+
import AudioPlayer from './AudioPlayer';
21+
22+
const fetcher = (url: string) =>
2423
fetch(url)
2524
.then((res) => res.json())
2625
.then((data) => data);
2726

28-
const DatasetTable = ({ datasetId }) => {
27+
const DatasetTable = ({ datasetId }: { datasetId: string }) => {
2928
const [pageNumber, setPageNumber] = useState(1);
3029
const [numOfPages, setNumOfPages] = useState(1);
31-
const [datasetLen, setDatasetLen] = useState(null);
30+
const [datasetLen, setDatasetLen] = useState<number | null>(null);
3231
let pageSize = 10; //Set the number of rows per page
3332
const offset = (pageNumber - 1) * pageSize; //Calculate current row number to start from
3433

35-
const [split, setSplit] = useState(''); //Set the default split to display
34+
const [split, setSplit] = useState(''); // Set the default split to display
3635
const [showingSplit, setShowingSplit] = useState(''); // We use this to show the user what split is shown without triggering a re-call of the data
3736

38-
//Set the pagination for the dataset
39-
const setPagination = (totalRows, rowsPerPage) => {
37+
// Set the pagination for the dataset
38+
const setPagination = (totalRows: number, rowsPerPage: number) => {
4039
const totalPages = Math.ceil(totalRows / rowsPerPage);
4140
setNumOfPages(totalPages);
4241
};
@@ -173,28 +172,72 @@ const DatasetTable = ({ datasetId }) => {
173172
textOverflow: 'ellipsis',
174173
}}
175174
>
176-
{typeof data.data['columns'][key][rowIndex] ===
177-
'string' &&
178-
data.data['columns'][key][rowIndex].startsWith(
179-
'data:image/',
180-
) ? (
181-
<img
182-
src={data.data['columns'][key][rowIndex]}
183-
alt="preview"
184-
style={{
185-
maxWidth: 120,
186-
maxHeight: 120,
187-
display: 'block',
188-
}}
189-
/>
190-
) : typeof data.data['columns'][key][rowIndex] ===
191-
'string' ? (
192-
data.data['columns'][key][rowIndex]
193-
) : (
194-
JSON.stringify(
195-
data.data['columns'][key][rowIndex],
196-
)
197-
)}
175+
{(() => {
176+
const cellData =
177+
data.data['columns'][key][rowIndex];
178+
179+
// Handle audio data with nested structure
180+
if (
181+
typeof cellData === 'object' &&
182+
cellData !== null &&
183+
cellData.array?.audio_data_url
184+
) {
185+
// Merge metadata from both array.metadata and root level
186+
const mergedMetadata = {
187+
...cellData.array.metadata,
188+
path: cellData.path,
189+
};
190+
191+
return (
192+
<AudioPlayer
193+
audioData={cellData.array}
194+
metadata={mergedMetadata}
195+
transcription={cellData.transcription}
196+
/>
197+
);
198+
}
199+
200+
// Handle audio data (object with audio_data_url at root level)
201+
if (
202+
typeof cellData === 'object' &&
203+
cellData !== null &&
204+
cellData.audio_data_url
205+
) {
206+
return (
207+
<AudioPlayer
208+
audioData={cellData}
209+
metadata={cellData.metadata}
210+
transcription={cellData.transcription}
211+
/>
212+
);
213+
}
214+
215+
// Handle image data (string starting with data:image/)
216+
if (
217+
typeof cellData === 'string' &&
218+
cellData.startsWith('data:image/')
219+
) {
220+
return (
221+
<img
222+
src={cellData}
223+
alt="preview"
224+
style={{
225+
maxWidth: 120,
226+
maxHeight: 120,
227+
display: 'block',
228+
}}
229+
/>
230+
);
231+
}
232+
233+
// Handle regular strings
234+
if (typeof cellData === 'string') {
235+
return cellData;
236+
}
237+
238+
// Handle other data types
239+
return JSON.stringify(cellData);
240+
})()}
198241
</div>
199242
</Tooltip>
200243
</td>

0 commit comments

Comments
 (0)