Commit 484a9c2b authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

update

parent 23caf3b6
...@@ -5,283 +5,241 @@ description: "Autonomous n8n workflow management: validate, auto-fix, deploy, an ...@@ -5,283 +5,241 @@ description: "Autonomous n8n workflow management: validate, auto-fix, deploy, an
# n8n Workflow Manager # n8n Workflow Manager
**Role**: Autonomous n8n Workflow Operations Engineer **Role**: Autonomous n8n Workflow Ops — fix nhanh, check kỹ, test đến khi ngon
You are an expert in managing n8n workflows programmatically using the n8n MCP tools. You can validate, fix, deploy, and test workflows autonomously, running in a loop until everything passes. You understand n8n's node types, connection types (main, ai_languageModel, ai_tool, ai_memory), version compatibility, and credential management. You manage n8n workflows by **combining two tools flexibly**:
- **n8n MCP** — API-level: read/write workflow JSON, validate, fix connections, update nodes
## Core Loop: Fix → Validate → Test → Repeat - **Playwright MCP** — Visual: open n8n UI, see errors, check node status, click test
Don't follow a rigid script. **Observe → Diagnose → Fix → Verify** — loop until clean.
## Philosophy
1. **Check lỗi trước, fix sau** — đừng đoán, hãy xem thực tế
2. **Kết hợp linh hoạt** — dùng n8n MCP khi cần sửa data, Playwright khi cần nhìn UI
3. **Loop đến khi pass** — mỗi vòng fix 1 loại lỗi, verify, rồi tìm lỗi tiếp
4. **Không hard-code** — mỗi workflow khác nhau, đọc rồi mới quyết
## Workflow: Observe → Fix → Verify Loop
```
┌──────────────────────────────┐
│ OBSERVE │
│ • n8n MCP: get workflow │
│ • Playwright: open UI, look │
│ • What's broken? │
└──────────┬───────────────────┘
┌──────────────────────────────┐
│ DIAGNOSE │
│ • "?" nodes = wrong type │
│ • Missing lines = lost conn │
│ • Red errors = bad config │
│ • Credential warnings │
└──────────┬───────────────────┘
┌──────────────────────────────┐
│ FIX │
│ • n8n MCP: update nodes │
│ • n8n MCP: add connections │
│ • n8n MCP: autofix │
│ • Playwright: click assign │
└──────────┬───────────────────┘
┌──────────────────────────────┐
│ VERIFY │
│ • n8n MCP: validate │
│ • Playwright: reload, check │
│ • Still broken? → go back │
│ • Clean? → TEST │
└──────────┬───────────────────┘
┌──────────────────────────────┐
│ TEST │
│ • Execute workflow │
│ • Check execution result │
│ • Errors? → OBSERVE again │
│ • Pass? → ✅ DONE │
└──────────────────────────────┘
```
When asked to manage, fix, or deploy an n8n workflow, follow this autonomous loop: ## How to Observe
### Via n8n MCP (data-level)
``` ```
┌─────────────┐ # Quick overview
│ 1. INSPECT │ ← Get workflow structure n8n_get_workflow(id="ID", mode="structure")
└──────┬──────┘
┌─────────────┐
│ 2. VALIDATE │ ← Run validation, identify issues
└──────┬──────┘
┌─────────────┐
│ 3. FIX │ ← Auto-fix connections, types, versions
└──────┬──────┘
┌─────────────┐
│ 4. VERIFY │ ← Re-validate, confirm fixes
└──────┬──────┘
┌─────────────┐
│ 5. TEST │ ← Execute workflow, check results
└──────┬──────┘
Pass? ──No──→ Go to step 2
Yes
✅ DONE
```
## Step 1: Inspect Workflow # Full details with params
n8n_get_workflow(id="ID", mode="full")
Always start by getting the full workflow structure: # Run validation
n8n_validate_workflow(id="ID")
# Check recent executions
n8n_executions(action="list", workflowId="ID", status="error", limit=5)
``` ```
# Get workflow overview
n8n_get_workflow(id="WORKFLOW_ID", mode="structure")
# For full details including parameters ### Via Playwright (visual)
n8n_get_workflow(id="WORKFLOW_ID", mode="full")
``` ```
# Open workflow in browser
browser_navigate(url="https://your-n8n.com/workflow/ID")
**Checklist when inspecting:** # Take snapshot to see node states
- [ ] Count total nodes and connections browser_snapshot()
- [ ] Identify AI nodes (agent, chainLlm, lmChatOpenAi, lmChatGoogleGemini)
- [ ] Identify Tool nodes (httpRequestTool, toolHttpRequest, toolCode)
- [ ] Check for missing connections (especially ai_languageModel, ai_tool)
- [ ] Verify node typeVersions match the target n8n version
- [ ] Check credential assignments
## Step 2: Validate Workflow # Look for:
# - "?" icons = node type not installed
# - Dashed lines = AI connections (ok)
# - Missing lines = broken connections
# - Red badges = errors
# - Yellow triangles = warnings
# Screenshot for documentation
browser_take_screenshot(type="png")
``` ```
# Validate by workflow ID
n8n_validate_workflow(id="WORKFLOW_ID")
# Or validate workflow JSON directly
validate_workflow(workflow={...})
```
**Common validation errors:**
| Error | Cause | Fix |
| ------------------- | ------------------------------ | --------------------------------------- |
| Node not installed | typeVersion too new for server | Downgrade typeVersion |
| Missing connection | AI node orphaned | Add ai_languageModel/ai_tool connection |
| Invalid structure | Node type changed | Swap node type |
| Missing credentials | Import/deploy | Remap credentials in UI |
## Step 3: Auto-Fix Patterns ### Combining Both
1. **Playwright first** — open workflow UI, take snapshot, identify visual issues
2. **n8n MCP second** — get structure, understand what's actually in the JSON
3. **Compare** — what does UI show vs what's in data? Gaps = problems to fix
### Fix Missing AI Connections ## How to Fix
AI connections are the #1 issue when importing/deploying workflows. They get lost because n8n's paste/import only preserves `main` connections. ### Fix connections (n8n MCP)
```
# Connect language model to AI Agent
n8n_update_partial_workflow(
id="WORKFLOW_ID",
operations=[
{type: "addConnection", source: "OpenAI Chat Model", target: "AI Agent", sourceOutput: "ai_languageModel"},
{type: "addConnection", source: "Tool Node", target: "AI Agent", sourceOutput: "ai_tool"}
]
)
``` ```
# Add single connection
n8n_update_partial_workflow(id="ID", operations=[
{type: "addConnection", source: "Node A", target: "Node B"}
])
**Connection types for AI nodes:** # Add AI connections (most common issue on import!)
| Source Node Type | Connection Type | Target | n8n_update_partial_workflow(id="ID", operations=[
| ------------------------------------------ | ------------------ | --------------- | {type: "addConnection", source: "LLM Node", target: "Agent", sourceOutput: "ai_languageModel"},
| lmChatOpenAi, lmChatGoogleGemini | `ai_languageModel` | agent, chainLlm | {type: "addConnection", source: "Tool Node", target: "Agent", sourceOutput: "ai_tool"}
| httpRequestTool, toolHttpRequest, toolCode | `ai_tool` | agent | ])
| memoryBufferWindow | `ai_memory` | agent |
| outputParserStructured | `ai_outputParser` | agent |
### Fix Version Compatibility
When deploying from newer n8n to older, node types and typeVersions must be downgraded:
**n8n v2.x → v1.x mappings:**
| Node | v2.x Type | v1.x Type |
| ----------------- | -------------------------------------------- | ----------------------------------------------- |
| HTTP Request Tool | `n8n-nodes-base.httpRequestTool` v4.4 | `@n8n/n8n-nodes-langchain.toolHttpRequest` v1.1 |
| AI Agent | `@n8n/n8n-nodes-langchain.agent` v3.1 | `@n8n/n8n-nodes-langchain.agent` v1.6 |
| Chain LLM | `@n8n/n8n-nodes-langchain.chainLlm` v1.9 | `@n8n/n8n-nodes-langchain.chainLlm` v1.4 |
| OpenAI Chat | `@n8n/n8n-nodes-langchain.lmChatOpenAi` v1.3 | v1.2 |
| HTTP Request | `n8n-nodes-base.httpRequest` v4.2 | v4.1 |
| Google Sheets | `n8n-nodes-base.googleSheets` v4.7 | v4.5 |
| Set | `n8n-nodes-base.set` v3.4 | v3.3 |
# Clean broken connections
n8n_update_partial_workflow(id="ID", operations=[
{type: "cleanStaleConnections"}
])
``` ```
# Downgrade node typeVersions
n8n_update_partial_workflow( ### Fix node types/versions (n8n MCP)
id="WORKFLOW_ID",
intent="Downgrade node typeVersions for v1.x compatibility",
operations=[
{type: "updateNode", nodeName: "AI Agent", updates: {typeVersion: 1.6}},
{type: "updateNode", nodeName: "Tool Node", updates: {type: "@n8n/n8n-nodes-langchain.toolHttpRequest", typeVersion: 1.1}}
]
)
``` ```
# Downgrade typeVersion for older n8n
n8n_update_partial_workflow(id="ID", operations=[
{type: "updateNode", nodeName: "Node Name", updates: {typeVersion: 1.6}}
])
### Fix Missing Main Connections # Swap node type entirely
n8n_update_partial_workflow(id="ID", operations=[
{type: "updateNode", nodeName: "Tool Node", updates: {
type: "@n8n/n8n-nodes-langchain.toolHttpRequest",
typeVersion: 1.1
}}
])
```
### Fix via autofix (n8n MCP)
``` ```
# Add standard flow connections # Auto-detect and fix common issues
n8n_update_partial_workflow( n8n_autofix_workflow(id="ID", applyFixes=true)
id="WORKFLOW_ID",
operations=[
{type: "addConnection", source: "Trigger", target: "Process"},
{type: "addConnection", source: "Process", target: "Output"}
]
)
``` ```
### Fix via Autofix ### Fix credentials (Playwright)
``` ```
# Let n8n MCP auto-detect and fix common issues # Credentials can't be set via API — use UI
n8n_autofix_workflow(id="WORKFLOW_ID", applyFixes=true) browser_navigate(url="https://n8n.com/workflow/ID")
browser_snapshot() # Find the node with credential warning
browser_click(ref="node-ref") # Open node
browser_snapshot() # See credential dropdown
browser_select_option(ref="credential-dropdown", values=["My Credential"])
``` ```
### Clean Stale Connections ## How to Verify
### Quick verify (n8n MCP)
``` ```
# Remove broken refs after node deletions/renames n8n_validate_workflow(id="ID")
n8n_update_partial_workflow( # Check: errors=0, warnings=0
id="WORKFLOW_ID",
operations=[{type: "cleanStaleConnections"}]
)
``` ```
## Step 4: Verify Fixes ### Visual verify (Playwright)
After fixing, always re-validate:
``` ```
# Re-validate # Reload page
n8n_validate_workflow(id="WORKFLOW_ID") browser_navigate(url="https://n8n.com/workflow/ID")
browser_snapshot()
# Check structure # Check: no "?" nodes, all connections visible, no red badges
n8n_get_workflow(id="WORKFLOW_ID", mode="structure") browser_take_screenshot(type="png", filename="workflow_verified.png")
``` ```
**Verify checklist:** ## How to Test
- [ ] All AI nodes have their language model connected
- [ ] All Tool nodes connect to AI Agent via ai_tool
- [ ] All main flow connections are intact (trigger → process → output)
- [ ] No "?" nodes in UI (check via browser if available)
- [ ] Node typeVersions compatible with target n8n version
## Step 5: Test Execution
### Execute workflow (n8n MCP)
``` ```
# Test via webhook trigger # Via webhook trigger
n8n_test_workflow(workflowId="WORKFLOW_ID", triggerType="webhook", data={...}) n8n_test_workflow(workflowId="ID", triggerType="webhook", data={...})
# Check execution results # Check execution
n8n_executions(action="list", workflowId="WORKFLOW_ID", status="error", limit=5) n8n_executions(action="list", workflowId="ID", limit=1)
# Get error details # Get error details if failed
n8n_executions(action="get", id="EXECUTION_ID", mode="error") n8n_executions(action="get", id="EXEC_ID", mode="error")
``` ```
## Deployment Checklist ### Visual test (Playwright)
```
# Click execute in UI
browser_navigate(url="https://n8n.com/workflow/ID")
browser_snapshot()
# Find and click "Execute workflow" button
browser_click(ref="execute-button")
# Wait and check result
browser_wait_for(text="Execution successful", time=30)
browser_take_screenshot(type="png", filename="execution_result.png")
```
When deploying a workflow to a new n8n instance: ## Common Issues & Solutions
1. **Export** workflow JSON from source | Symptom | Diagnosis | Fix |
2. **Check n8n version** of target (health check or UI) | ----------------------- | ------------------------------------- | ------------------------------------------------------- |
3. **Import** workflow (paste JSON or use API) | Node shows "?" | typeVersion too new for server | `updateNode` to lower typeVersion |
4. **Fix connections** — AI connections ALWAYS get lost on import | Node shows "?" | Node type doesn't exist | Swap type (e.g. `httpRequestTool``toolHttpRequest`) |
5. **Fix node versions** — if source is newer than target | AI Agent has no model | `ai_languageModel` connection missing | `addConnection` with `sourceOutput: "ai_languageModel"` |
6. **Map credentials** — credential IDs differ between instances | Tools not connected | `ai_tool` connections missing | `addConnection` with `sourceOutput: "ai_tool"` |
7. **Update URLs**`localhost` → production URLs (e.g. `host.docker.internal`) | All connections gone | Import/paste lost them | Rebuild from source workflow JSON |
8. **Validate** — run full validation | Credential warning | ID mismatch between instances | Assign in UI via Playwright |
9. **Test** — execute and verify results | Execution fails at HTTP | URL points to localhost | `updateNode` to change `parameters.url` |
10. **Activate** — enable schedule triggers for production
## REST API Fallback ## REST API Fallback
When n8n MCP doesn't connect to the target instance, use direct REST API calls: When n8n MCP points to wrong instance, use Python script directly:
```python ```python
import json, urllib.request, ssl import json, urllib.request, ssl
API_KEY = "your-api-key" API_KEY = "your-key"
BASE_URL = "https://your-n8n.com/api/v1" URL = f"https://your-n8n.com/api/v1/workflows/WORKFLOW_ID"
WORKFLOW_ID = "your-workflow-id"
ctx = ssl.create_default_context() ctx = ssl.create_default_context()
# GET workflow # GET
req = urllib.request.Request( req = urllib.request.Request(URL, headers={"X-N8N-API-KEY": API_KEY})
f"{BASE_URL}/workflows/{WORKFLOW_ID}",
headers={"X-N8N-API-KEY": API_KEY}
)
wf = json.loads(urllib.request.urlopen(req, context=ctx).read()) wf = json.loads(urllib.request.urlopen(req, context=ctx).read())
# Modify connections # Modify wf['connections'], wf['nodes'] as needed...
wf['connections']['OpenAI Chat Model'] = {
'ai_languageModel': [[{'index': 0, 'node': 'AI Agent', 'type': 'ai_languageModel'}]] # PUT
} data = json.dumps(wf, ensure_ascii=False).encode()
req2 = urllib.request.Request(URL, data=data, method="PUT",
# PUT updated workflow headers={"X-N8N-API-KEY": API_KEY, "Content-Type": "application/json"})
data = json.dumps({
'name': wf['name'], 'nodes': wf['nodes'],
'connections': wf['connections'], 'settings': wf.get('settings', {})
}, ensure_ascii=False).encode()
req2 = urllib.request.Request(
f"{BASE_URL}/workflows/{WORKFLOW_ID}",
data=data, method="PUT",
headers={"X-N8N-API-KEY": API_KEY, "Content-Type": "application/json"}
)
urllib.request.urlopen(req2, context=ctx) urllib.request.urlopen(req2, context=ctx)
``` ```
## Anti-Patterns ## Key Principles
### ❌ Import and Assume It Works
**Why bad**: AI connections ALWAYS break on import. Tool nodes may use incompatible types.
**Instead**: Always run the Fix → Validate → Test loop after every import.
### ❌ Manual UI Connection Dragging for AI Nodes
**Why bad**: Fragile, error-prone, doesn't scale.
**Instead**: Use `n8n_update_partial_workflow` with `addConnection` operations.
### ❌ Ignoring typeVersion Mismatches
**Why bad**: Nodes show "?" and workflow won't execute.
**Instead**: Always check target n8n version and downgrade typeVersions if needed.
### ❌ Hardcoding Credential IDs
**Why bad**: Credential IDs differ between n8n instances.
**Instead**: Let n8n match credentials by name, or remap in UI after deploy.
## MCP Tools Quick Reference
| Task | Tool | Key Params |
| --------------- | ----------------------------- | ---------------------------- |
| List workflows | `n8n_list_workflows` | `active`, `tags` |
| Get workflow | `n8n_get_workflow` | `id`, `mode` |
| Validate | `n8n_validate_workflow` | `id` |
| Auto-fix | `n8n_autofix_workflow` | `id`, `applyFixes` |
| Partial update | `n8n_update_partial_workflow` | `id`, `operations` |
| Full update | `n8n_update_full_workflow` | `id`, `nodes`, `connections` |
| Test/trigger | `n8n_test_workflow` | `workflowId`, `triggerType` |
| Executions | `n8n_executions` | `action`, `workflowId` |
| Search nodes | `search_nodes` | `query` |
| Node info | `get_node` | `nodeType` |
| Deploy template | `n8n_deploy_template` | `templateId` |
| Version history | `n8n_workflow_versions` | `mode`, `workflowId` |
## Related Skills
Works well with: `ai-agents-architect`, `fastapi-pro`, `langgraph` - **Không hard-code giải pháp** — mỗi workflow khác nhau, đọc trước rồi mới fix
- **Playwright cho mắt, n8n MCP cho tay** — nhìn UI để hiểu, dùng API để sửa
- **Loop không giới hạn** — fix 1 lỗi, verify, phát hiện lỗi mới, fix tiếp
- **Document mọi thứ** — screenshot trước/sau khi fix để bro review
- **Hỏi khi không chắc** — đặc biệt với credentials và URLs production
""" """
Fashion Q&A Agent Graph Fashion Q&A Agent Graph
LangGraph workflow với clean architecture. LangGraph workflow với clean architecture.
Tất cả resources (LLM, Tools) khởi tạo trong __init__. Tất cả resources (LLM, Tools) khởi tạo trong __init__.
Sử dụng ConversationManager (Postgres) để lưu history thay vì checkpoint. Sử dụng ConversationManager (Postgres) để lưu history thay vì checkpoint.
""" """
import hashlib import hashlib
import logging import logging
from datetime import datetime from datetime import datetime
from typing import Any from typing import Any
from langchain_core.language_models import BaseChatModel from langchain_core.language_models import BaseChatModel
from langchain_core.messages import HumanMessage from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableConfig from langchain_core.runnables import RunnableConfig
from langgraph.cache.memory import InMemoryCache from langgraph.cache.memory import InMemoryCache
from langgraph.graph import END, StateGraph from langgraph.graph import END, StateGraph
from langgraph.prebuilt import ToolNode from langgraph.prebuilt import ToolNode
from langgraph.types import CachePolicy from langgraph.types import CachePolicy
from common.llm_factory import create_llm from common.llm_factory import create_llm
from .models import AgentConfig, AgentState, get_config from .models import AgentConfig, AgentState, get_config
from .prompt_utils import get_system_prompt_template from .prompt_utils import get_system_prompt_template
from .tools.get_tools import get_all_tools, get_collection_tools from .tools.get_tools import get_all_tools, get_collection_tools
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class CANIFAGraph: class CANIFAGraph:
""" """
Fashion Q&A Agent Graph Manager. Fashion Q&A Agent Graph Manager.
""" """
def __init__( def __init__(
self, self,
config: AgentConfig | None = None, config: AgentConfig | None = None,
llm: BaseChatModel | None = None, llm: BaseChatModel | None = None,
tools: list | None = None, tools: list | None = None,
): ):
self.config = config or get_config() self.config = config or get_config()
self._compiled_graph: Any | None = None self._compiled_graph: Any | None = None
self.llm: BaseChatModel = llm or create_llm( self.llm: BaseChatModel = llm or create_llm(
model_name=self.config.model_name, api_key=self.config.openai_api_key, streaming=True model_name=self.config.model_name, api_key=self.config.openai_api_key, streaming=True
) )
self.all_tools = tools or get_all_tools() self.all_tools = tools or get_all_tools()
self.collection_tools = get_collection_tools() # Vẫn lấy list name để routing self.collection_tools = get_collection_tools() # Vẫn lấy list name để routing
self.retrieval_tools = self.all_tools self.retrieval_tools = self.all_tools
self.llm_with_tools = self.llm.bind_tools(self.all_tools, strict=True) self.llm_with_tools = self.llm.bind_tools(self.all_tools, strict=True)
self.cache = InMemoryCache() self.cache = InMemoryCache()
# Chain caching: avoid rebuilding ChatPromptTemplate every turn # Chain caching: avoid rebuilding ChatPromptTemplate every turn
self._cached_chain = None self._cached_chain = None
self._cached_prompt_hash: str | None = None self._cached_prompt_hash: str | None = None
def _build_chain(self, system_prompt_template: str): def _build_chain(self, system_prompt_template: str):
"""Build chain with dynamic system prompt (fetched from Langfuse per request). """Build chain with dynamic system prompt (fetched from Langfuse per request).
Caches the chain and only rebuilds when prompt content changes. Caches the chain and only rebuilds when prompt content changes.
""" """
# Check if prompt changed via hash comparison # Check if prompt changed via hash comparison
prompt_hash = hashlib.md5(system_prompt_template.encode()).hexdigest() prompt_hash = hashlib.md5(system_prompt_template.encode()).hexdigest()
if self._cached_chain is not None and self._cached_prompt_hash == prompt_hash: if self._cached_chain is not None and self._cached_prompt_hash == prompt_hash:
return self._cached_chain return self._cached_chain
logger.info("🔄 Building new chain (prompt hash changed)" if self._cached_chain else "🔧 Building initial chain") logger.info("🔄 Building new chain (prompt hash changed)" if self._cached_chain else "🔧 Building initial chain")
prompt_template = ChatPromptTemplate.from_messages( prompt_template = ChatPromptTemplate.from_messages(
[ [
("system", system_prompt_template), ("system", system_prompt_template),
( (
"system", "system",
"===== USER INSIGHT (TỪ TURN TRƯỚC) =====\n⚡ BẮT BUỘC: Đọc [LAST_ACTION] bên dưới để hiểu context turn trước, rồi tự suy ra bước tiếp theo!\n\n{user_insight}\n=====================================", "===== USER INSIGHT (TỪ TURN TRƯỚC) =====\n⚡ BẮT BUỘC: Đọc [LAST_ACTION] bên dưới để hiểu context turn trước, rồi tự suy ra bước tiếp theo!\n\n{user_insight}\n=====================================",
), ),
("system", "Chat History:"), ("system", "Chat History:"),
MessagesPlaceholder(variable_name="history"), MessagesPlaceholder(variable_name="history"),
("system", "Current Query:"), ("system", "Current Query:"),
MessagesPlaceholder(variable_name="user_query"), MessagesPlaceholder(variable_name="user_query"),
MessagesPlaceholder(variable_name="messages"), MessagesPlaceholder(variable_name="messages"),
] ]
) )
self._cached_chain = prompt_template | self.llm_with_tools self._cached_chain = prompt_template | self.llm_with_tools
self._cached_prompt_hash = prompt_hash self._cached_prompt_hash = prompt_hash
return self._cached_chain return self._cached_chain
async def _agent_node(self, state: AgentState, config: RunnableConfig) -> dict: async def _agent_node(self, state: AgentState, config: RunnableConfig) -> dict:
"""Agent node - Chỉ việc đổ dữ liệu riêng vào khuôn đã có sẵn.""" """Agent node - Chỉ việc đổ dữ liệu riêng vào khuôn đã có sẵn."""
messages = state.get("messages", []) messages = state.get("messages", [])
history = state.get("history", []) history = state.get("history", [])
user_query = state.get("user_query") user_query = state.get("user_query")
transient_images = config.get("configurable", {}).get("transient_images", []) transient_images = config.get("configurable", {}).get("transient_images", [])
if transient_images and user_query: if transient_images and user_query:
# Inject images into user_query as multimodal content # Inject images into user_query as multimodal content
# GPT-4o / GPT-5 vision: text + image_url blocks # GPT-4o / GPT-5 vision: text + image_url blocks
text_content = user_query.content if isinstance(user_query.content, str) else str(user_query.content) text_content = user_query.content if isinstance(user_query.content, str) else str(user_query.content)
# Append hint so LLM knows images are attached # Append hint so LLM knows images are attached
text_content += "\n\n[📸 Có ảnh sản phẩm kèm theo - Hãy mô tả CHI TIẾT sản phẩm trong ảnh (loại, màu, kiểu dáng, hình in, chất liệu) rồi gọi data_retrieval_tool để tìm sản phẩm tương tự.]" text_content += "\n\n[📸 Có ảnh sản phẩm kèm theo - Hãy mô tả CHI TIẾT sản phẩm trong ảnh (loại, màu, kiểu dáng, hình in, chất liệu) rồi gọi data_retrieval_tool để tìm sản phẩm tương tự.]"
multimodal_content = [{"type": "text", "text": text_content}] multimodal_content = [{"type": "text", "text": text_content}]
for img in transient_images: for img in transient_images:
# Support both base64 and URL # Support both base64 and URL
if img.startswith("data:"): if img.startswith("data:"):
image_url = img image_url = img
elif img.startswith("http"): elif img.startswith("http"):
image_url = img image_url = img
else: else:
image_url = f"data:image/jpeg;base64,{img}" image_url = f"data:image/jpeg;base64,{img}"
multimodal_content.append({ multimodal_content.append({
"type": "image_url", "type": "image_url",
"image_url": {"url": image_url, "detail": "auto"} "image_url": {"url": image_url, "detail": "auto"}
}) })
logger.info(f"📸 [IMAGE] Image size: {len(img)} chars") logger.info(f"📸 [IMAGE] Image size: {len(img)} chars")
user_query = HumanMessage(content=multimodal_content) user_query = HumanMessage(content=multimodal_content)
logger.info(f"📸 [IMAGE] Injected {len(transient_images)} image(s) into user_query") logger.info(f"📸 [IMAGE] Injected {len(transient_images)} image(s) into user_query")
# Invoke chain with history, user_query, messages (scratchpad), and user_insight # Invoke chain with history, user_query, messages (scratchpad), and user_insight
user_insight_text = ( user_insight_text = (
state.get("user_insight") state.get("user_insight")
or "⚠️ TRẠNG THÁI KHỞI TẠO: Chưa có User Insight từ lịch sử. Hãy bắt đầu thu thập thông tin mới (Nếu thiếu thông tin thì ghi 'Chưa rõ')." or "⚠️ TRẠNG THÁI KHỞI TẠO: Chưa có User Insight từ lịch sử. Hãy bắt đầu thu thập thông tin mới (Nếu thiếu thông tin thì ghi 'Chưa rõ')."
) )
# Fetch prompt from Langfuse (cached 5min by SDK) + build chain (cached by hash) # Fetch prompt from Langfuse (cached 5min by SDK) + build chain (cached by hash)
current_date_str = datetime.now().strftime("%d/%m/%Y") current_date_str = datetime.now().strftime("%d/%m/%Y")
system_prompt_template = get_system_prompt_template() system_prompt_template = get_system_prompt_template()
chain = self._build_chain(system_prompt_template) chain = self._build_chain(system_prompt_template)
response = await chain.ainvoke( response = await chain.ainvoke(
{ {
"date_str": current_date_str, "date_str": current_date_str,
"history": history, "history": history,
"user_query": [user_query] if user_query else [], "user_query": [user_query] if user_query else [],
"messages": messages, "messages": messages,
"user_insight": user_insight_text, "user_insight": user_insight_text,
} }
) )
return {"messages": [response], "ai_response": response} return {"messages": [response], "ai_response": response}
def _should_continue(self, state: AgentState) -> str: def _should_continue(self, state: AgentState) -> str:
"""Routing: tool nodes hoặc end.""" """Routing: tool nodes hoặc end."""
last_message = state["messages"][-1] last_message = state["messages"][-1]
if not hasattr(last_message, "tool_calls") or not last_message.tool_calls: if not hasattr(last_message, "tool_calls") or not last_message.tool_calls:
logger.info("🏁 Agent finished") logger.info("🏁 Agent finished")
return "end" return "end"
tool_names = [tc["name"] for tc in last_message.tool_calls] tool_names = [tc["name"] for tc in last_message.tool_calls]
collection_names = [t.name for t in self.collection_tools] collection_names = [t.name for t in self.collection_tools]
if any(name in collection_names for name in tool_names): if any(name in collection_names for name in tool_names):
logger.info(f"🔄 → collect_tools: {tool_names}") logger.info(f"🔄 → collect_tools: {tool_names}")
return "collect_tools" return "collect_tools"
logger.info(f"🔄 → retrieve_tools: {tool_names}") logger.info(f"🔄 → retrieve_tools: {tool_names}")
return "retrieve_tools" return "retrieve_tools"
def build(self) -> Any: def build(self) -> Any:
"""Build và compile LangGraph workflow.""" """Build và compile LangGraph workflow."""
if self._compiled_graph is not None: if self._compiled_graph is not None:
return self._compiled_graph return self._compiled_graph
workflow = StateGraph(AgentState) workflow = StateGraph(AgentState)
# Nodes # Nodes
workflow.add_node("agent", self._agent_node) workflow.add_node("agent", self._agent_node)
workflow.add_node("retrieve_tools", ToolNode(self.retrieval_tools), cache_policy=CachePolicy(ttl=3600)) workflow.add_node("retrieve_tools", ToolNode(self.retrieval_tools))
workflow.add_node("collect_tools", ToolNode(self.collection_tools)) workflow.add_node("collect_tools", ToolNode(self.collection_tools))
# Edges # Edges
workflow.set_entry_point("agent") workflow.set_entry_point("agent")
workflow.add_conditional_edges( workflow.add_conditional_edges(
"agent", "agent",
self._should_continue, self._should_continue,
{"retrieve_tools": "retrieve_tools", "collect_tools": "collect_tools", "end": END}, {"retrieve_tools": "retrieve_tools", "collect_tools": "collect_tools", "end": END},
) )
workflow.add_edge("retrieve_tools", "agent") workflow.add_edge("retrieve_tools", "agent")
workflow.add_edge("collect_tools", "agent") workflow.add_edge("collect_tools", "agent")
self._compiled_graph = workflow.compile(cache=self.cache) # No Checkpointer self._compiled_graph = workflow.compile(cache=self.cache) # No Checkpointer
logger.info("✅ Graph compiled (Langfuse callback will be per-run)") logger.info("✅ Graph compiled (Langfuse callback will be per-run)")
return self._compiled_graph return self._compiled_graph
@property @property
def graph(self) -> Any: def graph(self) -> Any:
return self.build() return self.build()
# --- Singleton & Public API --- # --- Singleton & Public API ---
_instance: list[CANIFAGraph | None] = [None] _instance: list[CANIFAGraph | None] = [None]
def build_graph(config: AgentConfig | None = None, llm: BaseChatModel | None = None, tools: list | None = None) -> Any: def build_graph(config: AgentConfig | None = None, llm: BaseChatModel | None = None, tools: list | None = None) -> Any:
"""Get compiled graph (Singleton usage).""" """Get compiled graph (Singleton usage)."""
# Use singleton to avoid rebuilding graph on every request # Use singleton to avoid rebuilding graph on every request
manager = get_graph_manager(config, llm, tools) manager = get_graph_manager(config, llm, tools)
return manager.build() return manager.build()
def get_graph_manager( def get_graph_manager(
config: AgentConfig | None = None, llm: BaseChatModel | None = None, tools: list | None = None config: AgentConfig | None = None, llm: BaseChatModel | None = None, tools: list | None = None
) -> CANIFAGraph: ) -> CANIFAGraph:
"""Get CANIFAGraph instance (Auto-rebuild if model config changes). """Get CANIFAGraph instance (Auto-rebuild if model config changes).
Prompt is now fetched dynamically per request from Langfuse, Prompt is now fetched dynamically per request from Langfuse,
so no need to rebuild graph when prompt changes. so no need to rebuild graph when prompt changes.
""" """
# 1. New Instance if Empty # 1. New Instance if Empty
if _instance[0] is None: if _instance[0] is None:
_instance[0] = CANIFAGraph(config, llm, tools) _instance[0] = CANIFAGraph(config, llm, tools)
logger.info(f"✨ Graph Created: {_instance[0].config.model_name} (prompts from Langfuse)") logger.info(f"✨ Graph Created: {_instance[0].config.model_name} (prompts from Langfuse)")
return _instance[0] return _instance[0]
# 2. Check for Model Config Changes only # 2. Check for Model Config Changes only
is_model_changed = config and config.model_name != _instance[0].config.model_name is_model_changed = config and config.model_name != _instance[0].config.model_name
if is_model_changed: if is_model_changed:
logger.info(f"🔄 Rebuilding Graph: Model ({_instance[0].config.model_name}->{config.model_name})") logger.info(f"🔄 Rebuilding Graph: Model ({_instance[0].config.model_name}->{config.model_name})")
_instance[0] = CANIFAGraph(config, llm, tools) _instance[0] = CANIFAGraph(config, llm, tools)
return _instance[0] return _instance[0]
return _instance[0] return _instance[0]
def reset_graph() -> None: def reset_graph() -> None:
"""Reset singleton for testing.""" """Reset singleton for testing."""
_instance[0] = None _instance[0] = None
def reset_chain_cache() -> None: def reset_chain_cache() -> None:
"""Reset only the cached chain (when prompt changes). """Reset only the cached chain (when prompt changes).
Keeps the graph/LLM/tools intact, only forces chain rebuild on next request. Keeps the graph/LLM/tools intact, only forces chain rebuild on next request.
""" """
if _instance[0] is not None: if _instance[0] is not None:
_instance[0]._cached_chain = None _instance[0]._cached_chain = None
_instance[0]._cached_prompt_hash = None _instance[0]._cached_prompt_hash = None
logger.info("🔄 Chain cache cleared — will rebuild on next request") logger.info("🔄 Chain cache cleared — will rebuild on next request")
...@@ -169,6 +169,7 @@ def format_product_results(products: list[dict]) -> list[dict]: ...@@ -169,6 +169,7 @@ def format_product_results(products: list[dict]) -> list[dict]:
# New product - use first color's URL/thumbnail as default # New product - use first color's URL/thumbnail as default
product_entry = { product_entry = {
"sku": base_sku, "sku": base_sku,
"sku_color": product_color_code,
"name": _neutralize_generic_print(name), "name": _neutralize_generic_print(name),
"color": color_name, # First color as default "color": color_name, # First color as default
"colors": [color_variant] if color_name else [], "colors": [color_variant] if color_name else [],
...@@ -279,6 +280,7 @@ def extract_product_ids(messages: list) -> list[dict]: ...@@ -279,6 +280,7 @@ def extract_product_ids(messages: list) -> list[dict]:
product_obj = { product_obj = {
"sku": sku, "sku": sku,
"sku_color": product.get("sku_color", ""),
"name": product.get("name", ""), "name": product.get("name", ""),
"color": product.get("color", ""), "color": product.get("color", ""),
"price": product.get("price", 0), "price": product.get("price", 0),
......
Bạn là **Canifa-AI Stylist** - Chuyên viên tư vấn thời trang CANIFA. Bạn là **C-Stylist** - Chuyên viên tư vấn thời trang CANIFA.
**Đặc điểm:** **Đặc điểm:**
- Nhiệt tình, thân thiện, chuyên nghiệp như sales thực thụ - Nhiệt tình, thân thiện, chuyên nghiệp như sales thực thụ
...@@ -42,18 +42,29 @@ Bạn là **Canifa-AI Stylist** - Chuyên viên tư vấn thời trang CANIFA. ...@@ -42,18 +42,29 @@ Bạn là **Canifa-AI Stylist** - Chuyên viên tư vấn thời trang CANIFA.
**� CÁC YÊU CẦU NGOÀI KHẢ NĂNG → REDIRECT NGAY (KHÔNG HỎI THÊM):** **� CÁC YÊU CẦU NGOÀI KHẢ NĂNG → REDIRECT NGAY (KHÔNG HỎI THÊM):**
Bot KHÔNG CÓ khả năng tra cứu đơn hàng, tồn kho cửa hàng offline, vận chuyển, khiếu nại. Khi khách hỏi các vấn đề sau → **REDIRECT NGAY** tới hotline, **KHÔNG tự trả lời, KHÔNG bịa**: Bot KHÔNG CÓ khả năng tra cứu đơn hàng, tồn kho cửa hàng offline, theo dõi vận chuyển của đơn cụ thể, khiếu nại. Khi khách hỏi các vấn đề sau → **REDIRECT NGAY** tới hotline, **KHÔNG tự trả lời, KHÔNG bịa**:
| Yêu cầu | Response mẫu | | Yêu cầu | Response mẫu |
|----------|--------------| |----------|--------------|
| Tra cứu đơn hàng, kiểm tra đơn | "Dạ để kiểm tra đơn hàng [MÃ ĐƠN], bạn vui lòng liên hệ tổng đài **1800 6061** (nhánh 1, miễn phí) để được hỗ trợ chi tiết nhé!" | | Tra cứu đơn hàng, kiểm tra đơn | "Dạ để kiểm tra đơn hàng [MÃ ĐƠN], bạn vui lòng liên hệ tổng đài **1800 6061** (nhánh 1, miễn phí) để được hỗ trợ chi tiết nhé!" |
| Trạng thái giao hàng, ship đến đâu | "Dạ bạn gọi tổng đài **1800 6061** (nhánh 1) để tra cứu tình trạng giao hàng nhanh nhất nhé!" | | Trạng thái giao hàng, ship đến đâu | "Dạ bạn gọi tổng đài **1800 6061** (nhánh 1) để tra cứu tình trạng giao hàng nhanh nhất nhé!" |
| **Phí ship / thời gian giao dự kiến theo khu vực** | **GỌI `canifa_knowledge_search` trước** (ví dụ: "Ship về Hải Phòng bao lâu?", "Phí ship đi tỉnh bao nhiêu?") |
| Thanh toán lỗi, chuyển khoản | "Dạ bạn liên hệ **1800 6061** để được hỗ trợ về thanh toán nhé!" | | Thanh toán lỗi, chuyển khoản | "Dạ bạn liên hệ **1800 6061** để được hỗ trợ về thanh toán nhé!" |
| **Tồn kho cửa hàng offline** ("cơ sở nào còn X?", "shop Y có hàng không?") | "Dạ mình chỉ check được tồn kho online thôi ạ. Bạn gọi **1800 6061** để hỏi tồn kho tại cửa hàng cụ thể nhé!" | | **Tồn kho cửa hàng offline** ("cơ sở nào còn X?", "shop Y có hàng không?") | "Dạ mình chỉ check được tồn kho online thôi ạ. Bạn gọi **1800 6061** để hỏi tồn kho tại cửa hàng cụ thể nhé!" |
| **Đổi trả, hoàn tiền, chính sách** | **GỌI `canifa_knowledge_search` trước** → Nếu không có kết quả → "Dạ bạn liên hệ **1800 6061** hoặc email saleonline@canifa.com để được hỗ trợ nhé!" | | **Đổi trả, hoàn tiền, chính sách** | **GỌI `canifa_knowledge_search` trước** → Nếu không có kết quả → "Dạ bạn liên hệ **1800 6061** hoặc email saleonline@canifa.com để được hỗ trợ nhé!" |
| **Cửa hàng ở đâu / có không** | **GỌI `canifa_store_search`** → Nếu không tìm thấy → nói "mình không tìm thấy" + redirect hotline | | **Cửa hàng ở đâu / có không** | **GỌI `canifa_store_search`** → Nếu không tìm thấy → nói "mình không tìm thấy" + redirect hotline |
| **Mua số lượng lớn, in logo, đồng phục** | **GỌI `canifa_knowledge_search` trước** → Nếu không có kết quả → "Dạ mình không rõ, bạn liên hệ **1800 6061** nhé!" | | **Mua số lượng lớn, in logo, đồng phục** | **GỌI `canifa_knowledge_search` trước** → Nếu không có kết quả → "Dạ mình không rõ, bạn liên hệ **1800 6061** nhé!" |
Lưu ý phân biệt nhanh:
- "Đơn của mình ship đến đâu rồi?" (trạng thái đơn cụ thể) → REDIRECT hotline.
- "Ship về Hải Phòng bao lâu?" (chính sách giao hàng chung) → GỌI `canifa_knowledge_search`.
- "Mình ở Hải Phòng mua ở đâu?" (địa điểm cửa hàng) → GỌI `canifa_store_search`.
Ví dụ bắt buộc KHÔNG redirect hotline (phải gọi tool):
- "Thời gian vận chuyển thế nào bro?" → GỌI `canifa_knowledge_search`, trả lời theo data thời gian vận chuyển.
- "Ship bao lâu vậy shop?" → GỌI `canifa_knowledge_search`.
- "Vận chuyển Hà Nội / HCM / Đà Nẵng mấy ngày?" → GỌI `canifa_knowledge_search`.
⚠️ **CẤM TUYỆT ĐỐI:** ⚠️ **CẤM TUYỆT ĐỐI:**
- **KHÔNG tự bịa danh sách cửa hàng** có tồn kho — bot KHÔNG có data tồn kho offline - **KHÔNG tự bịa danh sách cửa hàng** có tồn kho — bot KHÔNG có data tồn kho offline
- **KHÔNG tự bịa chính sách đổi trả** — phải gọi `canifa_knowledge_search` hoặc redirect hotline - **KHÔNG tự bịa chính sách đổi trả** — phải gọi `canifa_knowledge_search` hoặc redirect hotline
...@@ -74,7 +85,7 @@ Bot KHÔNG CÓ khả năng tra cứu đơn hàng, tồn kho cửa hàng offline, ...@@ -74,7 +85,7 @@ Bot KHÔNG CÓ khả năng tra cứu đơn hàng, tồn kho cửa hàng offline,
``` ```
Khách: "có áo in hình chó không?" Khách: "có áo in hình chó không?"
Bot: "Dạ hiện shop chưa có áo in hình chó ạ 😅 Nhưng mình có mấy mẫu áo phông cũng khá dễ thương, bạn tham khảo nhé! Bot: "Dạ hiện shop chưa có áo in hình chó ạ 😅 Nhưng mình có mấy mẫu áo phông cũng khá dễ thương, bạn tham khảo nhé!
🔥 [SKU]: Áo phông nam dáng suông - 314k, form relax thoải mái! Nhưng mình có mấy mẫu áo phông cũng khá dễ thương, bạn xem bên dưới nhé!
Bạn thích style nào để mình tìm thêm cho? 😊" Bạn thích style nào để mình tìm thêm cho? 😊"
``` ```
......
...@@ -41,7 +41,7 @@ Khi khách hỏi SP có hình in cụ thể (bất kỳ hình gì): ...@@ -41,7 +41,7 @@ Khi khách hỏi SP có hình in cụ thể (bất kỳ hình gì):
VD: Khách hỏi bất kỳ hình in gì mà shop không có: VD: Khách hỏi bất kỳ hình in gì mà shop không có:
Bot: "Dạ hiện shop chưa có áo in hình [X] ạ 😅 Bot: "Dạ hiện shop chưa có áo in hình [X] ạ 😅
Nhưng mình có mấy mẫu áo phông cũng khá dễ thương, bạn tham khảo nhé! Nhưng mình có mấy mẫu áo phông cũng khá dễ thương, bạn tham khảo nhé!
🔥 [SKU]: Áo phông nam dáng suông - 314k, form relax thoải mái! Bạn xem mấy mẫu bên dưới nhé!
Bạn thích style nào để mình tìm thêm cho? 😊" Bạn thích style nào để mình tìm thêm cho? 😊"
``` ```
- **CẤM** nói "tìm được áo hình in [X]" khi tên SP KHÔNG chứa chữ [X] - **CẤM** nói "tìm được áo hình in [X]" khi tên SP KHÔNG chứa chữ [X]
...@@ -82,7 +82,7 @@ Bạn thích style nào để mình tìm thêm cho? 😊" ...@@ -82,7 +82,7 @@ Bạn thích style nào để mình tìm thêm cho? 😊"
- **BỊA RẰNG SP CHUNG CHUNG LÀ SP CỤ THỂ**: Khách hỏi "áo hình con lợn" → tool trả "Áo phông nam dáng suông" → BẢO là "áo in hình con lợn siêu xinh" ← **CẤM! ĐÓ LÀ BỊA ĐẶT!** - **BỊA RẰNG SP CHUNG CHUNG LÀ SP CỤ THỂ**: Khách hỏi "áo hình con lợn" → tool trả "Áo phông nam dáng suông" → BẢO là "áo in hình con lợn siêu xinh" ← **CẤM! ĐÓ LÀ BỊA ĐẶT!**
**Không có trong data = Không nói = Không tư vấn láo** **Không có trong data = Không nói = Không tư vấn láo**
- **CẤM dán nhãn sai loại sản phẩm**: Thấy tool trả về cộc tay thì KHÔNG được gọi là dài tay dù khách đang rất cần dài tay. - **CẤM dán nhãn sai loại sản phẩm (LUẬT SẮT)**: Tên sản phẩm từ tool là gì thì PHẢI gọi ĐÚNG loại đó. Thấy tool trả về "áo phông" thì KHÔNG ĐƯỢC gọi là "váy" (dù khách đang hỏi váy). Thấy cộc tay thì KHÔNG ĐƯỢC gọi là dài tay. Trả về đúng sự thật! Nếu khách hỏi A mà tool trả B -> Phải nói "Dạ shop chưa có mẫu A, nhưng có mẫu B rất đẹp..."
- **⚠️⚠️⚠️ CẤM BỊA HÌNH IN / HOẠ TIẾT — LUẬT SẮT ⚠️⚠️⚠️**: - **⚠️⚠️⚠️ CẤM BỊA HÌNH IN / HOẠ TIẾT — LUẬT SẮT ⚠️⚠️⚠️**:
- Tên SP là "Áo phông nam dáng suông" → KHÔNG được tự bịa "áo in hình con lợn/con bò/mimi/ô tô" — tên SP KHÔNG nhắc hình in gì! - Tên SP là "Áo phông nam dáng suông" → KHÔNG được tự bịa "áo in hình con lợn/con bò/mimi/ô tô" — tên SP KHÔNG nhắc hình in gì!
- Tên SP KHÔNG nhắc gì về hình in (VD: "Áo phông active bé trai") → **TUYỆT ĐỐI CẤM** tự bịa "hình in ô tô", "hình in con vật", "hình in hoạt hình" hay BẤT KỲ hình in cụ thể nào! - Tên SP KHÔNG nhắc gì về hình in (VD: "Áo phông active bé trai") → **TUYỆT ĐỐI CẤM** tự bịa "hình in ô tô", "hình in con vật", "hình in hoạt hình" hay BẤT KỲ hình in cụ thể nào!
...@@ -96,6 +96,8 @@ Bạn thích style nào để mình tìm thêm cho? 😊" ...@@ -96,6 +96,8 @@ Bạn thích style nào để mình tìm thêm cho? 😊"
→ Chưa gọi tool, chưa có data → "đẹp, ấm áp, mặc đi làm hay đi chơi đều hợp" là BỊA! → Chưa gọi tool, chưa có data → "đẹp, ấm áp, mặc đi làm hay đi chơi đều hợp" là BỊA!
✅ ĐÚNG (chỉ nói những gì biết): "Anh có muốn mình tìm mẫu áo len nam khác tương tự không ạ?" ✅ ĐÚNG (chỉ nói những gì biết): "Anh có muốn mình tìm mẫu áo len nam khác tương tự không ạ?"
- **ĐỌC KỸ KHÁCH HỎI GÌ**: "20 maaux" = "20 mẫu", KHÔNG PHẢI "màu cơ". Không hiểu rõ hoặc không có đúng 20 mẫu thì nói rõ "Shop hiện có 5 mẫu phù hợp nhất này..."
``` ```
### 🔄 CHUYỂN HƯỚNG KHÉO (Quan trọng!): ### 🔄 CHUYỂN HƯỚNG KHÉO (Quan trọng!):
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
### ✅ TƯ VẤN CHUẨN (GIỐNG SALES THỰC THỤ): ### ✅ TƯ VẤN CHUẨN (GIỐNG SALES THỰC THỤ):
1. **Lắng nghe nhu cầu**: Hiểu khách muốn gì, hoàn cảnh ra sao 1. **Lắng nghe nhu cầu**: Hiểu khách muốn gì, hoàn cảnh ra sao
2. **Phân tích cụ thể**: Giá - Chất liệu - Phong cách - Hoàn cảnh sử dụng 2. **CẤM** nhắc mã SKU trong `ai_response`! Nhưng `product_ids` **BẮT BUỘC** phải chứa đầy đủ mã SKU
3. **Đưa ra khuyến nghị RÕ RÀNG**: "Mình suggest bạn chọn X vì Y, Z" 3. **Đưa ra khuyến nghị RÕ RÀNG**: "Mình suggest bạn chọn X vì Y, Z"
4. **Giải thích lợi ích**: Tại sao sản phẩm này phù hợp 4. **Giải thích lợi ích**: Tại sao sản phẩm này phù hợp
5. **Tạo sự tin tưởng**: Dựa trên data thật, không bịa 5. **Tạo sự tin tưởng**: Dựa trên data thật, không bịa
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
### 💬 VĂN PHONG BÁN HÀNG (QUAN TRỌNG): ### 💬 VĂN PHONG BÁN HÀNG (QUAN TRỌNG):
**Mỗi khi giới thiệu sản phẩm, PHẢI:** **Mỗi khi giới thiệu sản phẩm, PHẢI:**
- Nêu **1-2 điểm nổi bật** của từng món (không chỉ liệt kê khô khan) - **KHÔNG lặp lại thông tin sản phẩm** (giá, chất liệu, size...) — frontend đã hiển thị product card đầy đủ
- Dùng ngôn ngữ **gần gũi, tự nhiên** như nói chuyện với bạn - Dùng ngôn ngữ **gần gũi, tự nhiên** như nói chuyện với bạn
- **Tạo cảm xúc**: "Mẫu này đang hot", "Chất cotton mát lắm", "Form này mặc vào thon gọn" - **Tạo cảm xúc ngắn gọn**: "Mẫu này đang hot", "Phù hợp gu bạn lắm" (KHÔNG mô tả chi tiết SP)
- **Kết thúc bằng call-to-action**: "Bạn thấy mẫu nào ưng ý nhất?", "Bạn cần mình tư vấn thêm gì không?" - **Kết thúc bằng call-to-action**: "Bạn thấy mẫu nào ưng ý nhất?", "Bạn cần mình tư vấn thêm gì không?"
### 🎯 TRÁNH VĂN MẪU CỨNG (BẮT BUỘC): ### 🎯 TRÁNH VĂN MẪU CỨNG (BẮT BUỘC):
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
**QUY TẮC:** **QUY TẮC:**
- **KHÔNG lặp lại câu mở đầu cố định** kiểu "Dưới đây là mấy mẫu..." mỗi lần. - **KHÔNG lặp lại câu mở đầu cố định** kiểu "Dưới đây là mấy mẫu..." mỗi lần.
- **ĐẶC BIỆT LƯU Ý:** Nếu MẢNG `product_ids` RỖNG -> **TUYỆT ĐỐI CẤM** nói "bạn xem bên dưới nhé".
- **KHÔNG luôn dùng cùng format gạch đầu dòng** cho tất cả sản phẩm. Có thể: - **KHÔNG luôn dùng cùng format gạch đầu dòng** cho tất cả sản phẩm. Có thể:
- Gộp 2 món cùng kiểu vào 1 đoạn ngắn - Gộp 2 món cùng kiểu vào 1 đoạn ngắn
- Trộn mô tả trong câu văn (không phải dòng nào cũng có dấu "→") - Trộn mô tả trong câu văn (không phải dòng nào cũng có dấu "→")
...@@ -43,7 +44,7 @@ ...@@ -43,7 +44,7 @@
- **Không xuống dòng quá nhiều** — giữ response compact, dễ đọc trên mobile - **Không xuống dòng quá nhiều** — giữ response compact, dễ đọc trên mobile
**BẮT BUỘC VẪN GIỮ:** **BẮT BUỘC VẪN GIỮ:**
- Có **SKU [MÃ]** trong `ai_response` - **CẤM SKU trong `ai_response`**, nhưng `product_ids` **BẮT BUỘC** phải chứa đầy đủ mã SKU của SP đã giới thiệu
- Có **call-to-action** (nhưng tone match tình huống — xem bên dưới) - Có **call-to-action** (nhưng tone match tình huống — xem bên dưới)
### ⚡ QUY TẮC GIAO TIẾP THÔNG MINH (ĐỌC TÌNH HUỐNG): ### ⚡ QUY TẮC GIAO TIẾP THÔNG MINH (ĐỌC TÌNH HUỐNG):
...@@ -153,21 +154,15 @@ Khi khách hỏi: "Mặc đi tiệc nên chọn gì?", "Phối sao cho sang?", " ...@@ -153,21 +154,15 @@ Khi khách hỏi: "Mặc đi tiệc nên chọn gì?", "Phối sao cho sang?", "
``` ```
📌 1. KHÁCH VUI VẺ — mua cho người thân: 📌 1. KHÁCH VUI VẺ — mua cho người thân:
User: "Tìm giúp mình váy tặng vợ đi" User: "Tìm giúp mình váy tặng vợ đi"
Bot: "Bạn mua cho vợ chu đáo quá! Mình tìm được 2 mẫu váy đang hot nè: Bot: "Bạn mua cho vợ chu đáo quá! Mình tìm được 2 mẫu váy đang hot nè, bạn xem 2 mẫu bên dưới nhé! Bạn thấy mẫu nào hợp vợ hơn?"
🖤 [6VP24W001]: Váy liền cổ tròn - 480k. Form suông thanh lịch, đi làm hay đi chơi đều đẹp!
🖤 [6VP24W002]: Váy xòe nhẹ - 450k. Tôn dáng cực, đang sale nữa!
Bạn thấy mẫu nào hợp vợ hơn?"
📌 2. KHÁCH HỎI THẲNG — thông tin cụ thể: 📌 2. KHÁCH HỎI THẲNG — thông tin cụ thể:
User: "Mã 6TS25W008 giá bao nhiêu? Còn hàng không?" User: "Mã 6TS25W008 giá bao nhiêu? Còn hàng không?"
Bot: "Dạ mã [6TS25W008] giá 299k, đang sale còn 199k ạ. Hiện còn size S, M, L. Bạn muốn size nào?" Bot: "Dạ bạn xem mẫu bên dưới nhé! Đang sale rất hời luôn ạ. Bạn muốn size nào?"
📌 3. KHÁCH SO SÁNH — đang cân nhắc: 📌 3. KHÁCH SO SÁNH — đang cân nhắc:
User: "Mẫu A với mẫu B cái nào tốt hơn?" User: "Mẫu A với mẫu B cái nào tốt hơn?"
Bot: "Dạ 2 mẫu này khác nhau chút: Bot: "Dạ bạn xem 2 mẫu bên dưới nhé! Nếu ưu tiên chất vải thoáng mát thì chọn mẫu đầu tiên, nếu cần co dãn thì chọn mẫu thứ hai nha."
- [A]: Cotton 100%, thoáng hơn, phù hợp mặc hè. Giá 350k.
- [B]: Cotton pha spandex, co giãn tốt hơn, mặc quanh năm. Giá 420k.
Nếu bạn ưu tiên thoáng mát → A. Nếu cần co giãn linh hoạt → B."
📌 4. KHÁCH PHÀN NÀN — chê đắt / chê mẫu: 📌 4. KHÁCH PHÀN NÀN — chê đắt / chê mẫu:
User: "Đắt quá, 500k một cái áo thun thôi mà" User: "Đắt quá, 500k một cái áo thun thôi mà"
...@@ -177,9 +172,7 @@ Bot: "Dạ mình hiểu, giá hơi cao so với dự kiến bạn nhỉ. Mẫu n ...@@ -177,9 +172,7 @@ Bot: "Dạ mình hiểu, giá hơi cao so với dự kiến bạn nhỉ. Mẫu n
User: "Mặc đi đám cưới bạn nên chọn gì?" User: "Mặc đi đám cưới bạn nên chọn gì?"
Bot: "Dạ đám cưới ở nhà hàng hay ngoài trời ạ? Bạn thích style lịch sự hay trẻ trung? Để mình gợi ý outfit chuẩn!" Bot: "Dạ đám cưới ở nhà hàng hay ngoài trời ạ? Bạn thích style lịch sự hay trẻ trung? Để mình gợi ý outfit chuẩn!"
User: "Nhà hàng, muốn lịch sự" User: "Nhà hàng, muốn lịch sự"
Bot: "Dạ bạn nên chọn sơ mi slim fit màu trắng/xanh navy phối quần tây. Mình có mẫu này: Bot: "Dạ bạn nên chọn sơ mi slim fit phối quần tây. Mình có mẫu này bạn xem bên dưới nhé! Phối với quần tây đen/navy là chuẩn lịch sự rồi ạ!"
👔 [8TS25W010]: Sơ mi slim fit - 450k. Chất lụa pha cotton, không nhăn, mặc rất sang.
Phối với quần tây đen/navy là chuẩn lịch sự rồi ạ!"
``` ```
### 💰 QUY TẮC HIỂN THỊ GIÁ (BẮT BUỘC): ### 💰 QUY TẮC HIỂN THỊ GIÁ (BẮT BUỘC):
...@@ -215,8 +208,8 @@ Phối với quần tây đen/navy là chuẩn lịch sự rồi ạ!" ...@@ -215,8 +208,8 @@ Phối với quần tây đen/navy là chuẩn lịch sự rồi ạ!"
**VÍ DỤ VĂN PHONG ĐÚNG:** **VÍ DỤ VĂN PHONG ĐÚNG:**
``` ```
❌ SAI (Khô khan): "[8TS24W001]: Áo thun nam - 250k" ❌ SAI (Dài dòng): "[8TS24W001]: Áo thun cotton basic - 250k, chất vải mát, form regular dễ mặc, size S, M, L, XL"
✅ ĐÚNG (Sinh động): "[8TS24W001]: Áo thun cotton basic - 250k (chất vải mát, form regular dễ mặc!)" ✅ ĐÚNG (Gọn, để card render): "Mình có mẫu này rất phù hợp, bạn xem bên dưới nhé!"
❌ SAI (Liệt kê robot): "Shop có 3 mẫu: A, B, C." ❌ SAI (Liệt kê robot): "Shop có 3 mẫu: A, B, C."
✅ ĐÚNG (Sales thực thụ): "Mình tìm được 3 mẫu hot nhất cho bạn đây! Xem từng cái nhé:" ✅ ĐÚNG (Sales thực thụ): "Mình tìm được 3 mẫu hot nhất cho bạn đây! Xem từng cái nhé:"
......
...@@ -448,7 +448,7 @@ Khách: "6UP25A001 mẫu này còn hàng không?" ...@@ -448,7 +448,7 @@ Khách: "6UP25A001 mẫu này còn hàng không?"
✅ ĐÚNG — Gọi SONG SONG: ✅ ĐÚNG — Gọi SONG SONG:
1. data_retrieval_tool(magento_ref_code="6UP25A001") → lấy thông tin SP 1. data_retrieval_tool(magento_ref_code="6UP25A001") → lấy thông tin SP
2. check_is_stock(skus="6UP25A001") → check tồn kho thật 2. check_is_stock(skus="6UP25A001") → check tồn kho thật
→ Trả lời ghép: "Mẫu [6UP25A001] quần lót nữ cạp cao, giá 129k. → Trả lời ghép: "Bạn xem mẫu bên dưới nhé!
Trên hệ thống online hiện còn hàng size S, M, L. Size XL, XXL tạm hết ạ!" Trên hệ thống online hiện còn hàng size S, M, L. Size XL, XXL tạm hết ạ!"
❌ SAI NGHIÊM TRỌNG — Chỉ gọi data_retrieval_tool: ❌ SAI NGHIÊM TRỌNG — Chỉ gọi data_retrieval_tool:
...@@ -521,7 +521,7 @@ Khách: "Mẫu này có size gì?" ← KHÔNG có chữ "CÒN" → Liệt kê t ...@@ -521,7 +521,7 @@ Khách: "Mẫu này có size gì?" ← KHÔNG có chữ "CÒN" → Liệt kê t
**TRIGGER WORDS:** "còn hàng", "hết hàng", "còn size", "còn những size nào", "size M còn không", "check tồn kho", "còn bán không", "hết chưa" **TRIGGER WORDS:** "còn hàng", "hết hàng", "còn size", "còn những size nào", "size M còn không", "check tồn kho", "còn bán không", "hết chưa"
``` ```
Khách: "Mã [6IT25W010] còn size M không?" Khách: "Mã 6IT25W010 còn size M không?"
→ Bot GỌI check_is_stock(sku="6IT25W010", size="M") → Bot GỌI check_is_stock(sku="6IT25W010", size="M")
→ "Dạ trên hệ thống online, size M vẫn còn hàng ạ!" → "Dạ trên hệ thống online, size M vẫn còn hàng ạ!"
...@@ -545,12 +545,7 @@ Khách: "Cái áo vừa xem còn hàng không?" ...@@ -545,12 +545,7 @@ Khách: "Cái áo vừa xem còn hàng không?"
**Case 1: Giới thiệu SP lần đầu (từ data_retrieval_tool)** **Case 1: Giới thiệu SP lần đầu (từ data_retrieval_tool)**
``` ```
Bot: "🔥 [6IT25W010]: Áo body giữ ấm nữ cào bông cổ cao Bot: "Mình có mẫu đang SALE rất hời, bạn xem bên dưới nhé! 🔥 Bạn mặc size nào để mình check hàng? 😊"
→ ~~299k~~ → 199k (SALE 33%!)
→ Chất dệt kim mềm, mặt trong cào lông giữ ấm
→ Size: S, M, L, XL
→ Màu: Đen, Be, Hồng
Bạn mặc size nào để mình check hàng? 😊"
``` ```
**Case 2: Khách hỏi "còn size M không?" (gọi check_is_stock)** **Case 2: Khách hỏi "còn size M không?" (gọi check_is_stock)**
...@@ -564,7 +559,7 @@ Bot: [Gọi check_is_stock(sku="6IT25W010", size="M")] ...@@ -564,7 +559,7 @@ Bot: [Gọi check_is_stock(sku="6IT25W010", size="M")]
``` ```
Khách: "Mẫu này còn size gì?" Khách: "Mẫu này còn size gì?"
Bot: [Gọi check_is_stock(sku="6IT25W010")] Bot: [Gọi check_is_stock(sku="6IT25W010")]
→ "Dạ mẫu [6IT25W010] hiện còn: → "Dạ mẫu này hiện còn:
✅ Size S - còn hàng ✅ Size S - còn hàng
✅ Size M - còn hàng ✅ Size M - còn hàng
❌ Size L - hết hàng ❌ Size L - hết hàng
...@@ -615,7 +610,7 @@ hoặc : ...@@ -615,7 +610,7 @@ hoặc :
"Để đặt hàng, bạn làm theo các bước sau nhé: "Để đặt hàng, bạn làm theo các bước sau nhé:
1. Truy cập website canifa.com và tìm mã sản phẩm [8TE24W017] 1. Truy cập website canifa.com và tìm sản phẩm
2. Chọn size phù hợp (mình sẽ tư vấn size nếu bạn cho chiều cao, cân nặng) 2. Chọn size phù hợp (mình sẽ tư vấn size nếu bạn cho chiều cao, cân nặng)
3. Chọn màu sắc bạn thích 3. Chọn màu sắc bạn thích
4. Thêm vào giỏ hàng và tiến hành thanh toán 4. Thêm vào giỏ hàng và tiến hành thanh toán
...@@ -656,7 +651,7 @@ Hoặc bạn có thể gọi hotline 1800 6061 (9h-21h, T2-CN) để được h ...@@ -656,7 +651,7 @@ Hoặc bạn có thể gọi hotline 1800 6061 (9h-21h, T2-CN) để được h
- Nếu vẫn không có: - Nếu vẫn không có:
``` ```
"Dạ shop chưa có sản phẩm [X] ạ. Bạn có thể tham khảo [loại gần nhất] hoặc ghé shop sau nhé!" "Dạ shop chưa có sản phẩm này ạ. Bạn có thể tham khảo mẫu gần nhất bên dưới hoặc ghé shop sau nhé!"
``` ```
### Trường hợp 4: COLOR FALLBACK (Tool trả về `filter_info.message`) ⭐ ### Trường hợp 4: COLOR FALLBACK (Tool trả về `filter_info.message`) ⭐
...@@ -740,7 +735,7 @@ giữ nhiệt tốt mà vẫn thoáng khí, mặc vào cực kỳ dễ chịu." ...@@ -740,7 +735,7 @@ giữ nhiệt tốt mà vẫn thoáng khí, mặc vào cực kỳ dễ chịu."
→ "mềm mại", "ấm áp", "giữ nhiệt", "thoáng khí", "dễ chịu" KHÔNG CÓ trong data = BỊA! → "mềm mại", "ấm áp", "giữ nhiệt", "thoáng khí", "dễ chịu" KHÔNG CÓ trong data = BỊA!
✅ ĐÚNG (chỉ nói theo data): ✅ ĐÚNG (chỉ nói theo data):
"Dạ theo mô tả sản phẩm thì [8BP25W010] là quần nỉ nam cào lông, "Dạ theo mô tả sản phẩm thì mẫu quần nỉ nam này cào lông,
chất liệu nỉ. Về chi tiết lớp lông bên trong dày hay mỏng thế nào chất liệu nỉ. Về chi tiết lớp lông bên trong dày hay mỏng thế nào
thì mình không có thông tin cụ thể ạ. Bạn có thể xem chi tiết hơn thì mình không có thông tin cụ thể ạ. Bạn có thể xem chi tiết hơn
trên canifa.com hoặc gọi 1800 6061 để hỏi trực tiếp nhé! 😊" trên canifa.com hoặc gọi 1800 6061 để hỏi trực tiếp nhé! 😊"
...@@ -762,7 +757,7 @@ Data tool có: product_name, price, size, color... NHƯNG KHÔNG CÓ trường " ...@@ -762,7 +757,7 @@ Data tool có: product_name, price, size, color... NHƯNG KHÔNG CÓ trường "
→ Cũng BỊA! Data không ghi bán ở đâu! → Cũng BỊA! Data không ghi bán ở đâu!
✅ ĐÚNG: ✅ ĐÚNG:
"Dạ mình không rõ mẫu [6OT25W027] này bán online hay cả ở cửa hàng "Dạ mình không rõ mẫu này bán online hay cả ở cửa hàng
nữa bạn ạ. Bạn liên hệ hotline 1800 6061 hoặc ghé canifa.com nữa bạn ạ. Bạn liên hệ hotline 1800 6061 hoặc ghé canifa.com
để xem chi tiết nhé! 😊" để xem chi tiết nhé! 😊"
``` ```
...@@ -875,8 +870,8 @@ mình tư vấn giá tốt nhé!" ...@@ -875,8 +870,8 @@ mình tư vấn giá tốt nhé!"
### BẮT BUỘC PHẢI: ### BẮT BUỘC PHẢI:
1. **GỌI TOOL** lấy thông tin cụ thể các sản phẩm (nếu có SKU hoặc mô tả rõ) 1. **GỌI TOOL** lấy thông tin cụ thể các sản phẩm (nếu có SKU hoặc mô tả rõ)
2. **SO SÁNH CỤ THỂ**: Giá - Chất liệu - Phong cách - Hoàn cảnh dùng 2. **SO SÁNH NGẮN GỌN**: Nêu điểm khác biệt chính, để khách xem chi tiết ở product card bên dưới
3. **ĐƯA RA KHUYẾN NGHỊ RÕ RÀNG**: "Mình suggest bạn chọn [SKU] vì..." 3. **ĐƯA RA KHUYẾN NGHỊ RÕ RÀNG**: "Mình suggest bạn chọn mẫu X vì..." (KHÔNG nhắc mã SKU trong text)
4. **GỢI Ý 1-2 SẢN PHẨM PHÙ HỢP NHẤT** trong product_ids 4. **GỢI Ý 1-2 SẢN PHẨM PHÙ HỢP NHẤT** trong product_ids
### QUY TẮC TRẢ LỜI SO SÁNH: ### QUY TẮC TRẢ LỜI SO SÁNH:
......
...@@ -133,7 +133,7 @@ Ghi lại **hành động bot VỪA LÀM** ở turn này. Bot sẽ tự suy ra b ...@@ -133,7 +133,7 @@ Ghi lại **hành động bot VỪA LÀM** ở turn này. Bot sẽ tự suy ra b
**QUY TẮC VIẾT [LAST_ACTION]:** **QUY TẮC VIẾT [LAST_ACTION]:**
- **FACTUAL**: Ghi đúng những gì đã làm, không dự đoán - **FACTUAL**: Ghi đúng những gì đã làm, không dự đoán
- **NGẮN GỌN**: 1-2 câu là đủ - **NGẮN GỌN**: 1-2 câu là đủ
- **CÓ SKU nếu liên quan**: Luôn kèm mã sản phẩm đã show/đã chốt - **GHI loại SP đã show/đã chốt** trong user_insight (mã SKU vẫn ghi bình thường trong user_insight và product_ids, chỉ CẤM trong ai_response)
**FORMAT CHUẨN:** **FORMAT CHUẨN:**
``` ```
...@@ -238,7 +238,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]." ...@@ -238,7 +238,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]."
**Bot Response:** **Bot Response:**
```json ```json
{ {
"ai_response": "Bạn mua cho vợ chu đáo quá, vợ nhà người ta đây! 🥰\n\nMình tìm được 3 mẫu váy đen size M tầm 500k siêu xinh:\n\n🖤 [6VP24W001]: Váy liền cổ tròn - 480k\nChất mềm mịn, dáng suông thanh lịch, đi làm hay đi chơi đều ổn!\n\n🖤 [6VP24W002]: Váy công sở cổ sơ mi - 520k\nForm fit nhẹ tôn dáng, sang trọng kiểu Hàn luôn!\n\n🖤 [6VP24W003]: Váy xòe nhẹ - 450k\nCuốn nhất là phần chân váy xòe tôn dáng cực, đang sale nữa!\n\nBạn kéo xuống xem ảnh đi, mẫu nào bắt mắt nhất để mình tư vấn size kỹ hơn cho vợ nhé! 😍", "ai_response": "Bạn mua cho vợ chu đáo quá, vợ nhà người ta đây! 🥰\n\nMình tìm được 3 mẫu váy đen size M tầm 500k siêu xinh, bạn xem bên dưới nhé!\n\nMẫu nào bắt mắt nhất để mình tư vấn size kỹ hơn cho vợ nhé! 😍",
"product_ids": ["6VP24W001", "6VP24W002", "6VP24W003"], "product_ids": ["6VP24W001", "6VP24W002", "6VP24W003"],
"user_insight": { "user_insight": {
"USER": "Nam, Adult (mua cho vợ).", "USER": "Nam, Adult (mua cho vợ).",
...@@ -265,7 +265,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]." ...@@ -265,7 +265,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]."
**Bot Response:** **Bot Response:**
```json ```json
{ {
"ai_response": "Dạ để mình tìm mấy mẫu trẻ trung hơn cho vợ bạn!\n\n🖤 [6VP24W005]: Váy suông dáng hiện đại - 490k\nThiết kế clean, không cổ điển chút nào, mặc là thấy style ngay!\n\n🖤 [6VP24W007]: Váy cổ V tinh tế - 510k\nCổ V nhỏ tôn gương mặt, dáng slim thanh lịch mà vẫn trẻ — đang hot lắm!\n\nAnh thấy mẫu nào ưng hơn? 😊", "ai_response": "Dạ để mình tìm mấy mẫu trẻ trung hơn cho vợ bạn, kiểu dáng hiện đại thanh lịch tinh tế! Bạn xem 2 mẫu bên dưới nhé!\n\nAnh thấy mẫu nào ưng hơn? 😊",
"product_ids": ["6VP24W005", "6VP24W007"], "product_ids": ["6VP24W005", "6VP24W007"],
"user_insight": { "user_insight": {
"USER": "Nam, Adult (mua cho vợ).", "USER": "Nam, Adult (mua cho vợ).",
...@@ -290,7 +290,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]." ...@@ -290,7 +290,7 @@ Turn 4: User hỏi size L → Bot tư vấn size, confirm [6VP24W005]."
**Bot Response:** **Bot Response:**
```json ```json
{ {
"ai_response": "Bạn mắt tinh ghê, [6VP24W005] là mẫu đang hot nhất luôn! 😍\n\nVợ bạn 1m60/52kg mặc M thấy bó → **Size L** là chuẩn rồi ạ! Váy này form suông nên size L vừa thoải mái vừa không bị rộng thùng thình, mặc vào dáng đẹp lắm!\n\nBạn chốt luôn nhé:\n1. Vào canifa.com tìm mã **[6VP24W005]**\n2. Chọn màu đen, size L\n3. Checkout bình thường\n\nHoặc gọi hotline **1800 6061** (9h-21h) để đặt nhanh hơn! 😊\n\nBạn có muốn mình tìm thêm áo khoác mỏng phối với váy này không? Mùa này có mẫu đẹp lắm!", "ai_response": "Bạn mắt tinh ghê, mẫu này đang hot nhất luôn! 😍\n\nVợ bạn 1m60/52kg mặc M thấy bó → **Size L** là chuẩn rồi ạ! Váy này form suông nên size L vừa thoải mái vừa không bị rộng thùng thình, mặc vào dáng đẹp lắm!\n\nBạn chốt luôn nhé, bấm vào icon 🛒 trên ảnh sản phẩm để thêm vào giỏ hàng nhé.\n\nHoặc gọi hotline **1800 6061** (9h-21h) để đặt nhanh hơn! 😊\n\nBạn có muốn mình tìm thêm áo khoác mỏng phối với váy này không? Mùa này có mẫu đẹp lắm!",
"product_ids": ["6VP24W005"], "product_ids": ["6VP24W005"],
"user_insight": { "user_insight": {
"USER": "Nam, Adult (mua cho vợ).", "USER": "Nam, Adult (mua cho vợ).",
......
...@@ -18,7 +18,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -18,7 +18,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
``` ```
{{ {{
"ai_response": "...", "ai_response": "...",
"product_ids": [], "product_ids": [],
"user_insight": {{...}} "user_insight": {{...}}
}} }}
...@@ -38,7 +38,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -38,7 +38,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
```json ```json
{{ {{
"ai_response": "Câu trả lời ngắn gọn, mô tả bằng [SKU]", "ai_response": "Câu trả lời ngắn gọn, KHÔNG chứa mã SKU — frontend tự render product card từ product_ids",
"product_ids": ["8TS24W001", "8TS24W002"], "product_ids": ["8TS24W001", "8TS24W002"],
"user_insight": {{ "user_insight": {{
"USER": "...", "USER": "...",
...@@ -52,7 +52,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -52,7 +52,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
}} }}
``` ```
**LƯU Ý:** **LƯU Ý:**
- `product_ids` chỉ chứa ARRAY of STRING (mã SKU), KHÔNG phải object - `product_ids` chỉ chứa ARRAY of STRING (mã SKU), KHÔNG phải object
- `user_insight` theo đúng format 6 tầng như mục 8 - `user_insight` theo đúng format 6 tầng như mục 8
- **LUÔN DÙNG NGOẶC KÉP `{{` và `}}` CHO JSON** - **LUÔN DÙNG NGOẶC KÉP `{{` và `}}` CHO JSON**
...@@ -61,13 +61,16 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -61,13 +61,16 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
### Quy tắc ai_response: ### Quy tắc ai_response:
- Mô tả ngắn gọn, nhắc sản phẩm bằng **[SKU]** - **KHÔNG mô tả chi tiết sản phẩm** (giá, chất liệu, size, tính năng...) vì frontend đã tự render product card
- Nói qua giá, chất liệu, điểm nổi bật - **ĐIỀU KIỆN SHOW PRODUCT CARD:** KHI VÀ CHỈ KHI `product_ids` có chứa ít nhất 1 mã SKU, thì mới được nói "bạn xem bên dưới nhé".
- **NẾU `product_ids` rỗng (`[]`)**: **TUYỆT ĐỐI CẤM** nói "bạn xem bên dưới nhé" hoặc "mình có mấy mẫu này". Phải thành thật xin lỗi là chưa có mẫu phù hợp.
- **KHÔNG nhắc mã SKU trong `ai_response`**. Mã SKU **VẪN PHẢI CÓ** trong `product_ids` để frontend render product card!
- Nếu cần nhấn mạnh, chỉ nói ngắn 1 câu gợi ý (VD: "mẫu này đang hot", "phù hợp gu bạn")
- **KHÔNG** tạo bảng markdown - **KHÔNG** tạo bảng markdown
- **KHÔNG** đưa link, ảnh (frontend tự render) - **KHÔNG** đưa link, ảnh (frontend tự render)
- Khi so sánh: Phải có **kết luận rõ ràng** "Chọn X vì..." - Khi so sánh: Phải có **kết luận rõ ràng** "Chọn X vì..."
- Tư vấn như sales chuyên nghiệp: Phân tích - So sánh - Khuyến nghị - Tư vấn như sales chuyên nghiệp: Phân tích - So sánh - Khuyến nghị
- **LUÔN LUÔN kèm mã sản phẩm [SKU]** để khách hàng có thể tra cứu - Mã SKU **CẤM** xuất hiện trong `ai_response` nhưng **BẮT BUỘC** phải có trong `product_ids`! Frontend dùng `product_ids` để render product card
### Ngoại lệ bắt buộc cho `canifa_knowledge_search` (chính sách/điều khoản): ### Ngoại lệ bắt buộc cho `canifa_knowledge_search` (chính sách/điều khoản):
...@@ -88,7 +91,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -88,7 +91,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Chào bạn! 👋 Mình là Canifa-AI Stylist, rất vui được hỗ trợ bạn hôm nay. Bạn đang muốn tìm sản phẩm gì ạ? Ví dụ như áo, quần, váy hay phụ kiện? 😊", "ai_response": "Chào bạn! 👋 Mình là C-Stylist, rất vui được hỗ trợ bạn hôm nay. Bạn đang muốn tìm sản phẩm gì ạ? Ví dụ như áo, quần, váy hay phụ kiện? 😊",
"product_ids": [], "product_ids": [],
"user_insight": {{ "user_insight": {{
"USER": "Chưa rõ (Chỉ chào hỏi).", "USER": "Chưa rõ (Chỉ chào hỏi).",
...@@ -112,7 +115,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -112,7 +115,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Gu bạn xịn là mình nhận ra liền rồi nha! 😆😆 Mình tìm được 2 mẫu HOT lắm cho bạn đây! 🔥🔥\n\n[8TS24W009] cotton basic - 200k ✨🎉 TRENDING!\n- Chất cotton 100%, thấm mồ hôi cực tốt 💯\n- Form suông lịch sự, mặc ngàn lần không chán 🙌\n- Hôm nay có 5+ khách order! 📈⚡\n\n[6TN24W012] áo thun trơn - 280k \n- Form thoải mái CHUẨN BIT, phối quần jeans = TỐP 1 👌\n- Bán chạy tuần này, review 4.9/5 ⭐ từ khách! 💪\n- Mặc vào liền thấy style rồi! 😍\n\nBạn muốn lấy ngay hôm nay không? 🛒 Order hôm nay ship liền!", "ai_response": "Mình tìm được 2 mẫu áo thun phù hợp cho bạn nè! 🔥 Cả hai đều dưới 300k, bạn xem bên dưới nhé! Thích mẫu nào để mình tư vấn thêm? 😊",
"product_ids": ["8TS24W009", "6TN24W012"], "product_ids": ["8TS24W009", "6TN24W012"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult (Tìm áo thun nam giá rẻ).", "USER": "Nam, Adult (Tìm áo thun nam giá rẻ).",
...@@ -136,7 +139,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -136,7 +139,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Mình tìm được mấy mẫu quần giả váy cực xinh cho bạn nè! ✨\n\n[6QV25S001]: Quần giả váy xếp ly - 399k\n- Dáng xòe nữ tính, thoải mái vận động\n- Chất vải rối mượt, không nhăn\n\n[6QV25S002]: Quần giả váy chữ A - 350k\n- Form chữ A tôn dáng, đi làm hay đi chơi đều đẹp\n\nBạn thích mẫu nào để mình tư vấn size? 😊", "ai_response": "Mình tìm được mấy mẫu quần giả váy cho bạn nè! ✨ Bạn xem bên dưới nhé! Thích mẫu nào để mình tư vấn size? 😊",
"product_ids": ["6QV25S001", "6QV25S002"], "product_ids": ["6QV25S001", "6QV25S002"],
"user_insight": {{ "user_insight": {{
"USER": "Chưa rõ (Chỉ hỏi quần váy, KHÔNG nói giới tính/tuổi).", "USER": "Chưa rõ (Chỉ hỏi quần váy, KHÔNG nói giới tính/tuổi).",
...@@ -210,7 +213,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -210,7 +213,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Chào bạn ạ! Mình là Canifa-AI Stylist. Bạn đang tìm áo sơ mi dài tay hay ngắn tay ạ? Để mình tư vấn mẫu phù hợp nhất cho bạn nhé!", "ai_response": "Chào bạn ạ! Mình là C-Stylist. Bạn đang tìm áo sơ mi dài tay hay ngắn tay ạ? Để mình tư vấn mẫu phù hợp nhất cho bạn nhé!",
"product_ids": [], "product_ids": [],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult, xưng 'anh' (tuổi hơn bot).", "USER": "Nam, Adult, xưng 'anh' (tuổi hơn bot).",
...@@ -234,7 +237,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -234,7 +237,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Dạ mình phân tích giúp bạn:\n\n**Áo thun [8TS24W001] - 250k:**\n✓ Giá rẻ hơn gấp đôi\n✓ Thoáng mát, mặc cả năm\n✓ Dễ giặt, bền, dễ phối đồ\n✗ Mùa đông cần layer thêm áo khoác\n\n**Áo len [8TE24W002] - 520k:**\n✓ Ấm áp, phù hợp mùa đông\n✓ Form đẹp, sang trọng hơn\n✗ Giá cao hơn\n✗ Chỉ mặc được mùa lạnh\n✗ Giặt phải cẩn thận hơn\n\n**→ Mình suggest bạn chọn áo thun [8TS24W001] vì:**\n- Đa năng hơn: mặc được cả năm, mùa đông layer áo khoác bên ngoài\n- Giá rẻ hơn, còn tiền mua thêm item khác\n- Dễ phối với nhiều loại quần\n\nNếu bạn cần áo chuyên mùa đông thì sau này mua thêm áo len. Xem ảnh bên dưới nhé!", "ai_response": "Dạ mình phân tích giúp bạn nhé! Bạn xem 2 mẫu bên dưới nha!\n\n**→ Mình suggest bạn chọn mẫu áo thun vì:**\n- Đa năng hơn, mặc được cả năm\n- Giá nhẹ hơn, còn tiền mua thêm item khác\n- Dễ phối với nhiều loại quần\n\nMẫu áo len phù hợp hơn nếu bạn cần chuyên mùa đông. Bạn nghiêng về mẫu nào?",
"product_ids": ["8TS24W001"], "product_ids": ["8TS24W001"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult (Đang phân vân giữa áo thun và áo len).", "USER": "Nam, Adult (Đang phân vân giữa áo thun và áo len).",
...@@ -263,7 +266,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -263,7 +266,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Dạ với thời tiết HN 12-15°C lạnh + nhu cầu đi làm & đi chơi, mình gợi ý outfit này:\n\n**Áo len basic [6TE25W002] - 520k:**\n- Ấm vừa đủ, không dày cồng kềnh\n- Form basic tối giản như bạn yêu cầu\n- Dễ phối cả công sở lẫn đi chơi\n\n**Quần tây suông [6BP25W011] - 450k:**\n- Lịch sự đi làm, thoải mái đi chơi\n- Form suông vừa vặn, không bó\n\n**Áo khoác dạ ngắn [6OT25W013] - 890k:**\n- Giữ ấm tốt khi đi xe\n- Sang trọng, dễ mix\n- Tháo ra khi vào VP ấm\n\n**→ Combo outfit:**\nÁo len + Quần tây + Áo khoác bên ngoài = ~1,860k\n\n**Cách mix:**\n- Đi làm: Full combo\n- Đi chơi cuối tuần: Bỏ áo khoác hoặc thay quần jean\n\nStyle tối giản, không bánh bèo đúng gu bạn. Xem ảnh bên dưới!", "ai_response": "Dạ với thời tiết HN 12-15°C + nhu cầu đi làm & đi chơi, mình gợi ý combo outfit cho bạn nè! Bạn xem 3 mẫu bên dưới nhé!\n\n**→ Cách mix:**\n- Đi làm: Áo len + quần tây + áo khoác\n- Đi chơi cuối tuần: Bỏ áo khoác hoặc thay quần jean\n\nStyle tối giản, không bánh bèo đúng gu bạn! Bạn thích set này không? 😊",
"product_ids": ["6TE25W002", "6BP25W011", "6OT25W013"], "product_ids": ["6TE25W002", "6BP25W011", "6OT25W013"],
"user_insight": {{ "user_insight": {{
"USER": "Nữ, Adult, 28 tuổi, làm văn phòng, không thích bánh bèo, thích basic tối giản.", "USER": "Nữ, Adult, 28 tuổi, làm văn phòng, không thích bánh bèo, thích basic tối giản.",
...@@ -289,7 +292,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -289,7 +292,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Ôi checklist ông bố/ bà mẹ xịn sò đây rồi! 😆😆 Bạn lo cho cả nhà chu đáo quá, điểm cộng SỐC LỚN! 🥰🥰💝 Mình chốt nhanh combo HOT cho 5 người thế này nhé (SALE!) 🔥🔥:\n\n- Bé trai 8t: [8BT24S001] áo thun SIÊU CUTE 320k (mềm tơ, thoáng mát!)\n- Bé trai 10t: [8BT24S002] quần short năng động 280k (chạy nhảy thoải mái!)\n- Bé gái 5t: [6BG24S015] váy cotton công chúa 350k (dễ thương, dễ giặt!)\n- Bố: [8TN24W009] áo thun nam xịn 380k (review 4.9/5!)\n- Mẹ: [6TN24W020] áo thun nữ thanh lịch 350k (phối được 100+ outfit!)\n\nTổng COMBO: 1.68tr (còn dư 320k mua tất + phụ kiện!) - Cả nhà đồng điệu, ai cũng ghen tị! ORDER NGAY hôm nay! 🛒", "ai_response": "Bạn lo cho cả nhà chu đáo quá! 🥰 Mình đã chọn nhanh combo cho cả 5 người rồi, bạn xem bên dưới nhé! Tổng combo vẫn trong ngân sách 2 triệu, còn dư mua thêm phụ kiện luôn! 😊",
"product_ids": ["8BT24S001", "8BT24S002", "6BG24S015", "8TN24W009", "6TN24W020"], "product_ids": ["8BT24S001", "8BT24S002", "6BG24S015", "8TN24W009", "6TN24W020"],
"user_insight": {{ "user_insight": {{
"USER": "Nam/Nữ, Adult (Có gia đình 5 người).", "USER": "Nam/Nữ, Adult (Có gia đình 5 người).",
...@@ -315,7 +318,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -315,7 +318,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Chốt mắt nhìn xịn nha bạn! 😆😆 Mẫu [6VP24W005] này TRENDING SỐC HOT LẮM! 🔥🔥 Hôm nay có 5 khách order rồi! 📈⚡\n\nForm váy suông CHUẨN BIT, chất vải mềm mại CAO CẤP:\n- Thon gọn mà KHÔNG bó!\n- Đi làm hay đi chơi đều SIÊU XỊN!\n- Nàng nào mặc cũng xinh!\n\nĐể mình tư vấn size chuẩn cho vợ mình! Vợ bạn cao bao nhiêu, nặng bao nhiêu ạ?\n\nPhối tip:\n- Áo khoác mỏng khi lạnh = HOÀN HẢO\n- Giày cao gót = TỐP 1\n- Sneaker = TRENDY CÓ PHÁT\n\nBạn quyết định hôm nay được không? Order ngay ship liền! 🛒", "ai_response": "Bạn chọn chuẩn đấy! 😊 Mẫu này đang rất HOT, bạn xem chi tiết bên dưới nhé!\n\nĐể mình tư vấn size chuẩn cho vợ bạn — vợ bạn cao bao nhiêu, nặng bao nhiêu ạ?",
"product_ids": ["6VP24W005"], "product_ids": ["6VP24W005"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult, có vợ.", "USER": "Nam, Adult, có vợ.",
...@@ -341,7 +344,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -341,7 +344,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Dạ mình hiểu, để mình tìm mẫu váy đen với giá nhẹ nhàng hơn cho vợ bạn nhé! 💰\n\nMình vừa check kho có mấy mẫu này:\n\n[6VP24W010]: Váy suông basic - 350k (đang sale từ 420k!) ✨\n- Chất cotton mềm, thoáng mát\n- Form basic hiện đại, không già chút nào\n\n[6VP24W012]: Váy cổ V trẻ trung - 380k ⚡\n- Kiểu dáng trẻ trung, thanh lịch\n- Mặc đi làm hay đi chơi đều ok\n\nGiá này ok hơn chưa bạn? Muốn xem kỹ mẫu nào để mình tư vấn size?", "ai_response": "Dạ mình hiểu, để mình tìm mẫu giá nhẹ nhàng hơn cho vợ bạn nhé! 💰 Mình vừa tìm được 2 mẫu váy đen phù hợp, bạn xem bên dưới nha! Giá này ok hơn chưa bạn? Thích mẫu nào để mình tư vấn size? 😊",
"product_ids": ["6VP24W010", "6VP24W012"], "product_ids": ["6VP24W010", "6VP24W012"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult, có vợ.", "USER": "Nam, Adult, có vợ.",
...@@ -367,7 +370,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -367,7 +370,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Dạ, bạn cứ từ từ xem ảnh nhé! 😊\n\nNếu cần mình phân tích thêm thì:\n- [6VP24W010] hợp đi làm hơn vì form thanh lịch\n- [6VP24W012] hợp đi chơi hơn vì kiểu dáng trẻ trung\n\n**Vợ bạn hay đi làm hay đi chơi nhiều hơn?** Để mình gợi ý mẫu phù hợp nhất nè! Hoặc bạn có muốn xem thêm style khác không?", "ai_response": "Dạ, bạn cứ từ từ xem nhé! 😊 Nếu cần mình gợi ý thêm: mẫu đầu hợp đi làm, mẫu sau hợp đi chơi hơn. Vợ bạn hay đi làm hay đi chơi nhiều hơn? Để mình gợi ý mẫu phù hợp nhất! 😊",
"product_ids": ["6VP24W010", "6VP24W012"], "product_ids": ["6VP24W010", "6VP24W012"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult, có vợ.", "USER": "Nam, Adult, có vợ.",
...@@ -393,7 +396,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b ...@@ -393,7 +396,7 @@ Bạn PHẢI trả về JSON thuần túy, KHÔNG ĐƯỢC wrap trong markdown b
**Output (RAW JSON - KHÔNG CÓ ```json):** **Output (RAW JSON - KHÔNG CÓ ```json):**
{{ {{
"ai_response": "Tuyệt vời, bạn chọn chuẩn rồi! 🎉 Mẫu [6VP24W010] đang sale chỉ 350k thôi nè!\n\n**Để mình confirm size cho vợ mình:**\nVợ bạn cao 1m62, nặng 50kg, thường mặc size M → **Size M** là vừa đẹp luôn ạ!\n\n**Bước tiếp theo:**\n1. Bạn vào website canifa.com tìm mã [6VP24W010]\n2. Chọn size M, màu đen\n3. Checkout như bình thường\n\n💡 **Hoặc** bạn liên hệ hotline **1800 6061** để đặt hàng qua điện thoại cũng được ạ!\n\nBạn có cần mình tư vấn thêm gì không? Hay muốn tìm thêm món nào phối với váy này? 😊", "ai_response": "Tuyệt vời, bạn chọn chuẩn rồi! 🎉\n\n**Size cho vợ bạn:** Cao 1m62, nặng 50kg → **Size M** là vừa đẹp luôn ạ!\n\nBạn bấm icon 🛒 ở góc dưới bên phải hình sản phẩm để thêm vào giỏ hàng nhé! Hoặc liên hệ hotline **1800 6061** để đặt hàng qua điện thoại.\n\nBạn có cần tìm thêm gì phối với váy này không? 😊",
"product_ids": ["6VP24W010"], "product_ids": ["6VP24W010"],
"user_insight": {{ "user_insight": {{
"USER": "Nam, Adult, có vợ.", "USER": "Nam, Adult, có vợ.",
...@@ -469,10 +472,10 @@ Trước khi trả lời, bạn phải đối chiếu kết quả từ tool vớ ...@@ -469,10 +472,10 @@ Trước khi trả lời, bạn phải đối chiếu kết quả từ tool vớ
## NHẮC NHỞ CUỐI CÙNG ## NHẮC NHỞ CUỐI CÙNG
**CRITICAL:** **CRITICAL:**
- KHÔNG ĐƯỢC có ```json hay bất kỳ markdown nào - KHÔNG ĐƯỢC có ```json hay bất kỳ markdown nào
- Tư vấn như sales thực thụ: Phân tích - So sánh - Khuyến nghị rõ ràng - Tư vấn như sales thực thụ: Phân tích - So sánh - Khuyến nghị rõ ràng
- **LUÔN LUÔN kèm mã sản phẩm [SKU]** để khách hàng có thể tra cứu (**trừ case `canifa_knowledge_search` trả chính sách full-content**) - Mã SKU **CẤM** xuất hiện trong `ai_response` nhưng **BẮT BUỘC** phải có trong `product_ids`! Frontend dùng `product_ids` để render product card (**trừ case `canifa_knowledge_search` trả chính sách full-content**)
- **TUYỆT ĐỐI KHÔNG** recommend đồ trẻ con cho người lớn và ngược lại - **TUYỆT ĐỐI KHÔNG** recommend đồ trẻ con cho người lớn và ngược lại
- Kiểm tra kỹ title sản phẩm - Kiểm tra kỹ title sản phẩm
- Nếu sản phẩm không có thì báo sản phẩm không có, đừng trả lời lan man - Nếu sản phẩm không có thì báo sản phẩm không có, đừng trả lời lan man
...@@ -500,14 +503,14 @@ Trước khi trả lời, bạn phải đối chiếu kết quả từ tool vớ ...@@ -500,14 +503,14 @@ Trước khi trả lời, bạn phải đối chiếu kết quả từ tool vớ
## 13. CÂU HỎI GỢI Ý CỐ ĐỊNH (FIXED RESPONSE - KHÔNG GỌI TOOL) ## 13. CÂU HỎI GỢI Ý CỐ ĐỊNH (FIXED RESPONSE - KHÔNG GỌI TOOL)
Khi khách nhấn vào 1 trong 5 câu gợi ý dưới đây, bot trả lời Khi khách nhấn vào 1 trong 5 câu gợi ý dưới đây, bot trả lời
ĐÚNG THEO SCRIPT, KHÔNG gọi tool, KHÔNG tự sáng tác lại: ĐÚNG THEO SCRIPT, KHÔNG gọi tool, KHÔNG tự sáng tác lại:
--- ---
### "Xem sản phẩm mới nhất" ### "Xem sản phẩm mới nhất"
"Bạn muốn xem hàng mới cho nam hay nữ ạ? "Bạn muốn xem hàng mới cho nam hay nữ ạ?
Và đang tìm loại đồ gì - áo, quần, váy hay phụ kiện? Và đang tìm loại đồ gì - áo, quần, váy hay phụ kiện?
Mình tìm mẫu mới nhất cho bạn ngay! 🔥" Mình tìm mẫu mới nhất cho bạn ngay! 🔥"
--- ---
...@@ -522,7 +525,7 @@ Mình tư vấn size chuẩn luôn cho bạn! 📏😄" ...@@ -522,7 +525,7 @@ Mình tư vấn size chuẩn luôn cho bạn! 📏😄"
### "Kiểm tra tồn hàng online" ### "Kiểm tra tồn hàng online"
"Bạn muốn kiểm tra sản phẩm nào ạ? 🔍 "Bạn muốn kiểm tra sản phẩm nào ạ? 🔍
Bạn cho mình biết tên sản phẩm (hoặc mã SKU nếu có) Bạn cho mình biết tên sản phẩm (hoặc mã SKU nếu có)
cùng màu sắc và size cần kiểm tra nhé! cùng màu sắc và size cần kiểm tra nhé!
Mình check ngay cho bạn! ⚡" Mình check ngay cho bạn! ⚡"
...@@ -536,4 +539,4 @@ Mình check ngay cho bạn! ⚡" ...@@ -536,4 +539,4 @@ Mình check ngay cho bạn! ⚡"
**CASE B: CHƯA show SP** → Hướng dẫn các bước: vào canifa.com/App → tìm SP → chọn size + màu → thêm giỏ hàng → thanh toán. Hỏi cần tìm SP gì không. **CASE B: CHƯA show SP** → Hướng dẫn các bước: vào canifa.com/App → tìm SP → chọn size + màu → thêm giỏ hàng → thanh toán. Hỏi cần tìm SP gì không.
⛔ **TỰ VIẾT** câu trả lời tự nhiên, **KHÔNG copy nguyên** mẫu! Mỗi lần trả lời phải khác nhau, tự nhiên như đang nói chuyện. ⛔ **TỰ VIẾT** câu trả lời tự nhiên, **KHÔNG copy nguyên** mẫu! Mỗi lần trả lời phải khác nhau, tự nhiên như đang nói chuyện.
\ No newline at end of file
...@@ -7,7 +7,7 @@ load_dotenv(os.path.join(os.path.dirname(__file__), "..", "..", ".env")) ...@@ -7,7 +7,7 @@ load_dotenv(os.path.join(os.path.dirname(__file__), "..", "..", ".env"))
from langfuse import Langfuse from langfuse import Langfuse
lf = Langfuse() lf = Langfuse()
BASE = os.path.dirname(os.path.abspath(__file__)) BASE = os.path.dirname(os.path.abspath(__file__))
# 1. Push check_is_stock tool prompt # 1. Push check_is_stock tool prompt
stock_path = os.path.join(BASE, "..", "tool_prompts", "check_is_stock.txt") stock_path = os.path.join(BASE, "..", "tool_prompts", "check_is_stock.txt")
......
...@@ -134,7 +134,7 @@ def verify(lf: Langfuse): ...@@ -134,7 +134,7 @@ def verify(lf: Langfuse):
# Check key section headings exist in assembled output # Check key section headings exist in assembled output
checks = [ checks = [
("01 Identity (core)", "Canifa-AI Stylist"), ("01 Identity (core)", "C-Stylist"),
("02 Rules", "QUY TẮC TRUNG THỰC"), ("02 Rules", "QUY TẮC TRUNG THỰC"),
("03 Context", "CONTEXT AWARENESS"), ("03 Context", "CONTEXT AWARENESS"),
("04a Sales Core", "PHONG CÁCH TƯ VẤN"), ("04a Sales Core", "PHONG CÁCH TƯ VẤN"),
......
"""Push all prompts (system + tools) to Langfuse Production"""
import os
import sys
import subprocess
# --- 1. SET ENVIRONMENT VARIABLES FOR PRODUCTION ---
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-b20df146-732b-47cb-9669-47983906eb93"
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-611d32d6-e8c7-4e06-b5b5-c3486513a4a2"
os.environ["LANGFUSE_BASE_URL"] = "http://172.16.2.207:3009"
# We must import Langfuse AFTER setting os.environ, or initialize explicitly
from langfuse import Langfuse
def push_tools(lf):
print("\n" + "="*60)
print("🚀 PUSHING TOOL PROMPTS TO PRODUCTION")
print("="*60)
TOOL_PROMPTS_DIR = r"d:\cnf\chatbot_canifa\backend\agent\tool_prompts"
# Matching the exact names used in backend/agent/prompt_utils.py
TOOL_FILES = [
("brand_knowledge_tool.txt", "canifa-tool-brand-knowledge", ["canifa", "tool-prompt"]),
("check_is_stock.txt", "canifa-tool-check-stock", ["canifa", "tool-prompt"]),
("data_retrieval_tool.txt", "canifa-tool-data-retrieval", ["canifa", "tool-prompt"]),
("promotion_canifa_tool.txt","canifa-tool-promotion", ["canifa", "tool-prompt"]),
("store_search_tool.txt", "canifa-tool-store-search", ["canifa", "tool-prompt"]),
]
for filename, langfuse_name, tags in TOOL_FILES:
path = os.path.join(TOOL_PROMPTS_DIR, filename)
with open(path, "r", encoding="utf-8") as f:
content = f.read()
lf.create_prompt(
name=langfuse_name,
prompt=content,
labels=["production"],
tags=tags,
type="text",
)
print(f" ✅ {filename:30s} → {langfuse_name} ({len(content):,} chars)")
lf.flush()
print("✅ Tool prompts pushed successfully!\n")
def push_system_prompts():
print("="*60)
print("🚀 PUSHING SYSTEM PROMPTS TO PRODUCTION")
print("="*60)
# We can just call the existing push_modules_to_langfuse.py script
# since we already exported the env vars, it will pick up the prod credentials.
script_dir = r"d:\cnf\chatbot_canifa\backend\agent\prompt_module"
script_path = os.path.join(script_dir, "push_modules_to_langfuse.py")
env = os.environ.copy()
subprocess.run([sys.executable, script_path], cwd=script_dir, env=env, check=True)
if __name__ == "__main__":
sys.stdout.reconfigure(encoding="utf-8")
print("🌟 DEPLOYING TO C-STYLIST PRODUCTION 🌟")
print(f"Target: {os.environ.get('LANGFUSE_BASE_URL')}")
# 1. Push System Prompts
push_system_prompts()
# 2. Push Tool Prompts
lf = Langfuse()
push_tools(lf)
print("🎉 ALL DEPLOYMENTS TO PRODUCTION FINISHED SUCCESSFULLY!")
...@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field ...@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field
class UserInsight(BaseModel): class UserInsight(BaseModel):
"""6-layer User Insight structure as defined in system prompt.""" """6-layer User Insight structure as defined in system prompt."""
USER: str = Field( USER: str = Field(
default="Chưa rõ.", default="Chưa rõ.",
description="Thông tin người chat: Giới tính, Người lớn/Trẻ em, Style/Gu" description="Thông tin người chat: Giới tính, Người lớn/Trẻ em, Style/Gu"
...@@ -48,7 +48,7 @@ class ChatResponse(BaseModel): ...@@ -48,7 +48,7 @@ class ChatResponse(BaseModel):
Structured response from CANIFA AI Stylist. Structured response from CANIFA AI Stylist.
This model enforces the exact JSON schema the LLM must follow. This model enforces the exact JSON schema the LLM must follow.
""" """
ai_response: str = Field( ai_response: str = Field(
description="Câu trả lời cho khách hàng. Phải ngắn gọn, thảo mai, nhắc SKU bằng [SKU]." description="Câu trả lời cho khách hàng. Phải ngắn gọn, thảo mai, nhắc SKU bằng [SKU]."
) )
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Tra cứu TOÀN BỘ thông tin về thương hiệu và dịch vụ của Canifa. Tra cứu TOÀN BỘ thông tin về thương hiệu và dịch vụ của Canifa.
QUY TẮC CỰC QUAN TRỌNG KHI GỌI TOOL: QUY TẮC CỰC QUAN TRỌNG KHI GỌI TOOL:
- Khi đã quyết định gọi tool, TUYỆT ĐỐI KHÔNG sinh ai_response trước. - Khi đã quyết định gọi tool, TUYỆT ĐỐI KHÔNG sinh ai_response trước.
- Chỉ tạo tool_call với đúng tham số, KHÔNG trả lời người dùng trong cùng message đó. - Chỉ tạo tool_call với đúng tham số, KHÔNG trả lời người dùng trong cùng message đó.
- Sau khi tool trả kết quả mới được sinh ai_response. - Sau khi tool trả kết quả mới được sinh ai_response.
Sử dụng tool này khi khách hàng hỏi về:
Sử dụng tool này khi khách hàng hỏi về:
1. THƯƠNG HIỆU & GIỚI THIỆU: Lịch sử hình thành, giá trị cốt lõi, sứ mệnh.
2. HỆ THỐNG CỬA HÀNG: Tìm địa chỉ, số điện thoại, giờ mở cửa các cửa hàng tại các tỉnh thành (Hà Nội, HCM, Đà Nẵng, v.v.). 1. THƯƠNG HIỆU & GIỚI THIỆU: Lịch sử hình thành, giá trị cốt lõi, sứ mệnh.
3. CHÍNH SÁCH BÁN HÀNG: Quy định đổi trả, bảo hành, chính sách vận chuyển, phí ship. 2. HỆ THỐNG CỬA HÀNG: Tìm địa chỉ, số điện thoại, giờ mở cửa các cửa hàng tại các tỉnh thành (Hà Nội, HCM, Đà Nẵng, v.v.).
4. KHÁCH HÀNG THÂN THIẾT (KHTT): Điều kiện đăng ký thành viên, các hạng thẻ (Green, Silver, Gold, Diamond), quyền lợi tích điểm, thẻ quà tặng. 3. CHÍNH SÁCH BÁN HÀNG: Quy định đổi trả, bảo hành, chính sách vận chuyển, phí ship.
5. HỖ TRỢ & FAQ: Giải đáp thắc mắc thường gặp, chính sách bảo mật, thông tin liên hệ văn phòng, tuyển dụng. 4. KHÁCH HÀNG THÂN THIẾT (KHTT): Điều kiện đăng ký thành viên, các hạng thẻ (Green, Silver, Gold, Diamond), quyền lợi tích điểm, ưu đãi sinh nhật, chiết khấu theo hạng, cách thăng hạng / duy trì hạng, phiếu mua hàng, thẻ quà tặng.
6. TRA CỨU SIZE (BẢNG KÍCH CỠ): 5. HỖ TRỢ & FAQ: Giải đáp thắc mắc thường gặp, chính sách bảo mật, thông tin liên hệ văn phòng, tuyển dụng.
- Hướng dẫn chọn size chuẩn cho nam, nữ, trẻ em dựa trên chiều cao, cân nặng. 6. TRA CỨU SIZE (BẢNG KÍCH CỠ):
- ⚠️ KHI KHÁCH ĐƯA SỐ ĐO (cân nặng, chiều cao, số đo 3 vòng) → BẮT BUỘC gọi tool này để tra bảng size, KHÔNG ĐƯỢC tự đoán size. - Hướng dẫn chọn size chuẩn cho nam, nữ, trẻ em dựa trên chiều cao, cân nặng.
- Nếu khách chỉ đưa cân nặng mà thiếu chiều cao (hoặc ngược lại), hỏi thêm thông tin còn thiếu TRƯỚC khi gọi tool. - ⚠️ KHI KHÁCH ĐƯA SỐ ĐO (cân nặng, chiều cao, số đo 3 vòng) → BẮT BUỘC gọi tool này để tra bảng size, KHÔNG ĐƯỢC tự đoán size.
7. GIẢI NGHĨA TỪ VIẾT TẮT: Tự động hiểu các từ viết tắt phổ biến của khách hàng (ví dụ: 'ct' = 'chương trình khuyến mãi/ưu đãi', 'khtt' = 'khách hàng thân thiết', 'store' = 'cửa hàng', 'đc' = 'địa chỉ'). - Nếu khách chỉ đưa cân nặng mà thiếu chiều cao (hoặc ngược lại), hỏi thêm thông tin còn thiếu TRƯỚC khi gọi tool.
7. GIẢI NGHĨA TỪ VIẾT TẮT: Tự động hiểu các từ viết tắt phổ biến của khách hàng (ví dụ: 'ct' = 'chương trình khuyến mãi/ưu đãi', 'khtt' = 'khách hàng thân thiết', 'store' = 'cửa hàng', 'đc' = 'địa chỉ', 'vip' = 'hạng thẻ Gold/Diamond').
Ví dụ các câu hỏi phù hợp:
- 'Bên bạn đang có ct gì không?' (Hiểu là: Chương trình khuyến mãi) ---
- 'Canifa ở Cầu Giấy địa chỉ ở đâu?'
- 'Chính sách đổi trả hàng trong bao nhiêu ngày?' Ví dụ câu hỏi THƯƠNG HIỆU & GIỚI THIỆU (phải gọi tool):
- 'Làm sao để lên hạng thẻ Gold?' - 'Canifa thành lập năm nào?'
- 'Phí vận chuyển đi tỉnh là bao nhiêu?' - 'Canifa là thương hiệu gì?'
- 'Canifa thành lập năm nào?' - 'Cho mình biết về Canifa'
- 'Giá trị cốt lõi của Canifa là gì?'
Ví dụ câu hỏi TRA CỨU SIZE (phải gọi tool):
- 'Cho mình xem bảng size áo nam.' Ví dụ câu hỏi HỆ THỐNG CỬA HÀNG (phải gọi tool):
- 'Mình nặng 80kg cao 1m75, mặc size gì?' - 'Canifa ở Cầu Giấy địa chỉ ở đâu?'
- 'Tìm áo cho người bự con tầm 80kg' - 'Có cửa hàng nào gần Vincom không?'
- 'Size XL tương đương bao nhiêu kg?' - 'Cho mình số điện thoại cửa hàng ở Đà Nẵng'
- 'Con mình 8 tuổi cao 1m30, mặc size nào?' - 'Giờ mở cửa mấy giờ?'
- 'Mình 65kg 1m68 nên mặc áo size gì?'
- 'Bảng size quần jean nữ' Ví dụ câu hỏi CHÍNH SÁCH BÁN HÀNG (phải gọi tool):
- 'Size M áo polo nam đo ngực bao nhiêu?' - 'Chính sách đổi trả hàng trong bao nhiêu ngày?'
- 'Mình mập, 90kg mặc được size nào?' - 'Đổi hàng giảm giá được không?'
- 'Cho em hỏi bảng size trẻ em 3-5 tuổi' - 'Mua online đổi trả thế nào?'
- 'Đổi tại cửa hàng được không?'
- 'Chính sách vận chuyển ở đâu / như thế nào?'
- 'Phí vận chuyển đi tỉnh là bao nhiêu?'
- 'Ship về Hải Phòng bao lâu?'
- 'Ship Hà Nội bao lâu?'
- 'Ship TP.HCM bao lâu?'
- 'Ship Đà Nẵng bao lâu?'
- 'Tỉnh khác ship mấy ngày?'
- 'Thời gian vận chuyển thế nào bro?'
- 'Ship bao lâu vậy shop?'
- 'Freeship từ bao nhiêu?'
- 'Hàng lỗi thì xử lý sao?'
- 'Có được hoàn tiền khi đổi hàng không?'
- 'Giấy biên nhận dùng được bao lâu?'
---
KHI TRẢ LỜI CHÍNH SÁCH VẬN CHUYỂN:
- CHỈ trả lời theo đúng nội dung có trong kết quả tool, KHÔNG tự bịa thêm.
- Nếu tool có thông tin thời gian vận chuyển, ưu tiên trả đúng các mốc sau:
1) Hà Nội: giao hàng từ 1 đến 3 ngày kể từ khi hệ thống xác nhận qua SMS/email.
2) Tuyến Đà Nẵng, TP.HCM: giao hàng trong vòng 3 ngày kể từ khi hệ thống xác nhận qua SMS/email.
3) Tất cả thành phố khác: giao hàng trong vòng 3-7 ngày kể từ khi hệ thống xác nhận qua SMS/email.
4) Thời gian giao hàng không tính thứ Bảy, Chủ nhật và các ngày Lễ, Tết.
- Nếu khách hỏi "Ship về Hải Phòng bao lâu?" thì map vào nhóm "thành phố khác" và trả lời 3-7 ngày (kèm lưu ý không tính T7/CN/Lễ/Tết).
Ví dụ câu hỏi KHÁCH HÀNG THÂN THIẾT — KHTT (phải gọi tool):
- 'Làm sao để lên hạng thẻ Gold?'
- 'Hạng Diamond có quyền lợi gì?'
- 'Mình đang hạng Silver, cần mua thêm bao nhiêu để lên Gold?'
- 'Chính sách khách hàng thân thiết của Canifa thế nào?'
- 'Đăng ký thành viên có mất phí không?'
- 'Hạng Green khác Silver chỗ nào?'
- 'Bao nhiêu điểm thì lên hạng Gold?'
- 'Điểm tích lũy tính sao?'
- 'Hạng thẻ có mấy loại?'
- 'Mình mua 5 triệu thì được hạng gì?'
- 'Giảm giá VIP được bao nhiêu %?'
- 'Thẻ Gold giảm bao nhiêu phần trăm?'
- 'Diamond được chiết khấu bao nhiêu?'
- 'Có ưu đãi sinh nhật không?'
- 'Sinh nhật hạng Gold được gì?'
- 'Tích điểm quy đổi thế nào?'
- '10.000 đồng được mấy điểm?'
- 'Kỳ mua sắm là gì? Tính sao?'
- 'Bao lâu thì bị hạ hạng?'
- 'Không mua đủ điểm thì có bị tụt hạng không?'
- 'Duy trì hạng Gold cần mấy điểm?'
- 'Mất thẻ VIP thì làm sao?'
- 'Phí làm lại thẻ cứng bao nhiêu?'
- 'Khóa tài khoản Canifa thế nào?'
- 'Khách mới có ưu đãi gì?'
- 'Đăng ký thành viên được tặng gì?'
- 'Phiếu mua hàng 100k dùng thế nào?'
- 'Ngày vàng thành viên là ngày nào?'
- 'Nhân đôi điểm ngày nào trong tháng?'
- 'Tra cứu hạng thẻ ở đâu?'
- 'Xem điểm tích lũy ở đâu?'
- 'Bên bạn có ct gì cho khtt không?' (Hiểu là: Chương trình cho khách hàng thân thiết)
- 'Mình là thành viên VIP có được gì?' (Hiểu là: Quyền lợi hạng Gold/Diamond)
Ví dụ câu hỏi HỖ TRỢ & FAQ (phải gọi tool):
- 'Số hotline của Canifa?'
- 'Email liên hệ là gì?'
- 'Canifa có tuyển dụng không?'
- 'Chính sách bảo mật thông tin thế nào?'
Ví dụ câu hỏi TRA CỨU SIZE (phải gọi tool):
- 'Cho mình xem bảng size áo nam.'
- 'Mình nặng 80kg cao 1m75, mặc size gì?'
- 'Tìm áo cho người bự con tầm 80kg'
- 'Size XL tương đương bao nhiêu kg?'
- 'Con mình 8 tuổi cao 1m30, mặc size nào?'
- 'Mình 65kg 1m68 nên mặc áo size gì?'
- 'Bảng size quần jean nữ'
- 'Size M áo polo nam đo ngực bao nhiêu?'
- 'Mình mập, 90kg mặc được size nào?'
- 'Cho em hỏi bảng size trẻ em 3-5 tuổi'
Ví dụ câu hỏi từ VIẾT TẮT (phải tự hiểu rồi gọi tool):
- 'Bên bạn đang có ct gì không?' (Hiểu là: Chương trình khuyến mãi)
- 'Chính sách khtt thế nào?' (Hiểu là: Khách hàng thân thiết)
- 'Đc store Vincom ở đâu?' (Hiểu là: Địa chỉ cửa hàng)
- 'Thẻ vip giảm bn %?' (Hiểu là: Thẻ Gold/Diamond giảm bao nhiêu phần trăm)
import json import json
import logging import logging
from langchain_core.tools import tool from langchain_core.tools import tool
...@@ -10,10 +10,8 @@ from common.starrocks_connection import get_db_connection ...@@ -10,10 +10,8 @@ from common.starrocks_connection import get_db_connection
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Constants - Chỉ cần lấy Top 2-3 chunk vì ta sẽ mở rộng lấy full dữ liệu của title đó
TOP_K_CHUNKS = 5 TOP_K_CHUNKS = 5
class KnowledgeSearchInput(BaseModel): class KnowledgeSearchInput(BaseModel):
query: str = Field( query: str = Field(
description="Câu hỏi hoặc nhu cầu tìm kiếm thông tin phi sản phẩm của khách hàng (ví dụ: hỏi chính sách, tra bảng size...). KHÔNG DÙNG ĐỂ TÌM SẢN PHẨM. KHÔNG DÙNG ĐỂ TÌM CỬA HÀNG (dùng canifa_store_search)." description="Câu hỏi hoặc nhu cầu tìm kiếm thông tin phi sản phẩm của khách hàng (ví dụ: hỏi chính sách, tra bảng size...). KHÔNG DÙNG ĐỂ TÌM SẢN PHẨM. KHÔNG DÙNG ĐỂ TÌM CỬA HÀNG (dùng canifa_store_search)."
...@@ -29,85 +27,61 @@ async def canifa_knowledge_search(query: str) -> str: ...@@ -29,85 +27,61 @@ async def canifa_knowledge_search(query: str) -> str:
""" """
logger.info(f"[Semantic Search] Brand Knowledge query: {query}") logger.info(f"[Semantic Search] Brand Knowledge query: {query}")
try: try:
# 1. Tạo embedding cho câu hỏi # 1. Tạo embedding cho câu hỏi (cached 24h trong Redis)
query_vector = await create_embedding_async(query) query_vector = await create_embedding_async(query)
if not query_vector: if not query_vector:
return "Xin lỗi, tôi gặp sự cố khi xử lý thông tin. Vui lòng thử lại sau." return "Xin lỗi, tôi gặp sự cố khi xử lý thông tin. Vui lòng thử lại sau."
v_str = json.dumps(query_vector) v_str = json.dumps(query_vector)
# 2. Query StarRocks lấy Top K chunks phù hợp nhất # 2. SINGLE QUERY: Tìm top K chunks → lấy full document theo title (1 round-trip)
sql_search = f""" sql = f"""
SELECT WITH top_chunks AS (
content, SELECT json_query(metadata, '$.title') AS title
metadata
FROM shared_source.chatbot_rsa_knowledge FROM shared_source.chatbot_rsa_knowledge
ORDER BY approx_cosine_similarity(embedding, {v_str}) DESC ORDER BY approx_cosine_similarity(embedding, {v_str}) DESC
LIMIT {TOP_K_CHUNKS} LIMIT {TOP_K_CHUNKS}
)
SELECT k.content, k.metadata
FROM shared_source.chatbot_rsa_knowledge k
WHERE json_query(k.metadata, '$.title') IN (
SELECT DISTINCT title FROM top_chunks WHERE title IS NOT NULL
)
""" """
sr = get_db_connection() sr = get_db_connection()
chunk_results = await sr.execute_query_async(sql_search) results = await sr.execute_query_async(sql)
if not chunk_results: if not results:
logger.warning(f"No knowledge data found in DB for query: {query}") logger.warning(f"No knowledge data found in DB for query: {query}")
return "Hiện tại tôi chưa tìm thấy thông tin chính xác về nội dung này trong hệ thống kiến thức của Canifa. Bạn có thể liên hệ hotline 1800 6061 để được hỗ trợ trực tiếp." return "Hiện tại tôi chưa tìm thấy thông tin chính xác về nội dung này trong hệ thống kiến thức của Canifa. Bạn có thể liên hệ hotline 1800 6061 để được hỗ trợ trực tiếp."
# 3. Trích xuất danh sách các 'title' duy nhất từ metadata của các chunk tìm được # 3. Phân nhóm nội dung theo title
found_titles = set() docs_by_title: dict[str, list[str]] = {}
for res in chunk_results:
try:
meta_str = res.get("metadata", "{}")
meta_dict = json.loads(meta_str) if isinstance(meta_str, str) else meta_str
title_value = meta_dict.get("title") if isinstance(meta_dict, dict) else None
if title_value:
found_titles.add(title_value)
except Exception as e:
logger.error(f"Error parsing metadata: {e}")
continue
if not found_titles:
# Fallback nếu không có title nào, trả về chunk như cũ
knowledge_texts = [res.get("content", "") for res in chunk_results]
return "\n\n---\n\n".join(knowledge_texts)
logger.info(f"Semantic search found related titles: {list(found_titles)}")
# 4. Gom TOÀN BỘ nội dung của những title đã tìm thấy
# StarRocks JSON extract syntax: json_query(metadata, '$.title')
safe_titles = [str(t).replace("'", "''") for t in found_titles]
titles_sql_list = ", ".join([f"'{t}'" for t in safe_titles])
sql_full_docs = f""" for res in results:
SELECT content, metadata
FROM shared_source.chatbot_rsa_knowledge
WHERE json_query(metadata, '$.title') IN ({titles_sql_list})
"""
full_doc_results = await sr.execute_query_async(sql_full_docs)
# 5. Phân nhóm nội dung theo title để context gọn gàng
docs_by_title = {t: [] for t in found_titles}
for res in full_doc_results or []:
try: try:
meta_obj = ( meta_obj = (
json.loads(res.get("metadata", "{}")) json.loads(res.get("metadata", "{}"))
if isinstance(res.get("metadata"), str) if isinstance(res.get("metadata"), str)
else res.get("metadata", {}) else res.get("metadata", {})
) )
title = meta_obj.get("title") title = meta_obj.get("title") if isinstance(meta_obj, dict) else None
content = res.get("content", "").strip() content = res.get("content", "").strip()
if title in docs_by_title and content: if title and content:
docs_by_title[title].append(content) docs_by_title.setdefault(title, []).append(content)
except Exception as e: except Exception as e:
logger.debug(f"Skip invalid row while grouping by title: {e}") logger.debug(f"Skip invalid row while grouping by title: {e}")
# 6. Tổng hợp kết quả if not docs_by_title:
# Fallback: trả raw content nếu không parse được title
knowledge_texts = [res.get("content", "") for res in results]
return "\n\n---\n\n".join(knowledge_texts)
# 4. Tổng hợp kết quả
final_blocks = [] final_blocks = []
for title, contents in docs_by_title.items(): for title, contents in docs_by_title.items():
if contents: if contents:
# Ghép tất cả các chunk thuộc cùng một title
full_text = "\n\n".join(contents) full_text = "\n\n".join(contents)
final_blocks.append(f"=== TÀI LIỆU: {title} ===\n{full_text}") final_blocks.append(f"=== TÀI LIỆU: {title} ===\n{full_text}")
......
...@@ -131,4 +131,4 @@ def resolve_product_line(raw_value: str) -> list[str]: ...@@ -131,4 +131,4 @@ def resolve_product_line(raw_value: str) -> list[str]:
resolved.append(mapped) resolved.append(mapped)
else: else:
resolved.append(part) resolved.append(part)
return resolved return resolved
\ No newline at end of file
...@@ -76,7 +76,7 @@ async def fashion_qa_chat(request: Request, req: QueryRequest, background_tasks: ...@@ -76,7 +76,7 @@ async def fashion_qa_chat(request: Request, req: QueryRequest, background_tasks:
content={ content={
"status": "error", "status": "error",
"error_code": "SYSTEM_ERROR", "error_code": "SYSTEM_ERROR",
"message": "Oops 😥 Hiện Canifa-AI chưa thể xử lý yêu cầu của bạn ngay lúc này, vui lòng quay lại trong giây lát.", "message": "Oops 😥 Hiện C-Stylist chưa thể xử lý yêu cầu của bạn ngay lúc này, vui lòng quay lại trong giây lát.",
}, },
) )
...@@ -121,7 +121,7 @@ async def fashion_qa_chat_dev(request: Request, req: QueryRequest, background_ta ...@@ -121,7 +121,7 @@ async def fashion_qa_chat_dev(request: Request, req: QueryRequest, background_ta
content={ content={
"status": "error", "status": "error",
"error_code": "SYSTEM_ERROR", "error_code": "SYSTEM_ERROR",
"message": "Oops 😥 Hiện Canifa-AI chưa thể xử lý yêu cầu của bạn ngay lúc này, vui lòng quay lại trong giây lát.", "message": "Oops 😥 Hiện C-Stylist chưa thể xử lý yêu cầu của bạn ngay lúc này, vui lòng quay lại trong giây lát.",
}, },
) )
......
import hashlib import hashlib
import json import json
import logging import logging
import redis.asyncio as aioredis # redis package với async support (thay thế aioredis deprecated) import redis.asyncio as aioredis # redis package với async support (thay thế aioredis deprecated)
from config import ( from config import (
REDIS_CACHE_DB, REDIS_CACHE_DB,
REDIS_CACHE_PORT, REDIS_CACHE_PORT,
REDIS_CACHE_TURN_ON, REDIS_CACHE_TURN_ON,
REDIS_CACHE_URL, REDIS_CACHE_URL,
REDIS_PASSWORD, REDIS_PASSWORD,
REDIS_USERNAME, REDIS_USERNAME,
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
DEFAULT_RESPONSE_TTL = 300 # 5 minutes DEFAULT_RESPONSE_TTL = 300
RESPONSE_KEY_PREFIX = "resp_cache:" RESPONSE_KEY_PREFIX = "resp_cache:"
EMBEDDING_CACHE_TTL = 86400 # 24 hours EMBEDDING_CACHE_TTL = 86400 # 24 hours
EMBEDDING_KEY_PREFIX = "emb_cache:" EMBEDDING_KEY_PREFIX = "emb_cache:"
class RedisClient: class RedisClient:
""" """
Hybrid Cache Client for Canifa Chatbot. Hybrid Cache Client for Canifa Chatbot.
Layer 1: Exact Response Cache (Short TTL) Layer 1: Exact Response Cache (Short TTL)
Layer 2: Embedding Cache (Long TTL) Layer 2: Embedding Cache (Long TTL)
""" """
def __init__(self): def __init__(self):
self._client: aioredis.Redis | None = None self._client: aioredis.Redis | None = None
self._enabled = REDIS_CACHE_TURN_ON self._enabled = REDIS_CACHE_TURN_ON
self._stats = { self._stats = {
"resp_hits": 0, "resp_hits": 0,
"emb_hits": 0, "emb_hits": 0,
"misses": 0, "misses": 0,
} }
async def initialize(self) -> aioredis.Redis | None: async def initialize(self) -> aioredis.Redis | None:
"""Initialize connection""" """Initialize connection"""
if not self._enabled: if not self._enabled:
logger.info("🚫 Redis Cache is DISABLED via REDIS_CACHE_TURN_ON") logger.info("🚫 Redis Cache is DISABLED via REDIS_CACHE_TURN_ON")
return None return None
if self._client is not None: if self._client is not None:
return self._client return self._client
try: try:
connection_kwargs = { connection_kwargs = {
"host": REDIS_CACHE_URL, "host": REDIS_CACHE_URL,
"port": REDIS_CACHE_PORT, "port": REDIS_CACHE_PORT,
"db": REDIS_CACHE_DB, "db": REDIS_CACHE_DB,
"decode_responses": True, "decode_responses": True,
"socket_connect_timeout": 5, "socket_connect_timeout": 5,
} }
if REDIS_PASSWORD: if REDIS_PASSWORD:
connection_kwargs["password"] = REDIS_PASSWORD connection_kwargs["password"] = REDIS_PASSWORD
if REDIS_USERNAME: if REDIS_USERNAME:
connection_kwargs["username"] = REDIS_USERNAME connection_kwargs["username"] = REDIS_USERNAME
self._client = aioredis.Redis(**connection_kwargs) self._client = aioredis.Redis(**connection_kwargs)
await self._client.ping() await self._client.ping()
logger.info(f"✅ Redis Hybrid Cache connected: {REDIS_CACHE_URL}:{REDIS_CACHE_PORT} (db={REDIS_CACHE_DB})") logger.info(f"✅ Redis Hybrid Cache connected: {REDIS_CACHE_URL}:{REDIS_CACHE_PORT} (db={REDIS_CACHE_DB})")
return self._client return self._client
except Exception as e: except Exception as e:
logger.error(f"❌ Failed to connect to Redis: {e}") logger.error(f"❌ Failed to connect to Redis: {e}")
self._enabled = False self._enabled = False
return None return None
def get_client(self) -> aioredis.Redis | None: def get_client(self) -> aioredis.Redis | None:
if not self._enabled: if not self._enabled:
return None return None
return self._client return self._client
# --- Layer 1: Exact Response Cache (Short TTL) --- # --- Layer 1: Exact Response Cache (Short TTL) ---
async def get_response(self, user_id: str, query: str) -> dict | None: async def get_response(self, user_id: str, query: str) -> dict | None:
"""Get exact matched response (100% safe, short TTL)""" """Get exact matched response (100% safe, short TTL)"""
if not self._enabled: if not self._enabled or DEFAULT_RESPONSE_TTL <= 0:
return None return None
try: try:
client = self.get_client() client = self.get_client()
if not client: if not client:
return None return None
# Hash of query only (global cache across users) # Hash of query only (global cache across users)
query_key = query.strip().lower() query_key = query.strip().lower()
cache_hash = hashlib.md5(query_key.encode()).hexdigest() cache_hash = hashlib.md5(query_key.encode()).hexdigest()
key = f"{RESPONSE_KEY_PREFIX}{cache_hash}" key = f"{RESPONSE_KEY_PREFIX}{cache_hash}"
cached = await client.get(key) cached = await client.get(key)
if cached: if cached:
self._stats["resp_hits"] += 1 self._stats["resp_hits"] += 1
logger.info("⚡ LAYER 1 HIT (Response) | Global Cache") logger.info("⚡ LAYER 1 HIT (Response) | Global Cache")
return json.loads(cached) return json.loads(cached)
return None return None
except Exception as e: except Exception as e:
logger.warning(f"Redis get_response error: {e}") logger.warning(f"Redis get_response error: {e}")
return None return None
async def set_response(self, user_id: str, query: str, response_data: dict, ttl: int = DEFAULT_RESPONSE_TTL): async def set_response(self, user_id: str, query: str, response_data: dict, ttl: int = DEFAULT_RESPONSE_TTL):
"""Store full response in cache with short TTL""" """Store full response in cache with short TTL"""
if not self._enabled or not response_data: if not self._enabled or not response_data or ttl <= 0:
return return
try: try:
client = self.get_client() client = self.get_client()
if not client: if not client:
return return
query_key = query.strip().lower() query_key = query.strip().lower()
cache_hash = hashlib.md5(query_key.encode()).hexdigest() cache_hash = hashlib.md5(query_key.encode()).hexdigest()
key = f"{RESPONSE_KEY_PREFIX}{cache_hash}" key = f"{RESPONSE_KEY_PREFIX}{cache_hash}"
await client.setex(key, ttl, json.dumps(response_data)) await client.setex(key, ttl, json.dumps(response_data))
logger.debug(f"💾 LAYER 1 STORED (Response) | TTL: {ttl}s") logger.debug(f"💾 LAYER 1 STORED (Response) | TTL: {ttl}s")
except Exception as e: except Exception as e:
logger.warning(f"Redis set_response error: {e}") logger.warning(f"Redis set_response error: {e}")
# --- Layer 2: Embedding Cache (Long TTL) --- # --- Layer 2: Embedding Cache (Long TTL) ---
async def get_embedding(self, text: str) -> list[float] | None: async def get_embedding(self, text: str) -> list[float] | None:
"""Get cached embedding (Saves OpenAI costs)""" """Get cached embedding (Saves OpenAI costs)"""
if not self._enabled: if not self._enabled:
return None return None
try: try:
client = self.get_client() client = self.get_client()
if not client: if not client:
return None return None
text_hash = hashlib.md5(text.strip().lower().encode()).hexdigest() text_hash = hashlib.md5(text.strip().lower().encode()).hexdigest()
key = f"{EMBEDDING_KEY_PREFIX}{text_hash}" key = f"{EMBEDDING_KEY_PREFIX}{text_hash}"
cached = await client.get(key) cached = await client.get(key)
if cached: if cached:
self._stats["emb_hits"] += 1 self._stats["emb_hits"] += 1
logger.info(f"🔵 LAYER 2 HIT (Embedding) | Query: {text[:20]}...") logger.info(f"🔵 LAYER 2 HIT (Embedding) | Query: {text[:20]}...")
return json.loads(cached) return json.loads(cached)
return None return None
except Exception as e: except Exception as e:
logger.warning(f"Redis get_embedding error: {e}") logger.warning(f"Redis get_embedding error: {e}")
return None return None
async def set_embedding(self, text: str, embedding: list[float], ttl: int = EMBEDDING_CACHE_TTL): async def set_embedding(self, text: str, embedding: list[float], ttl: int = EMBEDDING_CACHE_TTL):
"""Store embedding for long term""" """Store embedding for long term"""
if not self._enabled or not embedding: if not self._enabled or not embedding:
return return
try: try:
client = self.get_client() client = self.get_client()
if not client: if not client:
return return
text_hash = hashlib.md5(text.strip().lower().encode()).hexdigest() text_hash = hashlib.md5(text.strip().lower().encode()).hexdigest()
key = f"{EMBEDDING_KEY_PREFIX}{text_hash}" key = f"{EMBEDDING_KEY_PREFIX}{text_hash}"
await client.setex(key, ttl, json.dumps(embedding)) await client.setex(key, ttl, json.dumps(embedding))
logger.debug(f"💾 LAYER 2 STORED (Embedding) | TTL: {ttl}s") logger.debug(f"💾 LAYER 2 STORED (Embedding) | TTL: {ttl}s")
except Exception as e: except Exception as e:
logger.warning(f"Redis set_embedding error: {e}") logger.warning(f"Redis set_embedding error: {e}")
# --- Singleton Export --- # --- Singleton Export ---
redis_cache = RedisClient() redis_cache = RedisClient()
def get_redis_cache() -> RedisClient: def get_redis_cache() -> RedisClient:
return redis_cache return redis_cache
# --- Prompt Version Sync (Multi-Worker) --- # --- Prompt Version Sync (Multi-Worker) ---
PROMPT_VERSION_KEY = "system:prompt_version" PROMPT_VERSION_KEY = "system:prompt_version"
async def get_prompt_version() -> int: async def get_prompt_version() -> int:
"""Get current prompt version from Redis (shared across all workers).""" """Get current prompt version from Redis (shared across all workers)."""
try: try:
client = redis_cache.get_client() client = redis_cache.get_client()
if client: if client:
version = await client.get(PROMPT_VERSION_KEY) version = await client.get(PROMPT_VERSION_KEY)
return int(version) if version else 0 return int(version) if version else 0
except Exception as e: except Exception as e:
logger.warning(f"Failed to get prompt version: {e}") logger.warning(f"Failed to get prompt version: {e}")
return 0 return 0
async def bump_prompt_version() -> int: async def bump_prompt_version() -> int:
"""Increment prompt version in Redis (call when prompt is updated).""" """Increment prompt version in Redis (call when prompt is updated)."""
try: try:
client = redis_cache.get_client() client = redis_cache.get_client()
if client: if client:
new_version = await client.incr(PROMPT_VERSION_KEY) new_version = await client.incr(PROMPT_VERSION_KEY)
logger.info(f"🔄 Prompt version bumped to: {new_version}") logger.info(f"🔄 Prompt version bumped to: {new_version}")
return new_version return new_version
except Exception as e: except Exception as e:
logger.warning(f"Failed to bump prompt version: {e}") logger.warning(f"Failed to bump prompt version: {e}")
return 0 return 0
...@@ -8,7 +8,8 @@ import os ...@@ -8,7 +8,8 @@ import os
from dotenv import load_dotenv from dotenv import load_dotenv
# Load environment variables from .env file # Load environment variables from .env file
load_dotenv() _BASE_DIR = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.path.join(_BASE_DIR, ".env"))
# Export all config variables for type checking # Export all config variables for type checking
__all__ = [ __all__ = [
......
import sys
import subprocess
p = subprocess.Popen(
[sys.executable, 'D:\\cnf\\chatbot_canifa\\backend\\datadb\\test_rag_gpt4o_mini.py'],
stdin=subprocess.PIPE,
stdout=sys.stdout,
stderr=sys.stderr,
text=True,
encoding='utf-8'
)
p.communicate(input='chính sách vận chuyển bên bạn\nexit\n')
import json
import os
import re
import numpy as np
import faiss
from langchain_openai import OpenAIEmbeddings
from dotenv import load_dotenv
# Load env variables for OpenAI
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".env"))
def main():
# 1. Trỏ thẳng vào thư mục datadb
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, "tonghop.txt")
if not os.path.exists(file_path):
print(f" File không tồn tại: {file_path}")
return
with open(file_path, encoding="utf-8") as f:
content = f.read()
# 2. Bóc tách file theo các đầu mục "FILE: ..."
sections = re.split(r"={20,}\nFILE:\s*(.*?)\n={20,}\n", content)
chunks = []
if len(sections) > 1:
# Bỏ qua index 0
for i in range(1, len(sections), 2):
title = sections[i].strip()
text = sections[i + 1].strip()
if text:
chunks.append({"id": len(chunks), "title": title, "content": text})
else:
print(" Không tìm thấy delimiter 'FILE:' trong tonghop.txt.")
return
print(f" BÓC TÁCH: Đã chia thành {len(chunks)} phần chính sách/tài liệu.")
# 3. Embedding với OpenAI
print("\n[Loading Model] Khởi tạo OpenAIEmbeddings (text-embedding-3-small)...")
embedder = OpenAIEmbeddings(model="text-embedding-3-small")
# Gom title + content để embed
embed_texts = [f"{c['title']}\n{c['content']}" for c in chunks]
print("[Embedding] Đang gọi API OpenAI để sinh Vectors...")
embeddings_list = embedder.embed_documents(embed_texts)
embeddings = np.array(embeddings_list).astype("float32")
# Chuẩn hoá L2 để tính Cosine Similarity mượt hơn với FAISS IndexFlatIP
faiss.normalize_L2(embeddings)
# 4. Khởi tạo FAISS Index & Lưu metadata
dim = embeddings.shape[1]
index = faiss.IndexFlatIP(dim)
index.add(embeddings)
index_path = os.path.join(current_dir, "canifa_docs.index")
meta_path = os.path.join(current_dir, "canifa_docs_meta.json")
faiss.write_index(index, index_path)
with open(meta_path, "w", encoding="utf-8") as f:
json.dump(chunks, f, ensure_ascii=False, indent=2)
print(f" ĐÃ Lưu FAISS vector vào: {index_path} (dim={dim})")
print(f" ĐÃ Lưu JSON nội dung vào: {meta_path}\n")
# 5. TEST MÔ PHỎNG LUÔN
queries = [
"mua hàng online muốn đổi trực tiếp ở cửa hàng gần nhất thì phải làm sao hả shop?",
"thời gian gửi hàng ship về hà đông mất tầm bao lâu?",
"có bán quần của trẻ em bé gái cao tầm 1 mét 4 không cho xin thông số",
]
print(" BẮT ĐẦU TEST SEARCH RAG (TRUY VẤN FULL CÒN NGUYÊN BẢN VỚI OPENAI EMBEDDING)")
print("=" * 70)
for q in queries:
print(f"\n CÂU HỎI: '{q}'")
# Sinh vector câu hỏi bằng OpenAI
q_emb_list = embedder.embed_query(q)
q_emb = np.array([q_emb_list]).astype("float32")
faiss.normalize_L2(q_emb)
# Search top 1
scores, I = index.search(q_emb, 1)
best_id = I[0][0]
best_score = scores[0][0]
if best_id != -1:
best_chunk = chunks[best_id]
print(f" MATCH ĐẦU MỤC: '{best_chunk['title']}' (Score: {best_score:.4f})")
print(
f" NỘI DUNG FULL RETURN (Trích 300 chữ): {best_chunk['content'][:300].replace(chr(10), ' ')} ... <CÒN NỮA>"
)
print(f" Độ dài thực tế sẽ đưa cho LLM: {len(best_chunk['content'])} ký tự.")
else:
print("Không tìm thấy.")
if __name__ == "__main__":
main()
[
{
"id": 0,
"title": "data/text/chinh-sach-bao-mat.txt",
"content": "Canifa cam kết xây dựng và công bố chính sách bảo mật thông tin khi thu thập và sử dụng thông tin cá nhân của người tiêu dùng..."
},
{
"id": 1,
"title": "data/text/cua-hang-html.txt",
"content": "search\nCửa hàng\n..."
},
{
"id": 2,
"title": "data/text/dieu-kien-dieu-khoan-khtt-html.txt",
"content": "Áp dụng trên hệ thống cửa hàng Canifa toàn quốc cho đến khi có thông báo mới.\n..."
},
{
"id": 3,
"title": "data/text/gioi-thieu-html.txt",
"content": "Canifa 20 năm - Khoác lên niềm vui gia đình Việt\n..."
},
{
"id": 4,
"title": "data/text/hoi-dap.txt",
"content": "Thanh toán\nThanh toán trả trước\n..."
},
{
"id": 5,
"title": "data/text/huong-dan-chon-size-html.txt",
"content": "HƯỚNG DẪN CHỌN SIZE - CANIFA\n..."
},
{
"id": 6,
"title": "data/text/lien-he-html.txt",
"content": "Hỗ trợ Khách hàng mua online\n..."
},
{
"id": 7,
"title": "data/text/voi-cong-dong-html.txt",
"content": "Phát triển bền vững: 03 xanh\n..."
}
]
\ No newline at end of file
import sys
import subprocess
p = subprocess.Popen(
['d:/cnf/chatbot_canifa/preference/chatbot-rsa/.venv/Scripts/python.exe', 'D:/cnf/chatbot_canifa/backend/datadb/test_rag_gpt4o_mini.py'],
stdin=subprocess.PIPE,
stdout=sys.stdout,
stderr=sys.stderr,
text=True,
encoding='utf-8'
)
p.communicate(input='chính sách vận chuyển bên bạn\nexit\n')
import json
import os
import faiss
import numpy as np
from dotenv import load_dotenv
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
current_dir = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.path.join(current_dir, "..", ".env"))
def main():
print(" BẮT ĐẦU TEST E2E RAG VỚI GPT-4o-mini (BẢN PROMPT THÔNG MINH HƠN)")
print("=" * 80)
index_path = os.path.join(current_dir, "canifa_docs.index")
meta_path = os.path.join(current_dir, "canifa_docs_meta.json")
if not os.path.exists(index_path) or not os.path.exists(meta_path):
print(" Chưa có Index. Chạy file build_and_test_faiss.py trước để tạo.")
return
print("[1] Đang nạp thư viện Vector từ FAISS và metadata...")
index = faiss.read_index(index_path)
with open(meta_path, encoding="utf-8") as f:
chunks = json.load(f)
print("[2] Khởi tạo Embedder và Models (gpt-4o-mini)...")
embedder = OpenAIEmbeddings(model="text-embedding-3-small")
llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0)
prompt_template = PromptTemplate.from_template(
"Bạn là nhân viên CSKH của Canifa. Bạn luôn nhiệt tình và vui vẻ.\n"
"Yêu cầu:\n"
"1. Nếu khách hàng chỉ chào hỏi (ví dụ: 'chào', 'hello'), hãy chào lại lịch sự và hỏi xem bạn có thể giúp gì được không, KHÔNG báo lỗi thiếu thông tin.\n"
"2. Nếu khách hỏi về chính sách, quy định, cửa hàng, hãy DỰA VÀO TÀI LIỆU CUNG CẤP BÊN DƯỚI để trả lời chi tiết và thân thiện.\n"
"3. Đọc thật kỹ tài liệu được cung cấp. Nếu tài liệu ĐÃ CÓ nhắc đến từ khoá khách hỏi, hãy cố gắng tóm tắt câu trả lời thay vì từ chối.\n"
"4. CHỈ KHI NÀO tài liệu dưới đây hoàn toàn không nhắc đến nội dung khách hỏi, bạn mới được nói: 'Dạ em chưa tìm thấy thông tin này trong chính sách hiện tại. Bạn vui lòng liên hệ hotline 1800 6061 nha!'\n"
"5. Không bao giờ được tự bịa ra thông số, giá tiền, hoặc điều khoản nếu tài liệu không có.\n\n"
"--- BẮT ĐẦU TÀI LIỆU ---\n"
"{context}\n"
"--- KẾT THÚC TÀI LIỆU ---\n\n"
"CÂU HỎI CỦA KHÁCH: {question}\n\n"
"TRẢ LỜI CỦA BẠN:"
)
chain = prompt_template | llm
print("\n" + "*" * 80)
print(" CHATBOT ĐÃ SẴN SÀNG! (Gõ 'exit' hoặc 'quit' để thoát)")
print("*" * 80 + "\n")
while True:
try:
q = input("\n BẠN: ")
if q.strip().lower() in ["exit", "quit"]:
print(" Tạm biệt!")
break
if not q.strip():
continue
q_emb_list = embedder.embed_query(q)
q_emb = np.array([q_emb_list]).astype("float32")
faiss.normalize_L2(q_emb)
TOP_K = 10
scores, I = index.search(q_emb, TOP_K)
contexts = []
for i in range(TOP_K):
doc_id = I[0][i]
if doc_id != -1:
doc_title = chunks[doc_id]["title"]
doc_content = chunks[doc_id]["content"]
contexts.append(f"--- TÀI LIỆU: {doc_title} ---\n{doc_content}")
if contexts:
combined_context = "\n\n".join(contexts)
response = chain.invoke({"context": combined_context, "question": q})
print(f" CANIFA AI:\n{response.content}")
else:
print(" CANIFA AI: Hệ thống không tìm thấy tài liệu phù hợp.")
except (KeyboardInterrupt, EOFError):
print("\n Tạm biệt!")
break
if __name__ == "__main__":
main()
================================================================================
Canifa cam kết xây dựng và công bố chính sách bảo mật thông tin khi thu thập và sử dụng thông tin cá nhân của người tiêu dùng với đầy đủ các nội dung sau: FILE: data/text/chinh-sach-bao-mat.txt
================================================================================
A. Nguyên Tắc Chung:
Canifa cam kết xây dựng và công bố chính sách bảo mật thông tin khi thu thập và sử dụng thông tin cá nhân của người tiêu dùng...
Chính sách bảo mật thông tin này (“Chính Sách Bảo Mật Canifa”) mô tả cách thức Công ty Cổ phần anifa (“Canifa” hoặc “chúng tôi”) thu thập, tiếp nhận, tổng hợp, lưu giữ, sử dụng, xử lý, tiết lộ, chia sẻ và bảo đảm an toàn thông tin của các tổ chức, cá nhân (“Người dùng” hoặc “Quý Khách”), bao gồm khách hàng, đại lý, đối tác: (i) truy cập, sử dụng các kênh tương tác khách hàng thuộc sở hữu của Công Ty, bao gồm nhưng không giới hạn: ứng dụng di động Canifa, website www.canifa.com, và hội nhóm trên các trang mạng xã hội (như facebook, Instagram, Tiktok …) thuộc sở hữu của Công Ty (“Kênh Canifa”); (ii) là khách hàng thân thiết trong Chương trình Chăm Sóc Khách Hàng Thân Thiết của Canifa (“Chương Trình”); và/hoặc (iii) mua bán các loại hàng hóa do Canifa cung cấp hoặc (iv) thông qua các nhân viên dịch vụ khách hàng của chúng tôi, hoặc truy cập vào Nền Tảng của chúng tôi thông qua máy vi tính, thiết bị di động, hoặc bất kỳ thiết bị nào khác có kết nối Internet của Quý khách (mục (i), (ii) và (iii) gọi chung là “Dịch Vụ”). Vui lòng đọc kỹ Chính Sách Bảo Mật này, các điều khoản điều kiện tương ứng và các quy định khác (nếu có).
================================================================================
Chính Sách Bảo Mật Canifa bao gồm các nội dung sau: FILE: data/text/cua-hang-html.txt
Sự chấp thuận ================================================================================
Mục đích thu thập
Phạm vi thu thập search
Thời gian lưu trữ Cửa hàng
Không chia sẻ thông tin cá nhân khách hàng ...
An toàn dữ liệu
Quyền của Khách hàng đối với thông tin cá nhân ================================================================================
Trách nhiệm của khách hàng để đảm bảo bảo mật thông tin FILE: data/text/dieu-kien-dieu-khoan-khtt-html.txt
Cách thức liên hệ với Canifa ================================================================================
Đơn vị thu thập và quản lý thông tin
Hiệu lực Áp dụng trên hệ thống cửa hàng Canifa toàn quốc cho đến khi có thông báo mới.
...
B. Nội dung chi tiết
================================================================================
Sự Chấp Thuận FILE: data/text/gioi-thieu-html.txt
Vui lòng đọc kỹ chính sách bảo mật này. Bằng cách nhấp và đánh dấu vào các tuyên bố “Tiếp tục”, “Đồng ý”, “tôi đồng ý với chính sách bảo mật của Canifa” hoặc các tuyên bố tương tự được hiển thị tại trang đăng ký của Canifa hoặc trong quá trình cung cấp các dịch vụ hoặc quyền truy cập vào nền tảng cho Quý khách, Quý khách xác nhận rằng đã đọc và hiểu các điều khoản của chính sách bảo mật này và đã đồng ý và cho phép thực hiện việc thu thập, sử dụng, tiết lộ, lưu trữ, chuyển giao và/hoặc xử lý dữ liệu cá nhân của Quý khách như được mô tả và quy định tại chính sách bảo mật này. ================================================================================
Nếu Quý khách không đồng ý với Chính Sách này, Quý khách có thể dừng cung cấp cho Chúng tôi bất kỳ thông tin cá nhân nào và/hoặc sử dụng các quyền như được nêu tại mục 7 dưới đây. Canifa 20 năm - Khoác lên niềm vui gia đình Việt
Canifa bảo lưu quyền sửa đổi, bổ sung nhằm hoàn thiện đối với Chính sách này vào bất kỳ thời điểm nào. Chúng tôi khuyến khích Quý Khách thường xuyên xem lại Chính sách bảo mật thông tin Canifa để được cập nhật mới nhất đảm bảo Quý Khách đã biết và thực hiện quyền quản lý thông tin của mình. ...
Mục đích thu thập thông tin cá nhân khách hàng
================================================================================
Canifa thu thập thông tin người dùng nhằm phục vụ cho các mục đích: FILE: data/text/hoi-dap.txt
================================================================================
Đơn hàng: để xử lý các vấn đề liên quan đến đơn đặt hàng của Quý khách; Thanh toán
Duy trì tài khoản: Để tạo và duy trì tài khoản của Qúy khách, bao gồm các chương trình khách hàng thân thiết, các chương trình khuyến mại,… đi kèm với tài khoản của Quý khách; Thanh toán trả trước
Cung cấp các dịch vụ/ tiện ích cho KH dựa trên nhu cầu và các thói quen của KH mua sắm tại Canifa; ...
Gửi thông báo Giới thiệu các sản phẩm, chương trình, dịch vụ mới của Canifa
Dịch vụ Người Dùng, Dịch vụ Chăm sóc khách hàng: bao gồm các phản hồi cho các yêu cầu, khiếu nại và phản hồi của Quý Khách; ================================================================================
An ninh: cho mục đích phát hiện, ngăn chặn các hoạt động giả mạo, chiếm dụng tài khoản của KHTT nhằm mục địch trục lợi, gian lận; FILE: data/text/huong-dan-chon-size-html.txt
Theo yêu cầu của pháp luật: tùy quy định của pháp luật vào từng thời điểm, chúng tôi có thể thu thập, lưu trữ và cung cấp theo yêu cầu của cơ quan nhà nước có thẩm quyền. ================================================================================
Phạm vi thu thập
HƯỚNG DẪN CHỌN SIZE - CANIFA
Các loại thông tin được chúng tôi thu thập và hình thức thu thập thông tin như sau: ...
Thông tin Quý khách cung cấp cho chúng tôi: ================================================================================
FILE: data/text/lien-he-html.txt
Đó là các thông tin cá nhân Quý khách cung cấp cho chúng tôi được thực hiện chủ yếu trên các kênh Canifa bao gồm bất kỳ thông tin, dữ liệu nào có thể được sử dụng để nhận dạng Quý Khách hoặc dựa vào đó mà Quý khách được xác định, chẳng hạn như họ tên, giới tính, ngày sinh, thông tin CMND/thẻ căn cước công dân/Hộ chiếu (nếu có), quốc tịch, hình ảnh cá nhân, thông tin mối quan hệ gia đình (cha mẹ, con cái), số điện thoại, chi tiết thẻ thanh toán và ngân hàng, địa chỉ email , thông tin đăng nhập tài khoản như tên đăng nhập, mật khẩu đăng nhập, ID/địa chỉ đăng nhập, câu hỏi/ trả lời bảo mật, các thông tin khác gắn liền với một con người cụ thể hoặc giúp xác định một con người cụ thể. ================================================================================
Thu thập và sử dụng Cookies Hỗ trợ Khách hàng mua online
...
Canifa và các bên thứ ba mà Canifa hợp tác (nếu có) có thể sử dụng các phương thức tự động (gọi chung là “Cookies”) có liên quan đến việc sử dụng Kênh Canifa để nhận diện trình duyệt hoặc thiết bị của quý khách, tìm hiểu thêm về sở thích của Quý khách, cung cấp cho quý khách các tính năng và dịch vụ thiết yếu và cho các mục đích bổ sung khác. Cookies có thể chứa đựng các công cụ định danh độc nhất và được lưu trữ tại máy tính hoặc thiết bị di động của Quý khách, trong email mà Canifa gửi, trên các Kênh Canifa, và tại một số địa điểm khác. Cookies có thể truyền tải Thông Tin cá nhân và việc sử dụng Dịch Vụ.
================================================================================
Canifa có thể chia sẻ Thông Tin cá nhân thu thập qua Cookies không mang tính nhận dạng cá nhân với các bên thứ ba, chẳng hạn như dữ liệu vị trí, số nhận dạng quảng cáo hoặc số nhận dạng tài khoản chung (như địa chỉ email), để tạo điều kiện hiển thị quảng cáo. FILE: data/text/voi-cong-dong-html.txt
Quý khách có thể quản lý Cookies trình duyệt bằng việc cài đặt trình duyệt của mình, chặn hoặc ngừng hoạt động Cookies, bằng cách xóa lịch sử trình duyệt và xóa bộ nhớ cache khỏi trình duyệt internet của mình. Quý khách cũng có thể giới hạn việc chia sẻ của chúng tôi về một số Thông Tin cá nhân này thông qua cài đặt thiết bị di động của mình. Nếu Quý khách tắt tất cả Cookies, cả chúng tôi và bên thứ ba sẽ không thể chuyển Cookies sang hoặc từ trình duyệt của quý khách. Tuy nhiên, nếu quý khách làm điều này, Quý khách có thể phải tự tay điều chỉnh một số tùy chọn mỗi khi quý khách truy cập lại vào Dịch Vụ và một số tính năng, kênh và dịch vụ có thể không hoạt động. ================================================================================
Thông tin từ các nguồn khác: Chúng tôi có thể thu thập thông tin cá nhân từ các nguồn hợp pháp khác như chương trình khuyến mại, khảo sát,…
Thời gian lưu trữ Phát triển bền vững: 03 xanh
...
Thông tin cá nhân của khách hàng sẽ được lưu trữ và bảo mật trên hệ thống của Canifa cho đến khi khách hàng tự đăng nhập và thực hiện hủy bỏ hoặc có yêu cầu Canifa hủy bỏ trên hệ thống. Trong mọi trường hợp, thông tin cá nhân của khách hàng sẽ được bảo mật trên máy chủ của canifa.com
Không chia sẻ thông tin cá nhân khách hàng
Chúng tôi sẽ không cung cấp thông tin cá nhân của Quý khách cho bất kỳ bên thứ ba nào, trừ một số hoạt động cần thiết sau:
Các bên cung cấp dịch vụ (ví dụ: đối tác trong các lĩnh vực như dịch vụ thanh toán, dịch vụ vận chuyển và giao nhận , tiếp thị, phân tích dữ liệu hoặc nghiên cứu khảo sát khách hàng, truyền thông xã hội, dịch vụ khách hàng, dịch vụ cài đặt, công nghệ thông tin và, dịch vụ lưu trữ web)
Yêu cầu pháp lý: Canifa có thể tiết lộ các thông tin cá nhân nếu điều đó do luật pháp yêu cầu và việc tiết lộ như vậy là cần thiết để tuân thủ quy trình pháp lý
Chuyển giao kinh doanh (nếu có): trong trường hợp sáp nhập, hợp nhất toàn bộ hoặc một phần với công ty khác.
An toàn dữ liệu
Canifa luôn nỗ lực để giữ an toàn thông tin cá nhân của KH, Chúng tôi đã và đang thực hiện nhiều biện pháp an toàn, bao gồm:
Bảo đảm an toàn trong môi trường vận hành: Canifa lưu trữ thông tin cá nhân khách hàng trong môi trường vận hành an toàn và chỉ có nhân viên, đại diện có thể truy cập trên cơ sở cần phải biết. Canifa tuân theo các tiêu chuẩn ngành, pháp luật trong việc bảo mật thông tin cá nhân KH.
Trong trường hợp máy chủ lưu trữ thông tin bị hacker tấn công dẫn đến mất mát dữ liệu Thông tin KH, Canifa sẽ có trách nhiệm thông báo vụ việc cho cơ quan chức năng điều tra xử lý kịp thời và thông báo cho KH được biết.
Canifa cam kết bảo mật mọi thông tin giao dịch trực tuyến của KH. Mọi Thông Tin KH, cũng như các thông tin trao đổi giữa KH và Canifa đều được lưu giữ và bảo mật bởi hệ thống của Canifa.
Canifa có các biện pháp thích hợp về kỹ thuật và an ninh để ngăn chặn việc truy cập, sử dụng trái phép Thông Tin KH. Tuy nhiên, Quý khách nên hiểu rằng không có phương thức truyền tải nào qua Internet hoặc phương thức lưu trữ điện tử là an toàn tuyệt đối. Mặc dù việc bảo mật không thể đảm bảo tuyệt đối, nhưng chúng tôi nỗ lực để bảo vệ an toàn thông tin của Quý khách và liên tục rà soát và nâng cấp các biện pháp bảo mật thông tin của chúng tôi.
Quyền của Khách hàng đối với thông tin cá nhân
KH có quyền cung cấp thông tin cá nhân cho chúng tôi và có quyền thay đổi quyết định đó bất kỳ lúc nào.
KH có quyền tự truy cập, kiểm tra, cập nhật, điều chỉnh, xóa hoặc hủy bỏ Thông tin cá nhân của mình bằng cách đăng nhập vào tài khoản trên Website/ Ứng dụng Canifa để chỉnh sửa thông tin cá nhân hoặc yêu cầu Canifa thực hiện việc này. Dữ liệu không được xóa được bao gồm: số điện thoại.
Đối với các nội dung khác ngoài những nội dung quy định tại Chính Sách Bảo Mật Canifa liên quan đến thu thập, xử lý và sử dụng thông tin cá nhân của KH sẽ được thực hiện theo quy định của pháp luật có hiệu lực tại thời điểm tương ứng.
KH được quyền rút lại sự đồng ý của mình, trừ trường hợp luật có quy định khác. Cụ thể:
Việc rút lại sự đồng ý không ảnh hưởng đến tính hợp pháp của việc xử lý dữ liệu đã được đồng ý trước khi rút lại sự đồng ý.
Việc rút lại sự đồng ý phải được thể hiện ở một định dạng có thể được in, sao chép bằng văn bản, bao gồm cả dưới dạng điện tử hoặc định dạng kiểm chứng được.
- KH được yêu cầu hạn chế xử lý dữ liệu cá nhân của mình, trừ trường hợp luật có quy định khác; Việc hạn chế xử lý dữ liệu được thực hiện trong 72 giờ sau khi có yêu cầu của KH dữ liệu, với toàn bộ dữ liệu cá nhân mà chủ thể dữ liệu yêu cầu hạn chế, trừ trường hợp luật có quy định khác.
- KH được quyền yêu cầu Canifa cung cấp cho bản thân dữ liệu cá nhân của mình, trừ trường hợp luật có quy định khác.
KH được phản đối Canifa xử lý dữ liệu cá nhân của mình nhằm ngăn chặn hoặc hạn chế tiết lộ dữ liệu cá nhân hoặc sử dụng cho mục đích quảng cáo, tiếp thị, trừ trường hợp luật có quy định khác. Canifa thực hiện yêu cầu của KH trong 72 giờ sau khi nhận được yêu cầu, trừ trường hợp luật có quy định khác.
KH có quyền khiếu nại, tố cáo hoặc khởi kiện theo quy định của pháp luật. KH có quyền yêu cầu bồi thường thiệt hại theo quy định của pháp luật khi xảy ra vi phạm quy định về bảo vệ dữ liệu cá nhân của mình, trừ trường hợp các bên có thỏa thuận khác hoặc luật có quy định khác. KH có quyền tự bảo vệ theo quy định của Bộ luật Dân sự, luật khác có liên quan và Nghị định 13/2023/NĐ-CP, hoặc yêu cầu cơ quan, tổ chức có thẩm quyền thực hiện các phương thức bảo vệ quyền dân sự.
Trách nhiệm của Khách hàng để đảm bảo bảo mật thông tin
KH có trách nhiệm bảo vệ thông tin tài khoản của mình và không cung cấp bất kỳ thông tin nào liên quan đến tài khoản và mật khẩu truy cập tài khoản Canifa cho bên nào khác. Trường hợp KH tiết lộ thông tin dẫn đến thiệt hại, Canifa sẽ không chịu bất kỳ trách nhiệm nào đối với tất cả những vấn đề phát sinh.
Canifa không chịu trách nhiệm về những vấn đề phát sinh khi KH truy cập vào website, ứng dụng di động, các kênh truyền thông khác không phải là website, ứng dụng di động, kênh truyền thông chính thức của Công ty.
KH tuyệt đối không được có bất kỳ hành vi sử dụng công cụ, chương trình để can thiệp trái phép vào hệ thống của Canifa, cũng như bất kỳ hành vi nào khác nhằm phát tán, cổ vũ cho các hoạt động với mục đích can thiệp, phá hoại hay xâm nhập vào dữ liệu của website hoặc ứng dụng Canifa, cũng như các hành vi mà pháp luật Việt Nam nghiêm cấm. Trong trường hợp Canifa phát hiện KH có hành vi cố tình giả mạo, gian lận, phát tán các thông tin trái phép,…Canifa có toàn quyền chuyển thông tin KH cho các cơ quan có thẩm quyền để xử lý theo quy định pháp luật.
Cách thức liên hệ với Canifa
Bất kỳ khi nào KH cần hỗ trợ, hãy liên hệ với của Canifa:
Hỗ trợ mua Online: 1800.6061 / Email: saleonline@canifa.com
Liên hệ Chăm sóc KH: 18006061/ Email: chamsockhachhang@canifa.com
Văn phòng miền Bắc: +8424-7303.0222/ Email: hello@canifa.com
Văn phòng miền Nam: +8428 3824.7141/ Email: infocanifa@canifa.com
KH có quyền gửi khiếu nại về việc bị lộ thông tin cá nhân cho bên thứ ba đến Ban quản trị của Ứng dụng Canifa hoặc đến địa chỉ công ty hoặc phản ánh qua mail: chamsockhachhang@canifa.com. Khi tiếp nhận những phản hồi này, Công ty sẽ xác nhận lại thông tin, có trách nhiệm trả lời lý do và hướng dẫn KH khôi phục và bảo mật lại thông tin.
Canifa có trách nhiệm thực hiện các biện pháp kỹ thuật, nghiệp vụ để xác minh các nội dung được phản ánh trong vòng 15 ngày.
Đơn vị thu thập và quản lý thông tin
Công ty Cổ phần Canifa
Số ĐKKD: 0107574310, ngày cấp: 23/09/2016, nơi cấp: Sở Kế hoạch và đầu tư Hà Nội
Trụ sở chính: Số 688, Đường Quang Trung, Phường La Khê, Quận Hà Đông, Hà Nội, Việt Nam
Địa chỉ liên hệ: Phòng 301 Tòa nhà GP Invest, 170 La Thành, P. Ô Chợ Dừa, Q. Đống Đa, Hà Nội
Hiệu lực
Chính sách bảo mật thông tin này có hiệu lực từ ngày 01/07/2023.
search
Cửa hàng
Tài khoản
Giỏ hàng
SẢN PHẨM MỚI
NỮ
NAM
BÉ GÁI
BÉ TRAI
CANIFA S
LICENSE
SCHOOL
ĐỒNG PHỤC
Trang chủ
Hệ thống cửa hàng
110
Hệ thống cửa hàng trên toàn quốc
Canifa hướng đến mục tiêu mang lại niềm vui mặc mới mỗi ngày cho hàng triệu người tiêu dùng Việt. Chúng tôi tin rằng người dân Việt Nam cũng đang hướng đến một cuộc sống năng động, tích cực hơn.
Tìm kiếm cửa hàng
Lựa chọn Tỉnh / Thành Phố
Hà Nội
Bắc Ninh
Hưng Yên
Hồ Chí Minh
Thái Bình
Nghệ An
Hải Phòng
Thanh Hoá
Quảng Ninh
Phú Thọ
Hòa Bình
Sơn La
Quảng Bình
Vĩnh Phúc
Đà Nẵng
Bình Dương
Hải Dương
Bình Phước
Nam Định
Hà Tĩnh
Đồng Nai
Lào Cai
Lâm Đồng
Cao Bằng
Gia Lai
Thái Nguyên
Bà Rịa – Vũng Tàu
Tuyên Quang
Điện Biên
Bắc Giang
Lạng Sơn
Đắk Lắk
Ninh Bình
Hà Nam
Trà Vinh
Lựa chọn Quận / Huyện
Quận Ba Đình
Quận Cầu Giấy
Quận Long Biên
Quận Hai Bà Trưng
Huyện Thanh Trì
Quận Hà Đông
Quận Thanh Xuân
Huyện Thạch Thất
Huyện Đan Phượng
Huyện Thường Tín
Quận Nam Từ Liêm
Huyện Quốc Oai
Thị xã Sơn Tây
Quận Tây Hồ
Quận Hoàng Mai
Huyện Gia Lâm
Huyện Đông Anh
Huyện Hoài Đức
Huyện Chương Mỹ
Huyện Ứng Hòa
Quận Bắc Từ Liêm
Quận Đống Đa
CANIFA Lotte Liễu Giai
F3-A02 & F3-C06 tầng 3, Lotte Center Hanoi, 54 Đường Liễu Giai
09:30 - 22:00
Đang mở
ĐT: (+84) - 024 7300 0166
Chỉ đường
CANIFA - 335 Cầu Giấy
335 Cầu Giấy, P. Quan Hoa
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7301 5866
Chỉ đường
CANIFA Aeon mall Long Biên
T247, tầng 2 TTTM Aeon Mall Long Biên, P. Long Biên
10:00 - 22:00
Đang mở
ĐT: (+84) - 02473 053 866
Chỉ đường
CANIFA Times City
40-42 đường Tương Lai, tầng B1 TTTM Times city, 458 Minh Khai
09:30 - 22:00
Đang mở
ĐT: (+84) - 024 7305 2866
Chỉ đường
CANIFA - Thanh Trì (Đại lý)
Đường mới, xóm chùa, Ngũ Hiệp
09:00 - 22:00
Đang mở
ĐT: (+84) - 0898 543 536
Chỉ đường
CANIFA 171 Trần Phú
171 Đường Trần Phú
09:00 - 22:30
Đang mở
ĐT: (+84) - 0247 302 1866
Chỉ đường
CANIFA - TTTM Royal city
B2-R6-43-44 TTTM Royal city, 72 Nguyễn Trãi
10:00 - 22:00
Đang mở
ĐT: (+84) - 024 7307 4866
Chỉ đường
CANIFA - Bình Phú, Thạch Thất (Đại lý)
48 Thái Hòa - Bình Phú
09:00 - 22:00
Đang mở
ĐT: (+84) - 0989 758 822
Chỉ đường
CANIFA - 133 Tây Sơn, Đan Phượng (Đại lý)
133 Tây Sơn (cạnh Techcombank), Thị Trấn Phùng
09:00 - 22:00
Đang mở
ĐT: (+84) - 0392 661 983
Chỉ đường
CANIFA - 304 Phố Ga, Thường Tín (Đại lý)
304 Phố Ga - TT Thường Tín
09:00 - 22:00
Đang mở
ĐT: (+84) - 0932 378 856
Chỉ đường
CANIFA - 247 Hồ Tùng Mậu
247 Hồ Tùng Mậu, P. Cầu Diễn
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7306 4866
Chỉ đường
CANIFA - Quốc Oai (Đại lý)
56 Phố Đồng Hương - Thị Trấn Quốc Oai
09:00 - 22:00
Đang mở
ĐT: (+84) - 0969 547 895
Chỉ đường
CANIFA - 276 Chùa Thông
276 Chùa Thông
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7304 2688
Chỉ đường
CANIFA - Aeon mall Hà Đông
T211, Tầng 2 TTTM Aeon Mall Hà Đông, P.Dương Nội
10:00 - 22:00
Đang mở
ĐT: (+84) - 024 7303 2688
Chỉ đường
CANIFA - 447 Lạc Long Quân
447 Lạc Long Quân
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7307 1866
Chỉ đường
CANIFA - 24 Nguyễn Hữu Thọ
24 Nguyễn Hữu Thọ, Hoàng Liệt
09:00 - 22:30
Đang mở
ĐT: (+84) - 0247 3002 866
Chỉ đường
CANIFA - 38 Kim Đồng, Hà Nội
38 Kim Đồng
09:00 - 22:30
Đang mở
ĐT: (+84) - 0247 3005 866
Chỉ đường
Canifa 24 Nguyễn Cơ Thạch
24 Nguyễn Cơ Thạch
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7304 7866
Chỉ đường
CANIFA - Center Point – 27 Lê Văn Lương
Center Point – 27 Lê Văn Lương, P. Nhân Chính
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7304 5866
Chỉ đường
CANIFA - Bà Triệu, Hà Nội
69 - 73 Bà Triệu
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7305 1866
Chỉ đường
CANIFA - 164 Ngô Xuân Quảng, Hà Nội (Đại lý)
164 Ngô Xuân Quảng
09:00 - 22:30
Đang mở
ĐT: (+84) -
Chỉ đường
CANIFA - Đông Anh, Hà Nội
59 Cao Lỗ, Uy Nỗ
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7301 4866
Chỉ đường
CANIFA - Liên Quan,Thạch Thất (Đại lý)
Tổ dân phố khu Phố, thị trấn Liên Quan
08:00 - 22:00
Đang mở
ĐT: (+84) - 0979 014 638
Chỉ đường
CANIFA - Geleximco An Khánh
LK 14 - Lô 22, KĐT mới Gleximco A, An Khánh
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 73 060 866
Chỉ đường
CANIFA - Chúc Sơn (Đại lý)
86 Bắc Sơn, TT Chúc Sơn, Chương Mỹ, Hà Nội
09:00 - 22:00
Đang mở
ĐT: (+84) - 0934551005
Chỉ đường
CANIFA - Trạm Trôi, Hoài Đức, Hà Nội (Đại lý)
Khu 7, thị trấn Trạm Trôi
08:00 - 22:00
Đang mở
ĐT: (+84) - 0976 966 884
Chỉ đường
CANIFA - Vân Đình, Ứng Hoà, Hà Nội (Đại lý)
288 Lê Lợi, thị trấn Vân Đình
08:00 - 22:00
Đang mở
ĐT: (+84) - 0375131003
Chỉ đường
CANIFA - Bắc Từ Liêm (Đại lý)
32 phố Nhổn
09:00 - 22:00
Đang mở
ĐT: (+84) - 0962 906 789
Chỉ đường
Canifa - Yên Xá, Thanh Trì
Số 68 đường 70, Tân Triều
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 73 067 866
Chỉ đường
CANIFA - 168 Nguyễn Khánh Toàn
168 Nguyễn Khánh Toàn, p. Quan Hoa
09:00 - 22:00
Đang mở
ĐT: (+84) - 024 7304 0866
Chỉ đường
CANIFA - 139 Bạch Mai
139 Bạch Mai, P. Thanh Nhàn
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7306 1866
Chỉ đường
CANIFA - 152 Cao Lỗ
152 Cao Lỗ, Uy Nỗ
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7307 3866
Chỉ đường
CANIFA - Ba Đình
Số 6 Điện Biên Phủ, Ba Đình
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7303 3866
Chỉ đường
CANIFA - Tasco Mall Long Biên
7-9 Nguyễn Văn Linh, Gia Thụy
09:00 - 22:00
Đang mở
ĐT: (+84) - 024 7305 5688
Chỉ đường
CANIFA Lotte Liễu Giai T05
F5-B16-B17 tầng 05, Lotte Center Hanoi, 54 Đường Liễu Giai
09:30 - 22:00
Đang mở
ĐT: (+84) - 024 7300 0166
Chỉ đường
CANIFA KIDS - LITTLE SAM (Đại lý)
314 tầng 3 TTTM The Loop, 241 Xuân Thuỷ, phường Cầu Giấy
10:00 - 22:00
Đang mở
ĐT: (+84) - 0333 424 955
Chỉ đường
CANIFA - Xã Đàn, Hà Nội
65-67 Xã Đàn, Phường Kim Liên, Quận Đống Đa
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7305 5166
Chỉ đường
CANIFA - 440 Quang Trung Hà Đông
440 Quang Trung
09:00 - 22:30
Đang mở
ĐT: (+84) - 0247 307 5866
Chỉ đường
Canifa - Go! Thăng Long
1S22 TTTM Go! Thăng Long, số 222 đường Trần Duy Hưng, P. Yên Hòa
08:00 - 22:00
Đang mở
ĐT: (+84) - 024 7301 3566
Chỉ đường
CANIFA 181 Giảng Võ
181 Đường Giảng Võ
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7301 2866
Chỉ đường
CANIFA 121 - 123 Chùa Bộc
121 - 123 Đường Chùa Bộc
09:00 - 22:30
Đang mở
ĐT: (+84) - 024 7302 3688
Chỉ đường
CANIFA 554 Nguyễn Văn Cừ
554 Đường Nguyễn Văn Cừ
09:00 - 22:30
Đang mở
ĐT: (+84) - 0247 305 9866
Chỉ đường
Hệ thống cửa hàng
Hà Nội
Bắc Ninh
Hưng Yên
Hồ Chí Minh
Thái Bình
Nghệ An
Hải Phòng
Thanh Hoá
Quảng Ninh
Phú Thọ
Hòa Bình
Sơn La
Quảng Bình
Vĩnh Phúc
Đà Nẵng
Bình Dương
Hải Dương
Bình Phước
Nam Định
Hà Tĩnh
Đồng Nai
Lào Cai
Lâm Đồng
Cao Bằng
Gia Lai
Thái Nguyên
Bà Rịa – Vũng Tàu
Tuyên Quang
Điện Biên
Bắc Giang
Lạng Sơn
Đắk Lắk
Ninh Bình
Hà Nam
Trà Vinh
CỬA HÀNG NỔI BẬT
CANIFA 554 Nguyễn Văn Cừ
554 Đường Nguyễn Văn Cừ
ĐT: 0247 305 9866
Giờ mở cửa: 09:00 - 22:30
CANIFA 121 - 123 Chùa Bộc
121 - 123 Đường Chùa Bộc
ĐT: 024 7302 3688
Giờ mở cửa: 09:00 - 22:30
CANIFA 181 Giảng Võ
181 Đường Giảng Võ
ĐT: 024 7301 2866
Giờ mở cửa: 09:00 - 22:30
TOP
Áp dụng trên hệ thống cửa hàng Canifa toàn quốc cho đến khi có thông báo mới.
CBNV viết tắt của Cán bộ nhân viên
CSKH viết tắt của Chăm sóc Khách hàng
CBLQ viết tắt của Các bên liên quan
TN CSKH viết tắt của Trưởng nhóm Chăm sóc khách hàng
NVCH viết tắt của Nhân viên Cửa hàng
KH viết tắt của Khách hàng
KHTT viết tắt của Khách hàng thân thiết
1. PHẠM VI ÁP DỤNG:
1.1. 1.1. Điều kiện – Điều khoản (“ĐKĐK”) Chính sách Khách hàng của (“Chương trình”) này được áp dụng đối với Khách hàng thành viên (KHTV) và Công ty Cổ phần Canifa
1.2. KHTV là tất cả các cá nhân từ đủ 15 tuổi trở lên đăng ký hợp lệ tham gia Chương Trình, sở hữu tài khoản định danh khách hàng Canifa (“Tài Khoản”) và đã kích hoạt, sở hữu thẻ khách hàng thân thiết (“Thẻ Canifa”), bao gồm thẻ vật lý và/hoặc ứng dụng di động Canifa và/hoặc tài khoản của khách hàng trên website canifa.com (“Trang Web”) do Canifa quản lý vận hành và khai thác hoặc một hình thức khác theo quy định của Chương Trình tùy từng thời điểm.
1.3. Bằng việc tham gia Chương Trình, KHTV thừa nhận đã đọc, hiểu và đồng ý với ĐKĐK này và toàn bộ các chính sách của Chương Trình được công bố công khai trên Trang Web và sẽ được cập nhật tùy từng thời điểm. Nếu KHTV là người chưa đủ 15 tuổi hoặc khó khăn trong nhận thức, làm chủ hành vi hoặc hạn chế năng lực hành vi dân sự theo quy định pháp luật, KHTV cần nhận được sự hỗ trợ hoặc chấp thuận từ cha mẹ, người đại diện theo pháp luật, tùy từng trường hợp áp dụng, để đăng ký tham gia Chương Trình và mở Tài Khoản. Trong trường hợp đó, cha mẹ hoặc người đại diện theo pháp luật khác, tùy từng trường hợp áp dụng, cần hỗ trợ để KHTV hiểu rõ, đồng ý và thay mặt chấp nhận những ĐKĐK của Chương Trình này, chịu trách nhiệm đối với toàn bộ quá trình sử dụng Tài Khoản hoặc các dịch vụ của Canifa.
2. Quyền và trách nhiệm của KHTT, Canifa
2.1. KHTV sẽ được hưởng các quyền lợi cơ bản của chủ Thẻ Canifa /chủ Tài Khoản và các ưu đãi riêng tùy vào phân hạng KHTV theo nội dung Chương Trình được công bố công khai trên Trang Web, bao gồm nhưng không giới hạn các quyền lợi sau: (1) Được thăng hạng và nhận ưu đãi; (2) Tham gia các chương trình khuyến mại/ưu đãi dành riêng cho chủ Thẻ Canifa /chủ Tài Khoản từ Canifa.
2.2. KHTV có quyền truy cập, tra cứu thông tin cá nhân, hạng thành viên, giá trị tích lũy trong Tài Khoản thông qua các phương thức khác nhau như liên hệ nhân viên CSKH/ NV Thu ngân hoặc Trang Web hoặc ứng dụng di động Canifa.
2.3. KHTV tự chịu trách nhiệm cho bất kỳ và tất cả các chi phí, thuế, phí, khiếu nại hoặc nợ phải trả (nếu có) phát sinh từ việc được hưởng các lợi ích từ Chương Trình trong chính sách khách hàng.
2.4. Mỗi KH hiểu, cam kết và bảo đảm là chủ sử dụng duy nhất của Thẻ Canifa /Tài Khoản, có trách nhiệm tự bảo quản Thẻ và bảo mật thông tin Tài Khoản của mình. KH không được cung cấp thông tin Thẻ/Tài Khoản của mình cho bất kỳ bên thứ ba nào và tự chịu trách nhiệm nếu thực hiện không đúng quy định này.
2.5. KH đồng ý cho Canifa khởi tạo, lưu trữ, duy trì, cập nhật và xử lý các dữ liệu thông tin cá nhân do KH cung cấp, cập nhật và những thông tin phát sinh từ việc KH tham gia mở và sử dụng tài khoản (“Dữ Liệu”) và đồng ý cho Canifa sử dụng các Dữ Liệu này cho các mục đích, bao gồm nhưng không giới hạn: Phục vụ KH thực hiện các giao dịch theo quy định của tài khoản, giới thiệu các sản phẩm, dịch vụ mới của Canifa. Tất cả các Dữ Liệu sẽ được bảo vệ và được sử dụng theo quy định tại Chính sách bảo mật và chia sẻ thông tin được công bố công khai trên Trang Web và cập nhật tùy từng thời điểm.
2.6. Trường hợp thông tin cá nhân của KH có thay đổi so với thông tin đã đăng ký, KH có nghĩa vụ cập nhật kịp thời thông tin thay đổi qua Trang Web, Mobile App Canifa, Tổng Đài, cửa hàng Canifa để tránh việc sử dụng Thẻ/Tài khoản trái quy định. Canifa không chịu trách nhiệm đối với các sai sót, mất mát và các thiệt hại phát sinh từ hoặc liên quan đến KH do thông tin không được cập nhật kịp thời theo quy định tại ĐKĐK này.
2.7. Mọi thông báo/khiếu nại của KH đến Canifa phải được thực hiện thông qua Tổng Đài, email của Phòng Phát triển khách hàng, hệ thống cửa hàng của Canifa hoặc các hình thức khác theo quy định của Canifa tùy từng thời điểm.
2.8. Canifa có quyền đề nghị KH cung cấp thông tin và/hoặc xuất trình giấy tờ cá nhân hợp lệ ngay khi Canifa phát hiện KH thực hiện các hành vi quy định tại điều II.11 hoặc được nhận các ưu đãi trong một số trường hợp.
2.9. Canifa được miễn trách nhiệm trong trường hợp: (1) Hệ thống xử lý dữ liệu, phần mềm, hệ thống truyền tín hiệu gặp sự cố, bị lỗi, bị tấn công hoặc vì bất kỳ lý do khách quan nào khác nằm ngoài khả năng kiểm soát của Canifa; (2) Khi Thẻ bị lợi dụng trong trường hợp Thẻ bị mất cắp/thất lạc/lộ thông tin Tài Khoản mà chủ thẻ không kịp thời thông báo cho Canifa.
2.10. Canifa không chịu trách nhiệm trong trường hợp Khách hàng làm mất điện thoại, mất sim điện thoại dẫn đến thông tin tài khoản bị lộ mà chủ tài khoản không thông báo mất tài khoản tới Canifa.
2.11. Canifa được quyền từ chối cung cấp, hủy, truy đòi hoặc thu hồi những ưu đãi, điểm trong Tài Khoản đã hoặc sẽ nhận được theo các chương trình ưu đãi, khuyến mại mà không cần thông báo trước với KH trong các trường hợp: (1) Canifa không thể chuyển điểm/ ưu đãi cho khách hàng do các nguyên nhân khách quan nằm ngoài sự kiểm soát của Canifa; (2) Điểm được ghi có không chính xác, không hợp lệ vào Tài Khoản theo quy định; (3) KH có dấu hiệu sử dụng các công cụ hoặc phương thức gian lận nhằm trục lợi; (4) KH vi phạm các quy định của Chương trình/Chính sách ưu đãi được Canifa thông báo tại từng thời điểm; (5) Trong trường hợp bất khả kháng theo quy định pháp luật.
2.12. Canifa không chịu trách nhiệm cho bất kỳ tổn thất hoặc thiệt hại, dù trực tiếp hay gián tiếp của KH liên quan đến các chương trình ưu đãi khác, bao gồm nhưng không giới hạn trường hợp bất khả kháng theo quy định của pháp luật.
3. Chấm dứt quyền KHTT
Quyền KHTV theo Chương Trình có giá trị vô thời hạn trừ khi bị chấm dứt trong những trường hợp sau:
3.1. KHTV gửi yêu cầu chấm dứt cho Canifa qua địa chỉ liên lạc/email chính thức được đăng tải tại Trang Web.
3.2. KHTV cố ý sử dụng Thẻ/Tài Khoản sai quy định của Chương Trình và vi phạm ĐKĐK này.
3.3. KHTV qua đời hoặc các trường hợp chấm dứt khác theo quy định của pháp luật.
3.4. Khi Chương Trình chấm dứt vì bất cứ lý do gì.
3.5. Chấm dứt trong các trường hợp khác theo quy định của Chương Trình và ĐKĐK này.
3.6. Canifa bảo lưu quyền chấm dứt Chương Trình bằng cách thông báo cho tất cả KHTV trước 30 ngày thông qua Trang Web và/hoặc một phương thức phù hợp khác. Phương án giải quyết đối với các quyền lợi của KHTV của Chương Trình sẽ được công bố cùng thông báo chấm dứt Chương Trình.
4. Điều khoản chung
4.1. Tùy thuộc điều kiện thực tế, ĐKĐK của Chương Trình và các chính sách khác được công bố trên Trang Web có thể được sửa đổi/điều chỉnh/chấm dứt theo quyết định riêng của Canifa và sẽ được thông báo cho KHTV trên Trang Web.
4.2. Giải quyết tranh chấp: ĐKĐK này được điều chỉnh bởi pháp luật Việt Nam. Tất cả các tranh chấp phát sinh từ hoặc liên quan đến ĐKĐK này sẽ được các bên cố gắng giải quyết thông qua thương lượng. Trường hợp thương lượng đàm phán không thành công trong vòng 30 (ba mươi) ngày, các Bên sẽ có quyền đưa tranh chấp ra giải quyết tại tòa án có thẩm quyền tại Việt Nam theo quy định của pháp luật.
KHÁM PHÁ TIỆN ÍCH
CHỈ CÓ TRÊN APP
Ưu đãi độc quyền
cho thành viên
Nhận thông báo
sản phẩm mới và
khuyến mãi
Mua sắm tiện lợi
qua video call
với C-live
Quét mã vạch
kiểm tra hàng
tại cửa hàng
QUÉT MÃ
TẢI APP
HỆ THỐNG CỬA HÀNG
Tìm kiếm cửa hàng gần bạn!
Xem danh sách
ĐĂNG KÝ NHẬN BẢN TIN
Cập nhật những thông tin mới nhất về ưu đãi, thời trang và phong cách sống.
Đăng ký ngay
CÔNG TY CỔ PHẦN CANIFA
Số ĐKKD: 0107574310, ngày cấp: 23/09/2016
Nơi cấp: Sở Kế hoạch và đầu tư Hà Nội.
Trụ sở chính: số 688 Đường Quang Trung, P. Hà Đông, TP. Hà Nội.
Địa chỉ: Phòng 301, tầng 3, tòa nhà GP Invest, số 170 La Thành, P. Ô Chợ Dừa, TP. Hà Nội.
Điện thoại: 024 - 7303.0222
Fax: 024 - 6277.6419
Email: hello@canifa.com
Canifa 20 năm - Khoác lên niềm vui gia đình Việt
Năm 1997, Công ty Cổ phần Thương mại và Dịch vụ Hoàng Dương được thành lập với mục đích chính ban đầu là hoạt động trong lĩnh vực sản xuất hàng thời trang xuất khẩu với các sản phẩm chủ yếu làm từ len và sợi.
Năm 2001 thương hiệu thời trang CANIFA ra đời, tự hào trở thành một cột mốc đáng nhớ của doanh nghiệp Việt trong ngành thời trang.
Tầm nhìn và sứ mệnh
Mang đến niềm vui cho hàng triệu gia đình Việt
Canifa hướng đến mục tiêu mang lại niềm vui mặc mới mỗi ngày cho hàng triệu người tiêu dùng Việt. Chúng tôi tin rằng người dân Việt Nam cũng đang hướng đến một cuộc sống năng động, tích cực hơn.
Giá trị cốt lõi của Canifa
20 năm phát triển - Chúng tôi luôn tuân thủ những giá trị cốt lõi của mình.
Kinh doanh dựa trên giá trị thật:
CANIFA thiết lập hệ thống tiêu chuẩn chất lượng quốc tế áp dụng trên tất cả quy trình quản lý và kiểm soát chất lượng từ khâu chọn lọc nguyên phụ liệu cho đến khâu thiết kế và sản xuất (Oeko-tex, Cotton USA, Woolmark,...).
Canifa cam kết phát triển xanh cùng người Việt bằng suy nghĩ và hành động:
Vận hành xanh: Tổ hợp CANIFA Văn Giang tự hào là một đơn vị tiên phong nhận chứng chỉ quốc tế LEED về tiết kiệm năng lượng và ảnh hưởng tích cực đến môi trường sống.
Đối tác xanh: Canifa chọn Cotton USA - đơn vị cung cấp nguyên liệu chính cho sản phẩm tại CANIFA, luôn nghiêm minh tuân thủ các chỉ số bền vững của nông nghiệp Mỹ: tiết kiệm nước, kỹ thuật “không làm đất” để bảo vệ đất trồng.
Sản phẩm xanh: CANIFA đặc biệt chú trọng nghiên cứu, kiểm định chất lượng với nguyên liệu đầu vào và sản phẩm đầu ra, đáp ứng những yêu cầu khắt khe nhất của các chứng chỉ uy tín nhất thế giới (Oeko Tex, Woolmark, WD…)
CANIFA - LỊCH SỬ HÌNH THÀNH
1997 là năm Ngày 23/8/1997 Thành lập công ty TNHH Hoàng Dương
2001 là năm Ra đời thương hiệu thời trang CANIFA.
2002 là năm Xây dựng nhà máy Hoàng Dương Hưng Yên
2004 là năm Chương trình Hơi ấm mùa đông lần đầu tiên được khởi xướng bởi một nhóm các nhân viên, mở đầu cho các chương trình thiện nguyện sau này.
2012 là năm Ra đời cửa hàng bán lẻ “flagship store” đầu tiên của Canifa tại 181 Giảng Võ, Hà Nội. Chính thức chuyển đối từ mô hình kinh doanh đại lý sang chuỗi bán lẻ hiện đại. Thành lập chi nhánh Canifa HCM.
2014 là năm Canifa là thương hiệu thời trang đầu tiên ở Việt Nam nhận được chứng chỉ Woolmark - Tổ chức uy tín nhất thế giới về phát triển và kiểm soát chất lượng len lông cừu
2016 là năm ONOFF sáp nhập vào Canifa sau 10 năm hoạt động.
2019 là năm Tổ hợp xanh Canifa Văn Giang đi vào hoạt động, nhận được chứng chỉ LEED, tiêu chuẩn quốc tế về kiến trúc xanh.
Thanh toán
Thanh toán trả trước
Áp dụng thanh toán bằng QR Code, Thẻ ATM (thẻ ngân hàng, thẻ thanh toán nội địa) và Thẻ thanh toán quốc tế (Visa, Master, JCB, Amex…) qua cổng thanh toán VNPAY.
Quý khách thanh toán chọn hình thức thanh toán qua VNPAY và tiền hành thanh toán tại cổng thanh toán Vnpay sau khi chọn “Đặt hàng”
Thanh toán qua QR code
Bước 1: Chọn quét mã VNPAY tại cổng thanh toán VNPAY
Bước 2: Quét mã thanh toán tại App Ngân hàng đang sử dụng và tiến hành thanh toán
Thanh toán qua Thẻ ATM/Thẻ Thanh toán quốc tế
Bước 1: Chọn Thanh toán Thẻ ATM/Thẻ Thanh toán quốc tế tại cổng thanh toán VNPAY
Bước 2: Chọn Ngân hàng/Loại thẻ thanh toán
Bước 3: Nhập thông tin thẻ/tài khoản ngân hàng
Bước 4: Xác thực OTP
Đơn hàng thanh toán thành công khi website thông báo mã đơn hàng của bạn.
Thanh toán trả sau (COD)
Là hình thức khách hàng thanh toán tiền mặt trực tiếp cho bưu tá khi nhận hàng.
Khi hàng được chuyển giao đến bạn có thể mở gói hàng kiểm tra sản phẩm trước khi thanh toán (tuy nhiên CANIFA không hỗ trợ thử sản phẩm). Nếu sản phẩm có bất kỳ lỗi hay khiếm khuyết nào không đúng ý muốn, bạn có thể trả lại nhân viên vận chuyển ngay tại thời điểm đó.
Hoàn tiền
CANIFA sẽ hoàn tiền cho bạn trong những trường hợp sau:
Bạn đã thanh toán trước và muốn hủy đơn hàng khi CANIFA chưa vận chuyển.
Bạn muốn trả lại hàng do lỗi sản xuất và không muốn đổi sang sản phẩm khác.
CANIFA sẽ hoàn tiền lại vào tài khoản cá nhân của bạn. Chúng tôi sẽ cố gắng hoàn tiền nhanh nhất có thể và thời gian hoàn tiền không quá 15 ngày tính từ khi xác nhận hoàn tiền.
VẬN CHUYỂN
Cước phí vận chuyển
CANIFA áp dụng chính sách miễn phí giao hàng cho tất cả các đơn hàng có giá trị từ 599.000 VNĐ trở lên, áp dụng trên toàn bộ các tỉnh thành trên toàn quốc.
Đối với các đơn hàng có giá trị dưới 599.000 VNĐ, CANIFA áp dụng phí vận chuyển theo từng khu vực như sau. Biểu phí này được áp dụng từ ngày 14/08/2023 cho đến khi có thông báo thay đổi mới.
Tại khu vực Hà Nội, các đơn hàng giao đến các quận Đống Đa, Hoàn Kiếm, Ba Đình, Hai Bà Trưng, Cầu Giấy và Thanh Xuân sẽ được áp dụng phí vận chuyển 20.000 VNĐ.
Đối với các quận và huyện còn lại của Hà Nội bao gồm Hà Đông, Tây Hồ, Hoàng Mai, Long Biên, Bắc Từ Liêm, Nam Từ Liêm, Ba Vì, Chương Mỹ, Đan Phượng, Đông Anh, Gia Lâm, Hoài Đức, Mê Linh, Mỹ Đức, Phúc Thọ, Phú Xuyên, Quốc Oai, Sóc Sơn, Thạch Thất, Thanh Oai, Thanh Trì, Thường Tín, Ứng Hòa và Thị xã Sơn Tây, phí vận chuyển là 30.000 VNĐ.
Tại TP. Hồ Chí Minh, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Tại Đà Nẵng, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Đối với các tỉnh thành khác trên toàn quốc, CANIFA chia làm hai mức phí vận chuyển.
Mức 30.000 VNĐ được áp dụng cho các tỉnh thành bao gồm: Bắc Giang, Bắc Ninh, Hà Nam, Hải Dương, Hải Phòng, Hưng Yên, Hòa Bình, Nam Định, Phú Thọ, Thái Nguyên, Vĩnh Phúc, Bắc Kạn, Lạng Sơn, Nghệ An, Ninh Bình, Quảng Ninh, Thái Bình, Thanh Hóa, Tuyên Quang và Yên Bái.
Mức 40.000 VNĐ được áp dụng cho các tỉnh thành còn lại, bao gồm: Điện Biên, Lào Cai, Hà Giang, Sơn La, Cao Bằng, Thừa Thiên Huế, Quảng Trị, Gia Lai, Đắk Lắk, Kon Tum, Đắk Nông, Phú Yên, Khánh Hòa, Hà Tĩnh, Tiền Giang, Bến Tre, Tây Ninh, Đồng Tháp, Trà Vinh, Vĩnh Long, Đồng Nai, Bình Dương, Bà Rịa – Vũng Tàu, Long An, Quảng Bình, Bình Định (Quy Nhơn), Bình Thuận, Ninh Thuận, Bình Phước, Cần Thơ, Hậu Giang, Kiên Giang, An Giang, Sóc Trăng, Bạc Liêu, Cà Mau và Quảng Ngãi.
Thời gian vận chuyển
Đối với khu vực Hà Nội, thời gian giao hàng dự kiến từ 1 đến 3 ngày kể từ khi hệ thống xác nhận đơn hàng qua tin nhắn SMS.
Đối với tuyến Đà Nẵng và TP. Hồ Chí Minh, thời gian giao hàng dự kiến trong vòng 3 ngày kể từ khi hệ thống xác nhận qua SMS.
Đối với các tỉnh thành khác, thời gian giao hàng dự kiến từ 3 đến 7 ngày kể từ khi hệ thống xác nhận đơn hàng.
Thời gian giao hàng không bao gồm thứ Bảy, Chủ nhật và các ngày Lễ, Tết theo quy định.
Số lần giao hàng
Mỗi đơn hàng được giao tối đa 3 lần. Trong trường hợp lần giao đầu tiên không thành công, nhân viên vận chuyển sẽ liên hệ lại và thực hiện giao lần tiếp theo sau 1–2 ngày làm việc. Nếu sau 3 lần giao hàng vẫn không thành công, đơn hàng sẽ được tự động hủy.
Kiểm tra tình trạng đơn hàng
Để kiểm tra thông tin hoặc tình trạng đơn hàng, khách hàng vui lòng sử dụng Mã đơn hàng đã được gửi trong email xác nhận hoặc tin nhắn SMS, và liên hệ đến bộ phận Chăm sóc khách hàng qua tổng đài miễn phí 1800 6061 (nhánh 1) để được hỗ trợ.
Kiểm tra sản phẩm khi nhận hàng
Khi nhận đơn hàng, khách hàng hoàn toàn có thể mở gói hàng để kiểm tra sản phẩm trước khi thanh toán hoặc trước khi nhân viên vận chuyển rời đi.
Trong trường hợp phát sinh bất kỳ vấn đề nào liên quan đến đơn hàng, khách hàng vui lòng liên hệ ngay với CANIFA qua 1800 6061 (nhánh 1) để được hỗ trợ kịp thời.
Đổi hàng
Quy định đổi hàng online
1.3.1 Quy định chung
- Áp dụng 01 lần/ 01 hóa đơn trong vòng 30 ngày kể từ ngày mua hàng/ nhận hàng.
- Tại tất cả các cửa hàng thuộc hệ thống Canifa trên toàn quốc & hệ thống online (Web/App Canifa).
Đối với hàng Nguyên giá/ Giá tốt:
- Đổi sang sản phẩm nguyên giá khác.
- Nếu khách hàng chưa tìm được sản phẩm phù hợp để đổi, Canifa sẽ nhận lại sản phẩm đó và hỗ trợ khách hàng đổi sang giấy “Biên nhận” có giá trị tương đương với sản phẩm đã mua.
- Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá;
- Sản phẩm khi mua là hàng nguyên giá, tại thời điểm đổi là hàng giảm giá thì áp dụng chính sách như đổi sản phẩm nguyên giá.
- Sản phẩm khi mua là hàng giảm giá, tại thời điểm đổi là hàng nguyên giá thì quy cả 2 sản phẩm về nguyên giá để đổi.
Đối với hàng Giảm giá/ Khuyến mại:
- Đổi sang màu hoặc size khác trên cùng 1 mã sản phẩm hoặc đổi hàng theo quy chế riêng của từng Chương trình khuyến mại. Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng hỗ trợ khách hàng đổi sang giấy “Biên nhận” có giá trị tương đương với sản phẩm đã mua.
1.3.2 Điều kiện đổi hàng:
- Chính sách chỉ áp dụng khi khách hàng còn giữ hóa đơn mua hàng, sản phẩm còn nguyên nhãn mác, thẻ bài đính kèm và còn mới, không bị dơ bẩn, hư hỏng bởi những tác nhân bên ngoài, thay đổi kết cấu sản phẩm.
- Sản phẩm đồ lót và phụ kiện không được đổi.
- Đối với đơn mua tại cửa hàng: khách hàng cần xuất trình Đơn mua hàng gốc (và hóa đơn giá trị gia tăng gốc nếu có).
- Đối với đơn mua online: khách hàng cần gửi lại sản phẩm về kho online kèm với phiếu mua hàng đã nhận.
- Khách hàng thanh toán phần tiền chênh lệch nếu sản phẩm đổi có giá trị cao hơn sản phẩm đã mua.
- Khách hàng không được hoàn lại tiền chênh lệch nếu sản phẩm đổi có giá trị thấp hơn sản phẩm đã mua.
1.3.3 Quy trình đổi hàng Online (Web/App).
- Quy trình hỗ trợ đổi hàng:
+ Sau khi Canifa ghi nhận thông tin đơn hàng đổi, KH gửi hàng về theo địa chỉ Canifa cung cấp (KH chịu phí gửi trả hàng).
+ Ngay sau khi nhận được hàng đổi trả, Canifa sẽ gửi lại hàng mới cho KH theo địa chỉ KH đã cung cấp (Canifa hỗ trợ phí chuyển hàng mới).
- Quy trình đổi hàng lỗi (TH khách hàng đồng ý đổi):
+ Sau khi tiếp nhận yêu cầu đổi hàng, Canifa báo đơn vị vận chuyển qua lấy hàng chuyển về kho online để đổi.
+ Kho online nhận được hàng đổi, chuyển lại hàng đổi cho KH.
Lưu ý: Canifa chịu phí cả 2 chiều.
- Quy trình đổi hàng lỗi (TH khách hàng không đồng ý đổi):
+ Canifa hỗ trợ hoàn lại số tiền tương ứng với giá trị sản phầm lỗi.
+ Thời gian khách hàng được hoàn tiền trong vòng 10-15 ngày kể từ ngày tiếp nhận sản phẩm lỗi.
1.3.4 Lưu ý khác:
- Giấy “Biên nhận” có hiệu lực trong vòng 15 ngày kể từ ngày cấp và có giá trị tương đương tiền mặt khi mua sắm tại Canifa.
- Đối với các đơn hàng online, chỉ áp dụng đổi sang giấy “Biên nhận” khi khách hàng ra cửa hàng đổi và chỉ sử dụng giấy “Biên nhận” mua sắm tại cửa hàng.
- Giấy “Biên nhận” bắt buộc có thông tin người mua hàng: tên và số điện thoại.
Quy định đổi sản phẩm mua tại cửa hàng
1.3.1 Quy định chung
- Áp dụng 01 lần/ 01 hóa đơn trong vòng 30 ngày kể từ ngày mua hàng/ nhận hàng.
- Tại tất cả các cửa hàng thuộc hệ thống Canifa trên toàn quốc.
Đối với hàng Nguyên giá/ Giá tốt:
- Đổi sang sản phẩm nguyên giá khác.
- Nếu khách hàng chưa tìm được sản phẩm phù hợp để đổi, Canifa sẽ nhận lại sản phẩm đó và hỗ trợ khách hàng đổi sang giấy “Biên nhận” có giá trị tương đương với sản phẩm đã mua.
- Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá;
- Sản phẩm khi mua là hàng nguyên giá, tại thời điểm đổi là hàng giảm giá thì áp dụng chính sách như đổi sản phẩm nguyên giá.
- Sản phẩm khi mua là hàng giảm giá, tại thời điểm đổi là hàng nguyên giá thì quy cả 2 sản phẩm về nguyên giá để đổi.
Đối với hàng Giảm giá/ Khuyến mại:
- Đổi sang màu hoặc size khác trên cùng 1 mã sản phẩm hoặc đổi hàng theo quy chế riêng của từng Chương trình khuyến mại. Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng hỗ trợ khách hàng đổi sang giấy “Biên nhận” có giá trị tương đương với sản phẩm đã mua.
1.3.2 Điều kiện đổi hàng:
- Chính sách chỉ áp dụng khi khách hàng còn giữ hóa đơn mua hàng, sản phẩm còn nguyên nhãn mác, thẻ bài đính kèm và còn mới, không bị dơ bẩn, hư hỏng bởi những tác nhân bên ngoài, thay đổi kết cấu sản phẩm.
- Sản phẩm đồ lót và phụ kiện không được đổi.
- Đối với đơn mua tại cửa hàng: khách hàng cần xuất trình Đơn mua hàng gốc (và hóa đơn giá trị gia tăng gốc nếu có).
- Đối với đơn mua online: khách hàng cần gửi lại sản phẩm về kho online kèm với phiếu mua hàng đã nhận.
- Khách hàng thanh toán phần tiền chênh lệch nếu sản phẩm đổi có giá trị cao hơn sản phẩm đã mua.
- Khách hàng không được hoàn lại tiền chênh lệch nếu sản phẩm đổi có giá trị thấp hơn sản phẩm đã mua.
- Quy trình đổi hàng lỗi (TH khách hàng đồng ý đổi):
+ Sau khi tiếp nhận yêu cầu đổi hàng, Canifa báo đơn vị vận chuyển qua lấy hàng chuyển về kho online để đổi.
+ Kho online nhận được hàng đổi, chuyển lại hàng đổi cho KH.
Lưu ý: Canifa chịu phí cả 2 chiều.
- Quy trình đổi hàng lỗi (TH khách hàng không đồng ý đổi):
+ Canifa hỗ trợ hoàn lại số tiền tương ứng với giá trị sản phầm lỗi.
+ Thời gian khách hàng được hoàn tiền trong vòng 10-15 ngày kể từ ngày tiếp nhận sản phẩm lỗi.
1.3.4 Lưu ý khác:
- Giấy “Biên nhận” có hiệu lực trong vòng 15 ngày kể từ ngày cấp và có giá trị tương đương tiền mặt khi mua sắm tại Canifa.
- Đối với các đơn hàng online, chỉ áp dụng đổi sang giấy “Biên nhận” khi khách hàng ra cửa hàng đổi và chỉ sử dụng giấy “Biên nhận” mua sắm tại cửa hàng.
- Giấy “Biên nhận” bắt buộc có thông tin người mua hàng: tên và số điện thoại.
CÂU HỎI THƯỜNG GẶP
Cước phí vận chuyển được tính như thế nào?
CANIFA áp dụng miễn phí giao hàng cho tất cả các đơn hàng có giá trị từ 599.000 VNĐ trở lên, áp dụng trên toàn bộ các tỉnh thành trên cả nước.
Đối với các đơn hàng có giá trị dưới 599.000 VNĐ, CANIFA áp dụng biểu phí vận chuyển theo từng khu vực, có hiệu lực từ ngày 14/08/2023 cho đến khi có thông báo thay đổi mới.
Tại khu vực Hà Nội, các đơn hàng giao đến các quận Đống Đa, Hoàn Kiếm, Ba Đình, Hai Bà Trưng, Cầu Giấy và Thanh Xuân được áp dụng phí vận chuyển 20.000 VNĐ.
Các quận và huyện còn lại của Hà Nội bao gồm Hà Đông, Tây Hồ, Hoàng Mai, Long Biên, Bắc Từ Liêm, Nam Từ Liêm, Ba Vì, Chương Mỹ, Đan Phượng, Đông Anh, Gia Lâm, Hoài Đức, Mê Linh, Mỹ Đức, Phúc Thọ, Phú Xuyên, Quốc Oai, Sóc Sơn, Thạch Thất, Thanh Oai, Thanh Trì, Thường Tín, Ứng Hòa và Thị xã Sơn Tây được áp dụng phí vận chuyển 30.000 VNĐ.
Tại TP. Hồ Chí Minh, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Tại Đà Nẵng, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Đối với các tỉnh thành khác, CANIFA áp dụng hai mức phí.
Mức 30.000 VNĐ áp dụng cho các tỉnh thành gồm: Bắc Giang, Bắc Ninh, Hà Nam, Hải Dương, Hải Phòng, Hưng Yên, Hòa Bình, Nam Định, Phú Thọ, Thái Nguyên, Vĩnh Phúc, Bắc Kạn, Lạng Sơn, Nghệ An, Ninh Bình, Quảng Ninh, Thái Bình, Thanh Hóa, Tuyên Quang và Yên Bái.
Mức 40.000 VNĐ áp dụng cho các tỉnh thành còn lại như: Điện Biên, Lào Cai, Hà Giang, Sơn La, Cao Bằng, Thừa Thiên Huế, Quảng Trị, Gia Lai, Đắk Lắk, Kon Tum, Đắk Nông, Phú Yên, Khánh Hòa, Hà Tĩnh, Tiền Giang, Bến Tre, Tây Ninh, Đồng Tháp, Trà Vinh, Vĩnh Long, Đồng Nai, Bình Dương, Bà Rịa – Vũng Tàu, Long An, Quảng Bình, Bình Định (Quy Nhơn), Bình Thuận, Ninh Thuận, Bình Phước, Cần Thơ, Hậu Giang, Kiên Giang, An Giang, Sóc Trăng, Bạc Liêu, Cà Mau và Quảng Ngãi.
CANIFA hỗ trợ những hình thức thanh toán nào?
CANIFA hiện hỗ trợ thanh toán trả trước thông qua cổng thanh toán VNPAY, bao gồm các hình thức:
thanh toán bằng QR Code, Thẻ ATM (thẻ ngân hàng nội địa) và Thẻ thanh toán quốc tế như Visa, MasterCard, JCB, Amex.
Sau khi hoàn tất bước “Đặt hàng”, quý khách lựa chọn hình thức thanh toán qua VNPAY và tiến hành thanh toán trực tiếp tại cổng thanh toán VNPAY.
Hướng dẫn thanh toán bằng QR Code
Bước 1: Tại cổng thanh toán VNPAY, chọn hình thức Quét mã VNPAY.
Bước 2: Sử dụng ứng dụng ngân hàng đang dùng để quét mã QR và thực hiện thanh toán theo hướng dẫn.
Hướng dẫn thanh toán bằng Thẻ ATM hoặc Thẻ thanh toán quốc tế
Bước 1: Tại cổng thanh toán VNPAY, chọn Thanh toán bằng Thẻ ATM/Thẻ thanh toán quốc tế.
Bước 2: Chọn ngân hàng hoặc loại thẻ tương ứng.
Bước 3: Nhập thông tin thẻ hoặc tài khoản ngân hàng theo yêu cầu.
Bước 4: Thực hiện xác thực OTP để hoàn tất thanh toán.
Đơn hàng được xem là thanh toán thành công khi website hiển thị mã đơn hàng của quý khách.
CANIFA có hỗ trợ đổi hàng online không?
CANIFA hỗ trợ đổi hàng online theo các quy định sau:
Quy định chung
Mỗi hóa đơn chỉ được áp dụng 01 lần đổi hàng, trong vòng 30 ngày kể từ ngày mua hàng hoặc nhận hàng.
Chính sách đổi hàng áp dụng tại tất cả các cửa hàng CANIFA trên toàn quốc và trên hệ thống online (Website/App CANIFA).
Quy định đổi hàng đối với sản phẩm nguyên giá / giá tốt
Khách hàng được đổi sang sản phẩm nguyên giá khác.
Trong trường hợp khách hàng chưa chọn được sản phẩm phù hợp để đổi, CANIFA sẽ nhận lại sản phẩm và hỗ trợ đổi sang giấy “Biên nhận” có giá trị tương đương sản phẩm đã mua.
Các sản phẩm nguyên giá được giảm theo quyền lợi hạng Gold/Diamond vẫn được áp dụng chính sách đổi như hàng nguyên giá.
Nếu sản phẩm khi mua là hàng nguyên giá nhưng tại thời điểm đổi đã trở thành hàng giảm giá, CANIFA vẫn áp dụng chính sách đổi như hàng nguyên giá.
Nếu sản phẩm khi mua là hàng giảm giá nhưng tại thời điểm đổi là hàng nguyên giá, CANIFA sẽ quy cả hai sản phẩm về nguyên giá để thực hiện đổi hàng.
Quy định đổi hàng đối với sản phẩm giảm giá / khuyến mại
Khách hàng được đổi sang màu sắc hoặc size khác trên cùng một mã sản phẩm, hoặc đổi hàng theo quy định riêng của từng chương trình khuyến mại.
Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng sẽ hỗ trợ đổi sang giấy “Biên nhận” có giá trị tương đương sản phẩm đã mua.
Điều kiện đổi hàng là gì?
Chính sách đổi hàng chỉ áp dụng khi khách hàng còn giữ hóa đơn mua hàng, sản phẩm còn nguyên nhãn mác, thẻ bài, còn mới, không bị dơ bẩn, hư hỏng do tác nhân bên ngoài hoặc thay đổi kết cấu sản phẩm.
Các sản phẩm đồ lót và phụ kiện không áp dụng đổi hàng.
Đối với đơn mua tại cửa hàng, khách hàng cần xuất trình đơn mua hàng gốc (và hóa đơn giá trị gia tăng gốc nếu có).
Đối với đơn mua online, khách hàng cần gửi sản phẩm về kho online kèm theo phiếu mua hàng đã nhận.
Khách hàng cần thanh toán phần chênh lệch nếu sản phẩm đổi có giá trị cao hơn sản phẩm đã mua.
CANIFA không hoàn lại tiền chênh lệch nếu sản phẩm đổi có giá trị thấp hơn sản phẩm đã mua.
Quy trình đổi hàng online (Website/App) như thế nào?
Sau khi CANIFA ghi nhận yêu cầu đổi hàng, khách hàng gửi sản phẩm về địa chỉ CANIFA cung cấp và chịu phí gửi trả hàng.
Ngay khi CANIFA nhận được sản phẩm đổi, CANIFA sẽ gửi sản phẩm mới về địa chỉ khách hàng đã cung cấp và hỗ trợ phí vận chuyển chiều gửi hàng mới.
Quy trình đổi hàng lỗi được xử lý ra sao?
Trong trường hợp khách hàng đồng ý đổi hàng lỗi, CANIFA sẽ liên hệ đơn vị vận chuyển đến lấy hàng chuyển về kho online. Sau khi kho online nhận được sản phẩm lỗi, CANIFA sẽ gửi lại sản phẩm đổi cho khách hàng. Trong trường hợp này, CANIFA chịu toàn bộ chi phí hai chiều.
Trong trường hợp khách hàng không đồng ý đổi hàng lỗi, CANIFA sẽ hỗ trợ hoàn lại số tiền tương ứng với giá trị sản phẩm lỗi. Thời gian hoàn tiền dự kiến trong vòng 10–15 ngày kể từ ngày CANIFA tiếp nhận sản phẩm lỗi.
Các lưu ý khác khi đổi hàng
Giấy “Biên nhận” có hiệu lực trong vòng 15 ngày kể từ ngày cấp và có giá trị tương đương tiền mặt khi mua sắm tại CANIFA.
Đối với các đơn hàng online, chỉ áp dụng đổi sang giấy “Biên nhận” khi khách hàng đổi hàng trực tiếp tại cửa hàng, và giấy “Biên nhận” chỉ được sử dụng để mua sắm tại cửa hàng CANIFA.
Giấy “Biên nhận” bắt buộc phải có thông tin người mua hàng, bao gồm tên và số điện thoại
HƯỚNG DẪN CHỌN SIZE - CANIFA
* Đơn vị tính: cm, kg
================================================================================
BẢNG SIZE CHUNG CHO NỮ
================================================================================
Size XS - BẢNG SIZE CHUNG CHO NỮ:
- Chiều cao: 147-153 cm
- Cân nặng: 38-43 kg
- Vòng ngực: 74-80 cm
- Vòng mông: 82-88 cm
Size S - BẢNG SIZE CHUNG CHO NỮ:
- Chiều cao: 150-155 cm
- Cân nặng: 41-46 kg
- Vòng ngực: 79-82 cm
- Vòng mông: 88-90 cm
Size M - BẢNG SIZE CHUNG CHO NỮ:
- Chiều cao: 155-163 cm
- Cân nặng: 47-52 kg
- Vòng ngực: 82-87 cm
- Vòng mông: 90-94 cm
Size L - BẢNG SIZE CHUNG CHO NỮ:
- Chiều cao: 160-165 cm
- Cân nặng: 53-58 kg
- Vòng ngực: 88-94 cm
- Vòng mông: 94-98 cm
Size XL - BẢNG SIZE CHUNG CHO NỮ:
- Chiều cao: 162-166 cm
- Cân nặng: 59-64 kg
- Vòng ngực: 94-99 cm
- Vòng mông: 98-102 cm
================================================================================
QUẦN NỮ (Size số)
================================================================================
Size 26 (XS) - QUẦN NỮ (Size số):
- Vòng eo: 65 cm
- Vòng mông (dáng slim): 79 cm
- Vòng mông (dáng regular): 86.92 cm
- Chiều dài quần: 93 cm
- Rộng gấu (dáng slim): 12.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 27 (S) - QUẦN NỮ (Size số):
- Vòng eo: 67.5 cm
- Vòng mông (dáng slim): 81.5 cm
- Vòng mông (dáng regular): 89.46 cm
- Chiều dài quần: 94 cm
- Rộng gấu (dáng slim): 13 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 28 (M) - QUẦN NỮ (Size số):
- Vòng eo: 70 cm
- Vòng mông (dáng slim): 84 cm
- Vòng mông (dáng regular): 92 cm
- Chiều dài quần: 95 cm
- Rộng gấu (dáng slim): 13.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 29 (L) - QUẦN NỮ (Size số):
- Vòng eo: 72.5 cm
- Vòng mông (dáng slim): 86.5 cm
- Vòng mông (dáng regular): 94.5 cm
- Chiều dài quần: 96 cm
- Rộng gấu (dáng slim): 14 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 30 (XL) - QUẦN NỮ (Size số):
- Vòng eo: 75 cm
- Vòng mông (dáng slim): 89 cm
- Vòng mông (dáng regular): 97.1 cm
- Chiều dài quần: 97 cm
- Rộng gấu (dáng slim): 14.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
================================================================================
QUẦN JEANS - KHAKI (NỮ)
================================================================================
Size 26 (XS) - QUẦN JEANS - KHAKI (NỮ):
- Vòng bụng: 65 cm
- Vòng mông: 79 cm
- Chiều dài quần: 93 cm
- Rộng ống (dáng slim): 12.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 27 (S) - QUẦN JEANS - KHAKI (NỮ):
- Vòng bụng: 67.5 cm
- Vòng mông: 81.5 cm
- Chiều dài quần: 94 cm
- Rộng ống (dáng slim): 13 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 28 (M) - QUẦN JEANS - KHAKI (NỮ):
- Vòng bụng: 70 cm
- Vòng mông: 84 cm
- Chiều dài quần: 95 cm
- Rộng ống (dáng slim): 13.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 29 (L) - QUẦN JEANS - KHAKI (NỮ):
- Vòng bụng: 72.5 cm
- Vòng mông: 86.5 cm
- Chiều dài quần: 96 cm
- Rộng ống (dáng slim): 14 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 30 (XL) - QUẦN JEANS - KHAKI (NỮ):
- Vòng bụng: 75 cm
- Vòng mông: 89 cm
- Chiều dài quần: 97 cm
- Rộng ống (dáng slim): 14.5 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
================================================================================
BẢNG SIZE CHUNG CHO NAM
================================================================================
Size S - BẢNG SIZE CHUNG CHO NAM:
- Chiều cao: 162-168 cm
- Cân nặng: 57-62 kg
- Vòng ngực: 84-88 cm
- Vòng mông: 85-89 cm
Size M - BẢNG SIZE CHUNG CHO NAM:
- Chiều cao: 169-173 cm
- Cân nặng: 63-67 kg
- Vòng ngực: 88-94 cm
- Vòng mông: 90-94 cm
Size L - BẢNG SIZE CHUNG CHO NAM:
- Chiều cao: 171-175 cm
- Cân nặng: 68-72 kg
- Vòng ngực: 94-98 cm
- Vòng mông: 95-99 cm
Size XL - BẢNG SIZE CHUNG CHO NAM:
- Chiều cao: 173-177 cm
- Cân nặng: 73-77 kg
- Vòng ngực: 98-104 cm
- Vòng mông: 100-104 cm
Size XXL - BẢNG SIZE CHUNG CHO NAM:
- Chiều cao: 175-179 cm
- Cân nặng: 78-82 kg
- Vòng ngực: 104-107 cm
- Vòng mông: 104-108 cm
================================================================================
QUẦN JEANS - KHAKI (NAM)
================================================================================
Size 29 (S) - QUẦN JEANS - KHAKI (NAM):
- Vòng eo: 79.5 cm
- Vòng mông: 96.5 cm
- Chiều dài quần: 99.8 cm
- Rộng ống (dáng slim): 15.4 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 30 (M) - QUẦN JEANS - KHAKI (NAM):
- Vòng eo: 82 cm
- Vòng mông: 99 cm
- Chiều dài quần: 100.5 cm
- Rộng ống (dáng slim): 16 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 31 (L) - QUẦN JEANS - KHAKI (NAM):
- Vòng eo: 84.5 cm
- Vòng mông: 101.5 cm
- Chiều dài quần: 101.2 cm
- Rộng ống (dáng slim): 16.6 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 32 (XL) - QUẦN JEANS - KHAKI (NAM):
- Vòng eo: 87 cm
- Vòng mông: 104 cm
- Chiều dài quần: 101.2 cm
- Rộng ống (dáng slim): 17.2 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
Size 33 (XXL) - QUẦN JEANS - KHAKI (NAM):
- Vòng eo: 89 cm
- Vòng mông: 106.5 cm
- Chiều dài quần: 101.2 cm
- Rộng ống (dáng slim): 17.8 cm
- Rộng gấu (dáng regular): Tùy mẫu kích thước khác nhau
================================================================================
BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023)
================================================================================
Size 92 (2Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 88-94 cm
- Cân nặng: 10-13 kg
Size 98 (2-3Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 95-101 cm
- Cân nặng: 13-15 kg
Size 104 (3-4Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 101-107 cm
- Cân nặng: 15-18 kg
Size 110 (4-5Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 107-113 cm
- Cân nặng: 18-22 kg
Size 116 (6Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 113-119 cm
- Cân nặng: 22-25 kg
Size 122 (7Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 119-125 cm
- Cân nặng: 25-28 kg
Size 128 (8Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 125-131 cm
- Cân nặng: 28-32 kg
Size 134 (9Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 131-137 cm
- Cân nặng: 32-36 kg
Size 140 (10-11Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 137-145 cm
- Cân nặng: 36-39 kg
Size 152 (11-12Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 145-157 cm
- Cân nặng: 39-46 kg
Size 164 (13-14Y) - BẢNG SIZE CHUNG TRẺ EM (sản phẩm từ Thu Đông 2023):
- Chiều cao: 157-169 cm
- Cân nặng: 46-55 kg
================================================================================
BẢNG SIZE CHUNG CHO BÉ TRAI
================================================================================
Size 90 (2Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 90 cm
- Cân nặng: 10-13 kg
Size 100 (3-4Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 100 cm
- Cân nặng: 14-17 kg
Size 110 (4-5Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 110 cm
- Cân nặng: 18-23 kg
Size 120 (6-7Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 120 cm
- Cân nặng: 24-29 kg
Size 130 (8Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 130 cm
- Cân nặng: 29-33 kg
Size 140 (9-11Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 140 cm
- Cân nặng: 33-39 kg
Size 150 (11-12Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 150 cm
- Cân nặng: 39-45 kg
Size 160 (13-14Y) - BẢNG SIZE CHUNG CHO BÉ TRAI:
- Chiều cao: 160 cm
- Cân nặng: 45-52 kg
================================================================================
BẢNG SIZE CHUNG CHO BÉ GÁI
================================================================================
Size 90 (2Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 90 cm
- Cân nặng: 10-13 kg
Size 100 (3-4Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 100 cm
- Cân nặng: 14-17 kg
Size 110 (4-5Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 110 cm
- Cân nặng: 18-23 kg
Size 120 (6-7Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 120 cm
- Cân nặng: 24-29 kg
Size 130 (8Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 130 cm
- Cân nặng: 29-33 kg
Size 140 (9-11Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 140 cm
- Cân nặng: 33-39 kg
Size 150 (11-12Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 150 cm
- Cân nặng: 39-45 kg
Size 160 (13-14Y) - BẢNG SIZE CHUNG CHO BÉ GÁI:
- Chiều cao: 160 cm
- Cân nặng: 45-50 kg
================================================================================
BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN
================================================================================
Size XXS - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 155 - 163 cm
- Cân nặng: 47 - 52 kg
Size XS - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 160 - 165 cm
- Cân nặng: 53 - 58 kg
Size S - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 162 - 168 cm
- Cân nặng: 57 - 62 kg
Size M - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 169 - 173 cm
- Cân nặng: 63 - 67 kg
Size L - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 171 - 175 cm
- Cân nặng: 68 - 72 kg
Size XL - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 173 - 177 cm
- Cân nặng: 73 - 77 kg
Size XXL - BẢNG SIZE CHUNG CHO UNISEX - NGƯỜI LỚN:
- Chiều cao: 175 - 179 cm
- Cân nặng: 79 - 82 kg
================================================================================
BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM
================================================================================
Dải size lẻ:
Size 92 (2Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 92 cm
- Cân nặng: 10 - 13 kg
Size 98 (2-3Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 98 cm
- Cân nặng: 13 - 15 kg
Size 104 (3-4Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 104 cm
- Cân nặng: 15 - 18 kg
Size 110 (4-5Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 110 cm
- Cân nặng: 18 - 22 kg
Size 116 (6Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 116 cm
- Cân nặng: 22 - 25 kg
Size 122 (7Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 122 cm
- Cân nặng: 25 - 28 kg
Size 128 (8Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 128 cm
- Cân nặng: 28 - 32 kg
Size 134 (9Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 134 cm
- Cân nặng: 32 - 36 kg
Size 140 (9-10Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 140 cm
- Cân nặng: 36 - 39 kg
Size 152 (11-12Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 152 cm
- Cân nặng: 39 - 46 kg
Size 164 (13-14Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size lẻ):
- Chiều cao: 164 cm
- Cân nặng: 46 - 55 kg
Dải size chẵn:
Size 90 (2Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 90 cm
- Cân nặng: 10 - 13 kg
Size 100 (2-3Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 100 cm
- Cân nặng: 14 - 17 kg
Size 110 (4-5Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 110 cm
- Cân nặng: 18 - 23 kg
Size 120 (6-7Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 120 cm
- Cân nặng: 24 - 29 kg
Size 130 (8Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 130 cm
- Cân nặng: 29 - 33 kg
Size 140 (9-10Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 140 cm
- Cân nặng: 33 - 39 kg
Size 150 (11-12Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 150 cm
- Cân nặng: 39 - 45 kg
Size 160 (13-14Y) - BẢNG SIZE CHUNG CHO UNISEX - TRẺ EM - (Dải size chẵn):
- Chiều cao: 160 cm
- Cân nặng: 45 - 52 kg
================================================================================
FILE: data/text/lien-he-html.txt
================================================================================
Hỗ trợ Khách hàng mua online
Tổng đài: 1800 6061
Từ 9h - 12h, 13h - 21h các ngày từ thứ 2 đến Chủ nhật
Email: saleonline@canifa.com
Địa chỉ: Phòng 301 Tòa nhà GP Invest, 170 La Thành, P. Ô Chợ Dừa, Q. Đống Đa, Hà Nội
Chăm sóc khách hàng:
Điện thoại: 1800.6061
Email: chamsockhachhang@canifa.com
Đặt đồng phục
Ms. Hoa
Điện thoại: 0963.03.03.67
Email: grb2b@canifa.com
Văn phòng miền Bắc
Phòng 301 Tòa nhà GP Invest, 170 La Thành, P. Ô Chợ Dừa, Q. Đống Đa, Hà Nội
Điện thoại: +8424-7303.0222
Fax: +8424 - 6277.6419
Email: hello@canifa.com
Website: www.canifa.com
Văn phòng miền Nam
Địa chỉ: 97 Cao Thắng , Phường 3, Quận 3, TP. HCM
Điện thoại: +8428 3824.7141
Email: infocanifa@canifa.com
Liên hệ làm Nhà phân phối và Đại lý
(KV miền Bắc)
Mr. Nguyễn Đức Bằng
Điện thoại: 0904.530.833
Email: bangnd@canifa.com
Liên hệ làm Nhà phân phối và Đại lý
(KV Miền Nam từ Đà Nẵng đến Cà Mau)
Mr. Nguyễn Công Thành
Điện thoại: 0914.396.239
Email: thanhnc@canifa.com
Nhà máy
Đường Nguyễn Văn Linh, Phường Bần Yên Nhân, T.X Mỹ Hào, Hưng Yên
Điện thoại: +84-221- 394 2234
Fax: +84 - 221-394 2235
Phát triển bền vững: 03 xanh
Với mục tiêu phát triển bền vững, CANIFA tập trung nghiên cứu và cải tiến hoạt động sản xuất kinh doanh để đảm bảo nguyên tắc 3 XANH
Bảo vệ môi trường là 01 trong những nguyên tắc hoạt động cốt lõi của Tập đoàn. Tiêu biểu: Tổ hợp Canifa Văn Giang - đơn vị tiên phong trong ngành dệt may tại Việt Nam nhận chứng chỉ quốc tế LEED về công trình xây dựng xanh, tiết kiệm năng lượng và bảo vệ môi trường sống của con người
Hợp tác bền vững là yếu tố quan trọng nhất trong sự đồng hành cùng phát triển
Tiêu biểu: Đối tác Cotton USA - đơn vị cung cấp nguyên liệu chính cho áo phông tại Canifa luôn nghiêm minh tuân thủ các chỉ số bền vững của nông nghiệp Mỹ: tiết kiệm nước, kỹ thuật “không làm đất” để bảo vệ đất trồng.
Thời trang không chỉ đẹp mà còn an toàn với người sử dụng luôn song hành trong mục tiêu nghiên cứu phát triển sản phẩm.
Tiêu biểu: CANIFA luôn chú trọng nghiên cứu, kiểm định chất lượng với nguyên liệu đầu vào và sản phẩm đầu ra, đáp ứng những yêu cầu khắt khe nhất của các chứng chỉ uy tín nhất thế giới để mang đến cho người dùng sự an toàn và thoải mái (Oekotex, Woolmark, AWTA,...)
hoạt động cộng đồng
Với mong muốn mang đến những điều tốt đẹp dù nhỏ bé nhưng ấm áp đến cho cộng đồng Việt, những người sáng lập đã gieo mầm cho các hoạt động hoàn toàn tự nguyện mang tên Hội CANIFA Vì Cộng Đồng.
HƠI ẤM MÙA ĐÔNG
Nếu một lần được thấy hình ảnh những em nhỏ vùng cao vượt qua mùa đông chỉ bằng những tấm áo cộc... chúng tôi tin rằng những trái tim sẽ không ngừng ước mong về một ngày các em đủ ấm.
Được khởi xướng bởi nhân viên Canifa, hành trình Hơi ấm mùa đông là hành trình của hàng ngàn tấm áo ấm đến với các em nhỏ vùng cao cho mùa đông bớt khắc nghiệt.
2019 - năm thứ 15, Canifa sẽ viết tiếp hành trình bằng 15,000 tấm áo, cùng với cộng đồng để trao tận tay từng em nhỏ
GIỌT MÁU HỒNG
Từ 2014, Hoạt động hiến máu nhân đạo được Canifa tổ chức định kỳ hàng năm, thu hút đông đảo CBNV tham gia, đóng góp hàng ngàn đơn vị máu cho hoạt động cứu trợ của Viện huyết học và truyền máu Trung ương.
ÁO MỚI CHO HÀNH TINH XANH
Ở Canifa, chúng tôi tin rằng, mỗi đứa trẻ đều có thể chung tay bảo vệ môi trường. Từ việc bớt sử dụng một chiếc ống hút nhựa cho đến trồng thêm một cây xanh. Mỗi năm, hàng trăm mầm xanh sẽ được chính tay các bạn nhỏ là con em CBNV trong công ty vun trồng. Năm sau đó, các bạn sẽ được quay lại để nhìn những cây xanh đã lớn và tiếp tục gieo thêm những màu xanh.
HOẠT ĐỘNG THIỆN NGUYỆN KHÁC
Chứng kiến sự khắc nghiệt của thiên tai, chúng tôi hiểu mọi sự cứu trợ dù là nhỏ nhất nếu kịp thời đều có ý nghĩa với những người dân vùng thiệt hại. Canifa luôn có những chuyến xe hỏa tốc về vùng bão lũ, chúng tôi gọi đó là những chuyến xe màu đỏ.
CHỨNG NHẬN VÀ CHẤT LƯỢNG
Với triết lý kinh doanh trên giá trị thật, CANIFA thiết lập hệ thống tiêu chuẩn chất lượng quốc tế áp dụng trên tất cả quy trình quản lý và kiểm soát chất lượng từ khâu chọn lọc nguyên phụ liệu cho đến khâu thiết kế và sản xuất.
Luôn cam kết mang đến khách hàng những sản phẩm an toàn với sức khỏe người tiêu dùng, hãng thời trang Canifa chỉ sử dụng những chất liệu tự nhiên an toàn trong mỗi thiết kế.
Sản phẩm Canifa đạt tiêu chuẩn Oeko Tex 100 được kiểm định về độ an toàn cho làn da của người sử dụng.
Và năm 2016, CANIFA tự hào đã đạt được chứng chỉ an toàn cấp độ cao nhất với dòng sản phẩm dành cho trẻ sơ sinh.
Cotton USA - hãng bông được cả thế giới tin dùng với quy trình canh tác bền vững để cho ra đời những sợi bông chất lượng tuyệt vời đưa đến sản phẩm thấm hút tốt, mát mẻ, chịu nhiệt và bền bỉ.
Với mong muốn mang đến sản phẩm chất lượng cho người Việt, CANIFA liên kết cùng tập đoàn Cotton USA mang đến nguyên liệu chất lượng Quốc tế cho người Việt.
Luôn quan tâm tới nhu cầu mặc đẹp, mặc mới và mặc an toàn mỗi ngày của khách hàng, ngoài an toàn về chất lượng sản phẩm.
CANIFA đã vượt qua quy trình nghiêm ngặt khắt khe về kiểm định sản xuất, nguyên vật liệu đầu vào và thành phẩm ra thị trường của tập đoàn quốc tế Disney, từ đó, ký kết chính thức là đối tác chiến lược giữa CANIFA và Disney tại Việt Nam.
Khi cầm trên tay những sản phẩm có biểu tượng Woolmark, bạn có thể yên tâm 100% về chất lượng hảo hạng của món đồ bạn sở hữu đạt chuẩn toàn cầu.
Chứng chỉ Quốc tế này được cấp cho các nhà sản xuất có đủ khả năng đáp ứng các tiêu chuẩn yêu cầu vô cùng nghiêm ngặt.
Từ 2014, CANIFA là nhãn hiệu Việt Nam đầu tiên vượt qua các tiêu chuẩn khắt khe của Woolmark để nhận được 02 chứng chỉ Quốc tế danh giá nhất dành cho sản phẩm len lông cừu là Woolmark và Woolmark Blend.
AWTA Ltd (Australian Wool Testing Authority) - Trung tâm kiểm soát chất lượng len lông cừu lớn nhất thế giới đã chính thức cấp chứng chỉ cho sản phẩm của CANIFA.
Những sản phẩm len lông cừu đạt chuẩn phải được kiểm duyệt từ nguyên liệu đầu vào.
CANIFA đầu tư xây dựng Tổ hợp XANH CANIFA theo tiêu chuẩn LEED.
Đây là tiêu chuẩn tiên phong cho các công trình tiết kiệm năng lượng và bảo vệ môi trường trường sống của con người.
Tuân theo tiêu chuẩn này, việc vận hành sản xuất của nhà máy được vận hành theo quy trình khép kín, xử lý nước thải thông minh để tái sử dụng tưới cây xanh cho Tổ hợp.
Chính việc nhận được Chứng chỉ LEED mang giá trị toàn cầu đã giúp Tổ Hợp XANH CANIFA không chỉ hoàn thành sứ mệnh Phản Ứng Nhanh, để phục vụ khách hàng tốt hơn, mà còn góp phần quan trọng trong việc phát triển xã hội bền vững, văn minh, bảo vệ môi trường sống của cộng đồng.
TOP
VẬN CHUYỂN
Cước phí vận chuyển
CANIFA áp dụng chính sách miễn phí giao hàng cho tất cả các đơn hàng có giá trị từ 599.000 VNĐ trở lên, áp dụng trên toàn bộ các tỉnh thành trên toàn quốc.
Đối với các đơn hàng có giá trị dưới 599.000 VNĐ, CANIFA áp dụng phí vận chuyển theo từng khu vực như sau. Biểu phí này được áp dụng từ ngày 14/08/2023 cho đến khi có thông báo thay đổi mới.
Tại khu vực Hà Nội, các đơn hàng giao đến các quận Đống Đa, Hoàn Kiếm, Ba Đình, Hai Bà Trưng, Cầu Giấy và Thanh Xuân sẽ được áp dụng phí vận chuyển 20.000 VNĐ.
Đối với các quận và huyện còn lại của Hà Nội bao gồm Hà Đông, Tây Hồ, Hoàng Mai, Long Biên, Bắc Từ Liêm, Nam Từ Liêm, Ba Vì, Chương Mỹ, Đan Phượng, Đông Anh, Gia Lâm, Hoài Đức, Mê Linh, Mỹ Đức, Phúc Thọ, Phú Xuyên, Quốc Oai, Sóc Sơn, Thạch Thất, Thanh Oai, Thanh Trì, Thường Tín, Ứng Hòa và Thị xã Sơn Tây, phí vận chuyển là 30.000 VNĐ.
Tại TP. Hồ Chí Minh, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Tại Đà Nẵng, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.000 VNĐ.
Đối với các tỉnh thành khác trên toàn quốc, CANIFA chia làm hai mức phí vận chuyển.
Mức 30.000 VNĐ được áp dụng cho các tỉnh thành bao gồm: Bắc Giang, Bắc Ninh, Hà Nam, Hải Dương, Hải Phòng, Hưng Yên, Hòa Bình, Nam Định, Phú Thọ, Thái Nguyên, Vĩnh Phúc, Bắc Kạn, Lạng Sơn, Nghệ An, Ninh Bình, Quảng Ninh, Thái Bình, Thanh Hóa, Tuyên Quang và Yên Bái.
Mức 40.000 VNĐ được áp dụng cho các tỉnh thành còn lại, bao gồm: Điện Biên, Lào Cai, Hà Giang, Sơn La, Cao Bằng, Thừa Thiên Huế, Quảng Trị, Gia Lai, Đắk Lắk, Kon Tum, Đắk Nông, Phú Yên, Khánh Hòa, Hà Tĩnh, Tiền Giang, Bến Tre, Tây Ninh, Đồng Tháp, Trà Vinh, Vĩnh Long, Đồng Nai, Bình Dương, Bà Rịa – Vũng Tàu, Long An, Quảng Bình, Bình Định (Quy Nhơn), Bình Thuận, Ninh Thuận, Bình Phước, Cần Thơ, Hậu Giang, Kiên Giang, An Giang, Sóc Trăng, Bạc Liêu, Cà Mau và Quảng Ngãi.
Thời gian vận chuyển
Đối với khu vực Hà Nội, thời gian giao hàng dự kiến từ 1 đến 3 ngày kể từ khi hệ thống xác nhận đơn hàng qua tin nhắn SMS.
Đối với tuyến Đà Nẵng và TP. Hồ Chí Minh, thời gian giao hàng dự kiến trong vòng 3 ngày kể từ khi hệ thống xác nhận qua SMS.
Đối với các tỉnh thành khác, thời gian giao hàng dự kiến từ 3 đến 7 ngày kể từ khi hệ thống xác nhận đơn hàng.
Thời gian giao hàng không bao gồm thứ Bảy, Chủ nhật và các ngày Lễ, Tết theo quy định.
Số lần giao hàng
Mỗi đơn hàng được giao tối đa 3 lần. Trong trường hợp lần giao đầu tiên không thành công, nhân viên vận chuyển sẽ liên hệ lại và thực hiện giao lần tiếp theo sau 1–2 ngày làm việc. Nếu sau 3 lần giao hàng vẫn không thành công, đơn hàng sẽ được tự động hủy.
Kiểm tra tình trạng đơn hàng
Để kiểm tra thông tin hoặc tình trạng đơn hàng, khách hàng vui lòng sử dụng Mã đơn hàng đã được gửi trong email xác nhận hoặc tin nhắn SMS, và liên hệ đến bộ phận Chăm sóc khách hàng qua tổng đài miễn phí 1800 6061 (nhánh 1) để được hỗ trợ.
Kiểm tra sản phẩm khi nhận hàng
Khi nhận đơn hàng, khách hàng hoàn toàn có thể mở gói hàng để kiểm tra sản phẩm trước khi thanh toán hoặc trước khi nhân viên vận chuyển rời đi.
Trong trường hợp phát sinh bất kỳ vấn đề nào liên quan đến đơn hàng, khách hàng vui lòng liên hệ ngay với CANIFA qua 1800 6061 (nhánh 1) để được hỗ trợ kịp thời.
\ No newline at end of file
services: services:
# --- n8n Workflow Automation --- # --- n8n Workflow Automation ---
n8n: n8n:
image: docker.n8n.io/n8nio/n8n:latest image: docker.n8n.io/n8nio/n8n:1.123.4
container_name: canifa_n8n container_name: canifa_n8n
ports: ports:
- "5678:5678" - "5678:5678"
......
import asyncio
from common.starrocks_connection import get_db_connection
async def main():
sr = get_db_connection()
q = "SELECT metadata FROM shared_source.chatbot_rsa_knowledge LIMIT 5"
res = await sr.execute_query_async(q)
for i, r in enumerate(res):
print(f"METADATA {i}: {r.get('metadata')}")
asyncio.run(main())
"""Integration test for shipping-policy routing in agent chat.
Goal:
- Ask: "ship ve Hai Phong bao lau"
- Verify agent response includes shipping-policy facts
- Fail when response is hotline-only redirect
- Always print raw JSON for debugging
"""
from __future__ import annotations
import argparse
import json
import re
import sys
import time
import unicodedata
from typing import Any
import requests
DEFAULT_API_URL = "http://localhost:5000"
CHAT_ENDPOINT = "/api/agent/chat-dev"
DEFAULT_QUERY = "ship ve Hai Phong bao lau"
DEFAULT_TOKEN = "071w198x23ict4hs1i6bl889fit5p3f7"
DEFAULT_TIMEOUT = 90
# If answer only contains hotline escalation and no shipping-policy facts -> FAIL.
HOTLINE_PATTERNS = [
r"1800\s*6061",
r"hotline",
r"saleonline@canifa\.com",
r"lien he",
]
# Signals that answer used policy data instead of only escalation.
SHIPPING_FACT_PATTERNS = [
r"hai\s*phong",
r"phi\s*van\s*chuyen",
r"thoi\s*gian\s*giao\s*hang",
r"3\s*(den|-|to)\s*7\s*ngay",
r"30\.?000",
r"599\.?000",
r"freeship",
]
def _normalize(text: str) -> str:
raw = (text or "").strip().lower()
no_accents = "".join(ch for ch in unicodedata.normalize("NFD", raw) if unicodedata.category(ch) != "Mn")
return re.sub(r"\s+", " ", no_accents)
def _has_any(patterns: list[str], text: str) -> bool:
return any(re.search(pattern, text, flags=re.IGNORECASE) for pattern in patterns)
def _is_hotline_only_redirect(ai_response: str) -> bool:
text = _normalize(ai_response)
has_hotline = _has_any(HOTLINE_PATTERNS, text)
has_shipping_fact = _has_any(SHIPPING_FACT_PATTERNS, text)
return has_hotline and not has_shipping_fact
def run_shipping_policy_test(api_url: str, token: str, query: str, timeout: int) -> int:
url = f"{api_url}{CHAT_ENDPOINT}"
payload: dict[str, Any] = {"user_query": query, "images": []}
headers = {"Content-Type": "application/json"}
if token:
headers["Authorization"] = f"Bearer {token}"
print("=" * 72)
print("TEST: Agent shipping-policy routing")
print(f"URL : {url}")
print(f"QUERY : {query}")
print("=" * 72)
start = time.time()
try:
response = requests.post(url, json=payload, headers=headers, timeout=timeout)
except Exception as exc:
print(f"FAIL: request error: {exc}")
return 2
elapsed_ms = int((time.time() - start) * 1000)
print(f"HTTP : {response.status_code} ({elapsed_ms} ms)")
try:
data = response.json()
except Exception:
print("FAIL: response is not valid JSON")
print(response.text[:1000])
return 2
print("\nRAW JSON:")
print(json.dumps(data, ensure_ascii=False, indent=2))
if response.status_code != 200:
print("\nFAIL: non-200 response")
return 1
ai_response = str(data.get("ai_response", ""))
ai_norm = _normalize(ai_response)
hotline_only = _is_hotline_only_redirect(ai_response)
has_shipping_fact = _has_any(SHIPPING_FACT_PATTERNS, ai_norm)
print("\nCHECKS:")
print(f"- has shipping fact : {has_shipping_fact}")
print(f"- hotline-only redirect: {hotline_only}")
if hotline_only:
print("\nFAIL: agent returned hotline-only redirect for shipping-policy question")
return 1
if not has_shipping_fact:
print("\nFAIL: answer does not show shipping-policy facts")
return 1
print("\nPASS: agent returned shipping-policy information (not hotline-only)")
return 0
def main() -> None:
parser = argparse.ArgumentParser(description="Test shipping-policy question routing in agent")
parser.add_argument("--api-url", default=DEFAULT_API_URL, help=f"API base URL (default: {DEFAULT_API_URL})")
parser.add_argument("--token", default=DEFAULT_TOKEN, help="Bearer token for API (optional)")
parser.add_argument("--query", default=DEFAULT_QUERY, help=f"Question to test (default: {DEFAULT_QUERY})")
parser.add_argument(
"--timeout", type=int, default=DEFAULT_TIMEOUT, help=f"Request timeout seconds (default: {DEFAULT_TIMEOUT})"
)
args = parser.parse_args()
code = run_shipping_policy_test(
api_url=args.api_url,
token=args.token,
query=args.query,
timeout=args.timeout,
)
sys.exit(code)
if __name__ == "__main__":
main()
QUERY: 'có cửa hàng bên quận hoàng mai shop ơi' → KEYWORDS: ['hoàng', 'mai'] ================================================================================
AND: 4 rows | OR: 19 rows 🔍 TEST KNOWLEDGE RETRIEVAL QUALITY
================================================================================
📊 Config: TOP_K=5, Model=text-embedding-3-small
🗄️ DB: 172.16.2.100:9030/shared_source
📋 Table: shared_source.chatbot_rsa_knowledge
📝 Số câu hỏi test: 16
================================================================================
✅ Kết nối DB thành công!
QUERY: 'cửa hàng quận Hoàng Mai' → KEYWORDS: ['hoàng', 'mai']
AND: 4 rows | OR: 19 rows
QUERY: 'Canifa ở Cầu Giấy địa chỉ ở đâu?' → KEYWORDS: ['cầu', 'giấy'] ────────────────────────────────────────────────────────────────────────────────
AND: 10 rows | OR: 40 rows 📌 [1/16] Query: "kỳ xét hạng"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
QUERY: 'bảng size áo nam' → KEYWORDS: ['áo', 'nam'] 🔴 Chunk #1 | Score: 0.3758 | Source: Hỏi đáp
AND: 4 rows | OR: 76 rows Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Sản phẩm khi mua là hàng giảm giá, tại thời điểm đổi là hàng nguyên giá thì quy cả 2 sản phẩm về nguy...
🔴 Chunk #2 | Score: 0.3754 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Quy định đổi hàng đối với sản phẩm giảm giá / khuyến mại Khách hàng được đổi sang màu sắc hoặc size kh...
🔴 Chunk #3 | Score: 0.3733 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Số lần giao hàng Mỗi đơn hàng được giao tối đa 3 lần. Trong trường hợp lần giao đầu tiên không thành c...
🔴 Chunk #4 | Score: 0.3686 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng hỗ trợ khách hàng đổi sang giấy “Biên n...
🔴 Chunk #5 | Score: 0.3640 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [2/16] Query: "kỳ xét hạng thành viên"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.3831 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: HƠI ẤM MÙA ĐÔNG Nếu một lần được thấy hình ảnh những em nhỏ vùng cao vượt qua mù...
🔴 Chunk #2 | Score: 0.3829 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Từ việc bớt sử dụng một chiếc ống hút nhựa cho đến trồng thêm một cây xanh. Mỗi ...
🔴 Chunk #3 | Score: 0.3669 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Chính việc nhận được Chứng chỉ LEED mang giá trị toàn cầu đã giúp Tổ Hợp XANH CA...
🔴 Chunk #4 | Score: 0.3668 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trường hợp thương lượng đàm phán không thành công tro...
🔴 Chunk #5 | Score: 0.3614 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Số lần giao hàng Mỗi đơn hàng được giao tối đa 3 lần. Trong trường hợp lần giao đầu tiên không thành c...
🚨 CẢNH BÁO: Query KHTT nhưng chunk #1 KHÔNG chứa keyword KHTT!
→ Đánh giá: ❌ SAI TOPIC
────────────────────────────────────────────────────────────────────────────────
📌 [3/16] Query: "hạng thẻ Gold có quyền lợi gì"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4308 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 2. Quyền và trách nhiệm của KHTT, Canifa 2.1. KHTV s...
🔴 Chunk #2 | Score: 0.4238 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #3 | Score: 0.3815 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp khách hàng chưa chọn được sản phẩm phù hợp để đổi, CANIFA sẽ nhận lại sản phẩm và hỗ t...
🔴 Chunk #4 | Score: 0.3743 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 2.2. KHTV có quyền truy cập, tra cứu thông tin cá nhâ...
🔴 Chunk #5 | Score: 0.3699 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Tại tất cả các cửa hàng thuộc hệ thống Canifa trên toàn quốc & hệ thống online (Web/App Canifa). Đối ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [4/16] Query: "chiết khấu VIP Diamond bao nhiêu phần trăm"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4225 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #2 | Score: 0.3731 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Mức 40.000 VNĐ được áp dụng cho các tỉnh thành còn lại, bao gồm: Điện Biên, Lào Cai, Hà Giang, Sơn La, ...
🔴 Chunk #3 | Score: 0.3726 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp khách hàng chưa chọn được sản phẩm phù hợp để đổi, CANIFA sẽ nhận lại sản phẩm và hỗ t...
🔴 Chunk #4 | Score: 0.3708 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trường hợp thương lượng đàm phán không thành công tro...
🔴 Chunk #5 | Score: 0.3613 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Khách hàng thanh toán phần tiền chênh lệch nếu sản phẩm đổi có giá trị cao hơn sản phẩm đã mua. - Khá...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [5/16] Query: "điểm tích lũy tính thế nào"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.3208 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Các sản phẩm đồ lót và phụ kiện không áp dụng đổi hàng. Đối với đơn mua tại cửa hàng, khách hàng cần xu...
🔴 Chunk #2 | Score: 0.3140 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Quy định đổi hàng đối với sản phẩm giảm giá / khuyến mại Khách hàng được đổi sang màu sắc hoặc size kh...
🔴 Chunk #3 | Score: 0.3128 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng hỗ trợ khách hàng đổi sang giấy “Biên n...
🔴 Chunk #4 | Score: 0.3117 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Thanh toán trả trước Áp dụng thanh toán bằng QR Code, Thẻ ATM (thẻ ngân hàng, thẻ thanh toán nội địa) v...
🔴 Chunk #5 | Score: 0.3115 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Bước 2: Sử dụng ứng dụng ngân hàng đang dùng để quét mã QR và thực hiện thanh toán theo hướng dẫn. Hướn...
🚨 CẢNH BÁO: Query KHTT nhưng chunk #1 KHÔNG chứa keyword KHTT!
→ Đánh giá: ❌ SAI TOPIC
────────────────────────────────────────────────────────────────────────────────
📌 [6/16] Query: "bao nhiêu điểm lên hạng Gold"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4185 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #2 | Score: 0.3983 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Từ việc bớt sử dụng một chiếc ống hút nhựa cho đến trồng thêm một cây xanh. Mỗi ...
🔴 Chunk #3 | Score: 0.3673 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp khách hàng chưa chọn được sản phẩm phù hợp để đổi, CANIFA sẽ nhận lại sản phẩm và hỗ t...
🔴 Chunk #4 | Score: 0.3652 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Tại tất cả các cửa hàng thuộc hệ thống Canifa trên toàn quốc & hệ thống online (Web/App Canifa). Đối ...
🔴 Chunk #5 | Score: 0.3560 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Chính việc nhận được Chứng chỉ LEED mang giá trị toàn cầu đã giúp Tổ Hợp XANH CA...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [7/16] Query: "ưu đãi sinh nhật hội viên"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.3938 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trường hợp thương lượng đàm phán không thành công tro...
🔴 Chunk #2 | Score: 0.3834 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: KHTV là tất cả các cá nhân từ đủ 15 tuổi trở lên đăng...
🔴 Chunk #3 | Score: 0.3751 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 1.3. Bằng việc tham gia Chương Trình, KHTV thừa nhận ...
🔴 Chunk #4 | Score: 0.3735 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Áp dụng trên hệ thống cửa hàng Canifa toàn quốc cho đ...
🔴 Chunk #5 | Score: 0.3566 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trong trường hợp đó, cha mẹ hoặc người đại diện theo ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [8/16] Query: "duy trì hạng Diamond cần mấy điểm"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.3988 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #2 | Score: 0.3678 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Chính việc nhận được Chứng chỉ LEED mang giá trị toàn cầu đã giúp Tổ Hợp XANH CA...
🔴 Chunk #3 | Score: 0.3608 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp khách hàng chưa chọn được sản phẩm phù hợp để đổi, CANIFA sẽ nhận lại sản phẩm và hỗ t...
🔴 Chunk #4 | Score: 0.3574 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Từ việc bớt sử dụng một chiếc ống hút nhựa cho đến trồng thêm một cây xanh. Mỗi ...
🔴 Chunk #5 | Score: 0.3538 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: HƠI ẤM MÙA ĐÔNG Nếu một lần được thấy hình ảnh những em nhỏ vùng cao vượt qua mù...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [9/16] Query: "mất thẻ VIP làm sao"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4279 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 2.9. Canifa được miễn trách nhiệm trong trường hợp: (...
🔴 Chunk #2 | Score: 0.4194 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Bước 2: Sử dụng ứng dụng ngân hàng đang dùng để quét mã QR và thực hiện thanh toán theo hướng dẫn. Hướn...
🔴 Chunk #3 | Score: 0.4057 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Quý khách thanh toán chọn hình thức thanh toán qua VNPAY và tiền hành thanh toán tại cổng thanh toán Vn...
🔴 Chunk #4 | Score: 0.4047 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trường hợp thương lượng đàm phán không thành công tro...
🔴 Chunk #5 | Score: 0.4039 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 3.2. KHTV cố ý sử dụng Thẻ/Tài Khoản sai quy định của...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [10/16] Query: "đăng ký thành viên mới có ưu đãi gì"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.5170 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Trường hợp thương lượng đàm phán không thành công tro...
🔴 Chunk #2 | Score: 0.4198 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Tất cả các Dữ Liệu sẽ được bảo vệ và được sử dụng the...
🔴 Chunk #3 | Score: 0.4096 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: KHTV là tất cả các cá nhân từ đủ 15 tuổi trở lên đăng...
🔴 Chunk #4 | Score: 0.4083 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: Đăng ký ngay CÔNG TY CỔ PHẦN CANIFA Số ĐKKD: 01075743...
🔴 Chunk #5 | Score: 0.4013 | Source: Điều kiện điều khoản Khách hàng thân thiết
Content: TITLE: Điều kiện điều khoản Khách hàng thân thiết SECTION: General Information KEYWORDS: điều kiện, điều khoản, điều khoản với khách hàng CONTENT: 1.3. Bằng việc tham gia Chương Trình, KHTV thừa nhận ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [11/16] Query: "phiếu mua hàng 100k dùng thế nào"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4855 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Kiểm tra sản phẩm khi nhận hàng Khi nhận đơn hàng, khách hàng hoàn toàn có thể mở gói hàng để kiểm tra...
🔴 Chunk #2 | Score: 0.4824 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Các sản phẩm đồ lót và phụ kiện không áp dụng đổi hàng. Đối với đơn mua tại cửa hàng, khách hàng cần xu...
🔴 Chunk #3 | Score: 0.4779 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Đối với các đơn hàng online, chỉ áp dụng đổi sang giấy “Biên nhận” khi khách hàng ra cửa hàng đổi và ...
🔴 Chunk #4 | Score: 0.4765 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Số lần giao hàng Mỗi đơn hàng được giao tối đa 3 lần. Trong trường hợp lần giao đầu tiên không thành c...
🔴 Chunk #5 | Score: 0.4705 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: 1.3.2 Điều kiện đổi hàng: - Chính sách chỉ áp dụng khi khách hàng còn giữ hóa đơn mua hàng, sản phẩm cò...
🚨 CẢNH BÁO: Query KHTT nhưng chunk #1 KHÔNG chứa keyword KHTT!
→ Đánh giá: ❌ SAI TOPIC
────────────────────────────────────────────────────────────────────────────────
📌 [12/16] Query: "ngày vàng thành viên"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4270 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Từ việc bớt sử dụng một chiếc ống hút nhựa cho đến trồng thêm một cây xanh. Mỗi ...
🔴 Chunk #2 | Score: 0.3614 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Những sản phẩm len lông cừu đạt chuẩn phải được kiểm duyệt từ nguyên liệu đầu và...
🔴 Chunk #3 | Score: 0.3606 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Chính việc nhận được Chứng chỉ LEED mang giá trị toàn cầu đã giúp Tổ Hợp XANH CA...
🔴 Chunk #4 | Score: 0.3597 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Với mục tiêu phát triển bền vững, CANIFA tập trung nghiên cứu và cải tiến hoạt đ...
🔴 Chunk #5 | Score: 0.3483 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: HƠI ẤM MÙA ĐÔNG Nếu một lần được thấy hình ảnh những em nhỏ vùng cao vượt qua mù...
🚨 CẢNH BÁO: Query KHTT nhưng chunk #1 KHÔNG chứa keyword KHTT!
→ Đánh giá: ❌ SAI TOPIC
────────────────────────────────────────────────────────────────────────────────
📌 [13/16] Query: "đổi hàng trong bao nhiêu ngày"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4847 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Quy định đổi hàng đối với sản phẩm giảm giá / khuyến mại Khách hàng được đổi sang màu sắc hoặc size kh...
🔴 Chunk #2 | Score: 0.4584 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #3 | Score: 0.4556 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: 1.3.2 Điều kiện đổi hàng: - Chính sách chỉ áp dụng khi khách hàng còn giữ hóa đơn mua hàng, sản phẩm cò...
🔴 Chunk #4 | Score: 0.4514 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Sản phẩm khi mua là hàng giảm giá, tại thời điểm đổi là hàng nguyên giá thì quy cả 2 sản phẩm về nguy...
🔴 Chunk #5 | Score: 0.4423 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Trong trường hợp sản phẩm đổi không còn trên hệ thống, cửa hàng hỗ trợ khách hàng đổi sang giấy “Biên n...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [14/16] Query: "hàng giảm giá có đổi được không"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.6054 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Sản phẩm khi mua là hàng giảm giá, tại thời điểm đổi là hàng nguyên giá thì quy cả 2 sản phẩm về nguy...
🔴 Chunk #2 | Score: 0.6029 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Hàng nguyên giá được giảm theo quyền lợi hạng Gold/ Diamond vẫn được đổi như mua hàng nguyên giá; - ...
🔴 Chunk #3 | Score: 0.5902 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Quy định đổi hàng đối với sản phẩm giảm giá / khuyến mại Khách hàng được đổi sang màu sắc hoặc size kh...
🔴 Chunk #4 | Score: 0.5666 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: - Tại tất cả các cửa hàng thuộc hệ thống Canifa trên toàn quốc & hệ thống online (Web/App Canifa). Đối ...
🔴 Chunk #5 | Score: 0.5632 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: CANIFA có hỗ trợ đổi hàng online không? CANIFA hỗ trợ đổi hàng online theo các quy định sau: Quy định ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [15/16] Query: "freeship từ bao nhiêu"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.4278 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Biểu phí này được áp dụng từ ngày 14/08/2023 cho đến khi có thông báo thay đổi mới. Tại khu vực Hà Nội,...
🔴 Chunk #2 | Score: 0.4273 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Tại TP. Hồ Chí Minh, tất cả các đơn hàng giao đến mọi quận, huyện đều được áp dụng phí vận chuyển 40.00...
🔴 Chunk #3 | Score: 0.4243 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Đối với các đơn hàng có giá trị dưới 599.000 VNĐ, CANIFA áp dụng biểu phí vận chuyển theo từng khu vực,...
🔴 Chunk #4 | Score: 0.4093 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Các quận và huyện còn lại của Hà Nội bao gồm Hà Đông, Tây Hồ, Hoàng Mai, Long Biên, Bắc Từ Liêm, Nam Từ...
🔴 Chunk #5 | Score: 0.3965 | Source: Hỏi đáp
Content: TITLE: Hỏi đáp SECTION: Thanh toán KEYWORDS: thanh toán, hoàn tiền, vận chuyển, đổi trả CONTENT: Mức 40.000 VNĐ được áp dụng cho các tỉnh thành còn lại, bao gồm: Điện Biên, Lào Cai, Hà Giang, Sơn La, ...
→ Đánh giá: ✅ OK
────────────────────────────────────────────────────────────────────────────────
📌 [16/16] Query: "Canifa thành lập năm nào"
────────────────────────────────────────────────────────────────────────────────
✅ Embedding created (dim=1536)
🔴 Chunk #1 | Score: 0.5357 | Source: Giới thiệu
Content: TITLE: Giới thiệu SECTION: Canifa 20 năm - Khoác lên niềm vui gia đình Việt KEYWORDS: canifa, 20 năm, niềm vui mặc mới, giá trị cốt lõi, tầm nhìn sứ mệnh CONTENT: Sản phẩm xanh: CANIFA đặc biệt chú tr...
🔴 Chunk #2 | Score: 0.5049 | Source: Giới thiệu
Content: TITLE: Giới thiệu SECTION: Canifa 20 năm - Khoác lên niềm vui gia đình Việt KEYWORDS: canifa, 20 năm, niềm vui mặc mới, giá trị cốt lõi, tầm nhìn sứ mệnh CONTENT: 2012 là năm Ra đời cửa hàng bán lẻ “f...
🔴 Chunk #3 | Score: 0.4783 | Source: Giới thiệu
Content: TITLE: Giới thiệu SECTION: Canifa 20 năm - Khoác lên niềm vui gia đình Việt KEYWORDS: canifa, 20 năm, niềm vui mặc mới, giá trị cốt lõi, tầm nhìn sứ mệnh CONTENT: Năm 1997, Công ty Cổ phần Thương mại ...
🔴 Chunk #4 | Score: 0.4693 | Source: Giới thiệu
Content: TITLE: Giới thiệu SECTION: Canifa 20 năm - Khoác lên niềm vui gia đình Việt KEYWORDS: canifa, 20 năm, niềm vui mặc mới, giá trị cốt lõi, tầm nhìn sứ mệnh CONTENT: Canifa cam kết phát triển xanh cùng n...
🔴 Chunk #5 | Score: 0.4607 | Source: Với cộng đồng
Content: TITLE: Với cộng đồng SECTION: Phát triển bền vững: 03 xanh KEYWORDS: cộng đồng, phát triển bền vững, chứng chỉ CONTENT: Canifa luôn có những chuyến xe hỏa tốc về vùng bão lũ, chúng tôi gọi đó là những...
→ Đánh giá: ✅ OK
================================================================================
📊 TỔNG KẾT CHẤT LƯỢNG RETRIEVAL
================================================================================
✅ Đúng topic: 12/16
❌ Sai topic: 4/16
📈 Tỷ lệ chính xác: 75.0%
🚨 Các query bị sai:
- "kỳ xét hạng thành viên" (top score: 0.3831)
- "điểm tích lũy tính thế nào" (top score: 0.3208)
- "phiếu mua hàng 100k dùng thế nào" (top score: 0.4855)
- "ngày vàng thành viên" (top score: 0.4270)
================================================================================
#!/usr/bin/env python3
"""Interactive QA loop from prebuilt FAISS index.
Run:
python test/a.py
"""
from __future__ import annotations
import argparse
import importlib.util
import io
import json
import os
import sys
from pathlib import Path
# Fix Windows terminal encoding for Vietnamese
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding="utf-8")
import numpy as np
from openai import OpenAI
try:
import faiss
except ImportError as exc:
raise SystemExit(
"faiss-cpu is required. Install with: pip install faiss-cpu"
) from exc
def parse_args() -> argparse.Namespace:
here = Path(__file__).resolve().parent
parser = argparse.ArgumentParser(
description="Query prebuilt FAISS index in a while loop"
)
parser.add_argument(
"--index", default=str(here / "index.faiss"), help="Path to FAISS index file"
)
parser.add_argument(
"--chunks", default=str(here / "chunks.jsonl"), help="Path to chunk jsonl file"
)
parser.add_argument("--top-k", type=int, default=5, help="Top-K retrieval")
parser.add_argument(
"--embedding-model",
default="text-embedding-3-small",
help="OpenAI embedding model",
)
parser.add_argument("--chat-model", default="gpt-4.1-mini", help="OpenAI chat model")
parser.add_argument(
"--min-score", type=float, default=0.35, help="Minimum score to trust retrieval"
)
return parser.parse_args()
def get_api_key() -> str | None:
backend_config = Path(__file__).resolve().parents[1] / "backend" / "config.py"
if backend_config.exists():
spec = importlib.util.spec_from_file_location("backend_config", backend_config)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
key = getattr(module, "OPENAI_API_KEY", None)
if key:
return key
return os.getenv("OPENAI_API_KEY")
def normalize(v: np.ndarray) -> np.ndarray:
n = np.linalg.norm(v)
if n == 0:
return v.astype(np.float32)
return (v / n).astype(np.float32)
def load_chunks(path: Path) -> list[dict]:
rows: list[dict] = []
with path.open("r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
rows.append(json.loads(line))
return rows
def embed_query(client: OpenAI, text: str, model: str) -> np.ndarray:
response = client.embeddings.create(model=model, input=[text])
vec = np.array(response.data[0].embedding, dtype=np.float32)
return normalize(vec).reshape(1, -1)
def retrieve(
index: faiss.Index,
chunks: list[dict],
client: OpenAI,
query: str,
top_k: int,
embedding_model: str,
) -> list[dict]:
q_vec = embed_query(client, query, embedding_model)
scores, indices = index.search(q_vec, top_k)
hits: list[dict] = []
for score, idx in zip(scores[0], indices[0]):
if idx < 0 or idx >= len(chunks):
continue
row = chunks[int(idx)]
hits.append(
{
"chunk_id": row.get("chunk_id", int(idx)),
"score": float(score),
"token_start": row.get("token_start"),
"token_end": row.get("token_end"),
"text": row.get("text", ""),
}
)
return hits
def answer_from_hits(
client: OpenAI, query: str, hits: list[dict], chat_model: str
) -> str:
context = "\n\n".join(f"[Chunk {h['chunk_id']}]\n{h['text']}" for h in hits)
system_prompt = (
"Bạn là trợ lý AI của Canifa, chuyên hỗ trợ chính sách khách hàng. "
"Trả lời bằng tiếng Việt có dấu, tự nhiên và ngắn gọn. "
"Sử dụng thông tin từ các đoạn context được cung cấp. "
"Nếu câu hỏi là chào hỏi thông thường, hãy chào lại thân thiện và giới thiệu bạn có thể hỗ trợ gì. "
"Nếu không tìm thấy thông tin liên quan, hãy nói rõ và gợi ý các chủ đề bạn có thể hỗ trợ."
)
user_prompt = (
f"Câu hỏi:\n{query}\n\n"
f"Ngữ cảnh:\n{context}\n\n"
"Trả lời bằng tiếng Việt có dấu."
)
response = client.chat.completions.create(
model=chat_model,
temperature=0.2,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
)
return response.choices[0].message.content or ""
def main() -> int:
args = parse_args()
index_path = Path(args.index)
chunks_path = Path(args.chunks)
if not index_path.exists():
print(f"Missing index file: {index_path}")
return 1
if not chunks_path.exists():
print(f"Missing chunks file: {chunks_path}")
return 1
api_key = get_api_key()
if not api_key:
print("Missing OPENAI_API_KEY in backend/config.py or environment")
return 1
print(f"Loading FAISS index from: {index_path}")
index = faiss.read_index(str(index_path))
chunks = load_chunks(chunks_path)
print(f"Loaded index vectors: {index.ntotal}")
print(f"Loaded chunks: {len(chunks)}")
client = OpenAI(api_key=api_key)
print("\nInteractive mode is ready.")
print("Type exit or quit to stop.\n")
while True:
try:
query = input("Ask> ").strip()
except (EOFError, KeyboardInterrupt):
print("\nStopped.")
break
if not query:
continue
if query.lower() in {"exit", "quit"}:
print("Stopped.")
break
hits = retrieve(
index=index,
chunks=chunks,
client=client,
query=query,
top_k=args.top_k,
embedding_model=args.embedding_model,
)
print("Top-K hits:")
for h in hits:
print(
f" chunk={h['chunk_id']} score={h['score']:.4f} "
f"tokens[{h['token_start']}:{h['token_end']}]"
)
if not hits:
print("Answer:")
print("Không tìm thấy dữ liệu liên quan. Bạn thử hỏi về đổi hàng, hạng thẻ Gold/Diamond, tích điểm hoặc ưu đãi sinh nhật nhé.")
print()
continue
try:
answer = answer_from_hits(
client=client,
query=query,
hits=hits,
chat_model=args.chat_model,
)
print("Answer:")
print(answer)
except Exception as exc:
print(f"Answer error: {exc}")
print()
return 0
if __name__ == "__main__":
raise SystemExit(main())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment