From a54eb2bd3e2b5f515e3e463e4248e192f33bd21b Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:00:23 +0530 Subject: [PATCH 01/22] feat - added openai for genai --- server/package-lock.json | 22 ++++++++++++++++++++++ server/package.json | 1 + server/src/config/openai.js | 18 ++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 server/src/config/openai.js diff --git a/server/package-lock.json b/server/package-lock.json index 9453af1..7cf03d9 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -21,6 +21,7 @@ "jsonwebtoken": "^9.0.3", "mongoose": "^9.1.6", "morgan": "^1.10.1", + "openai": "^6.25.0", "uuid": "^13.0.0" }, "devDependencies": { @@ -1730,6 +1731,27 @@ "wrappy": "1" } }, + "node_modules/openai": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.25.0.tgz", + "integrity": "sha512-mEh6VZ2ds2AGGokWARo18aPISI1OhlgdEIC1ewhkZr8pSIT31dec0ecr9Nhxx0JlybyOgoAT1sWeKtwPZzJyww==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/openid-client": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.1.tgz", diff --git a/server/package.json b/server/package.json index 8b5ddda..a362268 100644 --- a/server/package.json +++ b/server/package.json @@ -24,6 +24,7 @@ "jsonwebtoken": "^9.0.3", "mongoose": "^9.1.6", "morgan": "^1.10.1", + "openai": "^6.25.0", "uuid": "^13.0.0" }, "devDependencies": { diff --git a/server/src/config/openai.js b/server/src/config/openai.js new file mode 100644 index 0000000..810b0f4 --- /dev/null +++ b/server/src/config/openai.js @@ -0,0 +1,18 @@ +import OpenAI from "openai"; +import { woocommerceAITools } from "../utils/woocommerceAITools.js"; +export const openAIClient = new OpenAI(); + + +export async function getOpenAIResponse(message) { + const response = await openAIClient.chat.completions.create({ + model: "gpt-5-nano", + messages: [ + { role: "system", content: "You are a witty Hinglish Store Manager. Help the user manage their store." }, + { role: "user", content: message } + ], + tools : woocommerceAITools, + tool_choice : "auto", + + }); + return response.choices[0].message; +} \ No newline at end of file From 86c2cb7624a0f18e68aa1535065d8d84401d7d25 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:00:47 +0530 Subject: [PATCH 02/22] feat - added routes for chatting --- server/src/app.js | 4 +++- server/src/routes/ai.routes.js | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 server/src/routes/ai.routes.js diff --git a/server/src/app.js b/server/src/app.js index ca5ae70..0ddc6d7 100644 --- a/server/src/app.js +++ b/server/src/app.js @@ -7,6 +7,7 @@ import "dotenv/config"; import storeRoutes from './routes/store.routes.js'; import authRoutes from './routes/auth.routes.js'; import customDomainRoutes from './routes/domain.route.js'; +import aiRoutes from './routes/ai.routes.js' import { NODE_ENV } from "./config/env.js"; @@ -46,8 +47,9 @@ app.get('/health', (req, res) => { app.use('/api/stores', storeRoutes); -app.use('/api/auth/', authRoutes); +app.use('/api/auth', authRoutes); app.use('/api/domain',customDomainRoutes); +app.use('/api/ai', aiRoutes) app.use((err, req, res, next) => { diff --git a/server/src/routes/ai.routes.js b/server/src/routes/ai.routes.js new file mode 100644 index 0000000..8a0a5da --- /dev/null +++ b/server/src/routes/ai.routes.js @@ -0,0 +1,11 @@ +import express from "express"; +import { getAISuggestedTasks, getChatHistory, processAIChat } from "../controllers/ai.controller.js"; +import { authenticate } from "../middleware/auth.middleware.js"; + +const router = express.Router(); + +router.get("/chat/:storeId", authenticate, getChatHistory); +router.post("/chat",authenticate, processAIChat); +router.get("/suggestions/:storeId",authenticate, getAISuggestedTasks); + +export default router; \ No newline at end of file From 940223cab719127fd2da3e556ce3cd6467a805e3 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:01:04 +0530 Subject: [PATCH 03/22] feat - added collection for chats --- server/src/models/chat.model.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 server/src/models/chat.model.js diff --git a/server/src/models/chat.model.js b/server/src/models/chat.model.js new file mode 100644 index 0000000..426d6ff --- /dev/null +++ b/server/src/models/chat.model.js @@ -0,0 +1,29 @@ +import mongoose from 'mongoose'; + +const messageSchema = new mongoose.Schema({ + role: { + type: String, + enum: ['user', 'assistant', 'system'], + required: true + }, + content: { + type: String, + required: true + }, + timestamp: { + type: Date, + default: Date.now + } +}); + +const chatSchema = new mongoose.Schema({ + storeId: { + type: mongoose.Schema.Types.ObjectId, + required: true, + unique: true, + index: true + }, + messages: [messageSchema] +}, { timestamps: true }); + +export default mongoose.model('Chat', chatSchema); \ No newline at end of file From 07de5999f4436caabdeb4ccfec6aef235db3876d Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:01:35 +0530 Subject: [PATCH 04/22] feat - added UI for chatbot --- .../dashboard/components/StoreTable.jsx | 2 + client/src/app/customize/Customize.js | 243 +++++++++++++----- client/src/app/globals.css | 16 +- 3 files changed, 192 insertions(+), 69 deletions(-) diff --git a/client/src/app/(with-nav-bar)/dashboard/components/StoreTable.jsx b/client/src/app/(with-nav-bar)/dashboard/components/StoreTable.jsx index f715263..d90915c 100644 --- a/client/src/app/(with-nav-bar)/dashboard/components/StoreTable.jsx +++ b/client/src/app/(with-nav-bar)/dashboard/components/StoreTable.jsx @@ -238,6 +238,8 @@ const StoreTable = ({ stores, onDelete, isLoading, isDeleting,fetchStores }) => store.name )}&url=${encodeURIComponent( store.storeUrl + )}&storeId=${encodeURIComponent( + store._id )}` ) } diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 243e5d2..4c7dbc3 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -20,27 +20,19 @@ import { Button } from "../_components/ui/button"; import { Input } from "../_components/ui/input"; import { cn } from "../../lib/utils"; import Loader from "../_components/Loader"; +import api from "@/lib/api"; -/* ------------------ CONSTANTS ------------------ */ const INITIAL_MESSAGES = [ { id: "1", role: "bot", content: - "Hey! ๐Ÿ‘‹ I'm your store customization assistant. Tell me what you'd like to change โ€” colors, layout, products, branding โ€” and I'll help you out!", + "Hey! ๐Ÿ‘‹ I'm your store manager assistant. How can I help you bro ? ", timestamp: new Date(), }, ]; -const BOT_RESPONSES = [ - "Got it! I'm applying those changes to your store now. Check the preview on the right โ†’", - "Great choice! That's going to look amazing. Updating the preview...", - "Sure thing! I've noted that customization. What else would you like to tweak?", - "Perfect! The store is looking better already. Any other changes?", - "Done! Take a look at the preview. Want me to adjust anything else?", -]; - const DEVICE_ORDER = ["desktop", "tablet", "mobile"]; const DEVICE_WIDTH = { @@ -56,7 +48,8 @@ export default function Customize() { const searchParams = useSearchParams(); const storeName = searchParams.get("name") || "Store"; - + const storeId = searchParams.get("storeId"); + const [storeUrl, setStoreUrl] = useState( searchParams.get("url") || "" ); @@ -68,13 +61,66 @@ export default function Customize() { const [isFullscreen, setIsFullscreen] = useState(false); const [deviceView, setDeviceView] = useState("desktop"); const [isIframeLoading, setIsIframeLoading] = useState(true); + const [suggestedActions, setSuggestedActions] = useState([]); + const [loadingActions, setLoadingActions] = useState(true); + const [loadingChat, setLoadingChat] = useState(true); const scrollRef = useRef(null); + useEffect(() => { + const fetchChatHistory = async () => { + if (!storeId) { + setLoadingChat(false); + return; + } + setLoadingChat(true); + + + try { + const token = localStorage.getItem("jwt"); + const json = await api.get(`/ai/chat/${storeId}`,token); + + if (json.success && json.data && json.data.length > 0) { + const formattedHistory = json.data.map((msg, idx) => ({ + id: msg._id || String(Date.now() + idx), + role: msg.role === "assistant" ? "bot" : "user", + content: msg.content, + timestamp: new Date(msg.timestamp || Date.now()), + })); + + setMessages(formattedHistory); + } + } catch (error) { + console.error("Failed to fetch history:", error); + } finally { + setLoadingChat(false); + } + }; + + const fetchSuggestion = async () => { + if (!storeId) return; + setLoadingActions(true); + + try { + const token = localStorage.getItem("jwt"); + const json = await api.get(`/ai/suggestions/${storeId}`,token); + + if (json.success && json.data && json.data.length > 0) { + setSuggestedActions(json.data); + } + } catch (error) { + console.error("Failed to fetch history:", error); + } + setLoadingActions(false); + } + + fetchChatHistory(); + fetchSuggestion(); + }, [storeId]); + useEffect(() => { setIsIframeLoading(true); }, [iframeKey, storeUrl]); - /* ------------------ EFFECTS ------------------ */ useEffect(() => { if (scrollRef.current) { @@ -100,15 +146,16 @@ export default function Customize() { setDeviceView(next); }; - const handleSend = () => { - if (!input.trim()) return; + const handleSend = async () => { + if (!input.trim() || !storeId) return; + const userText = input.trim(); setMessages((prev) => [ ...prev, { id: String(Date.now()), role: "user", - content: input.trim(), + content: userText, timestamp: new Date(), }, ]); @@ -116,22 +163,50 @@ export default function Customize() { setInput(""); setIsTyping(true); - setTimeout(() => { + try { + const token = localStorage.getItem("jwt"); + + const json = await api.post('/ai/chat', + { message: userText, storeId }, + token + ); + + + if (json.success) { + setMessages((prev) => [ + ...prev, + { + id: String(Date.now() + 1), + role: "bot", + content: json.reply, + timestamp: new Date(), + }, + ]); + + if (json.toolExecuted) { + console.log(`[Action Triggered]: ${json.toolName} - Refreshing store preview...`); + setIframeKey((prevKey) => prevKey + 1); + } + + } else { + throw new Error(json.error || "Failed to process request"); + } + } catch (error) { + console.error("Chat error:", error); setMessages((prev) => [ ...prev, { - id: String(Date.now() + 1), + id: String(Date.now() + 2), role: "bot", - content: - BOT_RESPONSES[Math.floor(Math.random() * BOT_RESPONSES.length)], + content: "Sorry bhai, network issue ho gaya. Try again!", timestamp: new Date(), }, ]); + } finally { setIsTyping(false); - }, 1200); + } }; - /* ------------------ RENDER ------------------ */ return (
@@ -166,60 +241,92 @@ export default function Customize() {
{/* Messages */} -
- {messages.map((msg) => ( -
+ {loadingChat ? ( +
+ +
+ ) : +
+ {messages.map((msg) => (
- {msg.role === "bot" ? ( - - ) : ( - - )} +
+ {msg.role === "bot" ? ( + + ) : ( + + )} +
+ +
+ {msg.content} +
- -
- {msg.content} + ))} + + {isTyping && ( +
+
+ +
+
+ {[0, 1, 2].map((i) => ( + + ))} +
+ )} +
+ } +
+ {loadingActions ? ( +
+ {[1, 2, 3].map((i) => ( +
+ ))}
- ))} - - {isTyping && ( -
-
- -
-
- {[0, 1, 2].map((i) => ( - - ))} -
+ ) : ( +
+ {suggestedActions.map((action) => ( + + ))}
)}
diff --git a/client/src/app/globals.css b/client/src/app/globals.css index 3a8ba40..2b2c793 100644 --- a/client/src/app/globals.css +++ b/client/src/app/globals.css @@ -124,4 +124,18 @@ .animate-float { animation: floatY 1.8s ease-in-out infinite; -} \ No newline at end of file +} + +.hide-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; +} + +.hide-scrollbar::-webkit-scrollbar { + display: none; +} + +.hide-scrollbar::-webkit-scrollbar:horizontal { + display: none; +} + From 5f4cfe95a229badc6180612356a26a877cba21d7 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:01:59 +0530 Subject: [PATCH 05/22] feat - added ai tools for woocommerce store --- server/src/controllers/ai.controller.js | 157 +++++++++++++++++ server/src/controllers/store.controller.js | 2 + server/src/services/k8sServices.js | 44 ++++- server/src/services/woocommerceServices.js | 188 +++++++++++++++++++++ server/src/utils/woocommerceAITools.js | 161 ++++++++++++++++++ server/src/utils/woocommerceCommands.js | 40 +++++ 6 files changed, 584 insertions(+), 8 deletions(-) create mode 100644 server/src/controllers/ai.controller.js create mode 100644 server/src/services/woocommerceServices.js create mode 100644 server/src/utils/woocommerceAITools.js create mode 100644 server/src/utils/woocommerceCommands.js diff --git a/server/src/controllers/ai.controller.js b/server/src/controllers/ai.controller.js new file mode 100644 index 0000000..901d20b --- /dev/null +++ b/server/src/controllers/ai.controller.js @@ -0,0 +1,157 @@ +import { getOpenAIResponse } from "../config/openai.js"; +import { aiActionMap, SUGGESTION_RULES } from "../utils/woocommerceAITools.js"; +import { getStoreAudit } from "../services/woocommerceServices.js"; +import Store from '../models/store.model.js'; +import Chat from '../models/chat.model.js'; + + +export const processAIChat = async (req, res) => { + const { message, storeId } = req.body; + + try { + const store = await Store.findOne({ + _id: storeId, + owner: req.user.userId, + }); + + if (!store) { + return res.status(404).json({ + success: false, + message: "Store not found", + }); + } + + const namespace = store.namespace; + + // AI se response lo + const aiMsg = await getOpenAIResponse(message); + + // Default states + let finalReply = ""; + let actionData = null; + let isToolExecuted = false; + let executedToolName = null; + + // 1. Agar AI ne kisi Tool ko call kiya hai + if (aiMsg.tool_calls && aiMsg.tool_calls.length > 0) { + const toolCall = aiMsg.tool_calls[0]; + const fnName = toolCall.function.name; + const args = JSON.parse(toolCall.function.arguments); + + const action = aiActionMap[fnName]; + + if (action) { + actionData = await action.execute(namespace, args); + // Dynamic reply direct tere Action Map se aayega + finalReply = action.getReply(actionData, args); + executedToolName = fnName; + isToolExecuted = true; + } else { + finalReply = "Sorry bhai, ye function abhi main seekh raha hoon."; + } + } else { + // 2. Agar koi tool call nahi hua (Normal Chat) + finalReply = aiMsg.content || "Done bhai! Batao aur kya karna hai?"; + } + + // 3. Database mein Chat Save karo + await Chat.findOneAndUpdate( + { storeId }, + { + $push: { + messages: { + $each: [ + { role: 'user', content: message }, + { role: 'assistant', content: finalReply } + ] + } + } + }, + { upsert: true, new: true } + ); + + // 4. Single Unified Return (Frontend ke liye ekdum mast format) + return res.json({ + success: true, + reply: finalReply, + data: actionData, + toolExecuted: isToolExecuted, + toolName: executedToolName + }); + + } catch (error) { + console.error("AI Controller Error:", error); + res.status(500).json({ success: false, error: "Bhai, engine thoda garam ho gaya!" }); + } +}; + + +export const getAISuggestedTasks = async (req, res) => { + const { storeId } = req.params; + + try { + const store = await Store.findOne({ + _id: storeId, + owner: req.user.userId, + }); + + if (!store) { + return res.status(404).json({ + success: false, + message: "Store not found", + }); + } + + const namespace = store.namespace; + const auditResult = await getStoreAudit(namespace); + let activeSuggestions = []; + + if (auditResult.success && auditResult.audit && auditResult.audit.summary) { + const summary = auditResult.audit.summary; + + activeSuggestions = SUGGESTION_RULES + .filter(rule => rule.condition(summary)) + .map(rule => rule.data); + } else { + activeSuggestions = [ + { title: "๐Ÿค– Check Store Status", prompt: "Mere store ka poora haal-chaal batao." }, + { title: "๐Ÿ“ฆ Manage Products", prompt: "Mere products list karo." } + ]; + } + return res.json({ + success: true, + data: activeSuggestions.slice(0, 4) + }); + + } catch (error) { + console.error("Suggested Tasks Error:", error.message); + return res.status(500).json({ success: false, error: "Suggestions fetch nahi ho paye bhai!" }); + } +}; + + + +export const getChatHistory = async (req, res) => { + const { storeId } = req.params; + + try { + const chatRecord = await Chat.findOne({ storeId }); + + if (!chatRecord) { + return res.json({ + success: true, + data: [], + message: "Fresh chat hai bhai!" + }); + } + + return res.json({ + success: true, + data: chatRecord.messages + }); + + } catch (error) { + console.error("Chat History Fetch Error:", error.message); + return res.status(500).json({ success: false, error: "History load nahi ho payi bhai." }); + } +}; \ No newline at end of file diff --git a/server/src/controllers/store.controller.js b/server/src/controllers/store.controller.js index 7a9af74..9e16079 100644 --- a/server/src/controllers/store.controller.js +++ b/server/src/controllers/store.controller.js @@ -4,6 +4,7 @@ import { createNameSpaceAndBuildStore, deleteNameSpace, deployMedusaStoreFront } import { getStoreAdminUrl, getStoreDomain } from '../utils/helper.js'; import { MAX_STORE_FREE_LIMIT, PROHIBITED_SLUG } from '../utils/constant.js'; import { PROTOCOL } from '../config/env.js'; +import Chat from '../models/chat.model.js'; @@ -137,6 +138,7 @@ export const deleteStore = async (req, res) => { try { await deleteNameSpace(store.namespace); await Store.findByIdAndDelete(storeId); + await Chat.findOneAndDelete({ storeId }); } catch (err) { console.error(`[Background] Delete Failed for ${store.name}:`, err); await Store.findByIdAndUpdate(storeId, { diff --git a/server/src/services/k8sServices.js b/server/src/services/k8sServices.js index c57c137..efae3a4 100644 --- a/server/src/services/k8sServices.js +++ b/server/src/services/k8sServices.js @@ -1,15 +1,17 @@ import { exec } from 'child_process'; import util from 'util'; import { getCustomDomainCommand, getMedusaStoreCommand, getStoreCreationCommand, getStoreNamespaceCreationCommand, getStoreNamespaceDeletionCommand } from '../utils/commands.js'; +import { getPodsCommand } from '../utils/woocommerceCommands.js'; const execPromise = util.promisify(exec); -export const executeHelmCommand = async(command) => { +export const executeCommand = async(command) => { try { console.log(`[Helm] Deploying`); const { stdout } = await execPromise(command); - console.log(`[Helm] Success: ${stdout}`); + // console.log(`[Helm] Success: ${stdout}`); + return stdout; } catch (error) { console.error(`[Helm] Error: ${error.stderr || error.message}`); throw new Error(`Helm installation failed: ${error.message}`); @@ -20,9 +22,9 @@ export const executeHelmCommand = async(command) => { export const createNameSpaceAndBuildStore = async(namespace, storeType, domain,adminEmail, adminPassword, slug) => { console.log(`[Background] Starting deployment for (${namespace})...`); const namespaceCreationCommand = getStoreNamespaceCreationCommand(namespace); - await executeHelmCommand(namespaceCreationCommand); + await executeCommand(namespaceCreationCommand); const command = getStoreCreationCommand(namespace,storeType,domain,adminEmail,adminPassword,slug); - await executeHelmCommand(command); + await executeCommand(command); console.log(`[Background] Store ${namespace} is now READY!`); } @@ -30,14 +32,14 @@ export const createNameSpaceAndBuildStore = async(namespace, storeType, domain,a export const deleteNameSpace = async(namespace) => { console.log(`[Background] Deleting resources for namespace: ${namespace}...`); const command = getStoreNamespaceDeletionCommand(namespace); - await executeHelmCommand(command); + await executeCommand(command); console.log(`[Background] Store ${namespace} deleted successfully from DB & K8s`); } export const deployMedusaStoreFront = async(namespace,slug,domain,backendUrl, publishableKey) => { console.log(`[Background] Starting Storefront for: ${slug}...`); const command = getMedusaStoreCommand(namespace,slug,domain,backendUrl, publishableKey); - await executeHelmCommand(command); + await executeCommand(command); console.log(`[Background] Storefront ${slug} is now READY!`); } @@ -45,6 +47,32 @@ export const deployMedusaStoreFront = async(namespace,slug,domain,backendUrl, pu export const updateCustomDomain = async(store) => { const command = getCustomDomainCommand(store); - await executeHelmCommand(command); + await executeCommand(command); console.log(`Domain ${store.customDomain} is now ACTIVE`); -} \ No newline at end of file +} + +export const getPodName = async (namespace) => { + try { + const cmd = getPodsCommand(namespace); + const stdout = await executeCommand(cmd); + const podData = JSON.parse(stdout); + + const activePod = podData.items.find(pod => + pod.status.phase === "Running" && + !pod.metadata.name.includes("-db") + ); + + if (!activePod) { + console.error(`[Discovery] No running WordPress pod found in ${namespace}`); + return null; + } + + const podName = activePod.metadata.name; + console.log(`[Discovery] Found active pod: ${podName}`); + return podName; + + } catch (error) { + console.error("[Discovery] Error fetching pod:", error.message); + return null; + } +}; \ No newline at end of file diff --git a/server/src/services/woocommerceServices.js b/server/src/services/woocommerceServices.js new file mode 100644 index 0000000..d8dfbfb --- /dev/null +++ b/server/src/services/woocommerceServices.js @@ -0,0 +1,188 @@ +import { createCouponCommand, createProductCommand, getAllCouponsCommand, getAllOrdersCommand, getAllProductCommand, getCouponDeletionCommand, getEnableCODCommand, getEnabledPaymentMethodsCommand } from "../utils/woocommerceCommands.js"; +import { executeCommand, getPodName } from "./k8sServices.js"; + +export const enableCODPayment = async (namespace) => { + try { + const podName = await getPodName(namespace); + if (!podName) throw new Error("No active podName found"); + + const enableCODCommand = getEnableCODCommand(podName, namespace); + const output = await executeCommand(enableCODCommand); + return { success: true, output}; + } catch (error) { + console.error("Failed to enable COD:", error.message); + return { success: false, error: error.message }; + } +}; + +export const checkPaymentStatus = async (namespace) => { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + const cmd = getEnabledPaymentMethodsCommand(podName,namespace) + + try { + const stdout = await executeCommand(cmd); + const gateways = JSON.parse(stdout); + + const cod = gateways.find(g => g.id === 'cod'); + return { + success: true, + isCODEnabled: cod?.enabled === true || cod?.enabled === 'yes', + gateways + }; + } catch (err) { + return { success: false, error: err.message }; + } +}; + +export const addProductAndGetLink = async (namespace, productData) => { + + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + try { + const createCmd = createProductCommand(podName,namespace,productData) + const createOut = await executeCommand(createCmd); + const productId = createOut.match(/\d+/)[0]; + + const linkCmd = `kubectl exec ${podName} -n ${namespace} -- wp post get ${productId} --field=url --allow-root`; + const linkOut = await executeCommand(linkCmd); + + return { + success: true, + link: linkOut.trim(), + message: `Product added! Link: ${linkOut.trim()}` + }; + } catch (error) { + return { success: false, error: error.message }; + } +}; + +export const createCoupon = async (namespace, data) => { + try { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + const { code, amount, type } = data; + const cmd = createCouponCommand(podName,namespace,code,amount,type); + await executeCommand(cmd, "Coupon-Create"); + return { + success : true, + message : "Coupon added successfully!" + } + } catch (error) { + return { + success : false, + message : "Something went wrong" + } + } + +}; + +export const getAllCoupons = async (namespace) => { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + try { + const cmd = getAllCouponsCommand(podName,namespace); + const stdout = await executeCommand(cmd); + const coupons = JSON.parse(stdout); + + return { + success: true, + count: coupons.length, + data: coupons + }; + } catch (error) { + console.error("Error fetching coupons:", error.message); + return { success: false, error: error.message }; + } +}; + + +export const deleteStoreCoupon = async (namespace, couponId) => { + try { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + const cmd = getCouponDeletionCommand(podName,namespace,couponId); + await executeCommand(cmd); + + return { + success: true, + message: `Coupon ${couponId} has been deleted permanently.`, + }; + } catch (error) { + console.error("Error deleting coupon:", error.message); + return { success: false, error: error.message }; + } +}; + + +export const getAllOrders = async (namespace) => { + try { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + + const cmd = getAllOrdersCommand(podName,namespace) + const stdout = await executeCommand(cmd); + const orders = JSON.parse(stdout); + + return { + success: true, + count: orders.length, + data: orders + }; + } catch (error) { + console.error("Error fetching orders:", error.message); + return { success: false, error: error.message }; + } +}; + +export const getStoreAudit = async (namespace) => { + const podName = await getPodName(namespace); + if (!podName) return { error: "Pod not ready" }; + try { + console.log(`[Audit] Fetching full store snapshot for ${namespace}...`); + + const commands = { + products: getAllProductCommand(podName,namespace), + orders: getAllOrdersCommand(podName,namespace), + coupons: getAllCouponsCommand(podName,namespace), + payment: getEnabledPaymentMethodsCommand(podName,namespace) + }; + + const [prodOut, orderOut, coupOut, payOut] = await Promise.all([ + executeCommand(commands.products), + executeCommand(commands.orders), + executeCommand(commands.coupons), + executeCommand(commands.payment) + ]); + + + const cleanOutput = (output) => { + try { + const sanitized = output.trim(); + if (!sanitized) return []; + return JSON.parse(sanitized); + } catch (e) { + console.error("Parsing error:", e.message); + return []; + } + }; + const auditData = { + products: cleanOutput(prodOut), + orders: cleanOutput(orderOut), + coupons: cleanOutput(coupOut), + payments: cleanOutput(payOut), + summary: { + totalProducts: cleanOutput(prodOut).length, + totalOrders: cleanOutput(orderOut).length, + totalCoupons: cleanOutput(coupOut).length, + isCodEnabled: cleanOutput(payOut).some(p => p.id === 'cod' && p.enabled === true) + } + }; + + return { success: true, audit: auditData }; + + } catch (error) { + console.error("[Audit] Error:", error.message); + return { success: false, error: error.message }; + } +}; \ No newline at end of file diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js new file mode 100644 index 0000000..e18c2eb --- /dev/null +++ b/server/src/utils/woocommerceAITools.js @@ -0,0 +1,161 @@ +import * as woo from "../services/woocommerceServices.js"; + +export const woocommerceAITools = [ + { + type: "function", + function: { + name: "getStoreAudit", + description: "Get full store snapshot (products, orders, coupons, payments status). Call this when user asks about store health, stats, or overview.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "enableCODPayment", + description: "Enable Cash on Delivery (COD) payment method for the store.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "checkPaymentStatus", + description: "Check which payment methods (like COD) are currently enabled in the store.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "addProductAndGetLink", + description: "Add a new product to the store and get its live URL.", + parameters: { + type: "object", + properties: { + name: { type: "string", description: "Name of the product" }, + price: { type: "string", description: "Regular price of the product" } + }, + required: ["name", "price"] + } + } + }, + { + type: "function", + function: { + name: "createCoupon", + description: "Create a discount coupon in the store.", + parameters: { + type: "object", + properties: { + code: { type: "string", description: "Coupon code, e.g., SAVE50" }, + amount: { type: "string", description: "Discount value" }, + type: { type: "string", enum: ["percent", "fixed_cart"], description: "Type of discount" } + }, + required: ["code", "amount"] + } + } + }, + { + type: "function", + function: { + name: "getAllCoupons", + description: "Get a list of all active discount coupons in the store.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "deleteStoreCoupon", + description: "Delete a specific coupon using its ID.", + parameters: { + type: "object", + properties: { + couponId: { type: "string", description: "The ID of the coupon to delete" } + }, + required: ["couponId"] + } + } + }, + { + type: "function", + function: { + name: "getAllOrders", + description: "Get a list of all customer orders in the store.", + parameters: { type: "object", properties: {} } + } + } +]; + + +export const aiActionMap = { + getStoreAudit: { + execute: async (ns) => await woo.getStoreAudit(ns), + getReply: (result) => "Store ki report ready hai. Sab badhiya chal raha hai! ๐Ÿ“Š" + }, + + enableCODPayment: { + execute: async (ns) => await woo.enableCODPayment(ns), + getReply: () => "Bhai, Cash on Delivery (COD) enable kar diya hai! ๐Ÿ’ณ" + }, + + checkPaymentStatus: { + execute: async (ns) => await woo.checkPaymentStatus(ns), + getReply: (result) => result.isCODEnabled ? "COD active hai bhai! โœ…" : "Abhi COD band hai." + }, + + addProductAndGetLink: { + execute: async (ns, args) => await woo.addProductAndGetLink(ns, args), + // Dynamic reply using args + getReply: (result, args) => `Bhai, naya product '${args.name}' add kar diya hai! ๐Ÿš€ Preview refresh ho raha hai...` + }, + + createCoupon: { + execute: async (ns, args) => await woo.createCoupon(ns, args), + getReply: (result, args) => `Done! '${args.code}' coupon active ho gaya hai ${args.amount} discount ke sath. ๐ŸŽŸ๏ธ` + }, + + getAllCoupons: { + execute: async (ns) => await woo.getAllCoupons(ns), + getReply: (result) => `Total ${result.count} coupons mile hain bhai. ๐ŸŽซ` + }, + + deleteStoreCoupon: { + execute: async (ns, args) => await woo.deleteStoreCoupon(ns, args.couponId), + getReply: (result, args) => `Coupon ID ${args.couponId} delete kar diya permanently! ๐Ÿ—‘๏ธ` + }, + + getAllOrders: { + execute: async (ns) => await woo.getAllOrders(ns), + getReply: (result) => `Aapke paas total ${result.count} orders hain abhi. ๐Ÿ“ฆ` + } +}; + + +export const SUGGESTION_RULES = [ + { + condition: (summary) => !summary.isCodEnabled, + data: { title: "๐Ÿ’ณ Enable COD", prompt: "Bhai, store pe Cash on Delivery (COD) chalu kar de." } + }, + { + condition: (summary) => summary.totalProducts === 0, + data: { title: "๐Ÿ“ฆ Add First Product", prompt: "Ek 'Premium T-Shirt' add kar do 499 rupees mein." } + }, + { + condition: (summary) => summary.totalProducts > 0 && summary.totalOrders === 0, + data: { title: "๐Ÿ‘€ Wait for Orders", prompt: "Bhai, kya mere products live hain? Koi order nahi aaya abhi tak." } + }, + { + condition: (summary) => summary.totalProducts > 0 && summary.totalOrders > 0, + data: { title: "๐Ÿ“ˆ Check Orders", prompt: "Dikhao abhi tak kitne orders aaye hain." } + }, + { + condition: (summary) => summary.totalCoupons === 0, + data: { title: "๐ŸŽŸ๏ธ Create Coupon", prompt: "Naye customers ke liye 'WELCOME50' coupon bana do 50% discount ke sath." } + }, + { + condition: () => true, // Ye hamesha true rahega (Default fallback) + data: { title: "๐Ÿค– Store Audit", prompt: "Store ki poori report do, kya-kya active hai abhi?" } + } +]; diff --git a/server/src/utils/woocommerceCommands.js b/server/src/utils/woocommerceCommands.js new file mode 100644 index 0000000..8fb4d23 --- /dev/null +++ b/server/src/utils/woocommerceCommands.js @@ -0,0 +1,40 @@ +export const createProductCommand = (podName,namespace,productData) => { + const cmd = `kubectl exec ${podName} -n ${namespace} -- wp wc product create --name="${productData.name}" --regular_price="${productData.price}" --user=1 --allow-root`; + return cmd; +} + +export const getAllProductCommand = (podName,namespace) => { + const field = ['id', 'name', 'status', 'price', 'regular_price', 'permalink'].join(','); + const cmd = `kubectl exec ${podName} -n ${namespace} -- wp wc product list --user=1 --fields=${field} --format=json --allow-root`; + return cmd +} + +export const getPodsCommand = (namespace) => { + return `kubectl get pods -n ${namespace} -l app=${namespace} -o json`; +} + +export const getEnableCODCommand = (podName, namespace) => { + return `kubectl exec ${podName} -n ${namespace} -- wp wc payment_gateway update cod --enabled=true --user=1 --allow-root`; +}; + +export const getEnabledPaymentMethodsCommand = (podName, namespace) => { + return `kubectl exec ${podName} -n ${namespace} -- wp wc payment_gateway list --user=1 --fields=id,enabled --format=json --allow-root`; +} + +export const createCouponCommand = (podName,namespace,code,amount,type) => { + const cmd = `kubectl exec ${podName} -n ${namespace} -- wp wc shop_coupon create --code="${code}" --amount="${amount}" --discount_type="${type}" --user=1 --allow-root`; + return cmd; +} + +export const getAllCouponsCommand = (podName,namespace) => { + return `kubectl exec ${podName} -n ${namespace} -- wp wc shop_coupon list --user=1 --fields=id,code,amount,discount_type --format=json --allow-root`; +} + +export const getCouponDeletionCommand = (podName,namespace,couponId) => { + return `kubectl exec ${podName} -n ${namespace} -- wp wc shop_coupon delete ${couponId} --force=true --user=1 --allow-root`; +} + +export const getAllOrdersCommand = (podName,namespace) => { + const cmd = `kubectl exec ${podName} -n ${namespace} -- wp wc shop_order list --user=1 --fields=id,status,total,customer_id --format=json --allow-root`; + return cmd; +} \ No newline at end of file From 4e1c2ed697c32f91c7dbf9dff6a9180e9a4802b2 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 11:23:59 +0530 Subject: [PATCH 06/22] fix - increase memory limit --- server/src/charts/woocommerce/values-local.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/src/charts/woocommerce/values-local.yaml b/server/src/charts/woocommerce/values-local.yaml index 83077d9..af0efeb 100644 --- a/server/src/charts/woocommerce/values-local.yaml +++ b/server/src/charts/woocommerce/values-local.yaml @@ -26,10 +26,10 @@ wordpressUsername: "admin" wordpressPassword: "password123" wordpressEmail: "admin@example.com" -resources: - limits: - cpu: 500m - memory: 512Mi +resources: requests: - cpu: 200m - memory: 256Mi \ No newline at end of file + cpu: "300m" + memory: "512Mi" + limits: + cpu: "1000m" + memory: "1Gi" \ No newline at end of file From 0494f44fa0ac2a8979e4cebbc9f70fd8d64d1a8e Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 12:15:44 +0530 Subject: [PATCH 07/22] feat - added more info in ai replies --- server/src/controllers/ai.controller.js | 7 +-- server/src/utils/woocommerceAITools.js | 67 +++++++++++++++++++------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/server/src/controllers/ai.controller.js b/server/src/controllers/ai.controller.js index 901d20b..2931924 100644 --- a/server/src/controllers/ai.controller.js +++ b/server/src/controllers/ai.controller.js @@ -32,7 +32,6 @@ export const processAIChat = async (req, res) => { let isToolExecuted = false; let executedToolName = null; - // 1. Agar AI ne kisi Tool ko call kiya hai if (aiMsg.tool_calls && aiMsg.tool_calls.length > 0) { const toolCall = aiMsg.tool_calls[0]; const fnName = toolCall.function.name; @@ -42,7 +41,6 @@ export const processAIChat = async (req, res) => { if (action) { actionData = await action.execute(namespace, args); - // Dynamic reply direct tere Action Map se aayega finalReply = action.getReply(actionData, args); executedToolName = fnName; isToolExecuted = true; @@ -50,11 +48,9 @@ export const processAIChat = async (req, res) => { finalReply = "Sorry bhai, ye function abhi main seekh raha hoon."; } } else { - // 2. Agar koi tool call nahi hua (Normal Chat) finalReply = aiMsg.content || "Done bhai! Batao aur kya karna hai?"; } - // 3. Database mein Chat Save karo await Chat.findOneAndUpdate( { storeId }, { @@ -70,7 +66,6 @@ export const processAIChat = async (req, res) => { { upsert: true, new: true } ); - // 4. Single Unified Return (Frontend ke liye ekdum mast format) return res.json({ success: true, reply: finalReply, @@ -120,7 +115,7 @@ export const getAISuggestedTasks = async (req, res) => { } return res.json({ success: true, - data: activeSuggestions.slice(0, 4) + data: activeSuggestions }); } catch (error) { diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index e18c2eb..3544530 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -88,60 +88,85 @@ export const woocommerceAITools = [ } ]; - export const aiActionMap = { getStoreAudit: { execute: async (ns) => await woo.getStoreAudit(ns), - getReply: (result) => "Store ki report ready hai. Sab badhiya chal raha hai! ๐Ÿ“Š" + getReply: (result) => { + const summary = result?.audit?.summary || {}; + const products = summary.totalProducts || 0; + const orders = summary.totalOrders || 0; + const coupons = summary.totalCoupons || 0; + const codStatus = summary.isCodEnabled ? "enabled โœ…" : "disabled โŒ"; + + return `Here is your store audit: You currently have ${products} products, ${orders} orders, and ${coupons} active coupons. Cash on Delivery is currently ${codStatus}. Let me know what you'd like to manage next! ๐Ÿ“Š`; + } }, enableCODPayment: { execute: async (ns) => await woo.enableCODPayment(ns), - getReply: () => "Bhai, Cash on Delivery (COD) enable kar diya hai! ๐Ÿ’ณ" + getReply: () => "Cash on Delivery (COD) has been successfully enabled! Your customers can now select this payment method during checkout. ๐Ÿ’ณ" }, checkPaymentStatus: { execute: async (ns) => await woo.checkPaymentStatus(ns), - getReply: (result) => result.isCODEnabled ? "COD active hai bhai! โœ…" : "Abhi COD band hai." + getReply: (result) => result.isCODEnabled + ? "Payment status check complete. Cash on Delivery (COD) is currently active and available for your customers. โœ…" + : "Payment status check complete. Cash on Delivery (COD) is currently disabled. Would you like me to enable it for you?" }, addProductAndGetLink: { execute: async (ns, args) => await woo.addProductAndGetLink(ns, args), - // Dynamic reply using args - getReply: (result, args) => `Bhai, naya product '${args.name}' add kar diya hai! ๐Ÿš€ Preview refresh ho raha hai...` + getReply: (result, args) => `Success! I've added '${args.name}' to your catalog priced at ${args.price}. You can view the live product here: ${result?.link || 'your store'}. The preview on the right is refreshing now! ๐Ÿš€` }, createCoupon: { execute: async (ns, args) => await woo.createCoupon(ns, args), - getReply: (result, args) => `Done! '${args.code}' coupon active ho gaya hai ${args.amount} discount ke sath. ๐ŸŽŸ๏ธ` + getReply: (result, args) => { + const discountSymbol = args.type === 'percent' ? '%' : ' flat'; + return `Your promo code is ready! Customers can now use the code '${args.code.toUpperCase()}' at checkout to get a ${args.amount}${discountSymbol} discount. ๐ŸŽŸ๏ธ`; + } }, getAllCoupons: { execute: async (ns) => await woo.getAllCoupons(ns), - getReply: (result) => `Total ${result.count} coupons mile hain bhai. ๐ŸŽซ` + getReply: (result) => { + if (!result?.count || result.count === 0) { + return "You currently don't have any active coupons in your store. Let me know if you want me to create a new one! ๐ŸŽซ"; + } + + const couponDetails = result.data.map((coupon, index) => { + const discountSymbol = coupon.discount_type === 'percent' ? '%' : ' flat'; + return `${index + 1}. Code: ${coupon.code.toUpperCase()} | ID: ${coupon.id} | Discount: ${coupon.amount}${discountSymbol}`; + }).join("\n"); + + return `I found ${result.count} active coupons in your store:\n\n${couponDetails}\n\nIf you need to remove any old ones, just tell me the Coupon ID and I'll delete it for you! ๐Ÿ—‘๏ธ`; + } }, deleteStoreCoupon: { execute: async (ns, args) => await woo.deleteStoreCoupon(ns, args.couponId), - getReply: (result, args) => `Coupon ID ${args.couponId} delete kar diya permanently! ๐Ÿ—‘๏ธ` + getReply: (result, args) => `The coupon with ID ${args.couponId} has been permanently deleted from your store. It can no longer be used by customers. ๐Ÿ—‘๏ธ` }, getAllOrders: { execute: async (ns) => await woo.getAllOrders(ns), - getReply: (result) => `Aapke paas total ${result.count} orders hain abhi. ๐Ÿ“ฆ` + getReply: (result) => `You currently have a total of ${result.count} orders placed in your store. Let me know if you need to review specific order details! ๐Ÿ“ฆ` } }; -export const SUGGESTION_RULES = [ - { +export const SUGGESTION_RULES = [ { condition: (summary) => !summary.isCodEnabled, data: { title: "๐Ÿ’ณ Enable COD", prompt: "Bhai, store pe Cash on Delivery (COD) chalu kar de." } }, - { + { condition: (summary) => summary.totalProducts === 0, data: { title: "๐Ÿ“ฆ Add First Product", prompt: "Ek 'Premium T-Shirt' add kar do 499 rupees mein." } }, + { + condition: (summary) => summary.totalProducts > 0, + data: { title: "โž• Add Another Product", prompt: "Ek naya 'Smart Watch' add kar do 1999 rupees mein." } + }, { condition: (summary) => summary.totalProducts > 0 && summary.totalOrders === 0, data: { title: "๐Ÿ‘€ Wait for Orders", prompt: "Bhai, kya mere products live hain? Koi order nahi aaya abhi tak." } @@ -155,7 +180,19 @@ export const SUGGESTION_RULES = [ data: { title: "๐ŸŽŸ๏ธ Create Coupon", prompt: "Naye customers ke liye 'WELCOME50' coupon bana do 50% discount ke sath." } }, { - condition: () => true, // Ye hamesha true rahega (Default fallback) + condition: (summary) => summary.totalCoupons > 0, + data: { title: "๐ŸŽซ View Coupons", prompt: "Mere store ke saare active coupons dikhao." } + }, + { + condition: (summary) => summary.totalCoupons > 0, + data: { title: "๐Ÿ—‘๏ธ Manage Coupons", prompt: "Mujhe ek purana coupon delete karna hai, pehle saare coupons list karo." } + }, + { + condition: (summary) => summary.isCodEnabled, + data: { title: "โœ… Check Payments", prompt: "Verify karo ki mere store pe payment methods kaunse active hain." } + }, + { + condition: () => true, data: { title: "๐Ÿค– Store Audit", prompt: "Store ki poori report do, kya-kya active hai abhi?" } } -]; +]; \ No newline at end of file From e7213c58d85f9f4f3e5d89cfd4d8e3b5bc34b1a9 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 13:40:47 +0530 Subject: [PATCH 08/22] feat - added product link feature in chat --- client/src/app/customize/Customize.js | 71 +++++++++++++++---------- server/src/controllers/ai.controller.js | 15 ++++-- server/src/models/chat.model.js | 4 ++ server/src/utils/helper.js | 16 +++++- server/src/utils/woocommerceAITools.js | 13 ++++- 5 files changed, 86 insertions(+), 33 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 4c7dbc3..2688e12 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -85,6 +85,7 @@ export default function Customize() { id: msg._id || String(Date.now() + idx), role: msg.role === "assistant" ? "bot" : "user", content: msg.content, + meta : msg.meta, timestamp: new Date(msg.timestamp || Date.now()), })); @@ -250,40 +251,54 @@ export default function Customize() { ref={scrollRef} className="flex-1 overflow-y-auto px-4 py-4 space-y-4 hide-scrollbar" > - {messages.map((msg) => ( + {messages.map((msg) => ( +
+ {/* Avatar */}
-
- {msg.role === "bot" ? ( - - ) : ( - - )} -
+ {msg.role === "bot" ? ( + + ) : ( + + )} +
-
- {msg.content} -
+ {/* Message Bubble */} +
+ {/* Text Content */} +

{msg.content}

+ + {msg.meta?.link && ( + + {msg.meta.linkLabel || "View"} + + )}
+
))} {isTyping && ( diff --git a/server/src/controllers/ai.controller.js b/server/src/controllers/ai.controller.js index 2931924..86c1c19 100644 --- a/server/src/controllers/ai.controller.js +++ b/server/src/controllers/ai.controller.js @@ -27,7 +27,8 @@ export const processAIChat = async (req, res) => { const aiMsg = await getOpenAIResponse(message); // Default states - let finalReply = ""; + let finalReply = ""; + let structuredReply = null; let actionData = null; let isToolExecuted = false; let executedToolName = null; @@ -41,7 +42,14 @@ export const processAIChat = async (req, res) => { if (action) { actionData = await action.execute(namespace, args); - finalReply = action.getReply(actionData, args); + const reply = action.getReply(actionData, args, store); + if (typeof reply === "string") { + finalReply = reply; + } else { + finalReply = reply.message; + structuredReply = reply; + } + executedToolName = fnName; isToolExecuted = true; } else { @@ -58,7 +66,7 @@ export const processAIChat = async (req, res) => { messages: { $each: [ { role: 'user', content: message }, - { role: 'assistant', content: finalReply } + { role: 'assistant', content: finalReply, meta : structuredReply } ] } } @@ -69,6 +77,7 @@ export const processAIChat = async (req, res) => { return res.json({ success: true, reply: finalReply, + structured: structuredReply, data: actionData, toolExecuted: isToolExecuted, toolName: executedToolName diff --git a/server/src/models/chat.model.js b/server/src/models/chat.model.js index 426d6ff..af34ae3 100644 --- a/server/src/models/chat.model.js +++ b/server/src/models/chat.model.js @@ -10,6 +10,10 @@ const messageSchema = new mongoose.Schema({ type: String, required: true }, + meta: { + link: String, + linkLabel: String + }, timestamp: { type: Date, default: Date.now diff --git a/server/src/utils/helper.js b/server/src/utils/helper.js index 13ab063..ea16a6f 100644 --- a/server/src/utils/helper.js +++ b/server/src/utils/helper.js @@ -15,4 +15,18 @@ export const getStoreAdminUrl = (storeType, slug) => { } return `${PROTOCOL}${slug}.${BASE_DOMAIN}/wp-admin` -} \ No newline at end of file +} + +export const extractProductPath = (url) => { + try { + const parsed = new URL(url); + let pathname = parsed.pathname; + if (pathname.endsWith('/')) { + pathname = pathname.slice(0, -1); + } + + return pathname; + } catch (err) { + return null; + } +}; \ No newline at end of file diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index 3544530..10d645a 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -1,4 +1,5 @@ import * as woo from "../services/woocommerceServices.js"; +import { extractProductPath } from "./helper.js"; export const woocommerceAITools = [ { @@ -116,7 +117,17 @@ export const aiActionMap = { addProductAndGetLink: { execute: async (ns, args) => await woo.addProductAndGetLink(ns, args), - getReply: (result, args) => `Success! I've added '${args.name}' to your catalog priced at ${args.price}. You can view the live product here: ${result?.link || 'your store'}. The preview on the right is refreshing now! ๐Ÿš€` + + getReply: (result, args, store) => { + const productPath = extractProductPath(result?.link); + const fullUrl = `${store.storeUrl}${productPath}`; + + return { + message: `Success! I've added '${args.name}' priced at โ‚น${args.price}.`, + link: fullUrl, + linkLabel: "๐Ÿ”— View Live Product" + }; + } }, createCoupon: { From d09175e33336d0a969e6831dbaf3000adeeccc8f Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 13:47:36 +0530 Subject: [PATCH 09/22] fix- added preview product in inframe --- client/src/app/customize/Customize.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 2688e12..11f4d1c 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -288,14 +288,16 @@ export default function Customize() {

{msg.content}

{msg.meta?.link && ( - { + const normalized = normalizeUrl(msg.meta.link); + setStoreUrl(normalized); + setIframeKey((k) => k + 1); + }} className="inline-block text-xs font-medium px-3 py-1.5 rounded-lg bg-black text-white hover:bg-gray-800 transition" > {msg.meta.linkLabel || "View"} - + )}
From f4161f6461a735eb415d42296d6b9ae7b831aac6 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 14:14:01 +0530 Subject: [PATCH 10/22] fix - iframe loader position --- client/src/app/customize/Customize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 11f4d1c..abe29fd 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -423,7 +423,7 @@ export default function Customize() { {/* Animated Preview */}
Date: Wed, 4 Mar 2026 14:43:00 +0530 Subject: [PATCH 11/22] FIX - IFRAME PERmission issue --- server/src/charts/woocommerce/templates/ingress.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/server/src/charts/woocommerce/templates/ingress.yaml b/server/src/charts/woocommerce/templates/ingress.yaml index e3c17b6..f699fc0 100644 --- a/server/src/charts/woocommerce/templates/ingress.yaml +++ b/server/src/charts/woocommerce/templates/ingress.yaml @@ -4,6 +4,12 @@ metadata: name: {{ .Release.Name }} annotations: nginx.ingress.kubernetes.io/rewrite-target: / + + nginx.ingress.kubernetes.io/configuration-snippet: | + more_clear_headers "Content-Security-Policy"; + more_clear_headers "X-Frame-Options"; + add_header Content-Security-Policy "frame-ancestors *;" always; + # SSL toggle (if needed later) {{- if .Values.ingress.customDomain }} cert-manager.io/cluster-issuer: "letsencrypt-prod" From 2b9b01bff4e379c3006c06537a5eade32114d8ea Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:00:40 +0530 Subject: [PATCH 12/22] fix - admin url --- client/src/app/customize/Customize.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index abe29fd..2ab000a 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -51,7 +51,7 @@ export default function Customize() { const storeId = searchParams.get("storeId"); const [storeUrl, setStoreUrl] = useState( - searchParams.get("url") || "" + normalizeUrl(searchParams.get("url") || "") ); const [messages, setMessages] = useState(INITIAL_MESSAGES); @@ -136,6 +136,9 @@ export default function Customize() { if (!/^https?:\/\//i.test(url)) { return "https://" + url; } + if (finalUrl.match(/\/wp-admin$/i)) { + finalUrl += "/"; + } return url; }; From c40901ac3795ac948329c1878531da88cd354149 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:08:23 +0530 Subject: [PATCH 13/22] feat - added link to admin page for concerned action --- server/src/utils/woocommerceAITools.js | 74 +++++++++++++++++++++----- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index 10d645a..dd14314 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -89,30 +89,54 @@ export const woocommerceAITools = [ } ]; +const getAdminLink = (store, path = "") => { + + const baseAdminUrl = store.adminUrl.replace(/\/$/, ""); + return path ? `${baseAdminUrl}/${path}` : `${baseAdminUrl}/`; +}; + export const aiActionMap = { getStoreAudit: { execute: async (ns) => await woo.getStoreAudit(ns), - getReply: (result) => { + getReply: (result, args, store) => { const summary = result?.audit?.summary || {}; const products = summary.totalProducts || 0; const orders = summary.totalOrders || 0; const coupons = summary.totalCoupons || 0; const codStatus = summary.isCodEnabled ? "enabled โœ…" : "disabled โŒ"; - return `Here is your store audit: You currently have ${products} products, ${orders} orders, and ${coupons} active coupons. Cash on Delivery is currently ${codStatus}. Let me know what you'd like to manage next! ๐Ÿ“Š`; + return { + message: `Here is your store audit: You currently have ${products} products, ${orders} orders, and ${coupons} active coupons. Cash on Delivery is currently ${codStatus}. Let me know what you'd like to manage next! ๐Ÿ“Š`, + link: store.adminUrl, // Seedha Dashboard khulega + linkLabel: "๐Ÿ“Š Open Dashboard" + }; } }, enableCODPayment: { execute: async (ns) => await woo.enableCODPayment(ns), - getReply: () => "Cash on Delivery (COD) has been successfully enabled! Your customers can now select this payment method during checkout. ๐Ÿ’ณ" + getReply: (result, args, store) => { + return { + message: "Cash on Delivery (COD) has been successfully enabled! Your customers can now select this payment method during checkout. ๐Ÿ’ณ", + link: getAdminLink(store, "admin.php?page=wc-settings&tab=checkout"), + linkLabel: "๐Ÿ’ณ View Payment Settings" + }; + } }, checkPaymentStatus: { execute: async (ns) => await woo.checkPaymentStatus(ns), - getReply: (result) => result.isCODEnabled - ? "Payment status check complete. Cash on Delivery (COD) is currently active and available for your customers. โœ…" - : "Payment status check complete. Cash on Delivery (COD) is currently disabled. Would you like me to enable it for you?" + getReply: (result, args, store) => { + const msg = result.isCODEnabled + ? "Payment status check complete. Cash on Delivery (COD) is currently active and available for your customers. โœ…" + : "Payment status check complete. Cash on Delivery (COD) is currently disabled. Would you like me to enable it for you?"; + + return { + message: msg, + link: getAdminLink(store, "admin.php?page=wc-settings&tab=checkout"), + linkLabel: "โš™๏ธ Check Settings" + }; + } }, addProductAndGetLink: { @@ -132,17 +156,25 @@ export const aiActionMap = { createCoupon: { execute: async (ns, args) => await woo.createCoupon(ns, args), - getReply: (result, args) => { + getReply: (result, args, store) => { const discountSymbol = args.type === 'percent' ? '%' : ' flat'; - return `Your promo code is ready! Customers can now use the code '${args.code.toUpperCase()}' at checkout to get a ${args.amount}${discountSymbol} discount. ๐ŸŽŸ๏ธ`; + return { + message: `Your promo code is ready! Customers can now use the code '${args.code.toUpperCase()}' at checkout to get a ${args.amount}${discountSymbol} discount. ๐ŸŽŸ๏ธ`, + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "๐ŸŽซ View Coupons" + }; } }, getAllCoupons: { execute: async (ns) => await woo.getAllCoupons(ns), - getReply: (result) => { + getReply: (result, args, store) => { if (!result?.count || result.count === 0) { - return "You currently don't have any active coupons in your store. Let me know if you want me to create a new one! ๐ŸŽซ"; + return { + message: "You currently don't have any active coupons in your store. Let me know if you want me to create a new one! ๐ŸŽซ", + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "โž• Create Coupon" + }; } const couponDetails = result.data.map((coupon, index) => { @@ -150,18 +182,34 @@ export const aiActionMap = { return `${index + 1}. Code: ${coupon.code.toUpperCase()} | ID: ${coupon.id} | Discount: ${coupon.amount}${discountSymbol}`; }).join("\n"); - return `I found ${result.count} active coupons in your store:\n\n${couponDetails}\n\nIf you need to remove any old ones, just tell me the Coupon ID and I'll delete it for you! ๐Ÿ—‘๏ธ`; + return { + message: `I found ${result.count} active coupons in your store:\n\n${couponDetails}\n\nIf you need to remove any old ones, just tell me the Coupon ID and I'll delete it for you! ๐Ÿ—‘๏ธ`, + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "๐Ÿ› ๏ธ Manage Coupons" + }; } }, deleteStoreCoupon: { execute: async (ns, args) => await woo.deleteStoreCoupon(ns, args.couponId), - getReply: (result, args) => `The coupon with ID ${args.couponId} has been permanently deleted from your store. It can no longer be used by customers. ๐Ÿ—‘๏ธ` + getReply: (result, args, store) => { + return { + message: `The coupon with ID ${args.couponId} has been permanently deleted from your store. It can no longer be used by customers. ๐Ÿ—‘๏ธ`, + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "๐ŸŽซ View Remaining Coupons" + }; + } }, getAllOrders: { execute: async (ns) => await woo.getAllOrders(ns), - getReply: (result) => `You currently have a total of ${result.count} orders placed in your store. Let me know if you need to review specific order details! ๐Ÿ“ฆ` + getReply: (result, args, store) => { + return { + message: `You currently have a total of ${result.count} orders placed in your store. Let me know if you need to review specific order details! ๐Ÿ“ฆ`, + link: getAdminLink(store, "edit.php?post_type=shop_order"), + linkLabel: "๐Ÿ“ฆ View Orders" + }; + } } }; From 44ab8b02be1c2e218195ec3ed3d4e348c7017cc1 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:11:12 +0530 Subject: [PATCH 14/22] fix - issue fn usage before intialisation --- client/src/app/customize/Customize.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 2ab000a..31bc246 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -33,6 +33,16 @@ const INITIAL_MESSAGES = [ }, ]; + const normalizeUrl = (url) => { + if (!url) return ""; + if (!/^https?:\/\//i.test(url)) { + return "https://" + url; + } + if (finalUrl.match(/\/wp-admin$/i)) { + finalUrl += "/"; + } + return url; + }; const DEVICE_ORDER = ["desktop", "tablet", "mobile"]; const DEVICE_WIDTH = { @@ -131,16 +141,7 @@ export default function Customize() { /* ------------------ HELPERS ------------------ */ - const normalizeUrl = (url) => { - if (!url) return ""; - if (!/^https?:\/\//i.test(url)) { - return "https://" + url; - } - if (finalUrl.match(/\/wp-admin$/i)) { - finalUrl += "/"; - } - return url; - }; + const cycleDevice = () => { const next = From e9023ebc2d7024f7b74f9baadd62e477439a4d49 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:13:07 +0530 Subject: [PATCH 15/22] fix - typo --- client/src/app/customize/Customize.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 31bc246..69b1c47 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -35,12 +35,13 @@ const INITIAL_MESSAGES = [ const normalizeUrl = (url) => { if (!url) return ""; + if (url.match(/\/wp-admin$/i)) { + url += "/"; + } if (!/^https?:\/\//i.test(url)) { return "https://" + url; } - if (finalUrl.match(/\/wp-admin$/i)) { - finalUrl += "/"; - } + return url; }; const DEVICE_ORDER = ["desktop", "tablet", "mobile"]; From 57c87cd077662412cedbeb753419c8c9460ed4f8 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:23:53 +0530 Subject: [PATCH 16/22] feat - change iframe on tool calling with that url --- client/src/app/customize/Customize.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index 69b1c47..f3ccc62 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -176,7 +176,7 @@ export default function Customize() { { message: userText, storeId }, token ); - +console.log(json); if (json.success) { setMessages((prev) => [ @@ -184,7 +184,8 @@ export default function Customize() { { id: String(Date.now() + 1), role: "bot", - content: json.reply, + content: json.structured?.message, + meta : {...json?.structured } , timestamp: new Date(), }, ]); @@ -192,6 +193,7 @@ export default function Customize() { if (json.toolExecuted) { console.log(`[Action Triggered]: ${json.toolName} - Refreshing store preview...`); setIframeKey((prevKey) => prevKey + 1); + setStoreUrl(json?.structured?.link) } } else { From f107f9cb380025e3ad49eb7bc224e8c207d535dd Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:51:35 +0530 Subject: [PATCH 17/22] fix - change architecture of adding product and coupon --- server/src/utils/woocommerceAITools.js | 108 +++++++++---------------- 1 file changed, 37 insertions(+), 71 deletions(-) diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index dd14314..bd89fbd 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -1,5 +1,4 @@ import * as woo from "../services/woocommerceServices.js"; -import { extractProductPath } from "./helper.js"; export const woocommerceAITools = [ { @@ -29,32 +28,17 @@ export const woocommerceAITools = [ { type: "function", function: { - name: "addProductAndGetLink", - description: "Add a new product to the store and get its live URL.", - parameters: { - type: "object", - properties: { - name: { type: "string", description: "Name of the product" }, - price: { type: "string", description: "Regular price of the product" } - }, - required: ["name", "price"] - } + name: "guideToAddProduct", + description: "Guide the user to the product creation page. Call this when the user wants to add, list, or create a new product.", + parameters: { type: "object", properties: {} } } }, { type: "function", function: { - name: "createCoupon", - description: "Create a discount coupon in the store.", - parameters: { - type: "object", - properties: { - code: { type: "string", description: "Coupon code, e.g., SAVE50" }, - amount: { type: "string", description: "Discount value" }, - type: { type: "string", enum: ["percent", "fixed_cart"], description: "Type of discount" } - }, - required: ["code", "amount"] - } + name: "guideToCreateCoupon", + description: "Guide the user to the coupon management page. Call this when the user wants to create, add, or manage a discount coupon.", + parameters: { type: "object", properties: {} } } }, { @@ -138,34 +122,6 @@ export const aiActionMap = { }; } }, - - addProductAndGetLink: { - execute: async (ns, args) => await woo.addProductAndGetLink(ns, args), - - getReply: (result, args, store) => { - const productPath = extractProductPath(result?.link); - const fullUrl = `${store.storeUrl}${productPath}`; - - return { - message: `Success! I've added '${args.name}' priced at โ‚น${args.price}.`, - link: fullUrl, - linkLabel: "๐Ÿ”— View Live Product" - }; - } - }, - - createCoupon: { - execute: async (ns, args) => await woo.createCoupon(ns, args), - getReply: (result, args, store) => { - const discountSymbol = args.type === 'percent' ? '%' : ' flat'; - return { - message: `Your promo code is ready! Customers can now use the code '${args.code.toUpperCase()}' at checkout to get a ${args.amount}${discountSymbol} discount. ๐ŸŽŸ๏ธ`, - link: getAdminLink(store, "edit.php?post_type=shop_coupon"), - linkLabel: "๐ŸŽซ View Coupons" - }; - } - }, - getAllCoupons: { execute: async (ns) => await woo.getAllCoupons(ns), getReply: (result, args, store) => { @@ -210,45 +166,55 @@ export const aiActionMap = { linkLabel: "๐Ÿ“ฆ View Orders" }; } + }, + guideToAddProduct: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => { + return { + message: "Adding a new product is super easy! Click the button below, enter your product name, price, upload an image, and hit 'Publish'. ๐Ÿ“ฆ", + link: getAdminLink(store, "post-new.php?post_type=product"), + linkLabel: "โž• Add New Product" + }; + } + }, + + guideToCreateCoupon: { + execute: async () => ({ success: true }), // NO BACKEND CALL + getReply: (result, args, store) => { + return { + message: "To create a discount code, click the button below. Click 'Add coupon', type your custom code (e.g., FESTIVAL50), set the discount amount, and hit Publish! ๐ŸŽŸ๏ธ", + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "๐ŸŽซ Create/Manage Coupons" + }; + } } }; -export const SUGGESTION_RULES = [ { +export const SUGGESTION_RULES = [ + { condition: (summary) => !summary.isCodEnabled, - data: { title: "๐Ÿ’ณ Enable COD", prompt: "Bhai, store pe Cash on Delivery (COD) chalu kar de." } + data: { title: "๐Ÿ’ณ Enable COD", prompt: "Store pe Cash on Delivery (COD) chalu kar do." } }, - { + { condition: (summary) => summary.totalProducts === 0, - data: { title: "๐Ÿ“ฆ Add First Product", prompt: "Ek 'Premium T-Shirt' add kar do 499 rupees mein." } + data: { title: "๐Ÿ“ฆ Add First Product", prompt: "Bhai, mujhe naya product add karna hai, kahan se karu?" } }, { condition: (summary) => summary.totalProducts > 0, - data: { title: "โž• Add Another Product", prompt: "Ek naya 'Smart Watch' add kar do 1999 rupees mein." } - }, - { - condition: (summary) => summary.totalProducts > 0 && summary.totalOrders === 0, - data: { title: "๐Ÿ‘€ Wait for Orders", prompt: "Bhai, kya mere products live hain? Koi order nahi aaya abhi tak." } + data: { title: "โž• Add Another Product", prompt: "Mujhe ek aur naya product list karna hai store par." } }, { - condition: (summary) => summary.totalProducts > 0 && summary.totalOrders > 0, - data: { title: "๐Ÿ“ˆ Check Orders", prompt: "Dikhao abhi tak kitne orders aaye hain." } + condition: (summary) => summary.totalOrders === 0, + data: { title: "๐Ÿ‘€ Check Orders", prompt: "Bhai, kya mere store pe koi naya order aaya hai abhi tak?" } }, { condition: (summary) => summary.totalCoupons === 0, - data: { title: "๐ŸŽŸ๏ธ Create Coupon", prompt: "Naye customers ke liye 'WELCOME50' coupon bana do 50% discount ke sath." } - }, - { - condition: (summary) => summary.totalCoupons > 0, - data: { title: "๐ŸŽซ View Coupons", prompt: "Mere store ke saare active coupons dikhao." } + data: { title: "๐ŸŽŸ๏ธ Create Coupon", prompt: "Customers ke liye discount coupon banana hai, guide karo." } }, { condition: (summary) => summary.totalCoupons > 0, - data: { title: "๐Ÿ—‘๏ธ Manage Coupons", prompt: "Mujhe ek purana coupon delete karna hai, pehle saare coupons list karo." } - }, - { - condition: (summary) => summary.isCodEnabled, - data: { title: "โœ… Check Payments", prompt: "Verify karo ki mere store pe payment methods kaunse active hain." } + data: { title: "๐ŸŽซ Manage Coupons", prompt: "Mere store ke saare active coupons dikhao." } }, { condition: () => true, From aa52f5d545702e0bcbc4bbf31491d07e8088c4b5 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 15:57:32 +0530 Subject: [PATCH 18/22] fix - remove logs --- client/src/app/customize/Customize.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index f3ccc62..d384a9a 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -176,7 +176,6 @@ export default function Customize() { { message: userText, storeId }, token ); -console.log(json); if (json.success) { setMessages((prev) => [ @@ -193,7 +192,7 @@ console.log(json); if (json.toolExecuted) { console.log(`[Action Triggered]: ${json.toolName} - Refreshing store preview...`); setIframeKey((prevKey) => prevKey + 1); - setStoreUrl(json?.structured?.link) + setStoreUrl(normalizeUrl(json?.structured?.link)); } } else { From e34642be0cd3c728e98fec2b1942c773acdbbc0a Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 16:05:50 +0530 Subject: [PATCH 19/22] feat - added new tools --- server/src/utils/woocommerceAITools.js | 123 +++++++++++++++++++++---- 1 file changed, 105 insertions(+), 18 deletions(-) diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index bd89fbd..ffe5730 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -33,6 +33,14 @@ export const woocommerceAITools = [ parameters: { type: "object", properties: {} } } }, + { + type: "function", + function: { + name: "guideToAllProducts", + description: "Guide the user to the products list page. Call this when they want to edit, delete, or manage existing products.", + parameters: { type: "object", properties: {} } + } + }, { type: "function", function: { @@ -70,6 +78,38 @@ export const woocommerceAITools = [ description: "Get a list of all customer orders in the store.", parameters: { type: "object", properties: {} } } + }, + { + type: "function", + function: { + name: "guideToThemeCustomization", + description: "Guide the user to customize their store's appearance, theme, logo, or colors.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToShippingSettings", + description: "Guide the user to set up shipping zones, delivery charges, or free shipping.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToPaymentGateways", + description: "Guide the user to set up online payment gateways like Stripe, PayPal, or Razorpay.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToAnalytics", + description: "Guide the user to the store analytics/reports page to check sales and revenue.", + parameters: { type: "object", properties: {} } + } } ]; @@ -91,7 +131,7 @@ export const aiActionMap = { return { message: `Here is your store audit: You currently have ${products} products, ${orders} orders, and ${coupons} active coupons. Cash on Delivery is currently ${codStatus}. Let me know what you'd like to manage next! ๐Ÿ“Š`, - link: store.adminUrl, // Seedha Dashboard khulega + link: getAdminLink(store, ""), linkLabel: "๐Ÿ“Š Open Dashboard" }; } @@ -169,28 +209,67 @@ export const aiActionMap = { }, guideToAddProduct: { execute: async () => ({ success: true }), - getReply: (result, args, store) => { - return { - message: "Adding a new product is super easy! Click the button below, enter your product name, price, upload an image, and hit 'Publish'. ๐Ÿ“ฆ", - link: getAdminLink(store, "post-new.php?post_type=product"), - linkLabel: "โž• Add New Product" - }; - } + getReply: (result, args, store) => ({ + message: "Adding a new product is super easy! Click the button below, enter your product name, price, upload an image, and hit 'Publish'. ๐Ÿ“ฆ", + link: getAdminLink(store, "post-new.php?post_type=product"), + linkLabel: "โž• Add New Product" + }) + }, + + guideToAllProducts: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "You can view, edit, or delete all your existing products from the Products dashboard. Click below to manage your inventory! ๐Ÿ“‹", + link: getAdminLink(store, "edit.php?post_type=product"), + linkLabel: "๐Ÿ“‹ Manage Products" + }) }, guideToCreateCoupon: { - execute: async () => ({ success: true }), // NO BACKEND CALL - getReply: (result, args, store) => { - return { - message: "To create a discount code, click the button below. Click 'Add coupon', type your custom code (e.g., FESTIVAL50), set the discount amount, and hit Publish! ๐ŸŽŸ๏ธ", - link: getAdminLink(store, "edit.php?post_type=shop_coupon"), - linkLabel: "๐ŸŽซ Create/Manage Coupons" - }; - } + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "To create a discount code, click the button below. Click 'Add coupon', type your custom code (e.g., FESTIVAL50), set the discount amount, and hit Publish! ๐ŸŽŸ๏ธ", + link: getAdminLink(store, "edit.php?post_type=shop_coupon"), + linkLabel: "๐ŸŽซ Create/Manage Coupons" + }) + }, + guideToThemeCustomization: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Want to change how your store looks? You can update your logo, colors, and layout right from the Theme Customizer. Click below to start designing! ๐ŸŽจ", + link: getAdminLink(store, "customize.php"), + linkLabel: "๐ŸŽจ Customize Appearance" + }) + }, + + guideToShippingSettings: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Setting up delivery charges is important! Click below to go to Shipping Settings. From there, you can add 'Shipping Zones' and set up flat rates or free delivery. ๐Ÿšš", + link: getAdminLink(store, "admin.php?page=wc-settings&tab=shipping"), + linkLabel: "๐Ÿšš Shipping Settings" + }) + }, + + guideToPaymentGateways: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Want to accept online payments? Go to the Payments tab below. You can enable default options or add plugins for Stripe, PayPal, or Razorpay! ๐Ÿ’ณ", + link: getAdminLink(store, "admin.php?page=wc-settings&tab=checkout"), + linkLabel: "๐Ÿ’ณ Setup Online Payments" + }) + }, + + guideToAnalytics: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Let's check your store's performance! You can see your total sales, top products, and revenue directly in the WooCommerce Analytics dashboard. ๐Ÿ“ˆ", + link: getAdminLink(store, "admin.php?page=wc-admin&path=/analytics/overview"), + linkLabel: "๐Ÿ“ˆ View Analytics" + }) } }; - export const SUGGESTION_RULES = [ { condition: (summary) => !summary.isCodEnabled, @@ -218,6 +297,14 @@ export const SUGGESTION_RULES = [ }, { condition: () => true, - data: { title: "๐Ÿค– Store Audit", prompt: "Store ki poori report do, kya-kya active hai abhi?" } + data: { title: "๐ŸŽจ Change Store Look", prompt: "Mujhe store ka logo aur colors change karne hain." } + }, + { + condition: () => true, + data: { title: "๐Ÿšš Setup Shipping", prompt: "Delivery charges aur shipping kaise set karu?" } + }, + { + condition: (summary) => summary.totalOrders > 0, + data: { title: "๐Ÿ“ˆ View Sales", prompt: "Mere store ki total sales aur analytics dikhao." } } ]; \ No newline at end of file From 2d6b047ae4cef5e965d49cd6fe30f9d81856e591 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 16:12:31 +0530 Subject: [PATCH 20/22] feat - added more tools --- server/src/utils/woocommerceAITools.js | 76 ++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index ffe5730..6761bd1 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -110,6 +110,38 @@ export const woocommerceAITools = [ description: "Guide the user to the store analytics/reports page to check sales and revenue.", parameters: { type: "object", properties: {} } } + }, + { + type: "function", + function: { + name: "guideToUserManagement", + description: "Guide the user to manage staff, customers, or profile settings.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToPlugins", + description: "Guide the user to install new features, plugins, or manage existing ones.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToGeneralSettings", + description: "Guide the user to change store name, tagline, timezone, or email settings.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToSEO", + description: "Guide the user to SEO settings, permalinks, or site visibility.", + parameters: { type: "object", properties: {} } + } } ]; @@ -267,7 +299,43 @@ export const aiActionMap = { link: getAdminLink(store, "admin.php?page=wc-admin&path=/analytics/overview"), linkLabel: "๐Ÿ“ˆ View Analytics" }) + }, + guideToUserManagement: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Aap apne customers aur staff members ko yahan se manage kar sakte hain. Naya user add karne ke liye 'Add New' pe click karein! ๐Ÿ‘ฅ", + link: getAdminLink(store, "users.php"), + linkLabel: "๐Ÿ‘ฅ Manage Users" + }) + }, + + guideToPlugins: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Store mein naye features (jaise WhatsApp chat, Invoice PDF) add karne ke liye plugins install karein. ๐Ÿ”Œ", + link: getAdminLink(store, "plugin-install.php"), + linkLabel: "๐Ÿ”Œ Add New Plugins" + }) + }, + + guideToGeneralSettings: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Store ka title, description ya contact email change karne ke liye General Settings mein jao. โš™๏ธ", + link: getAdminLink(store, "options-general.php"), + linkLabel: "โš™๏ธ General Settings" + }) + }, + + guideToSEO: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "SEO aur links (Permalinks) manage karne ke liye niche click karein. Isse aapki site Google search mein behtar dikhegi! ๐Ÿ”", + link: getAdminLink(store, "options-permalink.php"), + linkLabel: "๐Ÿ” SEO/Link Settings" + }) } + }; export const SUGGESTION_RULES = [ @@ -306,5 +374,13 @@ export const SUGGESTION_RULES = [ { condition: (summary) => summary.totalOrders > 0, data: { title: "๐Ÿ“ˆ View Sales", prompt: "Mere store ki total sales aur analytics dikhao." } + }, + { + condition: () => true, + data: { title: "๐Ÿ”Œ Add Features", prompt: "Mujhe store pe naye features/plugins add karne hain." } + }, + { + condition: () => true, + data: { title: "๐Ÿ‘ฅ Manage Staff", prompt: "Staff members ya users kaise manage karu?" } } ]; \ No newline at end of file From 0c15af3d9333184b840dff88119bea3708d6f07c Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 16:19:36 +0530 Subject: [PATCH 21/22] feat - added more tools --- server/src/utils/woocommerceAITools.js | 96 ++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/server/src/utils/woocommerceAITools.js b/server/src/utils/woocommerceAITools.js index 6761bd1..4989135 100644 --- a/server/src/utils/woocommerceAITools.js +++ b/server/src/utils/woocommerceAITools.js @@ -142,6 +142,46 @@ export const woocommerceAITools = [ description: "Guide the user to SEO settings, permalinks, or site visibility.", parameters: { type: "object", properties: {} } } + }, + { + type: "function", + function: { + name: "guideToInventory", + description: "Guide user to manage stock levels, out-of-stock products, and inventory settings.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToTaxSettings", + description: "Guide user to setup GST, VAT, or other tax calculations for their products.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToEmailTemplates", + description: "Guide user to customize the emails sent to customers (Order confirmation, invoices).", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToMediaLibrary", + description: "Guide user to manage uploaded images, logos, and product photos.", + parameters: { type: "object", properties: {} } + } + }, + { + type: "function", + function: { + name: "guideToSystemStatus", + description: "Guide user to check if the store has any technical errors or server issues.", + parameters: { type: "object", properties: {} } + } } ]; @@ -334,6 +374,50 @@ export const aiActionMap = { link: getAdminLink(store, "options-permalink.php"), linkLabel: "๐Ÿ” SEO/Link Settings" }) + }, + guideToInventory: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Stock manage karne ke liye inventory page pe jao. Yahan aap check kar sakte ho kaunsa item out-of-stock hone wala hai! ๐Ÿ“ฆ", + link: getAdminLink(store, "admin.php?page=wc-reports&tab=stock"), + linkLabel: "๐Ÿ“ฆ Check Inventory" + }) + }, + + guideToTaxSettings: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "GST ya Tax settings set karne ke liye niche click karo. Yahan aap 'Tax Classes' aur 'Standard Rates' define kar sakte ho. ๐Ÿงพ", + link: getAdminLink(store, "admin.php?page=wc-settings&tab=tax"), + linkLabel: "๐Ÿงพ Setup Tax/GST" + }) + }, + + guideToEmailTemplates: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Customer ko jo emails jaate hain unka design ya content change karne ke liye yahan jao. ๐Ÿ“ง", + link: getAdminLink(store, "admin.php?page=wc-settings&tab=email"), + linkLabel: "๐Ÿ“ง Edit Email Templates" + }) + }, + + guideToMediaLibrary: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Aapki saari photos, logos aur files yahan store hoti hain. Inhe delete ya edit karne ke liye Library kholo. ๐Ÿ–ผ๏ธ", + link: getAdminLink(store, "upload.php"), + linkLabel: "๐Ÿ–ผ๏ธ Media Library" + }) + }, + + guideToSystemStatus: { + execute: async () => ({ success: true }), + getReply: (result, args, store) => ({ + message: "Agar store mein kuch gadbad lag rahi hai, toh System Status check karo. Ye batayega ki server aur plugins sahi se kaam kar rahe hain ya nahi. ๐Ÿ› ๏ธ", + link: getAdminLink(store, "admin.php?page=wc-status"), + linkLabel: "๐Ÿ› ๏ธ Check System Health" + }) } }; @@ -382,5 +466,17 @@ export const SUGGESTION_RULES = [ { condition: () => true, data: { title: "๐Ÿ‘ฅ Manage Staff", prompt: "Staff members ya users kaise manage karu?" } + }, + { + condition: () => true, + data: { title: "๐Ÿ“ง Custom Emails", prompt: "Mujhe customer ko jaane wale order emails edit karne hain." } + }, + { + condition: () => true, + data: { title: "๐Ÿงพ Setup GST", prompt: "Store pe GST/Tax kaise calculate karu?" } + }, + { + condition: () => true, + data: { title: "๐Ÿ–ผ๏ธ Manage Photos", prompt: "Meri saari uploaded images kahan dikhengi?" } } ]; \ No newline at end of file From f7b3c80b075be0e0314d1d3d28307f56946ef9b5 Mon Sep 17 00:00:00 2001 From: chetannn-github Date: Wed, 4 Mar 2026 16:22:23 +0530 Subject: [PATCH 22/22] fix - extraction --- client/src/app/customize/Customize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/app/customize/Customize.js b/client/src/app/customize/Customize.js index d384a9a..156b4ba 100644 --- a/client/src/app/customize/Customize.js +++ b/client/src/app/customize/Customize.js @@ -183,7 +183,7 @@ export default function Customize() { { id: String(Date.now() + 1), role: "bot", - content: json.structured?.message, + content: json.reply, meta : {...json?.structured } , timestamp: new Date(), },