DwightAI / api /index.js
sujoydev99's picture
redis added
5906edb
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);
}