越境 EC の販売者は、同じ商品を Shopee、Lazada、Amazon、TikTok Shop、自社ストアに複数の言語で出品することがよくあります。言語モデルを使えば、商品情報をまとめたスプレッドシートから、数百点分のタイトル、箇条書き、商品説明の下書きを一晩で作成できます。この記事では、CSV ファイルを読み込み、Ollama のローカルモデル(または OpenAI 互換の任意の AI API)に言語ごとの商品ページを生成させ、結果を新しい CSV ファイルに書き出す小さな Python スクリプトを作成します。書き出した結果は内容を確認したうえで、各マーケットプレイスのテンプレートにインポートします。
1 商品 1 行のスプレッドシートを作成し、UTF-8 で products.csv として保存します(Excel では CSV UTF-8 形式を選択)。列名は自由で、すべての列がモデルに渡されますが、スクリプトには一意の sku 列が必要です。
sku,name,category,specs,keywords
LS-01,Bamboo laptop stand,Office,"6 height levels; fits 10-17 inch laptops; foldable; 1.1 kg; natural bamboo","laptop stand, bamboo, ergonomic"
BT-07,Wireless earbuds,Audio,"Bluetooth 5.3; 30 h playback with case; IPX5; USB-C charging","wireless earbuds, bluetooth, sport"
スクリプトはモデルにこれらの情報だけを使うよう指示するため、素材、サイズ、対応機種、同梱物などの商品情報が正確であるほど、より良く、より安全な結果が得られます。
apt install -y python3-venv
python3 -m venv /opt/listing
/opt/listing/bin/pip install openai
openai Python ライブラリは Ollama の OpenAI 互換エンドポイントにも、ほとんどの AI プロバイダーにも対応しているため、同じスクリプトをローカルモデルでもクラウドモデルでも実行できます。Ollama のセットアップは「Ollama でローカル LLM を運用する」で解説しています。
cat > /opt/listing/listing.py <<'EOF2'
import csv, json, os, re, sys, time
from openai import OpenAI
client = OpenAI(base_url=os.environ.get("AI_BASE_URL", "http://127.0.0.1:11434/v1"),
api_key=os.environ.get("AI_API_KEY", "ollama"))
MODEL = os.environ.get("AI_MODEL", "qwen2.5:7b")
LANGS = [l.strip() for l in os.environ.get("LANGS", "English").split(",")]
SYSTEM = """You write e-commerce product listings for online marketplaces.
Use only the product facts provided. Never invent features, materials,
certifications, prices or delivery promises. No exaggerated claims.
Return JSON only, in this format:
{"title": "...", "bullets": ["...", "...", "...", "...", "..."], "description": "..."}
title: at most 120 characters, main keyword first.
bullets: 5 short points, each starting with the benefit.
description: 80 to 150 words of plain text."""
def ask(product, lang):
prompt = f"Write the listing in {lang}.\nProduct facts:\n{json.dumps(product, ensure_ascii=False)}"
for attempt in range(3):
r = client.chat.completions.create(model=MODEL, temperature=0.4, messages=[
{"role": "system", "content": SYSTEM}, {"role": "user", "content": prompt}])
m = re.search(r"\{.*\}", r.choices[0].message.content or "", re.S)
try:
data = json.loads(m.group(0))
if data.get("title") and isinstance(data.get("bullets"), list) and data.get("description"):
return data
except (AttributeError, ValueError):
pass
time.sleep(2)
raise RuntimeError(f"no valid answer for {product['sku']} / {lang}")
src, dst = sys.argv[1], sys.argv[2]
done = set()
if os.path.exists(dst):
with open(dst, encoding="utf-8-sig") as f:
done = {(r["sku"], r["language"]) for r in csv.DictReader(f)}
with open(src, encoding="utf-8-sig") as f:
products = list(csv.DictReader(f))
new_file = not os.path.exists(dst)
with open(dst, "a", newline="", encoding="utf-8-sig") as f: # utf-8-sig: Excel shows every language correctly
w = csv.writer(f)
if new_file:
w.writerow(["sku", "language", "title", "bullets", "description"])
for p in products:
for lang in LANGS:
if (p["sku"], lang) in done:
continue
d = ask(p, lang)
w.writerow([p["sku"], lang, str(d["title"]).strip(),
"\n".join(str(b).strip() for b in d["bullets"]), str(d["description"]).strip()])
f.flush()
print(p["sku"], lang, "done", flush=True)
EOF2
スクリプトは JSON 形式で回答を求めて内容を検証し、最大 3 回まで再試行します。完成した行はすぐに書き込まれ、2 回目以降の実行では出力ファイルにすでにある商品と言語の組み合わせをスキップします。そのため、ジョブが中断しても、止まったところから処理を再開できます。
cd /data/listings
LANGS="English,Thai,Malay,Japanese" nohup /opt/listing/bin/python /opt/listing/listing.py \
products.csv listings.csv > listing.log 2>&1 &
tail -f listing.log
CPU サーバーでは 7B モデルで 1 件あたり通常数十秒かかるため、500 商品を 4 言語で生成すると一晩がかりの処理になります。代わりにクラウドモデルを使う場合は、OpenAI 互換 API のアドレス、キー、モデル名を指定します。
AI_BASE_URL=https://ai.example.com/v1 AI_API_KEY=sk-your-key AI_MODEL=cloud-chat \
LANGS="English,Thai" /opt/listing/bin/python /opt/listing/listing.py products.csv listings.csv
AI プロバイダーは、サービス提供対象の地域から利用規約の範囲内で使用してください。
listings.csv を Excel または Google スプレッドシートで開き、言語でフィルターします。SYSTEM に追加します。たとえば、使用しない単語のリスト、イギリス英語かアメリカ英語か、絵文字を使わない、などです。SYSTEM に貼り付けます。モデルはその構成とトーンをかなり忠実に再現します。qwen2.5:14b のような大きなモデルは、タイ語、マレー語、ベトナム語の文章が目に見えて良くなりますが、その分速度が落ち、メモリも多く消費します。マーケットプレイスが重視するのは正確さとポリシーの遵守、検索エンジンが重視するのはコンテンツが役に立つかどうかです。人が確認した正確で具体的な商品ページであれば問題ありません。誤りや根拠のない主張を含む大量生産の文章は、誰が書いたかに関係なくリスクになります。
モデルが 3 回続けて有効な JSON ではない応答を返しています。同じコマンドをもう一度実行する(続きから再開されます)か、temperature を下げるか、より大きなモデルを使ってください。
はい。商品を切り抜いて白背景のメイン画像を一括作成する方法は「rembg で商品画像の背景を一括削除する」を参照してください。
上記の手順で解決しない場合は、サポートチケットを送信して IMIDC の 24 時間 365 日対応テクニカルサポートへご連絡ください。サーバー IP、使用しているモデル、実行したコマンド、listing.log の末尾数行を添えていただくと、より迅速に調査できます。