Spaces:
Running
Running
File size: 5,607 Bytes
691b9c2 b86c8e7 2ad00a1 b86c8e7 691b9c2 b86c8e7 fbc697b b86c8e7 ac489de fbc697b b86c8e7 fbc697b ac489de fbc697b b86c8e7 fbc697b ac489de fbc697b b86c8e7 9a8266c b86c8e7 9a8266c b86c8e7 9a8266c b86c8e7 fbc697b 125dc93 691b9c2 2ad00a1 691b9c2 2ad00a1 f338fae b86c8e7 fbc697b 28c68bc fbc697b b86c8e7 fbc697b 691b9c2 b86c8e7 691b9c2 b86c8e7 fbc697b b86c8e7 28c68bc 691b9c2 b86c8e7 691b9c2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# main.py
from fastapi import FastAPI, Request, UploadFile
from typing import Any, Dict, Tuple
from datetime import datetime
import json, os, asyncio
import httpx # pip install httpx
app = FastAPI()
GAS_WEBAPP_URL = os.getenv("GAS_WEBAPP_URL")
def print_human_friendly(payload: Dict[str, Any]) -> None:
order = [
("client","๐ค Client"),("source","๐ Source"),("event_name","๐ฏ Event Name"),
("event_id","๐งพ Event ID"),("value","๐ฐ Value"),("currency","๐ฑ Currency"),
("transaction_id","๐ณ Transaction ID"),("content_id","๐ Content ID"),
("content_type","๐ฆ Content Type"),("fbp","๐
ต fbp"),("fbc","๐
ต fbc"),
("ttclid","๐ธ๏ธ ttclid"),("ttp","๐ช ttp"),("scid","๐ช scid"),
("x_email","๐ง x_email (hashed)"),("x_phone","๐ฑ x_phone (hashed)"),
("x_fn","๐ง First Name"),("x_ln","๐ง Last Name"),
("timestamp","โฑ๏ธ Timestamp"),("client_ua","๐ฅ๏ธ Client UA"),
("user_info","๐ค User Info"), ("cart_data","๐ Cart Data"),
]
print("\n" + "-"*18 + " ๐ Human-friendly view " + "-"*18)
label_pad = 20
for key, label in order:
if isinstance(payload, dict) and key in payload and payload.get(key) not in (None, ""):
print(f"{label:<{label_pad}}: {payload.get(key)}")
contents = payload.get("contents") if isinstance(payload, dict) else None
if isinstance(contents, list):
print("\n๐งบ Contents:")
for idx, item in enumerate(contents, start=1):
if isinstance(item, dict):
cid = item.get("content_id","-")
name = item.get("content_name","-")
price = item.get("price","-")
qty = item.get("quantity","-")
print(f" #{idx} โข ID: {cid} | Name: {name} | Price: {price} | Qty: {qty}")
else:
print(f" #{idx} โข {item}")
elif contents is not None:
print("\n๐งบ Contents (raw):")
try:
parsed = contents if isinstance(contents,(dict,list)) else json.loads(str(contents))
print(json.dumps(parsed, ensure_ascii=False, indent=2))
except Exception:
print(str(contents))
# ๐ค User Info
ui = payload.get("user_info") if isinstance(payload, dict) else None
if ui is not None:
print("\n๐ค User Info:")
try:
print(json.dumps(ui, ensure_ascii=False, indent=2))
except Exception:
print(str(ui))
# ๐ Cart Data
cd = payload.get("cart_data") if isinstance(payload, dict) else None
if cd is not None:
print("\n๐ Cart Data:")
try:
print(json.dumps(cd, ensure_ascii=False, indent=2))
except Exception:
print(str(cd))
print("-"*60 + "\n")
async def post_to_gas_raw(raw_body: str, content_type: str) -> Tuple[int, str]:
if not GAS_WEBAPP_URL or GAS_WEBAPP_URL.startswith("YOUR_"):
return (0, "GAS_WEBAPP_URL is not configured")
headers = {"Content-Type": content_type or "application/json"}
timeout = httpx.Timeout(10.0, connect=5.0)
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
for attempt in range(1, 3):
try:
r = await client.post(GAS_WEBAPP_URL, content=raw_body.encode("utf-8"), headers=headers)
# ูู ูุงู 302/303 ูุงุชุจุนุช ุงูุชุญูููุ ููุจูู status 200 ูู ุงูุขุฎุฑ
# ุจุณ ูู ูุณู 302 ูุฃู ุณุจุจุ ุงุนุชุจุฑู ูุฌุงุญ ูุณุฌูู Location
if r.status_code in (301, 302, 303, 307, 308):
loc = r.headers.get("Location", "")
return (r.status_code, f"Redirected to: {loc}")
return (r.status_code, r.text[:5000])
except Exception as e:
if attempt == 2:
return (0, f"Error posting to GAS: {e}")
await asyncio.sleep(0.5)
@app.get("/ping")
async def ping():
return {"message": "pong"}
@app.post("/echo")
async def echo(request: Request) -> Dict[str, Any]:
body_bytes = await request.body()
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("\n" + "="*30 + f" ๐ NEW REQUEST ({now}) " + "="*30)
# ุงุทุจุน ุงูุจูุฏู ุงูุฎุงู
ูู
ุง ูู
raw_text = body_bytes.decode("utf-8", errors="ignore")
# print("\n๐ Request body:")
# print(raw_text)
# print("="*98)
# ุญุงูู ูุทุจุนู ุจุดูู ูุฏูู ููุท ูู JSON object (ููุนุฑุถ ููุทุ ุจุฏูู ุชุนุฏูู ุงูุจูุงูุงุช)
parsed: Any
try:
parsed = await request.json()
except Exception:
try:
parsed = json.loads(raw_text)
except Exception:
parsed = None
if isinstance(parsed, dict):
print_human_friendly(parsed)
else:
print("\n(โน๏ธ Human-friendly view skipped: payload is not a JSON object)\n")
# ๐ ุงุจุนุช ููู GAS ูู
ุง ูู (RAW) ุจููุณ content-type ุงููู ุฌู
ct = request.headers.get("content-type", "application/json")
gas_status, gas_body = await post_to_gas_raw(raw_text, ct)
print(f"๐ค GAS post status: {gas_status}")
# if gas_body:
# print(f"๐ GAS response: {gas_body[:1000]}")
return {
"received": parsed if isinstance(parsed, dict) else raw_text,
"forwarded_to_gas": True,
"gas_status": gas_status,
"info": {
"method": request.method,
"url": str(request.url),
"headers": dict(request.headers),
},
}
|