langgenius / dify

Dify is an open-source LLM app development platform. Dify's intuitive interface combines AI workflow, RAG pipeline, agent capabilities, model management, observability features and more, letting you quickly go from prototype to production.
https://dify.ai
Other
46.08k stars 6.5k forks source link

How to save user entered data in a form for personalizations? #6108

Closed lheng18 closed 2 months ago

lheng18 commented 2 months ago

Self Checks

1. Is this request related to a challenge you're experiencing? Tell me about your story.

Need to create a web site that allow users register and enter their own data through forms. How to integrate a regular database to the tool? Thanks!

2. Additional context or comments

No response

3. Can you help us with this feature?

dosubot[bot] commented 2 months ago

@lheng18 Hello there! I'm a bot here to help you with bugs, questions, and becoming a contributor. While you wait for a human maintainer, feel free to ask me anything.

To save user-entered data in a form for personalizations in Dify, you can follow these steps:

  1. Define the Form Schema: Use a schema validation library like zod to define the structure and validation rules for your form data.
  2. Create the Form Component: Use a form handling library like react-hook-form to create the form component.
  3. Handle Form Submission: Implement a function to handle form submission, which will send the form data to the backend service.
  4. Link to Database: Ensure that the backend service is configured to store the form data in the database.

Here is an example based on the provided code:

Step 1: Define the Form Schema

const accountFormSchema = z.object({
  email: z
    .string()
    .min(1, { message: 'login.error.emailInValid' })
    .email('login.error.emailInValid'),
  name: z.string().min(1, { message: 'login.error.nameEmpty' }),
  password: z.string().min(8, {
    message: 'login.error.passwordLengthInValid',
  }).regex(validPassword, 'login.error.passwordInvalid'),
});

Step 2: Create the Form Component

const InstallForm = () => {
  const { t } = useTranslation();
  const router = useRouter();
  const [showPassword, setShowPassword] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<AccountFormValues>({
    resolver: zodResolver(accountFormSchema),
    defaultValues: {
      name: '',
      password: '',
      email: '',
    },
  });

  const onSubmit: SubmitHandler<AccountFormValues> = async (data) => {
    await setup({
      body: {
        ...data,
      },
    });
    router.push('/signin');
  };

  const handleSetting = async () => {
    handleSubmit(onSubmit)();
  };

  useEffect(() => {
    fetchSetupStatus().then((res: SetupStatusResponse) => {
      if (res.step === 'finished') {
        window.location.href = '/signin';
      } else {
        fetchInitValidateStatus().then((res: InitValidateStatusResponse) => {
          if (res.status === 'not_started')
            window.location.href = '/init';
        });
      }
      setLoading(false);
    });
  }, []);

  return (
    loading
      ? <Loading />
      : <>
        <div className="sm:mx-auto sm:w-full sm:max-w-md">
          <h2 className="text-[32px] font-bold text-gray-900">{t('login.setAdminAccount')}</h2>
          <p className='mt-1 text-sm text-gray-600'>{t('login.setAdminAccountDesc')}</p>
        </div>
        <div className="grow mt-8 sm:mx-auto sm:w-full sm:max-w-md">
          <div className="bg-white">
            <form onSubmit={handleSubmit(onSubmit)}>
              <div className='mb-5'>
                <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.email')}
                </label>
                <div className="mt-1">
                  <input
                    {...register('email')}
                    placeholder={t('login.emailPlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm'}
                  />
                  {errors.email && <span className='text-red-400 text-sm'>{t(`${errors.email?.message}`)}</span>}
                </div>
              </div>
              <div className='mb-5'>
                <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.name')}
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <input
                    {...register('name')}
                    placeholder={t('login.namePlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
                  />
                </div>
                {errors.name && <span className='text-red-400 text-sm'>{t(`${errors.name.message}`)}</span>}
              </div>
              <div className='mb-5'>
                <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.password')}
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <input
                    {...register('password')}
                    type={showPassword ? 'text' : 'password'}
                    placeholder={t('login.passwordPlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
                  />
                  <div className="absolute inset-y-0 right-0 flex items-center pr-3">
                    <button
                      type="button"
                      onClick={() => setShowPassword(!showPassword)}
                      className="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500"
                    >
                      {showPassword ? '👀' : '😝'}
                    </button>
                  </div>
                </div>
                <div className={classNames('mt-1 text-xs text-gray-500', {
                  'text-red-400 !text-sm': errors.password,
                })}>{t('login.error.passwordInvalid')}</div>
              </div>
              <div>
                <Button variant='primary' className='w-full' onClick={handleSetting}>
                  {t('login.installBtn')}
                </Button>
              </div>
            </form>
            <div className="block w-hull mt-2 text-xs text-gray-600">
              {t('login.license.tip')}
              &nbsp;
              <Link
                className='text-primary-600'
                target='_blank' rel='noopener noreferrer'
                href={'https://docs.dify.ai/user-agreement/open-source'}
              >{t('login.license.link')}</Link>
            </div>
          </div>
        </div>
      </>
  );
};

export default InstallForm;

Step 3: Handle Form Submission

The onSubmit function handles the form submission and sends the data to the backend service using the setup function.

Step 4: Link to Database

Ensure that the setup function in your backend service is configured to store the form data in the database. This function should handle the necessary database operations to save the user data.

const onSubmit: SubmitHandler<AccountFormValues> = async (data) => {
  await setup({
    body: {
      ...data,
    },
  });
  router.push('/signin');
};

This code snippet demonstrates how to create a custom user registration form in Dify and link it to the database for storing user data [1].

To continue talking to Dosu, mention @dosu.

crazywoola commented 2 months ago

See this repo https://github.com/crazywoola/dify-tools-worker. You can create an external service to store user related data.