Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support document format for pipeline input and output #1586

Merged
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
15 changes: 15 additions & 0 deletions packages/toolkit/src/constant/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,18 @@ version: v1beta
# Click "⌘O" to add a new component
# component:
`;

export const DocumentInputAcceptMimeTypes = [
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"text/html",
"text/plain",
"text",
"text/markdown",
"text/csv",
"application/pdf",
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"use client";

import { Nullable } from "../../../type";
import { ComponentOutputFieldBaseProps } from "../../types";
import { FieldRoot } from "./FieldRoot";

export type DownloadableFileFieldProps = {
file: Nullable<string>;
} & ComponentOutputFieldBaseProps;

export const DownloadableFileField = (props: DownloadableFileFieldProps) => {
const { title, hideField, file } = props;

return (
<FieldRoot title={title} fieldKey={`${title}-field`}>
{!hideField && file ? (
<a
className="text-semantic-accent-default hover:text-semantic-accent-hover cursor-pointer underline font-sans text-xs font-medium"
download={`outout-${title}-download-file`}
href={file}
>
Download file
</a>
) : null}
</FieldRoot>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";

import { Nullable } from "../../../type";
import { ComponentOutputFieldBaseProps } from "../../types";
import { FieldRoot } from "./FieldRoot";

export type DownloadableFilesFieldProps = {
files: Nullable<string>[];
} & ComponentOutputFieldBaseProps;

export const DownloadableFilesField = (props: DownloadableFilesFieldProps) => {
const { title, hideField, files } = props;

return (
<FieldRoot title={title} fieldKey={`${title}-field`}>
{!hideField ? (
<div className="flex flex-col gap-2 flex-wrap">
{files.map((file, index) => {
if (!file) return null;

return (
<a
key={`${title}-download-file-${index}`}
className="text-semantic-accent-default hover:text-semantic-accent-hover cursor-pointer underline font-sans text-xs font-medium"
download={`outout-${title}-download-file-${index}`}
href={file}
>
Download file
</a>
);
})}
</div>
) : null}
</FieldRoot>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { AudioField } from "./AudioField";
import { AudiosField } from "./AudiosField";
import { DownloadableFileField } from "./DownloadableFileField";
import { DownloadableFilesField } from "./DownloadableFilesField";
import { ImageField } from "./ImageField";
import { ImagesField } from "./ImagesField";
import { NumberField } from "./NumberField";
Expand All @@ -24,4 +26,6 @@ export const ComponentOutputFields = {
TextsField,
VideoField,
VideosField,
DownloadableFileField,
DownloadableFilesField,
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export const FileField = ({
disabledFieldControl,
disabledReferenceHint,
instillFormat,
}: StartOperatorFreeFormFieldBaseProps & AutoFormFieldBaseProps) => {
accept,
}: StartOperatorFreeFormFieldBaseProps &
AutoFormFieldBaseProps & { accept: string }) => {
const [uploadedFile, setUploadedFiles] = React.useState<Nullable<File>>();
const inputRef = React.useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -54,7 +56,7 @@ export const FileField = ({
ref={inputRef}
title="Upload file"
fieldKey={path}
accept="*/*"
accept={accept}
onChange={async (e) => {
const file = e.target.files?.[0];
if (file) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ export const FilesField = ({
disabledFieldControl,
disabledReferenceHint,
instillFormat,
}: StartOperatorFreeFormFieldBaseProps & AutoFormFieldBaseProps) => {
accept,
}: StartOperatorFreeFormFieldBaseProps &
AutoFormFieldBaseProps & {
accept: string;
}) => {
const [uploadedFiles, setUploadedFiles] = React.useState<File[]>([]);
const inputRef = React.useRef<HTMLInputElement>(null);

Expand Down Expand Up @@ -56,7 +60,7 @@ export const FilesField = ({
keyPrefix={keyPrefix}
title="Upload files"
fieldKey={path}
accept="*/*"
accept={accept}
multiple={true}
onChange={async (e) => {
if (e.target.files && e.target.files.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export function pickComponentOutputFieldsFromInstillFormTree(
if (tree.instillFormat.includes("array:")) {
const arrayType = tree.instillFormat.replaceAll("array:", "").split("/")[0];

if (arrayType?.includes("structured")) {
if (arrayType?.includes("structured") || arrayType === "json") {
// Some time even the type hint is array:semi-structured, backend will still be possible
// to return array of string or array of number. So we need to handle that case here
if (Array.isArray(propertyValue) && propertyValue.length > 0) {
Expand Down Expand Up @@ -309,7 +309,16 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}

case "document": {
return (
<ComponentOutputFields.DownloadableFilesField
mode={mode}
title={title}
files={propertyValue}
hideField={hideField}
/>
);
}
default: {
return (
<ComponentOutputFields.TextsField
Expand All @@ -328,7 +337,7 @@ export function pickComponentOutputFieldsFromInstillFormTree(
const singularType = tree.instillFormat.split("/")[0];

// Process structured type like semi-structured, structured/detection_object...etc
if (singularType?.includes("structured")) {
if (singularType?.includes("structured") || singularType === "json") {
return (
<ComponentOutputFields.ObjectField
mode={mode}
Expand Down Expand Up @@ -395,7 +404,8 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}
case "semi-structured": {
case "semi-structured":
case "json": {
return (
<ComponentOutputFields.ObjectField
mode={mode}
Expand All @@ -405,6 +415,16 @@ export function pickComponentOutputFieldsFromInstillFormTree(
/>
);
}
case "document": {
return (
<ComponentOutputFields.DownloadableFileField
mode={mode}
title={title}
file={propertyValue}
hideField={hideField}
/>
);
}
default: {
return (
<ComponentOutputFields.TextField
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { PipelineVariableFieldMap } from "instill-sdk";
import { UseFormReturn } from "react-hook-form";

import { DocumentInputAcceptMimeTypes } from "../../../constant/pipeline";
import { Nullable } from "../../type";
import { TriggerRequestFormFields } from "../components";
import { FieldMode, StartOperatorFreeFormFieldItem } from "../types";
Expand Down Expand Up @@ -374,6 +375,7 @@ export function pickPipelineTriggerRequestFormFields({
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept="*/*"
/>
),
});
Expand All @@ -398,6 +400,55 @@ export function pickPipelineTriggerRequestFormFields({
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept="*/*"
/>
),
});
break;
case "document":
items.push({
key,
instillUIOrder: value.instillUiOrder,
component: (
<TriggerRequestFormFields.FileField
mode={mode}
key={key}
form={form}
path={key}
title={value.title}
onDeleteField={onDeleteField}
onEditField={onEditField}
description={value.description ?? null}
disabled={disabledFields}
keyPrefix={keyPrefix}
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept={DocumentInputAcceptMimeTypes.join(",")}
/>
),
});
break;
case "array:document":
items.push({
key,
instillUIOrder: value.instillUiOrder,
component: (
<TriggerRequestFormFields.FilesField
mode={mode}
key={key}
form={form}
path={key}
title={value.title}
onDeleteField={onDeleteField}
onEditField={onEditField}
description={value.description ?? null}
disabled={disabledFields}
keyPrefix={keyPrefix}
disabledFieldControl={disabledFieldControls}
disabledReferenceHint={disabledReferenceHint}
instillFormat={value.instillFormat}
accept={DocumentInputAcceptMimeTypes.join(",")}
/>
),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ export function transformPipelineTriggerRequestFieldsToZod(
break;
case "file":
case "*/*":
case "document":
zodSchema = zodSchema.setKey(key, z.string().nullable().optional());
break;
case "array:file":
case "array:*/*":
case "array:document":
zodSchema = zodSchema.setKey(
key,
z.array(z.string().nullable().optional()).nullable().optional(),
Expand Down
2 changes: 2 additions & 0 deletions packages/toolkit/src/view/recipe-editor/VscodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ const availableInstillFormats = [
"array:file",
"json",
"array:json",
"document",
"array:document",
];

const componentTopLevelKeys = ["type", "input", "setup", "condition", "task"];
Expand Down
Loading