collapsible.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <script lang="ts" setup>
  2. import type { FormLayout } from '@vben/common-ui';
  3. import type { CollapsibleParamSchema } from '@vben-core/shadcn-ui';
  4. import { ref } from 'vue';
  5. import { Page } from '@vben/common-ui';
  6. import { VbenCollapsibleParams } from '@vben-core/shadcn-ui';
  7. import { Button, Card, message, RadioGroup } from 'ant-design-vue';
  8. import { useVbenForm, z } from '#/adapter/form';
  9. import DocButton from '../doc-button.vue';
  10. const layouts: { label: string; value: FormLayout }[] = [
  11. { label: 'Vertical', value: 'vertical' },
  12. { label: 'Horizontal', value: 'horizontal' },
  13. ];
  14. const layout = ref(layouts[0]?.value ?? 'vertical');
  15. function getNumberValidator(key: string, limit?: [number?, number?]) {
  16. let validator = z.number({
  17. required_error: `${key} 值不能为空`,
  18. invalid_type_error: `${key} 值只能为数字`,
  19. });
  20. if (limit) {
  21. if (limit[0] !== undefined) {
  22. validator = validator.min(limit[0], {
  23. message: `${key} 值不能小于${limit[0]}`,
  24. });
  25. }
  26. if (limit[1] !== undefined) {
  27. validator = validator.max(limit[1], {
  28. message: `${key} 值不能大于${limit[1]}`,
  29. });
  30. }
  31. }
  32. // 设置zod-default提取默认值为null,不设置null,会提取为0,在reset后会绕过rules配置的vee-validate的校验
  33. return validator.default(null);
  34. }
  35. const paramsSchema: CollapsibleParamSchema[] = [
  36. {
  37. key: 'micro_batch_size',
  38. description: `批次大小,代表模型训练过程中,模型更新模型参数的数据步长,可理解为模型每看多少数据即更新一次模型参数,
  39. 一般建议的批次大小为16/32,表示模型每看16或32条数据即更新一次参数`,
  40. option: {
  41. min: 8,
  42. max: 1024,
  43. step: 8,
  44. },
  45. },
  46. {
  47. key: 'learning_rate',
  48. description:
  49. '学习率,代表每次更新数据的增量参数权重,学习率数值越大参数变化越大,对模型影响越大',
  50. option: {
  51. step: 1e-4,
  52. type: 'exponential',
  53. min: 0,
  54. max: 1,
  55. },
  56. },
  57. {
  58. key: 'eval_steps',
  59. description:
  60. '验证步数,训练阶段针模型的验证间隔步长,用于阶段性评估模型训练准确率、训练损失',
  61. option: {
  62. min: 1,
  63. max: 2_147_483_647,
  64. },
  65. },
  66. {
  67. key: 'num_train_epochs',
  68. description:
  69. '循环次数,代表模型训练过程中模型学习数据集的次数,可理解为看几遍数据,一般建议的范围是1-3遍即可,可依据需求进行调整',
  70. option: {
  71. min: 1,
  72. max: 200,
  73. },
  74. },
  75. {
  76. key: 'max_length',
  77. description: `序列长度,单个训练数据样本的最大长度,超出配置长度将丢弃`,
  78. option: {
  79. min: 500,
  80. max: 131_072,
  81. },
  82. },
  83. {
  84. key: 'warmup_ratio',
  85. description: '学习率预热比例,学习率预热阶段占总训练步数的比例',
  86. option: {
  87. min: 0,
  88. max: 1,
  89. precision: 2,
  90. step: 0.01,
  91. },
  92. },
  93. {
  94. key: 'save_steps',
  95. description: 'Checkpoint保存间隔',
  96. option: {
  97. min: 1,
  98. max: 2_147_483_647,
  99. },
  100. },
  101. ];
  102. const paramsValidator = z.object({
  103. micro_batch_size: getNumberValidator('micro_batch_size', [8, 1024]),
  104. learning_rate: getNumberValidator('learning_rate'),
  105. eval_steps: getNumberValidator('eval_steps', [1, 2_147_483_647]),
  106. num_train_epochs: getNumberValidator('num_train_epochs', [1, 200]),
  107. max_length: getNumberValidator('max_length', [500, 131_072]),
  108. warmup_ratio: getNumberValidator('warmup_ratio', [0, 1]),
  109. save_steps: getNumberValidator('save_steps', [1, 2_147_483_647]),
  110. });
  111. const [BaseForm, baseFormApi] = useVbenForm({
  112. showDefaultActions: false,
  113. // 所有表单项共用,可单独在表单内覆盖
  114. commonConfig: {
  115. colon: true,
  116. componentProps: {
  117. class: 'w-full',
  118. },
  119. },
  120. handleSubmit: onSubmit,
  121. layout: 'vertical',
  122. schema: [
  123. {
  124. component: 'Switch',
  125. fieldName: 'qat',
  126. componentProps: {
  127. checkedChildren: '开',
  128. unCheckedChildren: '关',
  129. class: 'w-auto',
  130. },
  131. label: 'QAT',
  132. defaultValue: false,
  133. },
  134. {
  135. component: VbenCollapsibleParams,
  136. componentProps: {
  137. params: paramsSchema,
  138. // maxHeight: 200, //限制最大高度,展开后可滚动
  139. },
  140. modelPropName: 'value',
  141. fieldName: 'params',
  142. label: '参数配置',
  143. formItemClass: 'col-span-8 items-baseline col-start-1',
  144. dependencies: {
  145. triggerFields: ['qat'],
  146. componentProps(values) {
  147. return {
  148. params: values.qat
  149. ? [
  150. {
  151. key: 'calib_steps',
  152. description: `校准步数;校准的数据集大小 = 校准步数 * 训练的batch_size`,
  153. option: {
  154. min: 1,
  155. },
  156. },
  157. ...paramsSchema,
  158. ]
  159. : paramsSchema,
  160. };
  161. },
  162. trigger(values, __, controller) {
  163. // 访问 form 内 VbenCollapsibleParams 的实例
  164. const paramsRef =
  165. controller.getFieldComponentRef<typeof VbenCollapsibleParams>(
  166. 'params',
  167. );
  168. if (values.qat) {
  169. paramsRef?.updateValues?.({
  170. calib_steps: 10,
  171. micro_batch_size: 32,
  172. learning_rate: 4e-5,
  173. eval_steps: 80,
  174. num_train_epochs: 3,
  175. max_length: 32_768,
  176. warmup_ratio: 0.1,
  177. save_steps: 80,
  178. });
  179. } else {
  180. paramsRef?.updateValues?.({
  181. calib_steps: null,
  182. micro_batch_size: 8,
  183. });
  184. }
  185. },
  186. rules(values) {
  187. if (values.qat) {
  188. return paramsValidator.extend({
  189. calib_steps: getNumberValidator('calib_steps', [1]),
  190. });
  191. }
  192. return paramsValidator;
  193. },
  194. },
  195. rules: paramsValidator,
  196. // defaultValue: {
  197. // micro_batch_size: 24,
  198. // },
  199. },
  200. {
  201. component: 'RichEditor',
  202. fieldName: 'richEditor',
  203. label: '富文本',
  204. formItemClass: 'col-span-12 items-baseline',
  205. collapsible: true,
  206. defaultCollapsed: false, // 默认false
  207. },
  208. ],
  209. wrapperClass: 'grid-cols-12',
  210. });
  211. function onSubmit(values: Record<string, any>) {
  212. message.info({
  213. content: `form values: ${JSON.stringify(values)}`,
  214. });
  215. }
  216. function onLayoutChange(layout: FormLayout) {
  217. baseFormApi.setState({
  218. layout,
  219. });
  220. }
  221. function handleSetFormValue() {
  222. baseFormApi.setFieldValue('params', {
  223. micro_batch_size: 8,
  224. learning_rate: 1e-5,
  225. eval_steps: 50,
  226. num_train_epochs: 3,
  227. max_length: 32_768,
  228. warmup_ratio: 0.05,
  229. save_steps: 50,
  230. });
  231. }
  232. function handleResetFormValue() {
  233. baseFormApi.resetForm(undefined, { force: true });
  234. }
  235. async function handleSubmitFormValue() {
  236. const { valid } = await baseFormApi.validate();
  237. if (valid) {
  238. baseFormApi.submitForm();
  239. }
  240. }
  241. </script>
  242. <template>
  243. <Page
  244. auto-content-height
  245. content-class="flex flex-col gap-4"
  246. title="可折叠表单项"
  247. >
  248. <template #description>
  249. <div class="text-muted-foreground">
  250. <p>可折叠表单项、以及可折叠参数配置组件示例</p>
  251. </div>
  252. </template>
  253. <template #extra>
  254. <DocButton class="mb-2" path="/components/common-ui/vben-form" />
  255. </template>
  256. <Card title="基础示例">
  257. <template #extra>
  258. <div class="inline-flex items-center gap-4!">
  259. <RadioGroup
  260. :options="layouts"
  261. option-type="button"
  262. v-model:value="layout"
  263. @update:value="onLayoutChange"
  264. />
  265. <Button type="primary" @click="handleSetFormValue">
  266. 设置表单值
  267. </Button>
  268. <Button type="primary" @click="handleSubmitFormValue">
  269. 提交表单
  270. </Button>
  271. <Button type="primary" @click="handleResetFormValue">
  272. 重置表单
  273. </Button>
  274. </div>
  275. </template>
  276. <div class="w-full overflow-hidden">
  277. <BaseForm />
  278. </div>
  279. </Card>
  280. </Page>
  281. </template>