Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai company
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
0
Merge Requests
0
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
ai company
Commits
95046f93
Commit
95046f93
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
6a363d3c
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 @
95046f93
This diff is collapsed.
Click to expand it.
backend/api/product_desc/product_generate_desc_web.py
0 → 100644
View file @
95046f93
This diff is collapsed.
Click to expand it.
backend/api/product_desc/test/test_fetch_image.py
0 → 100644
View file @
95046f93
"""
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 @
95046f93
"""
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