diff --git a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilderModal/MagicFormBuilderModalContent/PdfDetailsScreen.tsx b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilderModal/MagicFormBuilderModalContent/PdfDetailsScreen.tsx
index c51f7f1ea8..396141daa0 100644
--- a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilderModal/MagicFormBuilderModalContent/PdfDetailsScreen.tsx
+++ b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilderModal/MagicFormBuilderModalContent/PdfDetailsScreen.tsx
@@ -86,8 +86,6 @@ export const MagicFormBuilderPdfDetailsScreen = (): JSX.Element => {
return combinedText.trim()
}
- const isError = pdfFileText.length > 3000
-
return (
<>
@@ -97,7 +95,7 @@ export const MagicFormBuilderPdfDetailsScreen = (): JSX.Element => {
-
+
Upload a PDF - The PDF should not be a scanned copy and should not
contain any restricted or sensitive information.
@@ -105,7 +103,7 @@ export const MagicFormBuilderPdfDetailsScreen = (): JSX.Element => {
{
- if (pdfFileText && pdfFileText.length < 3001) return true
+ if (pdfFileText) return true
return 'This PDF file cannot be processed. Please ensure that the PDF uploaded contains selectable text and is not a scanned copy.'
},
}}
@@ -127,15 +125,11 @@ export const MagicFormBuilderPdfDetailsScreen = (): JSX.Element => {
/>
- {(isError || !pdfFileText) && (
-
- )}
+ {!pdfFileText && }
{!pdfFileText &&
(pdfFile
? `${errors.pdfFileText?.message}`
: 'Please upload a PDF.')}
- {isError &&
- `The PDF uploaded exceeds the character limit acceptable (${pdfFileText.length}/3000). Please try another form.`}
diff --git a/src/app/modules/form/admin-form/admin-form.assistance.constants.ts b/src/app/modules/form/admin-form/admin-form.assistance.constants.ts
index 921435bfc7..c35006f106 100644
--- a/src/app/modules/form/admin-form/admin-form.assistance.constants.ts
+++ b/src/app/modules/form/admin-form/admin-form.assistance.constants.ts
@@ -6,3 +6,5 @@ export enum Roles {
export const MODEL_TYPE = 'gpt-3.5-turbo'
export const sampleFormFields = `[{"title":"","description":"","required":"","disabled":"","fieldType":"section"},{"ValidationOptions":{"selectedValidation":null,"customVal":null},"allowPrefill":"","lockPrefill":"","title":"","description":"","required":"","disabled":"","fieldType":"textfield"},{"ValidationOptions":{"selectedValidation":null,"customVal":null},"title":"","description":"","required":"","disabled":"","fieldType":"textarea"},{"fieldOptions":[""],"othersRadioButton":"","title":"","description":"","required":"","disabled":"","fieldType":"radiobutton"},{"ValidationOptions":{"customMax":null,"customMin":null},"fieldOptions":[""],"othersRadioButton":"","validateByValue":"","title":"","description":"","required":"","disabled":"","fieldType":"checkbox"},{"fieldOptions":[""],"title":"","description":"","required":"","disabled":"","fieldType":"dropdown"},{"title":"","description":"","required":"","disabled":"","fieldType":"yes_no"},{"ratingOptions":{"steps":5,"shape":"Star"},"title":"","description":"","required":"","disabled":"","fieldType":"rating"},{"autoReplyOptions":{"hasAutoReply":"","autoReplySubject":"","autoReplySender":"","autoReplyMessage":"","includeFormSummary":""},"isVerifiable":"","hasAllowedEmailDomains":false,"allowedEmailDomains":[],"title":"","description":"","required":"","disabled":"","fieldType":"email"},{"allowIntlNumbers":"","isVerifiable":"","title":"","description":"","required":"","disabled":"","fieldType":"mobile"},{"allowIntlNumbers":"","title":"","description":"","required":"","disabled":"","fieldType":"homeno"},{"dateValidation":{"customMinDate":null,"customMaxDate":null,"selectedDateValidation":null},"invalidDays":[],"title":"","description":"","required":"","disabled":"","fieldType":"date"},{"addMoreRows":"","title":"","description":"","required":"","disabled":"","fieldType":"table","columns":[{"ValidationOptions":{"customVal":null,"selectedValidation":null},"allowPrefill":"","lockPrefill":"","columnType":"textfield","required":"","title":""}],"minimumRows":2,"maximumRows":null},{"title":"","description":"","required":"","disabled":"","fieldType":"attachment","attachmentSize":"1"},{"title":"","description":"","required":"","disabled":"","fieldType":"number","ValidationOptions":{"LengthValidationOptions":{"customVal":null,"selectedLengthValidation":null},"RangeValidationOptions":{"customMin":null,"customMax":null},"selectedValidation":null}},{"ValidationOptions":{"customMax":null,"customMin":null},"validateByValue":"","title":"","description":"","required":"","disabled":"","fieldType":"decimal"},{"title":"","description":"","required":"","disabled":"","fieldType":"nric"},{"title":"","description":"","required":"","disabled":"","fieldType":"uen"}]`
+
+export const fieldTypes = `'section','textfield','textarea','radiobutton','checkbox','dropdown','yes_no','rating','email','mobile','homeno','date','table','attachment','number','decimal','nric','uen'`
diff --git a/src/app/modules/form/admin-form/admin-form.assistance.controller.ts b/src/app/modules/form/admin-form/admin-form.assistance.controller.ts
index ff2bba3d7c..4536d956b6 100644
--- a/src/app/modules/form/admin-form/admin-form.assistance.controller.ts
+++ b/src/app/modules/form/admin-form/admin-form.assistance.controller.ts
@@ -21,10 +21,9 @@ const generateQuestionsSchema = Joi.object({
type: Joi.string()
.valid(...Object.values(ContentTypes))
.required(),
- content: Joi.alternatives().conditional('type', {
+ content: Joi.string().when('type', {
is: ContentTypes.PROMPT,
then: Joi.string().max(300).required(),
- otherwise: Joi.string().max(3000).required(), // max character of 3000 to cater for PDF uploads
}),
})
diff --git a/src/app/modules/form/admin-form/admin-form.assistance.service.ts b/src/app/modules/form/admin-form/admin-form.assistance.service.ts
index 351b4ad23e..eeed1e2480 100644
--- a/src/app/modules/form/admin-form/admin-form.assistance.service.ts
+++ b/src/app/modules/form/admin-form/admin-form.assistance.service.ts
@@ -111,7 +111,10 @@ export const generateFormFields = (
> => {
const messages: ChatRequestMessage[] = [
{ role: Roles.SYSTEM, content: schemaPromptBuilder(sampleFormFields) },
- { role: Roles.USER, content: formFieldsPromptBuilder(questions) },
+ {
+ role: Roles.USER,
+ content: formFieldsPromptBuilder(questions, sampleFormFields),
+ },
]
return ResultAsync.fromPromise(
azureOpenAi.getChatCompletions(deploymentId, messages),
@@ -132,6 +135,7 @@ export const generateFormFields = (
},
).andThen((chatCompletions) => {
const { message } = chatCompletions.choices[0]
+ // const {tokenUsage} = chatCompletions.usage?.totalTokens?
if (!message) {
return errAsync(new AssistanceConnectionError())
}
diff --git a/src/app/modules/form/admin-form/admin-form.assistance.utils.ts b/src/app/modules/form/admin-form/admin-form.assistance.utils.ts
index f7f29b191f..1db29af812 100644
--- a/src/app/modules/form/admin-form/admin-form.assistance.utils.ts
+++ b/src/app/modules/form/admin-form/admin-form.assistance.utils.ts
@@ -1,4 +1,5 @@
// type guard for OpenAIError
+import { fieldTypes } from './admin-form.assistance.constants'
import { OpenAIError } from './admin-form.assistance.types'
export function isOpenAIError(error: unknown): error is OpenAIError {
@@ -24,12 +25,12 @@ export const schemaPromptBuilder = (schema: string) => {
export const questionListPromptBuilder = (purpose: string) => {
return `I am a public officer who wants to create a form that collects ${purpose}.
- Give me a list of content / questions I should have in my form built with this form builder, in the form of "${expectedQuestionsListFormat}".`
+ Give me a list of content / questions I should have in my form built with this form builder, in the form of "${expectedQuestionsListFormat}", where must follow the category of types within ${fieldTypes}. Do not create the question if the does not exist in ${fieldTypes}.`
}
-export const formFieldsPromptBuilder = (questions: string) => {
+export const formFieldsPromptBuilder = (questions: string, schema: string) => {
return `Help me generate a form with the following list of questions: ${questions}
- Present the questions as FormSG form fields in JSON (list of form field schemas), in the form of "${expectedFormFieldSchemaFormat}" as defined by the system, without any code blocks. Format the JSON as a single line.`
+ Provide the questions as FormSG form fields in JSON format (with the following keys: ${schema}), in the form of "${expectedFormFieldSchemaFormat}" as defined by the system, without any code blocks. Format the JSON as a single line. Ensure the JSON generated only contain fieldTypes of types ${fieldTypes}. Do not create any fieldTypes which are not ${fieldTypes}. Replace values in <> with actual primitive values. Do not build the fieldType if a path required is not available.`
}
export const migratePromptBuilder = (parsedContent: string) => {
return `Help me generate the corresponding JSON form fields from content parsed from a PDF document.