أداة لوحة المعلومات مع واجهات برمجة تطبيقات Bird

زاكاري صامويلز

24‏/03‏/2022

البريد الإلكتروني

1 min read

أداة لوحة المعلومات مع واجهات برمجة تطبيقات Bird

زاكاري صامويلز

24‏/03‏/2022

البريد الإلكتروني

1 min read

أداة لوحة المعلومات مع واجهات برمجة تطبيقات Bird

هذا النص يلامس السطح فقط لما هو ممكن باستخدام Python, Plotly Dash, وواجهات برمجة التطبيقات الخاصة بنا.

منذ ما يقرب من عام، كتب توم مايرس، مدير نجاح العملاء في Bird، أداة إرسال بريد باستخدام واجهات برمجة تطبيقات Bird. في هذه المقالة، أتابع من حيث انتهى. تتيح أداته إرسال الوظائف بوقت محدد، ولكن ماذا لو أردنا إنشاء لوحات تحكم وسجلات أحداث خاصة بنا؟

ربما أريد إنشاء لوحة تحكم محددة لمجموعة أعمال أو لوحة تحكم للعملاء، لكن دون توفير وصول كامل للمستخدمين إلى واجهة المستخدم الخاصة بـBird. هذا السكربت يلمس فقط القمة لما يمكن تحقيقه باستخدام Python، وPlotly Dash، وواجهات برمجة التطبيقات الخاصة بنا. عند بناء لوحات تحكم تعالج بيانات API عالية الحجم، يجب أن تكون على دراية بأن المكونات التحتية مثل DNS يمكن أن تصبح عنق زجاجة - لقد واجهنا تحديات توسيع نطاق DNS في AWS التي أثرت على قدرات معالجة بياناتنا. لمحبي سير العمل البصري، يمكنك أيضًا استكشاف دمج Flow Builder مع وظائف Google Cloud وVision API لإضافة أتمتة مدعومة بالذكاء الاصطناعي إلى خطوط معالجة البيانات الخاصة بك.

بينما بدأت بحثي عبر الإنترنت، أردت إيجاد المسار الأقل مقاومة. كان بإمكاني إنشاء جميع لوحات التحكم وواجهة المستخدم بنفسي باستخدام HTML وPython، ولكن بعد بعض البحث في Google، صادفت Plotly's Dash، الذي يندمج بسهولة مع Python. اخترت Dash لسببين: 1) هو مفتوح المصدر، و2) بعد قراءة الوثائق بدا أنه قابل للتخصيص بسهولة لما كنت أحاول القيام به. Dash هو مكتبة مفتوحة المصدر مثالية لبناء ونشر تطبيقات البيانات مع واجهات مستخدم مخصصة. جعل هذا إنشاء واجهة مستخدم أمرًا بسيطًا للغاية. ثم أصبح السؤال، كم كان التطبيق معقدًا؟ كلما قضيت المزيد من الوقت، كلما أردت إضافة المزيد من الميزات.

للمشروع الأولي، أردت التأكد من أن لدي لوحة معلومات مع مقاييس قابلة للتخصيص وإطار زمني قابل للاختيار. في البداية، بدأت مع لوحة معلومات حيث يمكنك اختيار مقياس واحد فقط من القائمة المنسدلة. ثم، عندما تلقيت ردود الفعل من الزملاء، قمت بتحسين لوحة التحكم قليلاً لإضافة تحديد متعدد وعناوين المحاور. قررت أيضًا إضافة علامة تبويب إضافية لسجل الأحداث. وصلت إلى النقطة التي كنت فيها راضيًا عما لدي كنقطة انطلاق جيدة لأي شخص يرغب في بناء لوحات التحكم الخاصة به. للمطورين الذين يرغبون في تغذية بيانات webhook في الوقت الحقيقي في لوحات تحكمهم، اطلع على دليلنا حول بناء مستهلكي webhook باستخدام وظائف Azure. بالطبع، وضعت المشروع في Github لتتمكن من نسخه أو إنشاء فرع خاص بك.

البدء

للوصول إلى هذا التطبيق، ستحتاج إلى التأكد من أنك تقوم بتشغيل بايثون 3.10 أو أعلى وتثبيت المكتبات التالية:

  • requests

  • dash

  • pandas

ثم، أدخل مفتاح API الخاص بك في App.py وقم بتشغيل التطبيق. سيعمل على http://localhost:8050. لمزيد من المعلومات حول نشر هذا على خادم مواجه للجمهور (مثل AWS)، انظر الموارد التالية:

إنشاء صفحة لوحة التحكم

أولاً، قم بتهيئة إطار البيانات ولوحة المعلومات. بدون تهيئة لوحة المعلومات، لن تظهر أي لوحة في واجهة المستخدم.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

ثم قم ببناء التبويب الأول. هذا هو مزيج من استدعاء التطبيق (للتحقق من أي تبويب يتم استخدامه)؛ مع وظيفة شرطية للتحقق من أي تبويب تم تحديده حاليًا. الشيفرة أدناه تبني فقط لوحة المعلومات الفارغة وعناصر واجهة المستخدم (سنصل إلى تبويب الأحداث لاحقًا). عناصر dcc هي Dash Core Components وHTML Components مما يسمح باستخدام HTML بسهولة في واجهة المستخدم.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

لاحظ كيف أن إنشاء واجهة مستخدم لوحة المعلومات مع قائمة منسدلة متعددة التحديد والبحث بسيط مع dash. لإلغاء تفعيل التحديد المتعدد أو البحث، يمكن تعديل المعايير لإنشاء قائمة منسدلة بسهولة. وجدت أن الجزء الأكثر تعقيدًا في هذا المشروع كان بناء إطار البيانات الفعلي من المدخلات، وأيضًا جعل HTML + CSS يعمل بشكل صحيح في واجهة المستخدم.

يتيح Time Series Metrics API سحب 33 مقياسًا فرديًا مستندًا إلى نطاق التاريخ/الوقت. يمكنك التصفية بدرجة أعمق حسب النطاقات، الحملات، تجمعات IP، المجالات المرسلة، الحسابات الفرعية، وتحديد دقة بيانات السلاسل الزمنية. قد تكون هذه الفلاتر الإضافية جنباً إلى جنب مع تحليلات الإيصال تحسينًا مستقبليًا لهذا المشروع (ستحتاج معالجة الأخطاء إلى التنفيذ للعملاء الذين ليس لديهم حق الوصول إلى تحليلات الإيصال).

من خلال استخدام واستدعاء Metrics API، قمت ببناء لوحة معلومات مع المعايير المختارة للمستخدم والفترة الزمنية المحددة. ثم يتم تحديث لوحة المعلومات المهيأة.

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

ما يلي هو مثال لمقاييس متعددة مختارة وفترة زمنية موسعة.


Sparkpost analytics dashboard

ملاحظة: هناك العديد من العناصر المدمجة تلقائيًا في الرسم البياني في dash (التحويم، التكبير، الضبط التلقائي).

أولاً، قم بتهيئة إطار البيانات ولوحة المعلومات. بدون تهيئة لوحة المعلومات، لن تظهر أي لوحة في واجهة المستخدم.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

ثم قم ببناء التبويب الأول. هذا هو مزيج من استدعاء التطبيق (للتحقق من أي تبويب يتم استخدامه)؛ مع وظيفة شرطية للتحقق من أي تبويب تم تحديده حاليًا. الشيفرة أدناه تبني فقط لوحة المعلومات الفارغة وعناصر واجهة المستخدم (سنصل إلى تبويب الأحداث لاحقًا). عناصر dcc هي Dash Core Components وHTML Components مما يسمح باستخدام HTML بسهولة في واجهة المستخدم.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

لاحظ كيف أن إنشاء واجهة مستخدم لوحة المعلومات مع قائمة منسدلة متعددة التحديد والبحث بسيط مع dash. لإلغاء تفعيل التحديد المتعدد أو البحث، يمكن تعديل المعايير لإنشاء قائمة منسدلة بسهولة. وجدت أن الجزء الأكثر تعقيدًا في هذا المشروع كان بناء إطار البيانات الفعلي من المدخلات، وأيضًا جعل HTML + CSS يعمل بشكل صحيح في واجهة المستخدم.

يتيح Time Series Metrics API سحب 33 مقياسًا فرديًا مستندًا إلى نطاق التاريخ/الوقت. يمكنك التصفية بدرجة أعمق حسب النطاقات، الحملات، تجمعات IP، المجالات المرسلة، الحسابات الفرعية، وتحديد دقة بيانات السلاسل الزمنية. قد تكون هذه الفلاتر الإضافية جنباً إلى جنب مع تحليلات الإيصال تحسينًا مستقبليًا لهذا المشروع (ستحتاج معالجة الأخطاء إلى التنفيذ للعملاء الذين ليس لديهم حق الوصول إلى تحليلات الإيصال).

من خلال استخدام واستدعاء Metrics API، قمت ببناء لوحة معلومات مع المعايير المختارة للمستخدم والفترة الزمنية المحددة. ثم يتم تحديث لوحة المعلومات المهيأة.

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

ما يلي هو مثال لمقاييس متعددة مختارة وفترة زمنية موسعة.


Sparkpost analytics dashboard

ملاحظة: هناك العديد من العناصر المدمجة تلقائيًا في الرسم البياني في dash (التحويم، التكبير، الضبط التلقائي).

أولاً، قم بتهيئة إطار البيانات ولوحة المعلومات. بدون تهيئة لوحة المعلومات، لن تظهر أي لوحة في واجهة المستخدم.

df = pd.DataFrame({
    "Count": [0, 0],
    "Time": [0, 0]
})
fig = px.line(df, x="Time", y="Count")

ثم قم ببناء التبويب الأول. هذا هو مزيج من استدعاء التطبيق (للتحقق من أي تبويب يتم استخدامه)؛ مع وظيفة شرطية للتحقق من أي تبويب تم تحديده حاليًا. الشيفرة أدناه تبني فقط لوحة المعلومات الفارغة وعناصر واجهة المستخدم (سنصل إلى تبويب الأحداث لاحقًا). عناصر dcc هي Dash Core Components وHTML Components مما يسمح باستخدام HTML بسهولة في واجهة المستخدم.

html.H2("Analytics Dashboard"),
# Multi-select dropdown
dcc.Dropdown(
    [
        "Count Accepted",
        "Count Admin Bounce",
        "Count Block Bounce",
        "Count Bounce",
        "Count Clicked",
        "Count Delayed",
        "Count Delayed First",
        "Count Delivered",
        "Count Delivered First",
        "Count Delivered Subsequent",
        "Count Generation Failed",
        "Count Generation Rejection",
        "Count Hard Bounce",
        "Count Inband Bounce",
        "Count Initial Rendered",
        "Count Injected",
        "Count Out of Band Bounce",
        "Count Policy Rejection",
        "Count Rejected",
        "Count Rendered",
        "Count Sent",
        "Count Soft Bounce",
        "Count Spam Complaint",
        "Count Targeted",
        "Count Undetermined Bounce",
        "Count Unique Clicked",
        "Count Unique Confirmed Opened",
        "Count Unique Initial Rendered",
        "Count Unique Rendered",
        "Count Unsubscribe",
        "Total Delivery Time First",
        "Total Delivery Time Subsequent",
        "Total Message Volume",
    ],
    id="y-axis",
    multi=True,
    searchable=True,
    placeholder="Select metrics(s)",
),
# Date selector (max date allowed is set to today's date)
dcc.DatePickerRange(
    id="date-picker-range",
    start_date=date(2022, 1, 1),
    end_date=date(2022, 2, 1),
    max_date_allowed=date(
        datetime.today().year,
        datetime.today().month,
        datetime.today().day,
    ),
),
# Graph object
dcc.Graph(id="Emails", figure=fig)

لاحظ كيف أن إنشاء واجهة مستخدم لوحة المعلومات مع قائمة منسدلة متعددة التحديد والبحث بسيط مع dash. لإلغاء تفعيل التحديد المتعدد أو البحث، يمكن تعديل المعايير لإنشاء قائمة منسدلة بسهولة. وجدت أن الجزء الأكثر تعقيدًا في هذا المشروع كان بناء إطار البيانات الفعلي من المدخلات، وأيضًا جعل HTML + CSS يعمل بشكل صحيح في واجهة المستخدم.

يتيح Time Series Metrics API سحب 33 مقياسًا فرديًا مستندًا إلى نطاق التاريخ/الوقت. يمكنك التصفية بدرجة أعمق حسب النطاقات، الحملات، تجمعات IP، المجالات المرسلة، الحسابات الفرعية، وتحديد دقة بيانات السلاسل الزمنية. قد تكون هذه الفلاتر الإضافية جنباً إلى جنب مع تحليلات الإيصال تحسينًا مستقبليًا لهذا المشروع (ستحتاج معالجة الأخطاء إلى التنفيذ للعملاء الذين ليس لديهم حق الوصول إلى تحليلات الإيصال).

من خلال استخدام واستدعاء Metrics API، قمت ببناء لوحة معلومات مع المعايير المختارة للمستخدم والفترة الزمنية المحددة. ثم يتم تحديث لوحة المعلومات المهيأة.

# Build the API call utilizing the parameters provided
params = {
    "from": start_date + "T00:00",
    "to": end_date + "T00:00",
    "delimiter": ",",
    "precision": "day",
    "metrics": joined_values
}
api_url = BASE_URL + "/metrics/deliverability/time-series"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = json.loads(response_API.text)
new_df = pd.json_normalize(response_info, record_path=['results'])
value_array = joined_values.split(",")
# Build out a new dashboard utilizing the new metrics and dates from the updated API call
fig = px.line(
    new_df,
    x=new_df['ts'],
    y=value_array,
    labels={"value": "Count", "variable": "Metric", "ts": "Date"}
)
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="Count")
return fig

ما يلي هو مثال لمقاييس متعددة مختارة وفترة زمنية موسعة.


Sparkpost analytics dashboard

ملاحظة: هناك العديد من العناصر المدمجة تلقائيًا في الرسم البياني في dash (التحويم، التكبير، الضبط التلقائي).

إنشاء صفحة تفاصيل الحدث

كانت صفحة تفاصيل الحدث أكثر صعوبة قليلاً لأنني لم أكن أعرف أفضل طريقة لعرض جميع مقاييس الأحداث بطريقة سهلة القراءة. فكرت في إضافة معايير تصفية إلى هذه الصفحة، ومع ذلك، قررت أن ذلك سيضيف وقتًا كبيرًا إلى هذا المشروع لأن الجدول سيصبح ديناميكيًا (إلى جانب إضافة المعايير، ردود الفعل، إلخ). قررت عرض جميع الأحداث ووضع الطابع الزمني أولاً (حيث أنه بدون وضع الطابع الزمني أولاً، لم يكن الرسم البياني سهل القراءة). في البداية، وجدت أن الجدول بصيغة HTML الخام كان صعبًا للغاية على العيون. لم تكن هناك حدود ولا اختلافات في اللون بين الرأس والصفوف. لجعل الجدول أسهل في القراءة، تمكنت من استخدام CSS ضمن Dash.

الفكرة لتفاصيل الحدث مشابهة تقريبًا للوحة المعلومات، باستثناء أنني هذه المرة أدعو Events API وأجلب جميع الأحداث. لاحظ أن تفاصيل الحدث تعرض فقط أحدث 10 أحداث (باستخدام معلمة max_rows وتصفية API). يمكن زيادة هذا، ومع ذلك، قررت عرض أحدث 10 أحداث لأن كلما زادت الأحداث المعروضة، كلما طال زمن استجابة مكالمة API. يمكن تحقيق تحسين كبير بتمكين الترقيم وإضافة صفحة تالية / صفحة سابقة في واجهة المستخدم.

لبناء علامة تبويب الأحداث (الصفحة)، أولاً، أستدعي واجهة برمجة تطبيقات الأحداث وأقوم بتحليل استجابة JSON إلى إطار بيانات. ثم أفرز وأعيد ترتيب إطار البيانات لوضع الطابع الزمني كأول عمود. أخيرًا، أقوم ببناء جدول HTML من خلال التمرير عبر إطار البيانات.

# Build out and call the events API
params = {
    "events": "delivery,injection,bounce,delay,policy_rejection,out_of_band,open,click,"
              "generation_failure,generation_rejection,spam_complaint,list_unsubscribe,link_unsubscribe",
    "delimiter": ",",
    "page": "1",
    "per_page": "10",
}
api_url = f"{BASE_URL}/events/message"
response_API = requests.get(api_url, headers={"Authorization": API_KEY}, params=params)
response_info = response_API.json()
new_df = pd.json_normalize(response_info, record_path=["results"])
max_rows = 10  # Max number of results to show in the events table
# Sort columns and place timestamp as the first column in the table
new_df = new_df.reindex(sorted(new_df.columns), axis=1)
cols = ["timestamp"]
new_df = new_df[cols + [c for c in new_df.columns if c not in cols]]
# Show the new HTML with the events table (note: this table also references table.css)
return html.Div([
    html.H2("Event Details"),
    html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in new_df.columns], className="table_css")
        ),
        html.Tbody([
            html.Tr([
                html.Td(new_df.iloc[i][col], className="table_css")
                for col in new_df.columns
            ])
            for i in range(min(len(new_df), max_rows))
        ])
    ])
])

والذي يظهر على النحو التالي في واجهة المستخدم.

Sparkpost event details

الخطوات التالية

بالنسبة لشخص مهتم بإنشاء لوحة تحكم أو سجل أحداث خاص به، فهذا يُعتبر بداية جيدة. مع قابلية التخصيص هنا، السماء هي الحد.

كما نوقش أعلاه، بعض التحسينات المستقبلية التي يمكن القيام بها هي:

  • إضافة تحليلات التسليم إلى لوحة التحكم

  • إضافة المزيد من الفلاتر إلى لوحة التحكم

  • خيارات التخزين المؤقت الممكنة بحيث لا يتم استدعاء API في كل مرة لعرض الصفحات

  • تحسينات واجهة المستخدم

  • إضافة التصفية ورقم الصفحة إلى صفحة تفاصيل الأحداث

أود سماع أي تعليقات أو اقتراحات لتوسيع هذا المشروع.

~ زاك صامويلز، مهندس حلول أول في Bird

دعنا نوصلك بخبير من Bird.
رؤية القوة الكاملة لـ Bird في 30 دقيقة.

بتقديمك طلبًا، فإنك توافق على أن تقوم Bird بالاتصال بك بشأن منتجاتنا وخدماتنا.

يمكنك إلغاء الاشتراك في أي وقت. انظر بيان الخصوصية الخاص بـ Bird للتفاصيل حول معالجة البيانات.

دعنا نوصلك بخبير من Bird.
رؤية القوة الكاملة لـ Bird في 30 دقيقة.

بتقديمك طلبًا، فإنك توافق على أن تقوم Bird بالاتصال بك بشأن منتجاتنا وخدماتنا.

يمكنك إلغاء الاشتراك في أي وقت. انظر بيان الخصوصية الخاص بـ Bird للتفاصيل حول معالجة البيانات.

دعنا نوصلك بخبير من Bird.
رؤية القوة الكاملة لـ Bird في 30 دقيقة.

بتقديمك طلبًا، فإنك توافق على أن تقوم Bird بالاتصال بك بشأن منتجاتنا وخدماتنا.

يمكنك إلغاء الاشتراك في أي وقت. انظر بيان الخصوصية الخاص بـ Bird للتفاصيل حول معالجة البيانات.

R

وصول

G

نمو

م

إدارة

A

أتمتة

النشرة الإخبارية

ابقَ على اطلاع مع Bird من خلال التحديثات الأسبوعية إلى بريدك الوارد.