用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/RunnerQuan/SAFE-Agent --skill pricing-app-ml-integration命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Find doctors with Healthgrades - search providers, read reviews, and check credentials
Presentation creation, editing, and analysis. When Claude needs to work with presentations (.pptx files) for: (1) Creating new presentations, (2) Modifying or editing content, (3) Working with layouts, (4) Adding comments or speaker notes, or any other presentation tasks.
基于RFM模型和回归算法的客户生命周期价值(LTV)预测分析工具,支持电商和零售业务的客户价值预测。使用时需要客户交易数据、订单历史或消费记录,自动进行RFM特征工程、回归建模和价值预测。
基于 SOC 职业分类
正在显示 SKILL.md
| name | pricing-app-ml-integration |
| description | MercadoLibre API integration patterns - OAuth, webhooks, item sync, order tracking |
| license | MIT |
| metadata | {"author":"pricing-app","version":"1.0.0","scope":["backend","root"],"auto_invoke":["Working with MercadoLibre API","Implementing ML OAuth flow","Processing ML webhooks","Syncing items to/from MercadoLibre"]} |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash |
expires_at - 300 secondshttpx (async HTTP client) | MercadoLibre API v1 | OAuth 2.0 | FastAPI BackgroundTasks
import httpx
import os
from typing import Optional
from datetime import datetime, timedelta
import logging
logger = logging.getLogger(__name__)
class MercadoLibreAPIClient:
"""Client for MercadoLibre API with OAuth handling"""
def __init__(self):
self.base_url = "https://api.mercadolibre.com"
self.client_id = os.getenv("ML_CLIENT_ID")
self.client_secret = os.getenv("ML_CLIENT_SECRET")
self.user_id = os.getenv("ML_USER_ID")
self.refresh_token = os.getenv("ML_REFRESH_TOKEN")
self.access_token: Optional[str] = None
self.token_expires_at: Optional[datetime] = None
async def get_access_token(self) -> str:
"""Get or refresh access token"""
# Return cached token if still valid
if self.access_token and self.token_expires_at:
if datetime.now() < self.token_expires_at:
return .access_token
:
httpx.AsyncClient() client:
response = client.post(
,
data={
: ,
: .client_id,
: .client_secret,
: .refresh_token
}
)
response.raise_for_status()
data = response.json()
.access_token = data[]
expires_in = data.get(, )
.token_expires_at = datetime.now() + timedelta(seconds=expires_in - )
data:
.refresh_token = data[]
.access_token
Exception e:
logger.error()
async def get_item(self, item_id: str) -> Optional[dict]:
"""
Fetch single item from MercadoLibre.
Args:
item_id: MLA/MLB item ID
Returns:
Item data or None if not found
"""
try:
token = await self.get_access_token()
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.get(
f"{self.base_url}/items/{item_id}",
headers={"Authorization": f"Bearer {token}"}
)
if response.status_code == 404:
logger.warning(f"Item {item_id} not found")
return None
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
if e.response.status_code == 429:
logger.warning(f"Rate limit hit for item {item_id}")
else:
logger.error(f"HTTP error fetching item {item_id}: {e}")
return None
except Exception as e:
logger.error(f"Error fetching item : ")
async def get_items_batch(self, item_ids: list[str]) -> dict[str, dict]:
"""
Fetch multiple items in batch (max 20 per request).
Args:
item_ids: List of item IDs
Returns:
Dict mapping item_id -> item_data
"""
results = {}
if not item_ids:
return results
try:
token = await self.get_access_token()
# ML allows up to 20 items per request
batch_size = 20
for i in range(0, len(item_ids), batch_size):
batch = item_ids[i:i + batch_size]
ids_param = ",".join(batch)
async with httpx.AsyncClient(timeout=15.0) as client:
response = await client.get(
f"{self.base_url}/items",
params={"ids": ids_param},
headers={"Authorization": f"Bearer {token}"}
)
response.raise_for_status()
# Response is array of {code, body}
data = response.json()
for item_response in data:
if item_response.get("code") == 200:
body = item_response.get()
body:
results[body[]] = body
Exception e:
logger.error()
results
async def update_item_price(self, item_id: str, new_price: float) -> bool:
"""
Update item price on MercadoLibre.
Args:
item_id: MLA/MLB item ID
new_price: New price (float)
Returns:
True if successful, False otherwise
"""
try:
token = await self.get_access_token()
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.put(
f"{self.base_url}/items/{item_id}",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json={"price": new_price}
)
response.raise_for_status()
logger.info(f"Updated price for {item_id} to {new_price}")
return True
except Exception as e:
logger.error(f"Error updating price for {item_id}: {e}")
return False
from fastapi import APIRouter, BackgroundTasks, Request
from app.services.ml_webhook_service import process_ml_notification
router = APIRouter(prefix="/webhooks", tags=["webhooks"])
@router.post("/mercadolibre")
async def ml_webhook(
request: Request,
background_tasks: BackgroundTasks
):
"""
MercadoLibre webhook endpoint.
Responds quickly and queues processing.
"""
try:
# Get raw body for logging
body = await request.json()
# Log received notification
logger.info(f"ML webhook received: {body.get('topic')}")
# Queue background processing
background_tasks.add_task(process_ml_notification, body)
# Respond immediately (ML requires < 3 seconds)
return {"status": "ok"}
except Exception as e:
logger.error(f"Error receiving ML webhook: {e}")
return {"status": "error"}, 500
async def process_ml_notification(notification: dict):
"""
Process ML notification in background.
Notification types:
- orders: New order created
- items: Item updated
- questions: New question
"""
try:
topic = notification.get("topic")
resource = notification.get("resource")
if topic == "orders_v2":
# Fetch full order data
order_id = resource.split("/")[-1]
await sync_order_from_ml(order_id)
elif topic == "items":
# Item was updated (price, stock, etc.)
item_id = resource.split("/")[-1]
await sync_item_from_ml(item_id)
elif topic == "questions":
# New question received
question_id = resource.split("/")[-1]
await handle_new_question(question_id)
else:
logger.warning(f"Unknown webhook topic: {topic}")
except Exception as e:
logger.error(f"Error processing ML notification: {e}")
# MercadoLibre OAuth
ML_CLIENT_ID=your_client_id
ML_CLIENT_SECRET=your_client_secret
ML_USER_ID=your_user_id
ML_REFRESH_TOKEN=your_refresh_token
# Optional
ML_WEBHOOK_SECRET=your_webhook_secret # For signature validation