יצירת מיומנות מצבית עבור אליס בפונקציות ללא שרת של Yandex.Cloud ו-Python

בואו נתחיל עם החדשות. אתמול הודיעה Yandex.Cloud על השקת שירות מחשוב ללא שרתים פונקציות ענן של Yandex. זה אומר: אתה כותב רק את הקוד של השירות שלך (לדוגמה, אפליקציית אינטרנט או צ'אט בוט), והענן עצמו יוצר ומתחזק מכונות וירטואליות היכן שהוא פועל, ואף משכפל אותן אם העומס גדל. לא צריך לחשוב בכלל, זה מאוד נוח. והתשלום הולך רק לזמן החישובים.

עם זאת, ייתכן שחלק מהאנשים לא ישלמו כלל. אלה המפתחים הכישורים החיצוניים של אליס, כלומר, צ'אטבוטים מובנים בו. כל מפתח יכול לכתוב, לארח ולרשום מיומנות כזו, ומהיום אין צורך אפילו לארח מיומנויות - פשוט העלה את הקוד שלו לענן בטופס אותה פונקציה ללא שרת.

אבל יש כמה ניואנסים. ראשית, קוד חיית המחמד שלך עשוי לדרוש כמה תלות, וזה לא טריוויאלי לגרור אותם לענן. שנית, כל צ'אט בוט רגיל צריך לאחסן את מצב הדו-שיח איפשהו (מצבי ולכן); איך לעשות את זה בפונקציה ללא שרת בצורה הקלה ביותר? שלישית, איך אתה יכול לכתוב מיומנות מהירה ומלוכלכת עבור אליס או אפילו סוג של בוט עם עלילה שאינה אפס? על ניואנסים אלה, למעשה, המאמר.

יצירת מיומנות מצבית עבור אליס בפונקציות ללא שרת של Yandex.Cloud ו-Python

הכנה מוסרית

לחסרי סבלנות: אני אוסף את התלות הנדרשת עם makefile לפני העלאת הפונקציה לענן, אני מאחסן את מצב הדו-שיח ב-Yandex Object Storage (הוא תומך ב-S3 API), ואני משתמש בספרייה שלי כדי לנהל את הדו-שיח tgalice. כתוצאה מכך, מסתבר כזה מיומנות הדגמה. ועכשיו בואו ננתח את כל זה בפירוט קטן יותר.

לקצת פחות חסרי סבלנות, לפני שצוללים לסיפור המורכבות שלי, אני ממליץ בחום להתחיל בפשטות. כלומר, צור פונקציית echobot של קובץ יחיד, רשום ובדוק אותה במסוף המפתחים של Dialog; פרטים - ב דיאלוגים בבלוג и תיעוד ענן. ורק אז להתחיל.

אם אתה רוצה להרגיש מיד על מה אנחנו נלחמים, שאל את אליס'הפעל את המיומנות "הורוסקופ IT"'. הדיאלוג הבא צריך להתקיים:

אליס: שלום! אתה במיומנות "הורוסקופ IT". אמור "התחל" כדי לגלות מה הכוכבים מבטיחים לך.
משתמש: התחל
ת: נא לציין את שמך.
Yu: Vasisualy
ת: עכשיו ספר לי את שנת לידתך. רק ארבע ספרות, לא יותר.
יו: שני
ת: אנא נסה שוב. ציינו את שנת הלידה שלכם - ארבע ספרות.
יו: 2002
גדול! עכשיו תן שם לחודש הלידה שלך.
יו: פברואר
גדול! לבסוף, ספר לי את תאריך הלידה שלך - רק מספר, רק ספרה אחת או שתיים.
יו: 18
ת: תודה לך, Vasisual! עכשיו אנחנו יודעים: אתה בן 17 ואתה דלי. הנה אתה, כמובן, בר מזל! הכוכבים אומרים לך а что говорят звёзды, вы узнаете, запустив навык.

הבעיה היא שכדי לשמור אפילו על דיאלוג כל כך פשוט, צריך לזכור את השם ותאריך הלידה של המשתמש, ובסביבה ללא שרת זה לא טריוויאלי. זה לא יעבוד לאחסן את ההקשר ב-RAM או כקובץ בדיסק, בגלל Yandex.Cloud יכול להפעיל את הפונקציה על מספר מכונות וירטואליות בו זמנית ולעבור ביניהם באופן שרירותי. תצטרך להשתמש באחסון חיצוני כלשהו. Object Storage נבחר כאחסון די זול ופשוט ישירות ב-Yandex.Cloud (כלומר, כנראה מהיר). כחלופה חינמית, אתה יכול לנסות, למשל, יצירה בחינם מונגי מעונן איפשהו רחוק. גם ל-Object Storage (הוא תומך בממשק S3) וגם למונגו יש עטיפות Python נוחות.

בעיה נוספת היא שכדי לעבור ל-Object Storage, MongoDB ולכל מסד נתונים או מאגר נתונים אחר, אתה צריך כמה תלות חיצוניות שאתה צריך להעלות ל- Yandex Functions יחד עם קוד הפונקציה שלך. ואני רוצה לעשות את זה בנוחות. זה נוח לחלוטין (כמו ב-heroku), אבוי, זה לא יעבוד, אבל אתה יכול ליצור קצת נוחות בסיסית על ידי כתיבת סקריפט לבניית הסביבה (עשה קובץ).

איך להתחיל את מיומנות ההורוסקופ

  1. הכנה: התחברו לכל מכונה שמרימה לינוקס. בעיקרון, עם Windows זה כנראה יכול לעבוד גם כן, אבל הפעלת ה-makefile תדרוש קצת קסם. ובכל מקרה, תצטרכו להתקין Python 3.6 ומעלה.
  2. שיבוט מ-github דוגמה למיומנות הורוסקופ.
  3. הרשמה ב-Ya.Cloud: https://cloud.yandex.ru
  4. צור לעצמך שני דליים פנימה אחסון אובייקטים, קרא להם בכל שם {BUCKET NAME} и tgalice-test-cold-storage (שם אמצעי זה מקודד כעת לתוך main.py הדוגמה שלי). הדלי הראשון יהיה נחוץ רק לפריסה, השני - לאחסון מצבי דיאלוג.
  5. ליצור חשבון שירות, תן לו תפקיד editor, וקבל אישורים סטטיים עבורו {KEY ID} и {KEY VALUE} - נשתמש בהם כדי לתעד את מצב הדיאלוג. כל זה נחוץ כדי שהפונקציה מ- Ya.Cloud תוכל לגשת לאחסון מ- Ya.Cloud. מתישהו, אני מקווה, האישור יהפוך לאוטומטי, אבל לעת עתה - כך.
  6. (אופציונלי) להתקין ממשק שורת הפקודה yc. אפשר ליצור פונקציה גם דרך ממשק האינטרנט, אבל ה-CLI טוב כי כל מיני חידושים מופיעים בו מהר יותר.
  7. עכשיו אתה יכול, למעשה, להכין את מכלול התלות: הפעל על שורת הפקודה מהתיקיה עם דוגמת המיומנות make all. חבורה של ספריות (בעיקר, כרגיל, מיותרות) יותקנו בתיקייה dist.
  8. מלאו בעטים לאחסון חפצים (לדלי {BUCKET NAME}) הארכיון שהושג בשלב הקודם dist.zip. אם תרצה, תוכל לעשות זאת גם משורת הפקודה, למשל, באמצעות AWS CLI.
  9. צור פונקציה ללא שרת דרך ממשק האינטרנט או באמצעות כלי השירות yc. עבור כלי השירות, הפקודה תיראה כך:

yc serverless function version create
    --function-name=horoscope
    --environment=AWS_ACCESS_KEY_ID={KEY ID},AWS_SECRET_ACCESS_KEY={KEY VALUE}
    --runtime=python37
    --package-bucket-name={BUCKET NAME}
    --package-object-name=dist.zip
    --entrypoint=main.alice_handler
    --memory=128M
    --execution-timeout=3s

בעת יצירה ידנית של פונקציה, כל הפרמטרים מתמלאים באותו אופן.

כעת ניתן לבדוק את הפונקציה שיצרת דרך מסוף המפתחים, ולאחר מכן לסיים ולפרסם את המיומנות.

יצירת מיומנות מצבית עבור אליס בפונקציות ללא שרת של Yandex.Cloud ו-Python

מה יש מתחת למכסה המנוע

ה-makefile מכיל למעשה סקריפט פשוט למדי להתקנת תלות והכנסתם לארכיון. dist.zip, משהו כזה:

mkdir -p dist/
pip3 install -r requirements.txt --target dist/ 
cp main.py dist/main.py
cp form.yaml dist/form.yaml
cd dist && zip --exclude '*.pyc' -r ../dist.zip ./*

השאר הם כמה כלים פשוטים עטופים בספרייה tgalice. תהליך מילוי נתוני המשתמש מתואר על ידי התצורה form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'старт|нач(ать|ни)'
  suggests:
    - Старт
fields:
  - name: 'name'
    question: Пожалуйста, назовите своё имя.
  - name: 'year'
    question: Теперь скажите мне год вашего рождения. Только четыре цифры, ничего лишнего.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Пожалуйста, попробуйте ещё раз. Назовите год вашего рождения - четыре цифры.
  - name: 'month'
    question: Замечательно! Теперь назовите месяц вашего рождения.
    options:
      - январь
     ...
      - декабрь
    validate_message: То, что вы назвали, не похоже на месяц. Пожалуйста, назовите месяц вашего рождения, без других слов.
  - name: 'day'
    question: Отлично! Наконец, назовите мне дату вашего рождения - только число, всего одна или две цифры.
    validate_regexp: '[0123]?d$'
    validate_message: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

מחלקת python משתלטת על עבודת ניתוח התצורה הזו וחישוב התוצאה הסופית

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'январь': 'Козерог',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Спасибо, {}! Теперь мы знаем: вам {} лет, и вы {}. n'
                 'Вот это вам, конечно, повезло! Звёзды говорят вам: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

ליתר דיוק, מעמד הבסיס FormFillingDialogManager עוסקת במילוי ה"טופס", ובשיטת כיתת הילד handle_completed_form אומרת מה לעשות כשהיא מוכנה.

בנוסף לזרימה העיקרית הזו של הדיאלוג של המשתמש, יש צורך גם לברך את המשתמש, וכן להנפיק עזרה בפקודת "עזרה" ולשחרר מהמיומנות בפקודת "יציאה". בשביל זה ב tgalice יש גם תבנית, כך שכל מנהל הדו-שיח מורכב מחלקים:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='До свидания, приходите в навык "Айтишный гороскоп" ещё!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager עובד פשוט: הוא מנסה להחיל על המצב הנוכחי של הדיאלוג את כל מרכיביו בתורו, ובוחר את הרלוונטי הראשון.

כתגובה לכל הודעה, מנהל הדו-שיח מחזיר אובייקט פיתון Response, אשר לאחר מכן ניתן להמיר לטקסט רגיל, או להודעה באליס או בטלגרם - תלוי איפה הבוט פועל; הוא מכיל גם את המצב המשתנה של תיבת הדו-שיח שיש לשמור. כל המטבח הזה מטופל על ידי כיתה אחרת, DialogConnector, אז התסריט הישיר לתחילת מיומנות ב-Yandex Functions נראה כך:

...
session = boto3.session.Session()
s3 = session.client(
    service_name='s3',
    endpoint_url='https://storage.yandexcloud.net',
    aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
    region_name='ru-central1',
)
storage = tgalice.session_storage.S3BasedStorage(s3_client=s3, bucket_name='tgalice-test-cold-storage')
connector = tgalice.dialog_connector.DialogConnector(dialog_manager=dm, storage=storage)
alice_handler = connector.serverless_alice_handler

כפי שאתה יכול לראות, רוב הקוד הזה יוצר חיבור לממשק Object Storage S3. כיצד נעשה שימוש ישיר בחיבור הזה, אתה יכול לקרוא בקוד tgalice.
השורה האחרונה יוצרת פונקציה alice_handler - זה שהזמנו למשוך את Yandex.Cloud כאשר אנו מגדירים את הפרמטר --entrypoint=main.alice_handler.

זה, למעשה, הכל. Makefiles לבנייה, אחסון אובייקטים דמוי S3 לאחסון הקשר, וספריית פיתון tgalice. יחד עם התכונות חסרות השרת וכושר ההבעה של פיתון, זה מספיק כדי לפתח את המיומנות של אדם בריא.

אתה יכול לשאול למה אתה צריך ליצור tgalice? כל הקוד המשעמם שמעביר JSON מבקשה לתגובה ומאחסון לזיכרון ובחזרה טמון בו. יש גם אפליקציה רגילה, פונקציה להבנה ש"פברואר" דומה ל"פברואר", ועוד NLU לעניים. לפי הרעיון שלי, זה כבר אמור להספיק כדי להיות מסוגל לשרטט אבות טיפוס של מיומנות בקבצי yaml מבלי להיות מוסחת מדי על ידי פרטים טכניים.

אם אתה רוצה NLU רציני יותר, אתה יכול לדפוק אותו למיומנות שלך ראסה או דיפפלוב, אבל הקמתם תדרוש ריקוד נוסף עם טמבורין, במיוחד ללא שרת. אם לא מתחשק לך קידוד בכלל, עליך להשתמש בבנאי הסוג הוויזואלי איימילוג'יק. בעת יצירת tgalice, חשבתי על איזשהו נתיב ביניים. בוא נראה מה קורה.

ובכן, עכשיו הצטרף צ'אט למפתחי מיומנויות Aliy, לקרוא תיעודוליצור מדהים כישורים!

מקור: www.habr.com

קנה אירוח אמין לאתרים עם הגנת DDoS, שרתי VPS VDS 🔥 קנה אחסון אתרים אמין עם הגנת DDoS, שרתי VPS VDS | ProHoster