Spaces:
Runtime error
Runtime error
| import express, { Router } from "express"; | |
| import serverless from "serverless-http"; | |
| import Redis from "ioredis"; | |
| import { initClient } from './utils.js'; | |
| import { errorHandler, setJioCopilotSessionCookie } from './middleware.js'; | |
| import swaggerJSDoc from 'swagger-jsdoc'; | |
| import yaml from 'js-yaml' | |
| import fs from 'fs'; | |
| import { RedisListCache } from './cache.js'; | |
| import { | |
| getApplications, | |
| createApplication, | |
| getLocations, | |
| createLocation, | |
| updateLocation, | |
| getBrands, | |
| createBrand, | |
| updateBrand, | |
| createProduct, | |
| createInventory, | |
| getCompanyCreds, | |
| createUpdateCompanyCreds | |
| } from './functions.js' | |
| import OpenAI from 'openai'; | |
| import compression from 'compression'; | |
| import cookieParser from 'cookie-parser'; | |
| const listCache = new RedisListCache({ namespace: "fc" }) | |
| const redis = new Redis({ | |
| host: 'redis-12291.c305.ap-south-1-1.ec2.cloud.redislabs.com', | |
| port: 12291, | |
| password: 'KQCVapXXF2ioM4zF5krQFImzAYkKWY5l', | |
| username: "default" | |
| }); | |
| const skills = { | |
| getApplications, | |
| createApplication, | |
| getLocations, | |
| createLocation, | |
| updateLocation, | |
| getBrands, | |
| createBrand, | |
| updateBrand, | |
| createProduct, | |
| createInventory, | |
| getCompanyCreds, | |
| createUpdateCompanyCreds | |
| } | |
| const app = express(); | |
| const router = Router(); | |
| api.use("/api/", router); | |
| const port = process.env.PORT; | |
| app.use(express.json({})); | |
| const swaggerDefinition = { | |
| openapi: '3.0.0', | |
| info: { | |
| title: 'Express API Documentation', | |
| version: '1.0.0', | |
| description: 'This is the API documentation for my Express application.' | |
| }, | |
| servers: [{ | |
| url: "https://934a-45-119-30-178.ngrok-free.app" | |
| }] | |
| }; | |
| const options = { | |
| swaggerDefinition, | |
| // Path to the API docs | |
| apis: ['./index.js'], // Adjust the path according to your file structure | |
| }; | |
| app.use(compression()) | |
| app.use(cookieParser()) | |
| /** | |
| * @swagger | |
| * components: | |
| * schemas: | |
| * CompanyCreds: | |
| * type: object | |
| * properties: | |
| * clientId: | |
| * type: string | |
| * description: Client ID for the company | |
| * clientSecret: | |
| * type: string | |
| * description: Client secret for the company | |
| * required: | |
| * - clientId | |
| * - clientSecret | |
| * CreateUpdateLocation: | |
| * type: object | |
| * required: | |
| * - code | |
| * - name | |
| * - gst | |
| * - manager | |
| * - address | |
| * properties: | |
| * code: | |
| * type: string | |
| * description: Unique code for the location | |
| * name: | |
| * type: string | |
| * description: Name of the location | |
| * gst: | |
| * type: object | |
| * required: | |
| * - legal_name | |
| * - value | |
| * properties: | |
| * legal_name: | |
| * type: string | |
| * description: Legal name for GST purposes | |
| * value: | |
| * type: string | |
| * description: GST value | |
| * manager: | |
| * type: object | |
| * required: | |
| * - manager_name | |
| * - number | |
| * - country_code | |
| * properties: | |
| * manager_name: | |
| * type: string | |
| * description: Name of the manager | |
| * email: | |
| * type: string | |
| * description: Email of the manager | |
| * number: | |
| * type: string | |
| * description: Contact number of the manager | |
| * country_code: | |
| * type: string | |
| * description: Country code for the manager's contact number | |
| * address: | |
| * type: object | |
| * required: | |
| * - address1 | |
| * - country | |
| * - pincode | |
| * - city | |
| * - state | |
| * properties: | |
| * address1: | |
| * type: string | |
| * description: Primary address line | |
| * address2: | |
| * type: string | |
| * description: Secondary address line | |
| * country: | |
| * type: string | |
| * description: Country of the location | |
| * pincode: | |
| * type: string | |
| * description: Postal code of the location | |
| * city: | |
| * type: string | |
| * description: City of the location | |
| * state: | |
| * type: string | |
| * description: State of the location | |
| * latitude: | |
| * type: number | |
| * description: Latitude for the location | |
| * longitude: | |
| * type: number | |
| * description: Longitude for the location | |
| * landmark: | |
| * type: string | |
| * description: Landmark near the location | |
| * Brand: | |
| * type: object | |
| * properties: | |
| * name: | |
| * type: string | |
| * logo: | |
| * type: string | |
| * id: | |
| * type: string | |
| * BrandCreation: | |
| * type: object | |
| * required: | |
| * - name | |
| * - logo | |
| * - description | |
| * properties: | |
| * name: | |
| * type: string | |
| * logo: | |
| * type: string | |
| * description: | |
| * type: string | |
| * ErrorResponse: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * description: Error message | |
| */ | |
| router.get(['/swagger.yaml', '/swagger.json'], (req, res) => { | |
| // Initialize swagger-jsdoc | |
| const swaggerSpec = swaggerJSDoc(options); | |
| // Convert to YAML | |
| const swaggerYAML = yaml.dump(swaggerSpec); | |
| switch (req.path.split('.').pop()) { | |
| case 'json': | |
| res.setHeader('Content-Type', 'application/json'); | |
| return res.send(JSON.stringify(swaggerSpec, null, 2)); | |
| case 'yaml': | |
| res.setHeader('Content-Type', 'text/yaml'); | |
| return res.send(swaggerYAML); | |
| } | |
| }); | |
| /** | |
| * @swagger | |
| * /_healthz: | |
| * get: | |
| * operationId: getHealthZ | |
| * description: Check server health | |
| * responses: | |
| * 200: | |
| * description: Server is healthy | |
| * content: | |
| * text/plain: | |
| * schema: | |
| * type: string | |
| * example: Hello World! | |
| */ | |
| router.get("/_healthz", (req, res) => { | |
| res.send('Hello World!'); | |
| }); | |
| router.get("/privacy", (req, res) => { | |
| res.send('This is the privacy policy page!'); | |
| }); | |
| /** | |
| * @swagger | |
| * /company/{companyId}: | |
| * get: | |
| * operationId: getOrVerifyCompanyCredentials | |
| * description: Retrieve company credentials | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The company ID | |
| * responses: | |
| * 200: | |
| * description: Company credentials retrieved successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/CompanyCreds' | |
| * 404: | |
| * description: Company credentials not found | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| */ | |
| router.get("/company/:companyId", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const creds = await redis.get(`${companyId}:creds`); | |
| if (!creds) { | |
| throw { | |
| message: "company creds not found" | |
| } | |
| } | |
| res.json({ ...JSON.parse(creds), companyId }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}: | |
| * put: | |
| * operationId: updateCompanyCredentials | |
| * description: Update company credentials | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The company ID | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/CompanyCreds' | |
| * responses: | |
| * 200: | |
| * description: Company credentials updated successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * 400: | |
| * description: Invalid input | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| */ | |
| router.put("/company/:companyId", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const { clientId, clientSecret } = req.body | |
| const creds = await redis.set(`${companyId}:creds`, JSON.stringify({ clientId, clientSecret })); | |
| res.json({ message: "company creds saved" }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/applications: | |
| * get: | |
| * operationId: getSalesChannelByCompany | |
| * description: Retrieve applications for a specific company | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the company to retrieve applications for | |
| * responses: | |
| * 200: | |
| * description: List of applications for the specified company | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: array | |
| * items: | |
| * type: object | |
| * properties: | |
| * name: | |
| * type: string | |
| * description: Name of the application | |
| * id: | |
| * type: string | |
| * description: ID of the application | |
| * token: | |
| * type: string | |
| * description: Token associated with the application | |
| * domain: | |
| * type: string | |
| * description: Primary domain of the application | |
| * logo: | |
| * type: string | |
| * description: Logo URL of the application | |
| * 500: | |
| * description: Server error | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| */ | |
| router.get("/company/:companyId/applications", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const client = await initClient(companyId); | |
| let applications = await client.configuration.getApplications({ pageSize: 100 }); | |
| applications = applications.items.map(i => { | |
| return { | |
| name: i.name, | |
| id: i.id, | |
| token: i.token, | |
| domain: i.domains?.find(i => i.is_primary)?.name, | |
| logo: i.logo?.secure_url | |
| } | |
| }) | |
| res.json(applications) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/brands: | |
| * get: | |
| * summary: Retrieves a list of brands for a specific company | |
| * tags: [Brands] | |
| * operationId: getCompanyBrands | |
| * description: Fetches a list of brands associated with the given company ID. | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The unique identifier of the company | |
| * responses: | |
| * 200: | |
| * description: A list of brands | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: array | |
| * items: | |
| * $ref: '#/components/schemas/Brand' | |
| */ | |
| router.get("/company/:companyId/brands", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const client = await initClient(companyId); | |
| let brands = await client.companyProfile.getBrands({ pageSize: 300 }); | |
| brands = brands.items.map(i => { | |
| return { | |
| name: i?.brand?.name, | |
| logo: i?.brand?.logo, | |
| id: i?.brand?.uid, | |
| } | |
| }) | |
| res.json(brands) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/brands: | |
| * post: | |
| * summary: Creates a new brand for a specific company | |
| * tags: [Brands] | |
| * operationId: createCompanyBrand | |
| * description: Adds a new brand to the company profile. | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The unique identifier of the company | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/BrandCreation' | |
| * responses: | |
| * 200: | |
| * description: Brand created successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * id: | |
| * type: string | |
| * | |
| * /company/{companyId}/brands/{brandId}: | |
| * put: | |
| * summary: Creates a new brand for a specific company | |
| * tags: [Brands] | |
| * operationId: updateCompanyBrand | |
| * description: updated an existing brand. | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The unique identifier of the company | |
| * - in: path | |
| * name: brandId | |
| * required: true | |
| * schema: | |
| * type: number | |
| * description: The unique identifier of the brand | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/BrandCreation' | |
| * responses: | |
| * 200: | |
| * description: Brand updated successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * id: | |
| * type: string | |
| */ | |
| router.post("/company/:companyId/brands", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const client = await initClient(companyId); | |
| const { | |
| name, | |
| logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png", | |
| description | |
| } = req.body | |
| let brands = await client.companyProfile.createBrand({ | |
| body: { | |
| name, | |
| description, | |
| logo, | |
| banner: { portrait: logo, landscape: logo } | |
| } | |
| }); | |
| res.json({ message: "brand created", id: brands?.uid }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| router.put("/company/:companyId/brands/:brandId", async (req, res, next) => { | |
| try { | |
| const { companyId, brandId } = req.params; | |
| const client = await initClient(companyId); | |
| const { | |
| name, | |
| logo = "https://cdn.pixelbin.io/v2/falling-surf-7c8bb8/fyprod/wrkr/platform/pictures/favicon/original/ZWTmgEoFQ-platform-favicon.png", | |
| description | |
| } = req.body | |
| let brands = await client.companyProfile.editBrand({ | |
| brandId, | |
| body: { | |
| name, | |
| description, | |
| logo, | |
| banner: { portrait: logo, landscape: logo } | |
| } | |
| }); | |
| res.json({ message: "brand updated", id: brands?.id }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/locations: | |
| * get: | |
| * operationId: getLocationsByCompany | |
| * description: get all company locations | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the company to add a location for | |
| * responses: | |
| * 200: | |
| * description: location list | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: array | |
| * items: | |
| * properties: | |
| * id: | |
| * type: number | |
| * description: Location id | |
| * code: | |
| * type: string | |
| * description: Location code | |
| * name: | |
| * type: string | |
| * description: Location code | |
| * documents: | |
| * type: array | |
| * description: Location gst documents | |
| * items: | |
| * type: object | |
| * properties: | |
| * type: | |
| * type: string | |
| * description: document type | |
| * value: | |
| * type: string | |
| * description: document number | |
| * verified: | |
| * type: boolean | |
| * description: document number verification status | |
| * legal_name: | |
| * type: boolean | |
| * description: document owner | |
| * 400: | |
| * description: Invalid input | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| */ | |
| router.get("/company/:companyId/locations", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const client = await initClient(companyId.toString()); | |
| let locations = await client.companyProfile.getLocations({ pageSize: 100 }); | |
| locations = locations.items.map(i => { | |
| return { | |
| name: i.name, | |
| id: i.uid, | |
| code: i.code, | |
| documents: i.documents | |
| } | |
| }) | |
| res.json(locations) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/locations: | |
| * post: | |
| * operationId: createLocationsForCompany | |
| * description: Add a new location for a specific company | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the company to add a location for | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/CreateUpdateLocation' | |
| * responses: | |
| * 200: | |
| * description: Location created successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * id: | |
| * type: string | |
| * description: Location id | |
| * 400: | |
| * description: Invalid input | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| * /company/{companyId}/locations/{locationId}: | |
| * put: | |
| * operationId: updateLocationByCompany | |
| * description: update a location for a specific company | |
| * tags: [Company] | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the company to add a location for | |
| * - in: path | |
| * name: locationId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the location to be updated | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/CreateUpdateLocation' | |
| * responses: | |
| * 200: | |
| * description: Location updated successfully | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * id: | |
| * type: string | |
| * description: Location id | |
| * 400: | |
| * description: Invalid input | |
| * content: | |
| * application/json: | |
| * schema: | |
| * $ref: '#/components/schemas/ErrorResponse' | |
| */ | |
| router.post("/company/:companyId/locations", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const { code, | |
| name, | |
| gst: { | |
| legal_name, | |
| value | |
| }, | |
| manager: { | |
| manager_name, email, number, country_code | |
| }, | |
| address: { | |
| address1, | |
| address2, | |
| country, | |
| pincode, | |
| city, | |
| state, | |
| latitude = 19.2762702, | |
| longitude = 72.8929, | |
| landmark = "" | |
| }, | |
| } = req.body | |
| const client = await initClient(companyId); | |
| let locations = await client.companyProfile.createLocation({ | |
| body: { | |
| name, | |
| display_name: name, | |
| code, | |
| company: parseInt(companyId), | |
| documents: [{ | |
| type: "gst", | |
| legal_name: legal_name, | |
| value: value, verified: true | |
| }], | |
| address: { | |
| "address1": address1, | |
| "address2": address2, | |
| "country": country, | |
| "pincode": pincode, | |
| "city": city, | |
| "state": state, | |
| "latitude": latitude, | |
| "longitude": longitude, | |
| "landmark": landmark | |
| }, | |
| manager: { | |
| "name": manager_name, | |
| "email": email, | |
| "mobile_no": { | |
| "number": number, | |
| "country_code": country_code | |
| } | |
| }, | |
| contact_numbers: [ | |
| { | |
| "number": number, | |
| "country_code": country_code | |
| } | |
| ], | |
| store_type: "high_street" | |
| } | |
| }); | |
| res.json({ message: "location added", id: locations?.uid }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| router.put("/company/:companyId/locations/locationId", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const { code, | |
| name, | |
| gst: { | |
| legal_name, | |
| value | |
| }, | |
| manager: { | |
| manager_name, email, number, country_code | |
| }, | |
| address: { | |
| address1, | |
| address2, | |
| country, | |
| pincode, | |
| city, | |
| state, | |
| latitude = 19.2762702, | |
| longitude = 72.8929, | |
| landmark = "" | |
| }, | |
| } = req.body | |
| const client = await initClient(companyId); | |
| let locations = await client.companyProfile.createLocation({ | |
| body: { | |
| name, | |
| display_name: name, | |
| code, | |
| company: parseInt(companyId), | |
| documents: [{ | |
| type: "gst", | |
| legal_name: legal_name, | |
| value: value, verified: true | |
| }], | |
| address: { | |
| "address1": address1, | |
| "address2": address2, | |
| "country": country, | |
| "pincode": pincode, | |
| "city": city, | |
| "state": state, | |
| "latitude": latitude, | |
| "longitude": longitude, | |
| "landmark": landmark | |
| }, | |
| manager: { | |
| "name": manager_name, | |
| "email": email, | |
| "mobile_no": { | |
| "number": number, | |
| "country_code": country_code | |
| } | |
| }, | |
| contact_numbers: [ | |
| { | |
| "number": number, | |
| "country_code": country_code | |
| } | |
| ], | |
| store_type: "high_street" | |
| } | |
| }); | |
| res.json({ message: "location updated", id: locations?.id }) | |
| } catch (e) { | |
| next(e) | |
| } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/products: | |
| * post: | |
| * summary: Creates a new product for a given company. | |
| * description: This endpoint creates a new product with various attributes including name, slug, pricing, and more. | |
| * operationId: createProduct | |
| * tags: | |
| * - Products | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: Unique identifier of the company. | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * required: | |
| * - name | |
| * - slug | |
| * - seller_identifier | |
| * - brand_id | |
| * properties: | |
| * name: | |
| * type: string | |
| * description: Name of the product. | |
| * slug: | |
| * type: string | |
| * description: URL-friendly identifier for the product. | |
| * seller_identifier: | |
| * type: string | |
| * description: Unique identifier for the seller. | |
| * brand_id: | |
| * type: string | |
| * description: Unique identifier for the brand. | |
| * location_id: | |
| * type: string | |
| * description: Location identifier for the product. | |
| * mrp: | |
| * type: number | |
| * default: 999 | |
| * description: Maximum retail price of the product. | |
| * selling_price: | |
| * type: number | |
| * default: 499 | |
| * description: Selling price of the product. | |
| * responses: | |
| * 200: | |
| * description: Successful creation of the product. | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * id: | |
| * type: string | |
| * seller_identifier: | |
| * type: string | |
| */ | |
| router.post("/company/:companyId/products", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const { name, | |
| slug, | |
| seller_identifier, | |
| brand_id, location_id, mrp = 999, selling_price = 499 | |
| } = req.body; | |
| const obj = { | |
| "name": name, | |
| "slug": slug, | |
| "brand_uid": brand_id, | |
| "item_code": seller_identifier, | |
| "teaser_tag": {}, | |
| "net_quantity": {}, | |
| "tax_identifier": { | |
| "reporting_hsn": "1202355241H1", | |
| "hsn_code": "1202355241", | |
| "hsn_code_id": "65769883ba99dcf407a2b1ed" | |
| }, | |
| "country_of_origin": "India", | |
| "variants": {}, | |
| "variant_media": {}, | |
| "description": "PHA+WW91ciBwcm9kdWN0IGRlc2NyaXB0aW9uPC9wPg==", | |
| "short_description": "Your product description", | |
| "highlights": [], | |
| "company_id": 10, | |
| "template_tag": "c2-0-template", | |
| "currency": "INR", | |
| "media": [], | |
| "is_set": false, | |
| "sizes": [ | |
| { | |
| "size": "OS", | |
| "price": mrp, | |
| "price_effective": selling_price, | |
| "price_transfer": 0, | |
| "currency": "INR", | |
| "item_length": 1, | |
| "item_width": 1, | |
| "item_height": 1, | |
| "item_weight": 1, | |
| "item_dimensions_unit_of_measure": "cm", | |
| "item_weight_unit_of_measure": "gram", | |
| "track_inventory": true, | |
| "identifiers": [ | |
| { | |
| "gtin_value": seller_identifier, | |
| "gtin_type": "ean", | |
| "primary": true | |
| } | |
| ], | |
| "_custom_json": {}, | |
| "name": "OS" | |
| } | |
| ], | |
| "_custom_json": {}, | |
| "size_guide": "", | |
| "product_group_tag": [], | |
| "product_publish": { | |
| "product_online_date": "2023-12-11T08:38:10.082Z", | |
| "is_set": false | |
| }, | |
| "is_active": true, | |
| "custom_order": { | |
| "is_custom_order": false, | |
| "manufacturing_time": 0, | |
| "manufacturing_time_unit": "hours" | |
| }, | |
| "multi_size": false, | |
| "no_of_boxes": 1, | |
| "is_dependent": false, | |
| "item_type": "digital", | |
| "tags": [], | |
| "departments": [ | |
| 19771 | |
| ], | |
| return_config: { | |
| "returnable": false | |
| }, | |
| "category_slug": "c2-0-cat", | |
| "trader": [ | |
| { | |
| "type": "Manufacturer", | |
| "name": "Manufacturer", | |
| "address": [ | |
| "Manufacturer Address" | |
| ] | |
| } | |
| ], | |
| "return_config": { | |
| "returnable": true, | |
| time: 3, | |
| unit: "days" | |
| } | |
| } | |
| const client = await initClient(companyId); | |
| let product = await client.catalog.createProduct({ | |
| body: obj | |
| }); | |
| product = await client.catalog.getProduct({ | |
| itemId: product.uid | |
| }); | |
| res.json({ | |
| message: "product created", | |
| id: product.data.uid, | |
| seller_identifier: product?.data?.sizes?.[0]?.seller_identifier | |
| }); | |
| } catch (e) { next(e) } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/products/{productId}/inventory: | |
| * post: | |
| * summary: Updates inventory for a specific product. | |
| * description: This endpoint updates the inventory details for a given product, including location, pricing, and quantity. | |
| * operationId: updateInventory | |
| * tags: | |
| * - Inventory | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: Unique identifier of the company. | |
| * - in: path | |
| * name: productId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: Unique identifier of the product. | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * required: | |
| * - location_id | |
| * - seller_identifier | |
| * properties: | |
| * location_id: | |
| * type: string | |
| * description: Location identifier where the inventory is stored. | |
| * mrp: | |
| * type: number | |
| * default: 999 | |
| * description: Maximum retail price of the product. | |
| * selling_price: | |
| * type: number | |
| * default: 499 | |
| * description: Selling price of the product. | |
| * seller_identifier: | |
| * type: string | |
| * description: Unique identifier for the seller. | |
| * responses: | |
| * 200: | |
| * description: Successful update of inventory. | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| */ | |
| router.post("/company/:companyId/products/:productId/inventory", async (req, res, next) => { | |
| try { | |
| const { companyId, productId } = req.params; | |
| const { location_id, mrp = 999, selling_price = 499, id, seller_identifier } = req.body; | |
| const client = await initClient(companyId); | |
| let product = await client.catalog.getProduct({ | |
| itemId: productId | |
| }); | |
| let inv = await client.catalog.updateRealtimeInventory({ | |
| itemId: product.data.uid, | |
| sellerIdentifier: seller_identifier, | |
| body: { | |
| company_id: companyId, | |
| payload: [{ | |
| "seller_identifier": seller_identifier, | |
| "store_id": location_id, | |
| "price_marked": mrp, | |
| "price_effective": selling_price, | |
| "total_quantity": 10, | |
| "tags": [] | |
| }] | |
| } | |
| }) | |
| res.json({ message: "inv created" }); | |
| } catch (e) { next(e) } | |
| }) | |
| /** | |
| * @swagger | |
| * /company/{companyId}/sales_channel: | |
| * post: | |
| * operationId: addSalesChannel | |
| * summary: Create a sales channel for a given company | |
| * description: This endpoint creates a new sales channel for the specified company. | |
| * tags: | |
| * - Sales Channel | |
| * parameters: | |
| * - in: path | |
| * name: companyId | |
| * required: true | |
| * schema: | |
| * type: string | |
| * description: The ID of the company | |
| * requestBody: | |
| * required: true | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * brand_ids: | |
| * type: array | |
| * items: | |
| * type: integer | |
| * description: Array of brand IDs to be associated with the sales channel | |
| * name: | |
| * type: string | |
| * description: Name of the sales channel | |
| * subdomain: | |
| * type: string | |
| * description: subdomain associated with the sales channel | |
| * responses: | |
| * 200: | |
| * description: Sales channel successfully created | |
| * content: | |
| * application/json: | |
| * schema: | |
| * type: object | |
| * properties: | |
| * message: | |
| * type: string | |
| * app: | |
| * type: object | |
| * description: Details of the created sales channel | |
| * 400: | |
| * description: Bad request | |
| * 500: | |
| * description: Internal server error | |
| */ | |
| app.post("/company/:companyId/sales_channel", async (req, res, next) => { | |
| try { | |
| const { companyId } = req.params; | |
| const { brand_ids, name, subdomain } = req.body; | |
| const client = await initClient(companyId); | |
| let app = await client.configuration.createApplication({ | |
| body: { | |
| "app": { | |
| "company_id": (1).toString(), | |
| "channel_type": "website-and-mobile-apps", | |
| "auth": { | |
| "enabled": true | |
| }, | |
| "name": name, | |
| "desc": "", | |
| "mode": "live" | |
| }, | |
| "configuration": { | |
| "inventory": { | |
| "brand": { | |
| "criteria": "all", | |
| "brands": [] | |
| }, | |
| "store": { | |
| "criteria": "filter", | |
| "rules": [ | |
| { | |
| "companies": [companyId], | |
| "brands": brand_ids | |
| } | |
| ], | |
| "stores": [] | |
| }, | |
| "image": ["standard", "substandard", "default"], | |
| "franchise_enabled": false, | |
| "out_of_stock": true | |
| }, | |
| "payment": { | |
| "mode_of_payment": "ECOMM", | |
| "source": "ECOMM" | |
| }, | |
| "article_assignment": { | |
| "post_order_reassignment": true, | |
| "enforced_stores": [], | |
| "rules": { | |
| "store_priority": { | |
| "enabled": false, | |
| "storetype_order": [] | |
| } | |
| } | |
| } | |
| }, | |
| "domain": { | |
| "name": `${subdomain}.hostx5.de` | |
| } | |
| } | |
| }) | |
| res.json({ message: "inv created", app }); | |
| } catch (e) { next(e) } | |
| }) | |
| const chatHtml = fs.readFileSync('./chat.html', 'utf-8'); | |
| app.get('/', async (req, res, next) => { | |
| try { | |
| res.send(chatHtml); | |
| } catch (error) { | |
| console.error(error); | |
| res.send('Something needs to be fixed!'); | |
| } | |
| }); | |
| app.get('/talk', async (req, res, next) => { | |
| try { | |
| res.send(chatHtml); | |
| } catch (error) { | |
| console.error(error); | |
| res.send('Something needs to be fixed!'); | |
| } | |
| }); | |
| app.get('/history', setJioCopilotSessionCookie, async (req, res) => { | |
| const session = req.jio_copilot_anonymous_session; | |
| let messages = []; | |
| if (session) { | |
| messages = await listCache.getAll(session); | |
| } | |
| messages = messages.filter(message => message.role === 'user' || message.role === 'assistant'); | |
| res.json([{ role: 'assistant', content: 'Greetings! I\'m Jio Copilot, your digital aid for Jio platforms like TiraBeauty, JioCinema, JioMart, and JioFiber. Here to help with shopping, product exploration, content streaming, and internet/data plan navigation. How may I assist you today?' }, ...messages]); | |
| }); | |
| app.delete('/history', setJioCopilotSessionCookie, async (req, res) => { | |
| const session = req.jio_copilot_anonymous_session; | |
| if (session) { | |
| await listCache.clear(session); | |
| } | |
| res.json({ success: true }); | |
| }); | |
| router.post( | |
| '/openai', setJioCopilotSessionCookie, | |
| async (req, res, next) => { | |
| const functions = [ | |
| { | |
| "name": "getCompanyCreds", | |
| "description": "Retrieves credentials for a specific company based on its ID.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| } | |
| }, | |
| "required": ["company_id"] | |
| } | |
| }, { | |
| "name": "createUpdateCompanyCreds", | |
| "description": "Creates or updates credentials for a company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "clientId": { | |
| "type": "string", | |
| "description": "Client ID for authentication." | |
| }, | |
| "clientSecret": { | |
| "type": "string", | |
| "description": "Client secret for authentication." | |
| } | |
| }, | |
| "required": ["company_id", "clientId", "clientSecret"] | |
| } | |
| }, { | |
| "name": "getApplications", | |
| "description": "Retrieves a list of applications associated with a specific company ID.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| } | |
| }, | |
| "required": ["company_id"] | |
| } | |
| }, { | |
| "name": "createBrand", | |
| "description": "Creates a new brand under a specific company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "name": { | |
| "type": "string", | |
| "description": "Name of the new brand." | |
| }, | |
| "description": { | |
| "type": "string", | |
| "description": "Description of the new brand." | |
| }, | |
| "logo": { | |
| "type": "string", | |
| "description": "URL of the brand's logo." | |
| } | |
| }, | |
| "required": ["company_id", "name", "description"] | |
| } | |
| }, { | |
| "name": "updateBrand", | |
| "description": "Updates the details of an existing brand within a company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "brand_id": { | |
| "type": "string", | |
| "description": "Unique identifier of the brand to be updated." | |
| }, | |
| "name": { | |
| "type": "string", | |
| "description": "New name for the brand." | |
| }, | |
| "description": { | |
| "type": "string", | |
| "description": "New description for the brand." | |
| }, | |
| "logo": { | |
| "type": "string", | |
| "description": "New URL for the brand's logo." | |
| }, | |
| }, | |
| "required": ["company_id", "brand_id", "name", "description"] | |
| } | |
| }, { | |
| "name": "getBrands", | |
| "description": "Retrieves a list of all brands associated with a specific company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company for which brands are being retrieved." | |
| } | |
| }, | |
| "required": ["company_id"] | |
| } | |
| }, { | |
| "name": "getLocations", | |
| "description": "Retrieves a list of all locations associated with a specific company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company for which locations are being retrieved." | |
| } | |
| }, | |
| "required": ["company_id"] | |
| } | |
| }, { | |
| "name": "createLocation", | |
| "description": "Creates a new location for a specified company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "name": { | |
| "type": "string", | |
| "description": "name of the location." | |
| }, | |
| "code": { | |
| "type": "string", | |
| "description": "a unique code name." | |
| }, | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "address1": { | |
| "type": "string", | |
| "description": "Primary address line of the new location." | |
| }, | |
| "address2": { | |
| "type": "string", | |
| "description": "Secondary address line of the new location." | |
| }, | |
| "pincode": { | |
| "type": "number", | |
| "description": "Postal code of the new location." | |
| }, | |
| "state": { | |
| "type": "string", | |
| "description": "State where the new location is situated." | |
| }, | |
| "country": { | |
| "type": "string", | |
| "description": "State where the new location is situated." | |
| }, | |
| "city": { | |
| "type": "string", | |
| "description": "City where the new location is situated." | |
| }, | |
| "number": { | |
| "type": "string", | |
| "description": "Contact number for the new location. 10 digits" | |
| }, | |
| "country_code": { | |
| "type": "string", | |
| "description": "Country code for the contact number eg 91" | |
| }, | |
| "gst_name": { | |
| "type": "string", | |
| "description": "GST registered name associated with the new location." | |
| }, | |
| "gst_no": { | |
| "type": "string", | |
| "description": "GST number associated with the new location." | |
| }, | |
| "latitude": { | |
| "type": "number", | |
| "description": "Latitude coordinate for the new location." | |
| }, | |
| "longitude": { | |
| "type": "number", | |
| "description": "Longitude coordinate for the new location." | |
| }, | |
| "manager_name": { | |
| "type": "string", | |
| "description": "name of the store manager." | |
| }, | |
| "email": { | |
| "type": "string", | |
| "description": "email of the store manager." | |
| } | |
| }, | |
| "required": ["company_id", "address1", "city", "state", 'country', "pincode", "gst_name", "gst_no", 'manager_name', 'email', 'code', 'country_code', 'number'] | |
| } | |
| }, { | |
| "name": "updateLocation", | |
| "description": "update a existing location for a specified company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "location_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the location." | |
| }, | |
| "address1": { | |
| "type": "string", | |
| "description": "Primary address line of the new location." | |
| }, | |
| "address2": { | |
| "type": "string", | |
| "description": "Secondary address line of the new location." | |
| }, | |
| "pincode": { | |
| "type": "string", | |
| "description": "Postal code of the new location." | |
| }, | |
| "state": { | |
| "type": "string", | |
| "description": "State where the new location is situated." | |
| }, | |
| "city": { | |
| "type": "string", | |
| "description": "City where the new location is situated." | |
| }, | |
| "number": { | |
| "type": "string", | |
| "description": "Contact number for the new location." | |
| }, | |
| "country_code": { | |
| "type": "string", | |
| "description": "Country code for the contact number." | |
| }, | |
| "gst_name": { | |
| "type": "string", | |
| "description": "GST registered name associated with the new location." | |
| }, | |
| "gst_no": { | |
| "type": "string", | |
| "description": "GST number associated with the new location." | |
| }, | |
| "latitude": { | |
| "type": "number", | |
| "description": "Latitude coordinate for the new location." | |
| }, | |
| "longitude": { | |
| "type": "number", | |
| "description": "Longitude coordinate for the new location." | |
| } | |
| }, | |
| "required": ["company_id", 'brand_id', "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"] | |
| } | |
| }, { | |
| "name": "createProduct", | |
| "description": "Creates a new product in the company's catalog.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "name": { | |
| "type": "string", | |
| "description": "Name of the new product." | |
| }, | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "slug": { | |
| "type": "string", | |
| "description": "SEO-friendly URL segment for the product." | |
| }, | |
| "seller_identifier": { | |
| "type": "string", | |
| "description": "Unique identifier for the seller of the product." | |
| }, | |
| "brand_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the brand associated with the product." | |
| }, | |
| "mrp": { | |
| "type": "number", | |
| "description": "Maximum Retail Price of the product." | |
| }, | |
| "selling_price": { | |
| "type": "number", | |
| "description": "Selling price of the product." | |
| } | |
| }, | |
| "required": ["name", "company_id", "slug", "seller_identifier", "brand_id"] | |
| } | |
| }, { | |
| "name": "createInventory", | |
| "description": "Creates a new inventory record for a specific product in a company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "product_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the product." | |
| }, | |
| "seller_identifier": { | |
| "type": "string", | |
| "description": "Unique identifier for the seller of the product." | |
| }, | |
| "location_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the location where the inventory is stored." | |
| }, | |
| "mrp": { | |
| "type": "number", | |
| "description": "Maximum Retail Price of the product." | |
| }, | |
| "selling_price": { | |
| "type": "number", | |
| "description": "Selling price of the product." | |
| } | |
| }, | |
| "required": ["company_id", "product_id", "seller_identifier", "location_id"] | |
| } | |
| }, { | |
| "name": "createApplication", | |
| "description": "Creates a new application for a specified company.", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "company_id": { | |
| "type": "number", | |
| "description": "Unique identifier of the company." | |
| }, | |
| "brand_ids": { | |
| "type": "array", | |
| "description": "Array of brand IDs associated with the application.", | |
| "items": { | |
| "type": "number" | |
| } | |
| }, | |
| "name": { | |
| "type": "string", | |
| "description": "Name of the new application." | |
| }, | |
| "subdomain": { | |
| "type": "string", | |
| "description": "Subdomain for the application's URL." | |
| } | |
| }, | |
| "required": ["company_id", "brand_ids", "name", "subdomain"] | |
| } | |
| } | |
| ]; | |
| const messages = [{ | |
| role: 'system', | |
| content: `you are an onboarding buddy chatbot for fynd platform, you help logged in userd who have access to a company to clear their salechannels/ websites, always start by asking the same. when asking questions from the use ask one at a time, ask user for one input at a time. You must initiate the conversation always. | |
| NOTEs FOR YOU: | |
| always check if you have the credentials for a company_id | |
| you always show the function name and the generated JSON args when functions are called | |
| platform domain is platfrom.fyndx5.de | |
| to get started yo need to get the companyId, clientId and secret from the user. always check if the credentials exist, if not save them | |
| to create a sales channel you require at least one brand. fetch and show the brands | |
| to create a product you need a brand. fetch and show the brand | |
| once the product is created it takes some time reflect in the db before the inventory is added | |
| for a product to be visible on your sales channel you must also add inventory for it | |
| stores, location, warehouses mean the same, | |
| seller_identifier, item_code are unique indentifier of the product, both may be the same | |
| assume seller_identifier is a string separated by _ and in all caps always. | |
| assume data if possible | |
| UI Links: always give the ui link when performing actions | |
| company credentials create link = https://platform.fyndx5.de/company/{companyId}/apis/oauthclient/create | |
| company homepage url = https://platform.fyndx5.de/company/{companyId}/home | |
| company profile url = https://platform.fyndx5.de/company/{companyId}/profile | |
| company location url = https://platform.fyndx5.de/company/{companyId}/profile/edit-store/{locationId} | |
| company brand url = https://platform.fyndx5.de/company/{companyId}/profile/edit-brand/{brandId} | |
| company sales channels url = https://platform.fyndx5.de/company/{companyId}/application/{applicationId}/products | |
| company product listing url= https://platform.fyndx5.de/company/{companyId}/products/list | |
| company product url = https://platform.fyndx5.de/company/{companyId}/products/{itemId}/edit.` | |
| }]; | |
| const session = req.jio_copilot_anonymous_session; | |
| if (session) { | |
| messages.push(...(await listCache.getAll(session))); | |
| } | |
| const userMessage = { role: 'user', content: req.body.prompt }; | |
| messages.push(userMessage); | |
| await listCache.setItems(session, userMessage); | |
| res.setHeader('Cache-Control', 'no-cache'); | |
| res.setHeader('Content-Type', 'text/event-stream'); | |
| // res.setHeader('Access-Control-Allow-Origin', http://); | |
| res.setHeader('Connection', 'keep-alive'); | |
| res.flushHeaders(); | |
| try { | |
| await nextStep(session, messages, skills, functions, res); | |
| res.end(); | |
| } catch (error) { | |
| if (error.code === 'context_length_exceeded') { | |
| res.write('You have exhausted the conversation limit, clear history and start again!'); | |
| res.end(); | |
| } | |
| res.write('There is some issue is going on. Please try again later.'); | |
| res.end(); | |
| } | |
| }); | |
| app.use("/api", router); | |
| app.use(errorHandler) | |
| app.listen(port, async () => { | |
| console.log(`Example app listening at http://localhost:${port}`); | |
| const swaggerSpec = swaggerJSDoc(options); | |
| // Convert to YAML | |
| const swaggerYAML = yaml.dump(swaggerSpec); | |
| await fs.writeFileSync("swagger.yaml", swaggerYAML, 'utf-8') | |
| await fs.writeFileSync("swagger.json", JSON.stringify(swaggerSpec, null, 2), 'utf-8') | |
| }); | |
| async function nextStep(session, messages, skills, functions, res) { | |
| const conn = new OpenAI({ apiKey: "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" }); | |
| const streamResponse = await conn | |
| .chat.completions.create({ | |
| model: 'gpt-4', | |
| messages, | |
| functions, | |
| function_call: 'auto', | |
| temperature: 0.5, | |
| stream: true | |
| }).catch(async err => { | |
| console.error(err); | |
| const openAIError = new Error(err.error.message); | |
| openAIError.code = err.error.code; | |
| throw openAIError; | |
| }); | |
| let finalMessage = ''; | |
| const functionCall = { name: null, arguments: '' }; | |
| for await (const line of streamResponse) { | |
| const choice = line.choices[0]; | |
| if (choice.delta.function_call) { | |
| const fc = choice.delta.function_call; | |
| if (fc.name) { | |
| // res.write(`Detected Function: ${fc.name}\n\n`); | |
| // res.flush(); | |
| functionCall.name = fc.name; | |
| } | |
| if (fc.arguments) { | |
| functionCall.arguments += fc.arguments; | |
| } | |
| } else if (!choice.finish_reason && choice.delta.content) { | |
| finalMessage += choice.delta.content; | |
| res.write(`${choice.delta.content}`); | |
| res.flush(); | |
| } | |
| } | |
| if (!functionCall.name) { | |
| const assistantMessage = { role: 'assistant', content: finalMessage }; | |
| messages.push(assistantMessage); | |
| await listCache.setItems(session, assistantMessage); | |
| return; | |
| } | |
| const functionName = functionCall.name; | |
| const args = JSON.parse(functionCall.arguments); | |
| if (!skills[functionName]) { | |
| throw new Error(`No skill implemented for this function: ${functionName}`); | |
| } | |
| // res.write(`Executing Function: ${functionName} with arguments ${JSON.stringify(args)} \n\n`); | |
| // res.flush(); | |
| const skillRes = await skills[functionName]({ ...args, headers: { 'openai-ephemeral-user-id': session } }).catch(e => { | |
| return { message: e } | |
| }); | |
| if (skillRes) { | |
| const functionMessage = { role: 'function', name: functionName, content: JSON.stringify(skillRes) }; | |
| messages.push(functionMessage); | |
| await listCache.setItems(session, functionMessage); | |
| } | |
| return nextStep(session, messages, skills, functions, res); | |
| } | |
| export const handler = serverless(api); | |