find interface by llm

This commit is contained in:
Suman991 2026-04-10 23:12:41 +05:30
parent 4ea6a1b1b4
commit 4109dbec8d
10 changed files with 325 additions and 18 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
/node_modules
/build
test.js
# Logs
logs
*.log

202
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.1",
"license": "UNLICENSED",
"dependencies": {
"@cerebras/cerebras_cloud_sdk": "^1.64.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.3",
"@nestjs/core": "^11.0.1",
@ -17,6 +18,7 @@
"@nestjs/swagger": "^11.2.6",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.4",
"dotenv": "^17.4.1",
"mongoose": "^9.4.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
@ -718,6 +720,36 @@
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/@cerebras/cerebras_cloud_sdk": {
"version": "1.64.1",
"resolved": "https://registry.npmjs.org/@cerebras/cerebras_cloud_sdk/-/cerebras_cloud_sdk-1.64.1.tgz",
"integrity": "sha512-eQ0udGHS9xrWANi56yCS/FMcbwtysugD73YWipp89+zarbm2pd5hxqrmGlFqafS4Pwyo7cU7Qv31am5jdjqXFg==",
"license": "Apache-2.0",
"dependencies": {
"@types/node": "^18.11.18",
"@types/node-fetch": "^2.6.4",
"abort-controller": "^3.0.0",
"agentkeepalive": "^4.2.1",
"form-data-encoder": "1.7.2",
"formdata-node": "^4.3.2",
"node-fetch": "^2.6.7"
}
},
"node_modules/@cerebras/cerebras_cloud_sdk/node_modules/@types/node": {
"version": "18.19.130",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@cerebras/cerebras_cloud_sdk/node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"license": "MIT"
},
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@ -2167,6 +2199,18 @@
"rxjs": "^7.1.0"
}
},
"node_modules/@nestjs/config/node_modules/dotenv": {
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/@nestjs/config/node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
@ -2710,12 +2754,21 @@
"version": "24.12.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz",
"integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.13",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz",
"integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==",
"license": "MIT",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.4"
}
},
"node_modules/@types/qs": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz",
@ -3553,6 +3606,18 @@
"dev": true,
"license": "Apache-2.0"
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"license": "MIT",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@ -3615,6 +3680,18 @@
"node": ">=0.4.0"
}
},
"node_modules/agentkeepalive": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
"integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
"license": "MIT",
"dependencies": {
"humanize-ms": "^1.2.1"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/ajv": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
@ -3810,7 +3887,6 @@
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true,
"license": "MIT"
},
"node_modules/babel-jest": {
@ -4437,7 +4513,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
@ -4697,7 +4772,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@ -4744,9 +4818,9 @@
}
},
"node_modules/dotenv": {
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
"version": "17.4.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.1.tgz",
"integrity": "sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@ -4910,7 +4984,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@ -5175,6 +5248,15 @@
"node": ">= 0.6"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
@ -5518,7 +5600,6 @@
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
"dev": true,
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
@ -5531,11 +5612,16 @@
"node": ">= 6"
}
},
"node_modules/form-data-encoder": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
"integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
"license": "MIT"
},
"node_modules/form-data/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
@ -5545,7 +5631,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
@ -5554,6 +5639,19 @@
"node": ">= 0.6"
}
},
"node_modules/formdata-node": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
"integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
"license": "MIT",
"dependencies": {
"node-domexception": "1.0.0",
"web-streams-polyfill": "4.0.0-beta.3"
},
"engines": {
"node": ">= 12.20"
}
},
"node_modules/formidable": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz",
@ -5890,7 +5988,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
@ -5951,6 +6048,15 @@
"node": ">=10.17.0"
}
},
"node_modules/humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.0.0"
}
},
"node_modules/iconv-lite": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
@ -7705,6 +7811,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"deprecated": "Use your platform's native DOMException instead",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-emoji": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
@ -7715,6 +7841,48 @@
"lodash": "^4.17.21"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -9567,7 +9735,6 @@
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"node_modules/universalify": {
@ -9758,6 +9925,15 @@
"defaults": "^1.0.3"
}
},
"node_modules/web-streams-polyfill": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
"integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
"license": "MIT",
"engines": {
"node": ">= 14"
}
},
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",

View File

@ -20,6 +20,7 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@cerebras/cerebras_cloud_sdk": "^1.64.1",
"@nestjs/common": "^11.0.1",
"@nestjs/config": "^4.0.3",
"@nestjs/core": "^11.0.1",
@ -28,6 +29,7 @@
"@nestjs/swagger": "^11.2.6",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.4",
"dotenv": "^17.4.1",
"mongoose": "^9.4.1",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",

View File

@ -0,0 +1,9 @@
import { Module } from "@nestjs/common";
import { LlmService } from "./services/llm.service";
@Module({
imports:[],
controllers:[],
providers:[],
})
export class CommonModule{}

View File

@ -0,0 +1,89 @@
import Cerebras from "@cerebras/cerebras_cloud_sdk";
import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Form } from "src/form/schemas/form.schema";
const interfaceSchema = {
type: "object",
properties: {
fields: {
type: "array",
items: {
type: "object",
properties: {
keyName: { type: "string" },
tsType: { type: "string" },
includeInInterface: { type: "boolean" }
},
required: ["keyName", "tsType", "includeInInterface"],
additionalProperties: false
}
}
},
required: ["fields"],
additionalProperties: false
};
@Injectable()
export class LlmService {
private cerebras: Cerebras;
constructor(private configService: ConfigService) {
this.cerebras = new Cerebras({
apiKey: this.configService.get<string>('CEREBRAS_API_KEY'),
});
}
async generateFormInterface(form: Form): Promise<string> {
const relevant = form.fields!
.filter(f => f.keyType !== "button")
.map(({ keyName, keyType, keySubType, options }) => ({
keyName,
keyType,
...(keySubType && { keySubType }),
...(keyType === "checkbox" && { hasOptions: !!options?.length }),
}));
const completion = await this.cerebras.chat.completions.create({
model: "llama3.1-8b",
messages: [
{
role: "system",
content: `You are a TypeScript expert. Given form field descriptors, return the correct TypeScript type for each.
Type rules:
input[number|range] number
input[file] File | null
input[date|datetime-local|month|week|time] string
input[text|email|password|tel|url|search|color|hidden] string
textarea | select | radio string
multiselect string[]
checkbox with hasOptions: true string[]
checkbox with hasOptions: false boolean`,
},
{
role: "user",
content: JSON.stringify(relevant),
},
],
response_format: {
type: "json_schema",
json_schema: {
name: "interface_schema",
strict: true,
schema: interfaceSchema,
},
},
});
const { fields: typed } = JSON.parse((completion.choices as any)[0].message.content);
const tsInterface = `export interface ${form.name.replace(/\s+/g, '')}FormValues {\n${
typed
.filter(f => f.includeInInterface)
.map(f => ` ${f.keyName}: ${f.tsType};`)
.join("\n")
}\n}`;
return tsInterface;
}
}

View File

@ -49,7 +49,7 @@ export class QueryFormDto {
example: false,
description: 'true = deleted only, false = active only, omit = all',
})
// @Type(() => Boolean)
// @Type(() => Boolean) // don't use this(unreliable)
@Transform(({ value }) => {
if (value === 'true' || value === true) return true;
if (value === 'false' || value === false) return false;

View File

@ -35,6 +35,11 @@ export class FormController {
async find(@Param('formId') formId: string) {
return await this.formService.find(formId);
}
@Get(':formId/interface')
@ApiOperation({summary:'Get interface for the form provided by llm'})
async getInterface(@Param('formId') formId:string){
return await this.formService.findInterface(formId);
}
@Patch(':id/fields/:fieldId')
@ApiOperation({ summary: 'update a field in a form' })

View File

@ -4,6 +4,7 @@ import { FormController } from './form.controller';
import { MongooseModule } from '@nestjs/mongoose';
import { Form, FormSchema } from './schemas/form.schema';
import { Field, FieldSchema } from './schemas/field.schema';
import { LlmService } from 'src/common/services/llm.service';
@Module({
imports:[
@ -13,6 +14,6 @@ import { Field, FieldSchema } from './schemas/field.schema';
])
],
controllers: [FormController],
providers: [FormService],
providers: [FormService,LlmService],
})
export class FormModule {}

View File

@ -1,4 +1,4 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Injectable, NotFoundException, ServiceUnavailableException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Form, FormDocument, Status } from './schemas/form.schema';
import { Model } from 'mongoose';
@ -8,6 +8,7 @@ import { CreateUpdateDto } from './dto/create-update.dto';
import { QueryFormDto } from './dto/query-form.dto';
import { FormQueryBuilder } from './helpers/form-query.builder';
import { PaginatedResponse } from 'src/interfaces/paginated-response.interface';
import { LlmService } from 'src/common/services/llm.service';
// Reusable projections
const LIST_PROJECTION = {
@ -22,7 +23,10 @@ const DETAIL_PROJECTION = { _id: 0, __v: 0 };
@Injectable()
export class FormService {
constructor(@InjectModel(Form.name) private formModel: Model<FormDocument>) {}
constructor(
@InjectModel(Form.name) private formModel: Model<FormDocument>,
private llmService: LlmService,
) {}
async createOrUpdate(dto: CreateUpdateDto): Promise<Form> {
if (!dto.id) {
@ -87,9 +91,27 @@ export class FormService {
.select(DETAIL_PROJECTION)
.exec();
if (!form) throw new NotFoundException(`Form ${formId} not found`);
return form;
}
async findInterface(formId: string): Promise<string> {
const form = await this.formModel
.findOne({ id: formId, deletedAt: null })
.select(DETAIL_PROJECTION)
.exec();
if (!form) throw new NotFoundException(`Form ${formId} not found`);
try{
let tsInference=await this.llmService.generateFormInterface(form)
return tsInference
}catch(err){
throw new ServiceUnavailableException('llm down')
}
}
async updateField(
formId: string,
fieldId: string,

View File

@ -1,5 +1,5 @@
// ─── Parent types ───
export type ParentKeyType = "input" | "textarea" | "select" | "multiselect" | "checkbox";
export type ParentKeyType = "input" | "textarea" | "select" | "multiselect" | "checkbox"|"button";
// ─── Child types (only for "input") ───
export type InputSubType = "text" | "email" | "number" | "password" | "button" | "color" | "date" | "datetime-local" | "file" | "hidden" | "image" | "month" | "radio" | "range" | "reset" | "search" | "submit" | "tel" | "time" | "url" | "week" ;
@ -11,6 +11,7 @@ export const PARENT_TYPE_LABELS: Readonly<Record<ParentKeyType, string>> = {
select: "Select",
multiselect: "Multiselect",
checkbox: "Checkbox",
button:"button",
} as const;
export const INPUT_SUB_TYPE_LABELS: Readonly<Record<InputSubType, string>> = {