Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
chatbot-canifa-feedback
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
chatbot-canifa-feedback
Commits
2fe68ad3
Commit
2fe68ad3
authored
Apr 24, 2026
by
Vũ Hoàng Anh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add n8n ultra description API + product web desc generator
parent
37a3151d
Changes
4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
911 additions
and
0 deletions
+911
-0
n8n_desc.py
backend/api/product_desc/n8n_desc.py
+381
-0
product_generate_desc_web.py
backend/api/product_desc/product_generate_desc_web.py
+340
-0
test_fetch_image.py
backend/api/product_desc/test/test_fetch_image.py
+86
-0
test_n8n_desc.py
backend/api/product_desc/test/test_n8n_desc.py
+104
-0
No files found.
backend/api/product_desc/n8n_desc.py
0 → 100644
View file @
2fe68ad3
This diff is collapsed.
Click to expand it.
backend/api/product_desc/product_generate_desc_web.py
0 → 100644
View file @
2fe68ad3
This diff is collapsed.
Click to expand it.
backend/api/product_desc/test/test_fetch_image.py
0 → 100644
View file @
2fe68ad3
"""
Test script: Kiểm tra fetch ảnh từ URL Canifa → base64
Mục đích: Chứng minh API tự lấy ảnh từ URL, n8n KHÔNG cần gửi base64.
Chạy: python -m backend.api.product_desc.test.test_fetch_image
hoặc: python backend/api/product_desc/test/test_fetch_image.py
"""
import
httpx
import
base64
import
sys
# ─── Sample data từ Google Sheets ────────────────────────────────────────────
SAMPLE_IMAGE_URL
=
"http://mdp.canifa.com/images-web/cache/c8/00/c80079b26cd5437c1473d98930fc1a07.jpg"
def
test_fetch_image
():
print
(
"="
*
60
)
print
(
"🧪 TEST: Fetch ảnh từ URL Canifa → Base64"
)
print
(
"="
*
60
)
print
(
f
"
\n
📎 URL: {SAMPLE_IMAGE_URL}"
)
try
:
# Fetch ảnh — giống hệt logic trong product_generate_desc_web.py
r
=
httpx
.
get
(
SAMPLE_IMAGE_URL
,
headers
=
{
"User-Agent"
:
"Mozilla/5.0"
},
timeout
=
15
,
follow_redirects
=
True
,
)
r
.
raise_for_status
()
# Thông tin response
content_type
=
r
.
headers
.
get
(
"content-type"
,
"unknown"
)
size_bytes
=
len
(
r
.
content
)
size_kb
=
round
(
size_bytes
/
1024
,
1
)
print
(
f
"
\n
✅ Fetch thành công!"
)
print
(
f
" Status code : {r.status_code}"
)
print
(
f
" Content-Type: {content_type}"
)
print
(
f
" Size : {size_bytes:,} bytes ({size_kb} KB)"
)
# Convert base64
b64
=
base64
.
b64encode
(
r
.
content
)
.
decode
()
b64_len
=
len
(
b64
)
b64_preview
=
b64
[:
80
]
+
"..."
print
(
f
"
\n
🔄 Base64 encode:"
)
print
(
f
" Length : {b64_len:,} chars"
)
print
(
f
" Preview : {b64_preview}"
)
# Validate — check JPEG magic bytes (FFD8FF)
is_jpeg
=
r
.
content
[:
3
]
==
b
'
\xff\xd8\xff
'
is_png
=
r
.
content
[:
4
]
==
b
'
\x89
PNG'
fmt
=
"JPEG"
if
is_jpeg
else
(
"PNG"
if
is_png
else
"Unknown"
)
print
(
f
"
\n
🖼️ Format: {fmt}"
)
# Simulate Groq API payload
data_url
=
f
"data:{content_type};base64,{b64[:20]}..."
print
(
f
"
\n
📦 Data URL cho AI Vision:"
)
print
(
f
" {data_url}"
)
print
(
f
"
\n
{'=' * 60}"
)
print
(
f
"✅ KẾT LUẬN: n8n KHÔNG cần gửi base64!"
)
print
(
f
" → Chỉ cần gửi 'image_url' (Link ảnh từ Sheets)"
)
print
(
f
" → API tự fetch + convert base64 server-side"
)
print
(
f
" → Rồi gửi cho AI Vision model (Llama 4 Scout)"
)
print
(
f
"{'=' * 60}"
)
return
True
except
httpx
.
HTTPStatusError
as
e
:
print
(
f
"
\n
❌ HTTP Error: {e.response.status_code}"
)
print
(
f
" URL có thể bị chặn hoặc không tồn tại"
)
return
False
except
httpx
.
ConnectError
as
e
:
print
(
f
"
\n
❌ Connection Error: {e}"
)
print
(
f
" Không kết nối được tới mdp.canifa.com"
)
return
False
except
Exception
as
e
:
print
(
f
"
\n
❌ Error: {type(e).__name__}: {e}"
)
return
False
if
__name__
==
"__main__"
:
ok
=
test_fetch_image
()
sys
.
exit
(
0
if
ok
else
1
)
backend/api/product_desc/test/test_n8n_desc.py
0 → 100644
View file @
2fe68ad3
"""
Test script: Goi API /api/product-desc/n8n-generate
Simulate n8n HTTP Request node gui data tu Google Sheets.
Chay: py backend/api/product_desc/test/test_n8n_desc.py
"""
import
httpx
import
json
import
sys
import
time
# Fix encoding for Windows
if
sys
.
platform
==
"win32"
:
sys
.
stdout
.
reconfigure
(
encoding
=
"utf-8"
)
API_URL
=
"http://127.0.0.1:5000/api/product-desc/n8n-generate"
# ── Sample data giong het n8n gui tu Google Sheets ──
SAMPLE_PAYLOAD
=
{
"ma_san_pham"
:
"UNKNOWN"
,
"ten_san_pham"
:
"Ao ba lo"
,
"image_url"
:
"https://mdp.canifa.com/images-web/cache/e5/9b/e59b8c724757b142b3eb0d6ebf8d8f7f.jpg"
,
"thanh_phan"
:
""
,
"dac_tinh_chat_lieu"
:
""
,
"mo_ta_chung"
:
""
,
"tinh_nang"
:
""
,
"kieu_dang"
:
""
,
"hoan_canh"
:
""
,
"featuring"
:
""
,
"chung_chi"
:
""
,
"huong_dan_su_dung"
:
""
,
}
def
main
():
print
(
"="
*
60
)
print
(
"TEST: n8n Ultra Description API"
)
print
(
"="
*
60
)
# Step 1: Check server is running
print
(
"
\n
[1/3] Checking server..."
)
try
:
r
=
httpx
.
get
(
"http://127.0.0.1:5000/health"
,
timeout
=
5
)
if
r
.
status_code
==
200
:
print
(
" Server OK"
)
else
:
print
(
f
" Server returned {r.status_code}"
)
sys
.
exit
(
1
)
except
httpx
.
ConnectError
:
print
(
" Server NOT running at http://127.0.0.1:5000"
)
print
(
" -> Start server first: py backend/server.py"
)
sys
.
exit
(
1
)
# Step 2: Send request
print
(
f
"
\n
[2/3] POST {API_URL}"
)
print
(
f
" Product: {SAMPLE_PAYLOAD['ten_san_pham']}"
)
print
(
f
" Image URL: {SAMPLE_PAYLOAD['image_url'][:60]}..."
)
t0
=
time
.
time
()
try
:
r
=
httpx
.
post
(
API_URL
,
json
=
SAMPLE_PAYLOAD
,
timeout
=
120
)
elapsed
=
round
(
time
.
time
()
-
t0
,
2
)
except
Exception
as
e
:
print
(
f
" ERROR: {e}"
)
sys
.
exit
(
1
)
# Step 3: Parse response
print
(
f
"
\n
[3/3] Response (took {elapsed}s)"
)
print
(
f
" Status: {r.status_code}"
)
try
:
data
=
r
.
json
()
except
Exception
:
print
(
f
" Raw: {r.text[:500]}"
)
sys
.
exit
(
1
)
if
data
.
get
(
"status"
)
==
"success"
:
print
(
f
" Product: {data.get('ten_san_pham')}"
)
print
(
f
" Server elapsed: {data.get('elapsed_s')}s"
)
ai_desc
=
data
.
get
(
"ai_description"
,
""
)
print
(
f
"
\n
{'=' * 60}"
)
print
(
"AI DESCRIPTION:"
)
print
(
"="
*
60
)
print
(
ai_desc
)
print
(
f
"
\n
{'=' * 60}"
)
print
(
f
"Length: {len(ai_desc)} chars"
)
# Vision debug
vd
=
data
.
get
(
"vision_data"
,
{})
if
vd
:
print
(
f
"
\n
Vision data: {json.dumps(vd, ensure_ascii=False, indent=2)}"
)
print
(
f
"
\n
KET QUA: OK"
)
else
:
print
(
f
" ERROR: {data.get('message')}"
)
if
data
.
get
(
"raw"
):
print
(
f
" Raw: {data['raw'][:300]}"
)
sys
.
exit
(
1
)
if
__name__
==
"__main__"
:
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment