Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions integ-tests/baml_src/ai-content-pipeline/api_functions.baml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// API integration functions for external services
// Using std::fetch_value for real HTTP calls to API server

function FetchMeetingInfo(meeting_id: string) -> ZoomMeeting {
let api_url = env.API_BASE_URL + "/api/meetings/" + meeting_id;

return std::fetch_value<ZoomMeeting>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {}
});
}

function FetchRecordingInfo(recording_id: string) -> ZoomRecording {
let api_url = env.API_BASE_URL + "/api/recordings/" + recording_id;

return std::fetch_value<ZoomRecording>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {}
});
}

function FetchRecordingsForMeeting(meeting_id: string) -> ZoomRecording[] {
let api_url = env.API_BASE_URL + "/api/meetings/" + meeting_id + "/recordings";

return std::fetch_value<ZoomRecording[]>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {}
});
}

function FetchTranscriptFromZoom(meeting_id: string, recording_id: string) -> string {
let api_url = env.API_BASE_URL + "/api/meetings/" + meeting_id + "/recordings/" + recording_id + "/transcript";

let response_data = std::fetch_value<map<string, string>>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {}
});

return response_data["transcript"];
}

function DownloadZoomRecording(recording: ZoomRecording) -> map<string, string> {
let api_url = env.API_BASE_URL + "/api/recordings/" + recording.id + "/download";

return std::fetch_value<map<string, string>>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {
"recording_id": recording.id,
"download_url": recording.download_url
}
});
}

function UploadVideoToYoutube(file_path: string, metadata: VideoMetadata) -> YouTubeVideo {
let api_url = env.API_BASE_URL + "/api/youtube/upload";

return std::fetch_value<YouTubeVideo>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {
"file_path": file_path,
"title": metadata.title,
"description": metadata.description,
"tags": metadata.tags.join(","),
"category": metadata.category,
"privacy_status": "private"
}
});
}

function UpdateJobStatus(meeting_id: string, recording_id: string, youtube_id: string?, status: string) -> VideoProcessingJob {
let job_id = meeting_id + "_" + recording_id;
let api_url = env.API_BASE_URL + "/api/jobs/" + job_id;

return std::fetch_value<VideoProcessingJob>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {
"status": status,
"youtube_video_id": youtube_id,
"updated_at": GetCurrentTimestamp()
}
});
}

function FetchJobDetails(job_id: string) -> VideoProcessingJob {
let api_url = env.API_BASE_URL + "/api/jobs/" + job_id;

return std::fetch_value<VideoProcessingJob>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {}
});
}

function CreateProcessingJob(meeting_id: string, recording_id: string) -> VideoProcessingJob {
let api_url = env.API_BASE_URL + "/api/jobs";

return std::fetch_value<VideoProcessingJob>(std::Request {
base_url: api_url,
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + env.API_TOKEN
},
query_params: {
"zoom_meeting_id": meeting_id,
"zoom_recording_id": recording_id,
"status": "pending",
"created_at": GetCurrentTimestamp()
}
});
}
198 changes: 198 additions & 0 deletions integ-tests/baml_src/ai-content-pipeline/expression_functions.baml
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Expression functions for AI Content Pipeline orchestration

function ProcessVideoWorkflow(zoom_meeting_id: string, zoom_recording_id: string) -> VideoProcessingJob {
emit let progress_percent: int = 0;

# Initialization
progress_percent = 10;
let meeting_info = FetchMeetingInfo(zoom_meeting_id);
let recording_info = FetchRecordingInfo(zoom_recording_id);

# Downloading Recording
progress_percent = 20;
let download_result = DownloadZoomRecording(recording_info);

# Extracting Transcript
progress_percent = 40;
let transcript = FetchTranscriptFromZoom(zoom_meeting_id, zoom_recording_id);

# Generating Metadata
progress_percent = 60;
let video_metadata = GenerateCompleteVideoMetadata(transcript, meeting_info);

# Uploading to YouTube
progress_percent = 80;
let youtube_result = UploadVideoToYoutube(download_result.file_path, video_metadata);

# Updating Database
progress_percent = 95;
let final_job = UpdateJobStatus(zoom_meeting_id, zoom_recording_id, youtube_result.video_id, "completed");

# Completed
progress_percent = 100;
return final_job;
}

function GenerateCompleteVideoMetadata(transcript: string, meeting_info: ZoomMeeting) -> VideoMetadata {
# Extracting Topics
let topics = ExtractKeyTopics(transcript);

# Classifying Meeting
let meeting_type = ClassifyMeetingType(transcript, meeting_info.topic);

# Generating Title
let title = GenerateVideoTitle(topics, meeting_info.topic);

# Generating Description
let description = GenerateVideoDescription(transcript, topics, title);

# Generating Tags
let tags = GenerateVideoTags(topics, meeting_info.topic);

# Determining Category
let category = DetermineVideoCategory(meeting_type, topics);

return VideoMetadata {
title: title,
description: description,
tags: tags,
category: category,
thumbnail_url: null,
duration_seconds: meeting_info.duration
};
}

function SelectBestRecording(recordings: ZoomRecording[]) -> ZoomRecording? {
emit let recordings_count: int = recordings.length();

# Validating Input
if (recordings_count == 0) {
return null;
}

# Evaluating Recordings
let mut best_recording: ZoomRecording? = null;
let mut best_priority: int = -1;

for recording in recordings {
let priority = GetRecordingPriority(recording.recording_type);
if (priority > best_priority) {
best_priority = priority;
best_recording = recording;
}
}

return best_recording;
}

function GetRecordingPriority(recording_type: string) -> int {
if (recording_type == "speaker_view") {
return 3;
} else if (recording_type == "screen_share") {
return 2;
} else if (recording_type == "gallery_view") {
return 1;
} else {
return 0;
}
}

function BatchProcessVideos(job_ids: string[]) -> VideoProcessingJob[] {
emit let batch_progress: int = 0;
emit let total_jobs: int = job_ids.length();
emit let completed_jobs: int = 0;

let mut results: VideoProcessingJob[] = [];

for job_id in job_ids {
emit let current_job: string = job_id;

// Fetch job details
let job_details = FetchJobDetails(job_id);

// Process the video
let processed_job = ProcessVideoWorkflow(
job_details.zoom_meeting_id,
job_details.zoom_recording_id
);

results = results + [processed_job];
completed_jobs = completed_jobs + 1;
batch_progress = (completed_jobs * 100) / total_jobs;
}

return results;
}

function ValidateVideoProcessingInputs(zoom_meeting_id: string, zoom_recording_id: string) -> bool {
# Checking Meeting ID
if (zoom_meeting_id.length() == 0) {
return false;
}

# Checking Recording ID
if (zoom_recording_id.length() == 0) {
return false;
}

return true;
}

// Workflow coordination with error handling
function ProcessVideoWithErrorHandling(zoom_meeting_id: string, zoom_recording_id: string) -> VideoProcessingJob {
emit let error_count: int = 0;
emit let current_attempt: int = 1;
emit let max_retries: int = 3;

# Input Validation
let is_valid = ValidateVideoProcessingInputs(zoom_meeting_id, zoom_recording_id);
if (!is_valid) {
return VideoProcessingJob {
id: zoom_meeting_id + "_" + zoom_recording_id,
zoom_meeting_id: zoom_meeting_id,
zoom_recording_id: zoom_recording_id,
status: "failed",
error_message: "Invalid input parameters",
youtube_video_id: null,
created_at: GetCurrentTimestamp(),
updated_at: GetCurrentTimestamp()
};
}

# Retry Loop
while (current_attempt <= max_retries) {
emit let retry_attempt: int = current_attempt;

let result = TryProcessVideo(zoom_meeting_id, zoom_recording_id);

if (result.status == "completed") {
return result;
} else {
error_count = error_count + 1;
current_attempt = current_attempt + 1;
}
}

# Max Retries Exceeded
return VideoProcessingJob {
id: zoom_meeting_id + "_" + zoom_recording_id,
zoom_meeting_id: zoom_meeting_id,
zoom_recording_id: zoom_recording_id,
status: "failed",
error_message: "Maximum retries exceeded",
youtube_video_id: null,
created_at: GetCurrentTimestamp(),
updated_at: GetCurrentTimestamp()
};
}

function TryProcessVideo(zoom_meeting_id: string, zoom_recording_id: string) -> VideoProcessingJob {
// This wraps ProcessVideoWorkflow with try/catch semantics
// In actual implementation, this would handle exceptions
return ProcessVideoWorkflow(zoom_meeting_id, zoom_recording_id);
}

function GetCurrentTimestamp() -> string {
// This would need to be implemented as a builtin or API call
return "2024-01-01T00:00:00Z";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetCurrentTimestamp returns a constant value; update this to generate a dynamic current timestamp.

Suggested change
return "2024-01-01T00:00:00Z";
return now();

}
Loading
Loading