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