Overview
This walkthrough demonstrates how to build a stock analysis and investment tips extraction model from YouTube financial content. You’ll learn how to:- Process 5 YouTube videos about stocks and investing
- Use question/answer templates to extract simple, structured JSON output
- Generate training data that captures stock tickers, actionable tips, and risks mentioned
- Create train/validation splits and get model recommendations
- Launch fine-tuning to create a specialized financial intelligence model
stocks_mentioned: Array of ticker symbols (e.g., [“AAPL”, “TSLA”])investment_tips: List of actionable advice from the videorisks_mentioned: Warnings or cautionary statements discussedvideo_topic: Brief description of the main topic
Export your Prem API key as
API_KEY before running any script.
The example uses 5 curated financial YouTube videos. You can modify the YOUTUBE_URLS array to use your own videos.1
Setup: Define your YouTube URLs
const API_KEY = process.env.API_KEY;
// Define the YouTube videos you want to analyze
const YOUTUBE_URLS = [
'https://www.youtube.com/watch?v=JH-k5f4Yclc',
'https://www.youtube.com/watch?v=YEWhxcpMS1c',
'https://www.youtube.com/watch?v=cb8up3HVXis',
'https://www.youtube.com/watch?v=26xatIiMv88',
'https://www.youtube.com/watch?v=-Da3gUdzCvs'
];
import os
import requests
API_KEY = os.getenv("API_KEY")
# Define the YouTube videos you want to analyze
YOUTUBE_URLS = [
"https://www.youtube.com/watch?v=JH-k5f4Yclc",
"https://www.youtube.com/watch?v=YEWhxcpMS1c",
"https://www.youtube.com/watch?v=cb8up3HVXis",
"https://www.youtube.com/watch?v=26xatIiMv88",
"https://www.youtube.com/watch?v=-Da3gUdzCvs"
]
2
Create project and generate synthetic dataset
const res = await fetch('https://studio.premai.io/api/v1/public/projects/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'Stock Analysis Project', goal: 'Extract investment insights from financial videos' })
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const { project_id } = await res.json();
const formData = new FormData();
formData.append('project_id', project_id);
formData.append('name', 'Financial YouTube Dataset');
// Add YouTube URLs
YOUTUBE_URLS.forEach((url: string, index: number) => {
formData.append(`youtube_urls[${index}]`, url);
});
formData.append('pairs_to_generate', '50');
formData.append('pair_type', 'qa');
formData.append('temperature', '0.3');
// Add rules and constraints
formData.append('rules[]', 'stocks_mentioned: List all stock ticker symbols mentioned (e.g., AAPL, TSLA, NVDA)');
formData.append('rules[]', 'investment_tips: Extract 3-5 specific, actionable pieces of advice from the video');
formData.append('rules[]', 'risks_mentioned: List any warnings, risks, or cautionary statements discussed');
formData.append('rules[]', 'video_topic: Write a short phrase describing the main topic of the video');
formData.append('rules[]', 'Only output valid JSON with no additional text before or after');
formData.append('rules[]', 'If a field has no relevant information, use an empty array [] or empty string ""');
formData.append('rules[]', 'Use exact quotes or close paraphrases from the video content');
formData.append('rules[]', 'Do not invent or infer information not explicitly stated');
// Define question format
const questionFormat = `Extract investment information from the following video transcript:
{VIDEO_TRANSCRIPT}
Provide the output in this JSON format:
{
"stocks_mentioned": ["TICKER1", "TICKER2"],
"investment_tips": ["tip 1", "tip 2", "tip 3"],
"risks_mentioned": ["risk 1", "risk 2"],
"video_topic": "brief description of main topic"
}`;
formData.append('question_format', questionFormat);
// Define answer format
const answerFormat = `{
"stocks_mentioned": ["<TICKER_SYMBOL_1>", "<TICKER_SYMBOL_2>"],
"investment_tips": ["<specific_tip_1>", "<specific_tip_2>", "<specific_tip_3>"],
"risks_mentioned": ["<risk_or_warning_1>", "<risk_or_warning_2>"],
"video_topic": "<main_topic_of_video>"
}`;
formData.append('answer_format', answerFormat);
const res2 = await fetch('https://studio.premai.io/api/v1/public/datasets/create-synthetic', {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` },
body: formData
});
if (!res2.ok) throw new Error(`${res2.status}: ${await res2.text()}`);
const { dataset_id } = await res2.json();
YOUTUBE_URLS = [
"https://www.youtube.com/watch?v=JH-k5f4Yclc",
"https://www.youtube.com/watch?v=YEWhxcpMS1c",
"https://www.youtube.com/watch?v=cb8up3HVXis",
"https://www.youtube.com/watch?v=26xatIiMv88",
"https://www.youtube.com/watch?v=-Da3gUdzCvs"
]
response = requests.post(
"https://studio.premai.io/api/v1/public/projects/create",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"name": "Stock Analysis Project", "goal": "Extract investment insights from financial videos"}
)
response.raise_for_status()
project_id = response.json()["project_id"]
# Define question format
question_format = """Extract investment information from the following video transcript:
{VIDEO_TRANSCRIPT}
Provide the output in this JSON format:
{
"stocks_mentioned": ["TICKER1", "TICKER2"],
"investment_tips": ["tip 1", "tip 2", "tip 3"],
"risks_mentioned": ["risk 1", "risk 2"],
"video_topic": "brief description of main topic"
}"""
# Define answer format
answer_format = """{
"stocks_mentioned": ["<TICKER_SYMBOL_1>", "<TICKER_SYMBOL_2>"],
"investment_tips": ["<specific_tip_1>", "<specific_tip_2>", "<specific_tip_3>"],
"risks_mentioned": ["<risk_or_warning_1>", "<risk_or_warning_2>"],
"video_topic": "<main_topic_of_video>"
}"""
form_data = {
"project_id": project_id,
"name": "Financial YouTube Dataset",
"pairs_to_generate": "50",
"pair_type": "qa",
"temperature": "0.3",
"rules[]": [
"stocks_mentioned: List all stock ticker symbols mentioned (e.g., AAPL, TSLA, NVDA)",
"investment_tips: Extract 3-5 specific, actionable pieces of advice from the video",
"risks_mentioned: List any warnings, risks, or cautionary statements discussed",
"video_topic: Write a short phrase describing the main topic of the video",
"Only output valid JSON with no additional text before or after",
"If a field has no relevant information, use an empty array [] or empty string \"\"",
"Use exact quotes or close paraphrases from the video content",
"Do not invent or infer information not explicitly stated"
],
"question_format": question_format,
"answer_format": answer_format
}
# Add YouTube URLs
for i, url in enumerate(YOUTUBE_URLS):
form_data[f"youtube_urls[{i}]"] = url
response = requests.post(
"https://studio.premai.io/api/v1/public/datasets/create-synthetic",
headers={"Authorization": f"Bearer {API_KEY}"},
data=form_data
)
response.raise_for_status()
dataset_id = response.json()["dataset_id"]
3
Wait for dataset generation
let dataset;
let checks = 0;
do {
await sleep(5000);
const res = await fetch(`https://studio.premai.io/api/v1/public/datasets/${dataset_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
dataset = await res.json();
if (checks++ % 6 === 0) {
console.log(`Status: ${dataset.status}, ${dataset.datapoints_count} datapoints`);
}
} while (dataset.status === 'processing');
checks = 0
while True:
time.sleep(5)
response = requests.get(
f"https://studio.premai.io/api/v1/public/datasets/{dataset_id}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
dataset = response.json()
if checks % 6 == 0:
print(f"Status: {dataset['status']}, {dataset['datapoints_count']} datapoints")
checks += 1
if dataset["status"] != "processing":
break
4
Create snapshot and get recommendations
const res = await fetch('https://studio.premai.io/api/v1/public/snapshots/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ dataset_id, split_percentage: 80 })
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const { snapshot_id } = await res.json();
const res2 = await fetch('https://studio.premai.io/api/v1/public/recommendations/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ snapshot_id })
});
if (!res2.ok) throw new Error(`${res2.status}: ${await res2.text()}`);
let recs;
do {
await sleep(5000);
const res3 = await fetch(`https://studio.premai.io/api/v1/public/recommendations/${snapshot_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res3.ok) throw new Error(`${res3.status}: ${await res3.text()}`);
recs = await res3.json();
} while (recs.status === 'processing');
response = requests.post(
"https://studio.premai.io/api/v1/public/snapshots/create",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"dataset_id": dataset_id, "split_percentage": 80}
)
response.raise_for_status()
snapshot_id = response.json()["snapshot_id"]
response = requests.post(
"https://studio.premai.io/api/v1/public/recommendations/generate",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"snapshot_id": snapshot_id}
)
response.raise_for_status()
while True:
time.sleep(5)
response = requests.get(
f"https://studio.premai.io/api/v1/public/recommendations/{snapshot_id}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
recs = response.json()
if recs["status"] != "processing":
break
5
Launch fine-tuning job
const experiments = recs.recommended_experiments
.filter((e: any) => e.recommended)
.map(({ recommended, reason_for_recommendation, ...experiment }: any) => experiment);
const res = await fetch('https://studio.premai.io/api/v1/public/finetuning/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ snapshot_id, name: 'YouTube Model', experiments })
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const { job_id } = await res.json();
experiments = [
{k: v for k, v in exp.items() if k not in ["recommended", "reason_for_recommendation"]}
for exp in recs["recommended_experiments"] if exp["recommended"]
]
response = requests.post(
"https://studio.premai.io/api/v1/public/finetuning/create",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={"snapshot_id": snapshot_id, "name": "YouTube Model", "experiments": experiments}
)
response.raise_for_status()
job_id = response.json()["job_id"]
6
Monitor job progress
for (let i = 0; i < 30; i++) {
await sleep(10000);
const res = await fetch(`https://studio.premai.io/api/v1/public/finetuning/${job_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const job = await res.json();
console.log(`Status: ${job.status}`);
job.experiments.forEach((e: any) => {
console.log(` - Exp #${e.experiment_number}: ${e.status} ${e.model_id || ''}`);
});
if (job.status !== 'processing') break;
}
for i in range(30):
time.sleep(10)
response = requests.get(
f"https://studio.premai.io/api/v1/public/finetuning/{job_id}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
job = response.json()
print(f"Status: {job['status']}")
for exp in job["experiments"]:
print(f" - Exp #{exp['experiment_number']}: {exp['status']} {exp.get('model_id', '')}")
if job["status"] != "processing":
break
Full Example
#!/usr/bin/env bun
/**
* Example 2: YouTube synthetic dataset workflow
* 1. Create project → 2. Generate synthetic data from YouTube → 3. Create snapshot → 4. Get recommendations → 5. Run finetuning
*/
const API_KEY = process.env.API_KEY;
const YOUTUBE_URLS = [
'https://www.youtube.com/watch?v=JH-k5f4Yclc',
'https://www.youtube.com/watch?v=YEWhxcpMS1c',
'https://www.youtube.com/watch?v=cb8up3HVXis',
'https://www.youtube.com/watch?v=26xatIiMv88',
'https://www.youtube.com/watch?v=-Da3gUdzCvs'
];
if (!API_KEY) {
console.error('Error: API_KEY environment variable is required');
console.error('Please create a .env file based on .env.example');
process.exit(1);
}
function sleep(ms: number) {
return new Promise((r) => setTimeout(r, ms));
}
async function main() {
console.log('\n=== YouTube Synthetic Workflow ===\n');
// 1. Create project
console.log('1. Creating project...');
const res1 = await fetch('https://studio.premai.io/api/v1/public/projects/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'Stock Analysis Project', goal: 'Extract investment insights from financial videos' }),
});
if (!res1.ok) throw new Error(`${res1.status}: ${await res1.text()}`);
const { project_id } = await res1.json();
console.log(` ✓ Project: ${project_id}\n`);
// 2. Generate synthetic dataset
console.log('2. Generating synthetic dataset from YouTube...');
console.log(` URLs: ${YOUTUBE_URLS.length} financial videos`);
const formData = new FormData();
formData.append('project_id', project_id);
formData.append('name', 'Financial YouTube Dataset');
// Add multiple YouTube URLs
YOUTUBE_URLS.forEach((url, index) => {
formData.append(`youtube_urls[${index}]`, url);
});
formData.append('pairs_to_generate', '50');
formData.append('pair_type', 'qa');
formData.append('temperature', '0.3');
// Add rules and constraints
formData.append('rules[]', 'stocks_mentioned: List all stock ticker symbols mentioned (e.g., AAPL, TSLA, NVDA)');
formData.append('rules[]', 'investment_tips: Extract 3-5 specific, actionable pieces of advice from the video');
formData.append('rules[]', 'risks_mentioned: List any warnings, risks, or cautionary statements discussed');
formData.append('rules[]', 'video_topic: Write a short phrase describing the main topic of the video');
formData.append('rules[]', 'Only output valid JSON with no additional text before or after');
formData.append('rules[]', 'If a field has no relevant information, use an empty array [] or empty string ""');
formData.append('rules[]', 'Use exact quotes or close paraphrases from the video content');
formData.append('rules[]', 'Do not invent or infer information not explicitly stated');
// Define question format
const questionFormat = `Extract investment information from the following video transcript:
{VIDEO_TRANSCRIPT}
Provide the output in this JSON format:
{
"stocks_mentioned": ["TICKER1", "TICKER2"],
"investment_tips": ["tip 1", "tip 2", "tip 3"],
"risks_mentioned": ["risk 1", "risk 2"],
"video_topic": "brief description of main topic"
}`;
formData.append('question_format', questionFormat);
// Define answer format
const answerFormat = `{
"stocks_mentioned": ["<TICKER_SYMBOL_1>", "<TICKER_SYMBOL_2>"],
"investment_tips": ["<specific_tip_1>", "<specific_tip_2>", "<specific_tip_3>"],
"risks_mentioned": ["<risk_or_warning_1>", "<risk_or_warning_2>"],
"video_topic": "<main_topic_of_video>"
}`;
formData.append('answer_format', answerFormat);
const res2 = await fetch('https://studio.premai.io/api/v1/public/datasets/create-synthetic', {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` },
body: formData,
});
if (!res2.ok) throw new Error(`${res2.status}: ${await res2.text()}`);
const { dataset_id } = await res2.json();
console.log(` ✓ Dataset: ${dataset_id}`);
// Wait for dataset (can take several minutes)
console.log(' Waiting for generation (may take 5-10 minutes)...');
let dataset;
let checks = 0;
do {
await sleep(5000);
const res = await fetch(`https://studio.premai.io/api/v1/public/datasets/${dataset_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
dataset = await res.json();
if (checks++ % 6 === 0) {
console.log(` Status: ${dataset.status}, ${dataset.datapoints_count} datapoints`);
}
} while (dataset.status === 'processing');
console.log(` ✓ Ready: ${dataset.datapoints_count} datapoints\n`);
// 3. Create snapshot
console.log('3. Creating snapshot...');
const res3 = await fetch('https://studio.premai.io/api/v1/public/snapshots/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ dataset_id, split_percentage: 80 }),
});
if (!res3.ok) throw new Error(`${res3.status}: ${await res3.text()}`);
const { snapshot_id } = await res3.json();
console.log(` ✓ Snapshot: ${snapshot_id}\n`);
// 4. Generate recommendations
console.log('4. Generating recommendations...');
const res4 = await fetch('https://studio.premai.io/api/v1/public/recommendations/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ snapshot_id }),
});
if (!res4.ok) throw new Error(`${res4.status}: ${await res4.text()}`);
let recs;
do {
await sleep(5000);
const res = await fetch(`https://studio.premai.io/api/v1/public/recommendations/${snapshot_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
recs = await res.json();
} while (recs.status === 'processing');
console.log(` ✓ Recommended experiments:`);
const recommendedCount = recs.recommended_experiments.filter((e: any) => e.recommended).length;
console.log(` Total experiments: ${recs.recommended_experiments.length}, Recommended: ${recommendedCount}`);
recs.recommended_experiments.forEach((e: any) => {
if (e.recommended) console.log(` - ${e.base_model_id} (LoRA: ${e.lora})`);
});
console.log();
// 5. Create finetuning job
console.log('5. Creating finetuning job...');
const experiments = recs.recommended_experiments
.filter((e: any) => e.recommended)
.map(({ recommended, reason_for_recommendation, ...experiment }: any) => experiment);
if (experiments.length === 0) {
console.error('\n✗ Error: No recommended experiments found. Cannot create finetuning job.');
process.exit(1);
}
const res5 = await fetch('https://studio.premai.io/api/v1/public/finetuning/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ snapshot_id, name: 'YouTube Model', experiments }),
});
if (!res5.ok) throw new Error(`${res5.status}: ${await res5.text()}`);
const { job_id } = await res5.json();
console.log(` ✓ Job: ${job_id}\n`);
// 6. Monitor (5 minutes max)
console.log('6. Monitoring job...');
for (let i = 0; i < 30; i++) {
await sleep(10000);
const res = await fetch(`https://studio.premai.io/api/v1/public/finetuning/${job_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const job = await res.json();
console.log(` Status: ${job.status}`);
job.experiments.forEach((e: any) => {
console.log(` - Exp #${e.experiment_number}: ${e.status} ${e.model_id || ''}`);
});
if (job.status !== 'processing') break;
}
console.log('\n✓ Done!\n');
}
main().catch((err) => {
console.error('\n✗ Error:', err.message);
process.exit(1);
});
#!/usr/bin/env python3
"""
Example 2: YouTube synthetic dataset workflow
1. Create project → 2. Generate synthetic data from YouTube → 3. Create snapshot → 4. Get recommendations → 5. Run finetuning
"""
import os
import time
import requests
API_KEY = os.getenv("API_KEY")
YOUTUBE_URLS = [
"https://www.youtube.com/watch?v=JH-k5f4Yclc",
"https://www.youtube.com/watch?v=YEWhxcpMS1c",
"https://www.youtube.com/watch?v=cb8up3HVXis",
"https://www.youtube.com/watch?v=26xatIiMv88",
"https://www.youtube.com/watch?v=-Da3gUdzCvs"
]
if not API_KEY:
print("Error: API_KEY environment variable is required")
exit(1)
def api(endpoint: str, method: str = "GET", **kwargs):
response = requests.request(
method=method,
url=f"https://studio.premai.io{endpoint}",
headers={"Authorization": f"Bearer {API_KEY}", **kwargs.pop("headers", {})},
**kwargs
)
if not response.ok:
err = response.json() if response.content else {}
error_msg = err.get("error", str(err)) if isinstance(err, dict) else str(err)
raise Exception(f"{response.status_code}: {error_msg}")
return response.json()
def main():
print("\n=== YouTube Synthetic Workflow ===\n")
# Create project
print("1. Creating project...")
result = api("/api/v1/public/projects/create", method="POST", headers={"Content-Type": "application/json"}, json={"name": "Stock Analysis Project", "goal": "Extract investment insights from financial videos"})
project_id = result["project_id"]
print(f" ✓ Project: {project_id}\n")
# Generate synthetic dataset
print("2. Generating synthetic dataset from YouTube...")
print(f" URLs: {len(YOUTUBE_URLS)} financial videos")
# Define question format
question_format = """Extract investment information from the following video transcript:
{VIDEO_TRANSCRIPT}
Provide the output in this JSON format:
{
"stocks_mentioned": ["TICKER1", "TICKER2"],
"investment_tips": ["tip 1", "tip 2", "tip 3"],
"risks_mentioned": ["risk 1", "risk 2"],
"video_topic": "brief description of main topic"
}"""
# Define answer format
answer_format = """{
"stocks_mentioned": ["<TICKER_SYMBOL_1>", "<TICKER_SYMBOL_2>"],
"investment_tips": ["<specific_tip_1>", "<specific_tip_2>", "<specific_tip_3>"],
"risks_mentioned": ["<risk_or_warning_1>", "<risk_or_warning_2>"],
"video_topic": "<main_topic_of_video>"
}"""
form_data = {
"project_id": project_id,
"name": "Financial YouTube Dataset",
"pairs_to_generate": "50",
"pair_type": "qa",
"temperature": "0.3",
"rules[]": [
"stocks_mentioned: List all stock ticker symbols mentioned (e.g., AAPL, TSLA, NVDA)",
"investment_tips: Extract 3-5 specific, actionable pieces of advice from the video",
"risks_mentioned: List any warnings, risks, or cautionary statements discussed",
"video_topic: Write a short phrase describing the main topic of the video",
"Only output valid JSON with no additional text before or after",
"If a field has no relevant information, use an empty array [] or empty string \"\"",
"Use exact quotes or close paraphrases from the video content",
"Do not invent or infer information not explicitly stated"
],
"question_format": question_format,
"answer_format": answer_format
}
# Add YouTube URLs
for i, url in enumerate(YOUTUBE_URLS):
form_data[f"youtube_urls[{i}]"] = url
result = api("/api/v1/public/datasets/create-synthetic", method="POST", data=form_data)
dataset_id = result["dataset_id"]
print(f" ✓ Dataset: {dataset_id}")
# Wait for dataset (can take several minutes)
print(" Waiting for generation (may take 5-10 minutes)...")
checks = 0
while True:
time.sleep(5)
dataset = api(f"/api/v1/public/datasets/{dataset_id}")
if checks % 6 == 0:
print(f" Status: {dataset['status']}, {dataset['datapoints_count']} datapoints")
checks += 1
if dataset["status"] != "processing":
break
print(f" ✓ Ready: {dataset['datapoints_count']} datapoints\n")
# Create snapshot
print("3. Creating snapshot...")
result = api("/api/v1/public/snapshots/create", method="POST", headers={"Content-Type": "application/json"}, json={"dataset_id": dataset_id, "split_percentage": 80})
snapshot_id = result["snapshot_id"]
print(f" ✓ Snapshot: {snapshot_id}\n")
# Generate recommendations
print("4. Generating recommendations...")
api("/api/v1/public/recommendations/generate", method="POST", headers={"Content-Type": "application/json"}, json={"snapshot_id": snapshot_id})
while True:
time.sleep(5)
recs = api(f"/api/v1/public/recommendations/{snapshot_id}")
if recs["status"] != "processing":
break
print(" ✓ Recommended experiments:")
recommended_count = sum(1 for e in recs["recommended_experiments"] if e["recommended"])
print(f" Total experiments: {len(recs['recommended_experiments'])}, Recommended: {recommended_count}")
for e in recs["recommended_experiments"]:
if e["recommended"]:
print(f" - {e['base_model_id']} (LoRA: {e['lora']})")
print()
# Create finetuning job
print("5. Creating finetuning job...")
experiments = [
{k: v for k, v in exp.items() if k not in ["recommended", "reason_for_recommendation"]}
for exp in recs["recommended_experiments"] if exp["recommended"]
]
if not experiments:
print("\n✗ Error: No recommended experiments found. Cannot create finetuning job.")
exit(1)
result = api("/api/v1/public/finetuning/create", method="POST", headers={"Content-Type": "application/json"}, json={"snapshot_id": snapshot_id, "name": "YouTube Model", "experiments": experiments})
job_id = result["job_id"]
print(f" ✓ Job: {job_id}\n")
# Monitor (5 minutes max)
print("6. Monitoring job...")
for i in range(30):
time.sleep(10)
job = api(f"/api/v1/public/finetuning/{job_id}")
print(f" Status: {job['status']}")
for exp in job["experiments"]:
print(f" - Exp #{exp['experiment_number']}: {exp['status']} {exp.get('model_id', '')}")
if job["status"] != "processing":
break
print("\n✓ Done!\n")
if __name__ == "__main__":
try:
main()
except Exception as err:
print(f"\n✗ Error: {err}")
exit(1)