Skip to content

Commit b2df1a1

Browse files
committed
Fine-tuning and post train chat eval POC
- Demonstrates an end to end knowledge submission, generate, train and post-train side-by-side model comparison for the user to validate their knowledge submission is included in the newly trained checkpoint. - For this to function for the frontend to make REST API calls to Instructlab this uses an api-server that frontends ilab. The code is here https://github.com/nerdalert/ilab-api-server - The demo was run on a 24GB GPU leveraging the simple pipeline. Will get an example acceslerated pipeline demo with some hardware soon. - Training and generation for the demo took around ~30-45m or so. - All functionality is decoupled from the system via REST making it serviceable out of the gate and enabling the UI functionality. Signed-off-by: Brent Salisbury <[email protected]>
1 parent 438617a commit b2df1a1

File tree

19 files changed

+4032
-464
lines changed

19 files changed

+4032
-464
lines changed

package-lock.json

Lines changed: 2210 additions & 462 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@
1919
"dependencies": {
2020
"@fortawesome/fontawesome-svg-core": "^6.7.1",
2121
"@next/env": "^15.0.3",
22+
"@patternfly/chatbot": "^2.1.0-prerelease.17",
2223
"@patternfly/react-core": "^6.0.0",
2324
"@patternfly/react-icons": "^6.0.0",
2425
"@patternfly/react-styles": "^6.0.0",
2526
"@patternfly/react-table": "^6.0.0",
2627
"axios": "^1.7.9",
28+
"@patternfly/virtual-assistant": "^2.0.2",
29+
"date-fns": "^4.1.0",
30+
"dompurify": "^3.2.2",
2731
"fs": "^0.0.1-security",
2832
"isomorphic-git": "^1.27.2",
2933
"js-yaml": "^4.1.0",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// src/pages/api/fine-tune/data-sets.ts
2+
'use server';
3+
4+
import { NextRequest, NextResponse } from 'next/server';
5+
6+
export async function GET(req: NextRequest) {
7+
try {
8+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
9+
10+
const response = await fetch(`${API_SERVER}/data`);
11+
const data = await response.json();
12+
13+
if (!response.ok) {
14+
return NextResponse.json({ error: 'Failed to fetch datasets' }, { status: response.status });
15+
}
16+
17+
return NextResponse.json(data, { status: 200 });
18+
} catch (error) {
19+
console.error('Error fetching datasets:', error);
20+
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
21+
}
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use server';
2+
3+
import { NextResponse } from 'next/server';
4+
5+
export async function POST(request: Request) {
6+
try {
7+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
8+
9+
const response = await fetch(`${API_SERVER}/data/generate`, {
10+
method: 'POST'
11+
});
12+
13+
if (!response.ok) {
14+
console.error('Error response from API server:', response.status, response.statusText);
15+
return NextResponse.json({ error: 'Failed to generate data' }, { status: response.status });
16+
}
17+
18+
const responseData = await response.json();
19+
20+
// Return the response from the API server to the client
21+
return NextResponse.json(responseData, { status: 200 });
22+
} catch (error) {
23+
console.error('Error generating data:', error);
24+
return NextResponse.json({ error: 'An error occurred while generating data' }, { status: 500 });
25+
}
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// src/app/api/fine-tune/jobs/[job_id]/logs/route.ts
2+
import { NextResponse } from 'next/server';
3+
4+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
5+
6+
export async function GET(request: Request, { params }: { params: { job_id: string } }) {
7+
const { job_id } = await Promise.resolve(params);
8+
9+
try {
10+
const response = await fetch(`${API_SERVER}/jobs/${job_id}/logs`, {
11+
method: 'GET'
12+
});
13+
14+
if (!response.ok) {
15+
const errorText = await response.text();
16+
console.error('Error from API server:', errorText);
17+
return NextResponse.json({ error: 'Error fetching logs' }, { status: 500 });
18+
}
19+
20+
const logs = await response.text();
21+
return new NextResponse(logs, {
22+
status: 200,
23+
headers: { 'Content-Type': 'text/plain' }
24+
});
25+
} catch (error) {
26+
console.error('Error fetching logs:', error);
27+
return NextResponse.json({ error: 'Error fetching logs' }, { status: 500 });
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// src/app/api/fine-tune/jobs/[job_id]/status/route.ts
2+
'use server';
3+
4+
import { NextResponse } from 'next/server';
5+
6+
export async function GET(request: Request, { params }: { params: { job_id: string } }) {
7+
const { job_id } = params;
8+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
9+
10+
try {
11+
// Forward the request to the API server
12+
const response = await fetch(`${API_SERVER}/jobs/${job_id}/status`, {
13+
method: 'GET'
14+
});
15+
16+
if (!response.ok) {
17+
const errorText = await response.text();
18+
console.error('Error from API server:', errorText);
19+
return NextResponse.json({ error: 'Error fetching job status' }, { status: 500 });
20+
}
21+
22+
const result = await response.json();
23+
// Return the job status to the client
24+
return NextResponse.json(result, { status: 200 });
25+
} catch (error) {
26+
console.error('Error fetching job status:', error);
27+
return NextResponse.json({ error: 'Error fetching job status' }, { status: 500 });
28+
}
29+
}

src/app/api/fine-tune/jobs/route.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// src/app/api/fine-tune/jobs/route.ts
2+
'use server';
3+
4+
import { NextResponse } from 'next/server';
5+
6+
export async function GET(request: Request) {
7+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
8+
9+
try {
10+
const response = await fetch(`${API_SERVER}/jobs`);
11+
if (!response.ok) {
12+
const errorText = await response.text();
13+
console.error('Error from API server:', errorText);
14+
return NextResponse.json({ error: 'Error fetching jobs' }, { status: 500 });
15+
}
16+
const result = await response.json();
17+
return NextResponse.json(result, { status: 200 });
18+
} catch (error) {
19+
console.error('Error fetching jobs:', error);
20+
return NextResponse.json({ error: 'Error fetching jobs' }, { status: 500 });
21+
}
22+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// src/app/api/model/serve-base/route.ts
2+
'use server';
3+
4+
import { NextResponse } from 'next/server';
5+
6+
export async function POST() {
7+
try {
8+
console.log('Received serve-base model request');
9+
10+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
11+
const endpoint = `${API_SERVER}/model/serve-base`;
12+
13+
console.log(`Forwarding request to the API server: ${endpoint}`);
14+
15+
// No request body needed for serving the base model
16+
const response = await fetch(endpoint, {
17+
method: 'POST',
18+
headers: { 'Content-Type': 'application/json' }
19+
});
20+
21+
console.log('Response from API server (serve-base):', {
22+
status: response.status,
23+
statusText: response.statusText
24+
});
25+
26+
if (!response.ok) {
27+
console.error('Error response from the API server:', response.status, response.statusText);
28+
return NextResponse.json({ error: 'Failed to serve the base model on the API server' }, { status: response.status });
29+
}
30+
31+
// Parse response safely
32+
let responseData;
33+
try {
34+
const text = await response.text();
35+
responseData = text ? JSON.parse(text) : {};
36+
console.log('Parsed response data (serve-base):', responseData);
37+
} catch (error) {
38+
console.error('Error parsing JSON response from API server:', error);
39+
return NextResponse.json({ error: 'Invalid JSON response from the API server' }, { status: 500 });
40+
}
41+
42+
if (!responseData.job_id) {
43+
console.error('Missing job_id in API server response for serve-base:', responseData);
44+
return NextResponse.json({ error: 'API server response does not contain job_id' }, { status: 500 });
45+
}
46+
47+
// Return the response from the API server to the client
48+
console.log('Returning success response with job_id (serve-base):', responseData.job_id);
49+
return NextResponse.json(responseData, { status: 200 });
50+
} catch (error) {
51+
console.error('Unexpected error during serve-base:', error);
52+
return NextResponse.json({ error: 'An unexpected error occurred during serving the base model' }, { status: 500 });
53+
}
54+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// src/app/api/model/serve-latest/route.ts
2+
'use server';
3+
4+
import { NextResponse } from 'next/server';
5+
6+
export async function POST() {
7+
try {
8+
console.log('Received serve-latest model request');
9+
10+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
11+
const endpoint = `${API_SERVER}/model/serve-latest`;
12+
13+
console.log(`Forwarding request to API server: ${endpoint}`);
14+
15+
// No request body needed for serving the latest model
16+
const response = await fetch(endpoint, {
17+
method: 'POST',
18+
headers: { 'Content-Type': 'application/json' }
19+
});
20+
21+
console.log('Response from API server:', {
22+
status: response.status,
23+
statusText: response.statusText
24+
});
25+
26+
if (!response.ok) {
27+
console.error('Error response from API server:', response.status, response.statusText);
28+
return NextResponse.json({ error: 'Failed to serve the latest model on the API server' }, { status: response.status });
29+
}
30+
31+
// Parse response safely
32+
let responseData;
33+
try {
34+
const text = await response.text();
35+
responseData = text ? JSON.parse(text) : {};
36+
console.log('Parsed response data (serve-latest):', responseData);
37+
} catch (error) {
38+
console.error('Error parsing JSON response from API server:', error);
39+
return NextResponse.json({ error: 'Invalid JSON response from the API server' }, { status: 500 });
40+
}
41+
42+
if (!responseData.job_id) {
43+
console.error('Missing job_id in API server response for serve-latest:', responseData);
44+
return NextResponse.json({ error: 'API server response does not contain job_id' }, { status: 500 });
45+
}
46+
47+
// Return the response from the API server to the client
48+
console.log('Returning success response with job_id (serve-latest):', responseData.job_id);
49+
return NextResponse.json(responseData, { status: 200 });
50+
} catch (error) {
51+
console.error('Unexpected error during serve-latest:', error);
52+
return NextResponse.json({ error: 'An unexpected error occurred during serving the latest model' }, { status: 500 });
53+
}
54+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// src/app/api/fine-tune/model/train
2+
'use server';
3+
4+
import { NextResponse } from 'next/server';
5+
6+
export async function POST(request: Request) {
7+
try {
8+
console.log('Received train job request');
9+
10+
// Parse the request body for required data
11+
const { modelName, branchName } = await request.json();
12+
const API_SERVER = process.env.NEXT_PUBLIC_API_SERVER!;
13+
14+
console.log('Request body:', { modelName, branchName });
15+
16+
if (!modelName || !branchName) {
17+
console.error('Missing required parameters: modelName and branchName');
18+
return NextResponse.json({ error: 'Missing required parameters: modelName and branchName' }, { status: 400 });
19+
}
20+
21+
// Forward the request to the API server
22+
const endpoint = `${API_SERVER}/model/train`;
23+
24+
console.log(`Forwarding request to API server: ${API_SERVER}`);
25+
26+
const response = await fetch(endpoint, {
27+
method: 'POST',
28+
headers: {
29+
'Content-Type': 'application/json'
30+
},
31+
body: JSON.stringify({
32+
modelName,
33+
branchName
34+
})
35+
});
36+
37+
console.log('Response from API server:', {
38+
status: response.status,
39+
statusText: response.statusText
40+
});
41+
42+
if (!response.ok) {
43+
console.error('Error response from API server:', response.status, response.statusText);
44+
return NextResponse.json({ error: 'Failed to train the model on the API server' }, { status: response.status });
45+
}
46+
47+
// Parse response safely
48+
let responseData;
49+
try {
50+
const text = await response.text();
51+
responseData = text ? JSON.parse(text) : {};
52+
console.log('Parsed response data:', responseData);
53+
} catch (error) {
54+
console.error('Error parsing JSON response from API server:', error);
55+
return NextResponse.json({ error: 'Invalid JSON response from the API server' }, { status: 500 });
56+
}
57+
58+
if (!responseData.job_id) {
59+
console.error('Missing job_id in API server response:', responseData);
60+
return NextResponse.json({ error: 'API server response does not contain job_id' }, { status: 500 });
61+
}
62+
63+
// Return the response from the API server to the client
64+
console.log('Returning success response with job_id:', responseData.job_id);
65+
return NextResponse.json(responseData, { status: 200 });
66+
} catch (error) {
67+
console.error('Unexpected error during training:', error);
68+
return NextResponse.json({ error: 'An unexpected error occurred during training' }, { status: 500 });
69+
}
70+
}

0 commit comments

Comments
 (0)