diff --git a/simpletuner/simpletuner_sdk/server/services/cloud/job_submission.py b/simpletuner/simpletuner_sdk/server/services/cloud/job_submission.py index 421770f54..b6e776444 100644 --- a/simpletuner/simpletuner_sdk/server/services/cloud/job_submission.py +++ b/simpletuner/simpletuner_sdk/server/services/cloud/job_submission.py @@ -49,6 +49,16 @@ class SubmissionContext: reservation_id: Optional[str] = None quota_warnings: List[str] = field(default_factory=list) + @property + def tracker_metadata(self) -> Dict[str, str]: + metadata = {} + project = self.config.get("--tracker_project_name") or self.config.get("tracker_project_name") + if project: + metadata["tracker_project_name"] = project + if self.tracker_run_name: + metadata["tracker_run_name"] = self.tracker_run_name + return metadata + @dataclass class SubmissionResult: @@ -206,8 +216,7 @@ async def submit( unified_job.output_url = f"https://huggingface.co/{hub_model_id}" if snapshot_metadata: unified_job.metadata["snapshot"] = snapshot_metadata - if ctx.tracker_run_name: - unified_job.metadata["tracker_run_name"] = ctx.tracker_run_name + unified_job.metadata.update(ctx.tracker_metadata) if ctx.hardware_profile: unified_job.metadata["hardware_profile"] = ctx.hardware_profile @@ -296,8 +305,7 @@ async def _create_upload_job( metadata: Dict[str, Any] = {"upload_id": job_id} if snapshot_metadata: metadata["snapshot"] = snapshot_metadata - if ctx.tracker_run_name: - metadata["tracker_run_name"] = ctx.tracker_run_name + metadata.update(ctx.tracker_metadata) if ctx.hardware_profile: metadata["hardware_profile"] = ctx.hardware_profile @@ -327,8 +335,7 @@ async def _update_upload_job_from_provider( metadata.setdefault("prediction_id", cloud_job.job_id) if snapshot_metadata: metadata["snapshot"] = snapshot_metadata - if ctx.tracker_run_name: - metadata["tracker_run_name"] = ctx.tracker_run_name + metadata.update(ctx.tracker_metadata) if ctx.upload_id: metadata["upload_id"] = ctx.upload_id if ctx.hardware_profile: diff --git a/simpletuner/static/js/modules/cloud/index.js b/simpletuner/static/js/modules/cloud/index.js index 772c1e683..0781cc259 100644 --- a/simpletuner/static/js/modules/cloud/index.js +++ b/simpletuner/static/js/modules/cloud/index.js @@ -612,7 +612,7 @@ if (!window.cloudDashboardComponent) { filtered = filtered.filter(j => { const jobId = (j.job_id || '').toLowerCase(); const configName = (j.config_name || '').toLowerCase(); - const trackerName = (j.metadata?.tracker_run_name || '').toLowerCase(); + const trackerName = this.jobDisplayName(j).toLowerCase(); const status = (j.status || '').toLowerCase(); const provider = (j.provider || '').toLowerCase(); return jobId.includes(query) || configName.includes(query) || diff --git a/simpletuner/static/js/modules/cloud/jobs.js b/simpletuner/static/js/modules/cloud/jobs.js index 9a1e09206..3ce34fe34 100644 --- a/simpletuner/static/js/modules/cloud/jobs.js +++ b/simpletuner/static/js/modules/cloud/jobs.js @@ -5,6 +5,25 @@ */ window.cloudJobMethods = { + async continueJob(job) { + const trainer = Alpine.store('trainer'); + if (trainer.continuingJob || job.job_type !== 'local' || job.status !== 'failed') return; + trainer.continuingJob = job.job_id; + try { + const switched = await trainer.switchEnvironment(job.metadata?.env_name || job.config_name); + if (!switched) return; + trainer.switchTab('basic'); + await htmx.ajax('GET', '/web/trainer/tabs/basic', { target: '#tab-content', swap: 'innerHTML' }); + await Alpine.nextTick(); + document.getElementById('runBtn').click(); + } catch (error) { + console.error('Failed to continue job:', error); + window.showToast('Failed to continue job', 'error'); + } finally { + trainer.continuingJob = null; + } + }, + async loadJobs(syncActive = false) { if (!syncActive) { this.jobsLoading = true; diff --git a/simpletuner/static/js/modules/cloud/utilities.js b/simpletuner/static/js/modules/cloud/utilities.js index 9f189e42c..75e710d40 100644 --- a/simpletuner/static/js/modules/cloud/utilities.js +++ b/simpletuner/static/js/modules/cloud/utilities.js @@ -46,7 +46,12 @@ window.cloudUtilityMethods = { }, jobDisplayName(job) { - return job.metadata?.tracker_run_name || job.config_name || job.job_id.substring(0, 8); + const metadata = job.metadata || {}; + const config = metadata.runtime_config || {}; + const project = metadata.tracker_project_name || config['--tracker_project_name'] || config.tracker_project_name; + const run = metadata.tracker_run_name || config['--tracker_run_name'] || config.tracker_run_name || + metadata.run_name || job.config_name || job.job_id.substring(0, 8); + return project ? `${project} / ${run}` : run; }, formatDuration(seconds) { @@ -204,7 +209,7 @@ window.cloudComputedProperties = { filtered = filtered.filter(j => { const jobId = (j.job_id || '').toLowerCase(); const configName = (j.config_name || '').toLowerCase(); - const trackerName = (j.metadata?.tracker_run_name || '').toLowerCase(); + const trackerName = window.cloudUtilityMethods.jobDisplayName(j).toLowerCase(); const status = (j.status || '').toLowerCase(); const provider = (j.provider || '').toLowerCase(); diff --git a/simpletuner/templates/partials/cloud_job_card.html b/simpletuner/templates/partials/cloud_job_card.html index 15a296d47..b6d8925b3 100644 --- a/simpletuner/templates/partials/cloud_job_card.html +++ b/simpletuner/templates/partials/cloud_job_card.html @@ -20,7 +20,7 @@ + :title="jobDisplayName(job)" x-text="jobDisplayName(job)">
@@ -74,6 +74,14 @@ +