Skip to content

Commit 3f2b10f

Browse files
committed
feat: download zip folder functionality
1 parent ce55fa8 commit 3f2b10f

3 files changed

Lines changed: 82 additions & 3 deletions

File tree

src/components/User/Dashboard/DatasetOrganizer/LLMPanel.tsx

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
downloadJSON,
99
buildEvidenceBundle,
1010
extractSubjectsFromFiles,
11+
buildIngestInfo,
1112
} from "./utils/llmHelpers";
1213
import {
1314
getDatasetDescriptionPrompt,
@@ -32,6 +33,7 @@ import {
3233
Alert,
3334
} from "@mui/material";
3435
import { Colors } from "design/theme";
36+
import JSZip from "jszip";
3537
import React, { useState, useEffect } from "react";
3638
import { FileItem } from "redux/projects/types/projects.interface";
3739

@@ -214,7 +216,7 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
214216
// Call 1: Generate dataset_description.json
215217
// ==========================================
216218
setStatus("1/3 Generating dataset_description.json...");
217-
const ddPrompt = getDatasetDescriptionPrompt(userText);
219+
const ddPrompt = getDatasetDescriptionPrompt(userText, evidenceBundle);
218220

219221
let ddResponse;
220222
if (currentProvider.isAnthropic) {
@@ -795,6 +797,43 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
795797
URL.revokeObjectURL(url);
796798
};
797799

800+
const handleDownloadPackage = async () => {
801+
const zip = new JSZip();
802+
const outputDir = "bids-output";
803+
804+
// _staging/ files
805+
const ingestInfo = buildIngestInfo(baseDirectoryPath, outputDir);
806+
zip.file("_staging/ingest_info.json", JSON.stringify(ingestInfo, null, 2));
807+
zip.file("_staging/BIDSPlan.yaml", bidsPlan); // your already-generated YAML
808+
zip.file(
809+
"_staging/evidence_bundle.json",
810+
JSON.stringify(evidenceBundle, null, 2)
811+
);
812+
// trio files (get content from the AI-generated FileItems)
813+
const dd = files.find(
814+
(f) => f.source === "ai" && f.name === "dataset_description.json"
815+
);
816+
const readme = files.find(
817+
(f) => f.source === "ai" && f.name === "README.md"
818+
);
819+
const participants = files.find(
820+
(f) => f.source === "ai" && f.name === "participants.tsv"
821+
);
822+
823+
if (dd?.content) zip.file("dataset_description.json", dd.content);
824+
if (readme?.content) zip.file("README.md", readme.content);
825+
if (participants?.content)
826+
zip.file("participants.tsv", participants.content);
827+
828+
const blob = await zip.generateAsync({ type: "blob" });
829+
const url = URL.createObjectURL(blob);
830+
const a = document.createElement("a");
831+
a.href = url;
832+
a.download = "bids-output.zip";
833+
a.click();
834+
URL.revokeObjectURL(url);
835+
};
836+
798837
return (
799838
<Paper
800839
sx={{
@@ -1130,6 +1169,15 @@ const LLMPanel: React.FC<LLMPanelProps> = ({
11301169
{/* Download */}
11311170
{bidsPlan ? "Download BIDSPlan.yaml" : "Download Script"}
11321171
</Button>
1172+
<Button
1173+
size="small"
1174+
startIcon={<Download />}
1175+
onClick={handleDownloadPackage}
1176+
disabled={!bidsPlan && !generatingTrio}
1177+
>
1178+
{/* Download */}
1179+
Download zip file for convert
1180+
</Button>
11331181
</Box>
11341182

11351183
<Paper

src/components/User/Dashboard/DatasetOrganizer/utils/llmHelpers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,19 @@ export const extractSubjectsFromFiles = (
380380

381381
return { subjects, strategy };
382382
};
383+
384+
export const buildIngestInfo = (
385+
baseDirectoryPath: string,
386+
outputDir: string
387+
): object => {
388+
return {
389+
step: "ingest",
390+
timestamp: new Date().toISOString(),
391+
input_path: baseDirectoryPath,
392+
input_type: "directory",
393+
output_dir: outputDir,
394+
staging_dir: null,
395+
actual_data_path: baseDirectoryPath, // ← the key field executor uses
396+
status: "complete",
397+
};
398+
};

src/components/User/Dashboard/DatasetOrganizer/utils/llmPrompts.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,30 @@
44
* Prompt for dataset_description.json generation
55
* Based on auto-bidsify's PROMPT_TRIO_DATASET_DESC
66
*/
7-
export const getDatasetDescriptionPrompt = (userText: string): string => {
7+
export const getDatasetDescriptionPrompt = (
8+
userText: string,
9+
evidenceBundle?: any
10+
): string => {
11+
const documentsContext =
12+
evidenceBundle?.documents
13+
?.map((d: any) => `[${d.filename}]:\n${d.content}`)
14+
.join("\n\n") || "";
815
return `You are a BIDS dataset_description.json generator.
916
1017
CRITICAL: Use the following user-provided content to extract dataset information!
1118
1219
USER-PROVIDED CONTENT:
1320
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14-
${userText}
21+
${userText || "(no readme/instructions provided)"}
22+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
23+
24+
ALL UPLOADED DOCUMENTS (search these for dataset name, authors, etc.):
25+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26+
${documentsContext || "(no documents)"}
1527
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
28+
29+
Also consider the dataset folder name for clues about the dataset name:
30+
File paths start with: ${evidenceBundle?.root || ""}
1631
1732
CRITICAL RULES:
1833
- Authors MUST be array: ["Name 1", "Name 2", "Name 3"]

0 commit comments

Comments
 (0)