import express from "express"; import Redis from "ioredis"; import { initClient } from './utils.js'; import { errorHandler } from './middleware.js'; import swaggerJSDoc from 'swagger-jsdoc'; import yaml from 'js-yaml' import fs from 'fs'; import { RedisListCache } from './cache.js'; 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 app = express(); 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 }; /** * @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 * - email * - 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 */ app.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! */ app.get("/_healthz", (req, res) => { res.send('Hello World!'); }); app.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' */ app.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' */ app.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' */ app.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' */ app.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 */ app.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?.id }) } catch (e) { next(e) } }) app.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' */ app.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' */ app.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?.id }) } catch (e) { next(e) } }) app.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 */ app.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 */ app.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.post( '/openai', async (req, res, next) => { try { const functions = [ { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "name": "createLocation", "description": "Creates a new location for a specified company.", "parameters": { "type": "object", "properties": { "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": "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", "address1", "city", "state", "pincode", "country_code", "gst_name", "gst_no"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } }, { "type": "function", "function": { "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"] } } } ]; console.log(req.body) 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. when asking questions from the use ask one at a time, ask user for one input at a time. You must initiate the conversation NOTE: 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, department and category. fetch and show the brand, departments 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 UI Links: always give the ui link when performing actions company credentials create link = https://platform.fynd.com/company/{companyId}/apis/oauthclient/create company homepage url = https://platform.fynd.com/company/{companyId}/home company profile url = https://platform.fynd.com/company/{companyId}/profile company location url = https://platform.fynd.com/company/{companyId}/profile/edit-store/{locationId} company brand url = https://platform.fynd.com/company/{companyId}/profile/edit-brand/{brandId} company sales channels url = https://platform.fynd.com/company/{companyId}/application/{applicationId}/products company product listing url= https://platform.fynd.com/company/{companyId}/products/list company product url = https://platform.fynd.com/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(); 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(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-1106-preview', 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 } }); if (skillRes) { const functionMessage = { role: 'function', name: functionName, content: JSON.stringify(skillRes) }; messages.push(functionMessage); await listCache.setItems(session, functionMessage); } return nextStep(conn, session, messages, skills, functions, res); }