הקמת אפליקציה אינטרנטית למערכת שאלות ותשובות מבוססת בינה מלאכותית

מחבר:
בתאריך:

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

את צד השרת נבנה באמצעות Flask - סביבת עבודה מינימלית ליצירת אפליקציות בשפת פייתון. בצד הלקוח נשתמש ב- jQuery כי היא הייתה ונשארה הספריה הפשוטה ביותר כשעובדים עם JavaScript.

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

הקמת אפליקציה אינטרנטית למערכת שאלות ותשובות מבוססת בינה מלאכותית

סרטון קצר שמדגים את האפליקציה בפעולה:

 

מנוע החיפוש Elasticsearch

מנוע החיפוש עליו מבוסס הפרויקט הוא Elasticsearch כפי שהסברתי במדריך קודם מערכת שאלות ותשובות. נריץ את מנוע החיפוש:

$ sudo systemctl start elasticsearch

 

תיקיית הפרויקט

בתוך תיקיית הפרויקט נשים קובץ main.py בתוכו נכתוב את צד השרת של האפליקציה שיקלוט נתונים מהטופס ויחזיר תשובה, ותיקיית static בתוכה נשים קובץ index.html שיכיל את הטופס.

 

הקמת סביבה וירטאולית והתקנת התלויות

נקים סביבת עבודה וירטואלית לתוכה נתקין את הספריות בהם הפרויקט תלוי:

$ python3 -m venv venv

נפעיל את סביבת העבודה:

$ source venv/bin/activate

נתקין את הספריות בהם הפרויקט תלוי:

(venv) $ pip3 install farm-haystack
(venv) $ pip3 install Flask
  • הפלגאין farm-haystack מגשר בין הקוד שאנחנו כותבים בפייתון ובין Elasticsearch.
  • Flask היא סביבת העבודה שבתוכה תוקם האפליקציה האינטרנטית.

נקפיד לעבוד רק בתוך הסביבה הוירטואלית.

 

הקמת אפליקציה אינטרנטית

את צד השרת נבנה באמצעות Flask - סביבת עבודה מינימלית ליצירת אפליקציות בשפת פייתון.

בתוך הקובץ main.py נכתוב את צד השרת של האפליקציה. נתחיל מיבוא התלויות.

בשביל האפליקציה האינטרנטית:

import uuid
from flask import Flask, request, jsonify

בשביל מיצוי תשובות מהטקסט:

from haystack.document_store.elasticsearch import ElasticsearchDocumentStore
from haystack.retriever.sparse import ElasticsearchRetriever
from haystack.reader.farm import FARMReader
from haystack.pipeline import ExtractiveQAPipeline

נגדיר אפליקציה של Flask:

# set the project root directory as the static folder
app = Flask(__name__, static_url_path='')

נגדיר את הנתיב שבו יוצג הטופס:

@app.route('/')
def root():
    return app.send_static_file('index.html')

דף הבית של הפרויקט הוא הדף היחיד שרואה המשתמש. בתוכו נמצא הטופס ואת התבנית שלו ניצור בתוך הקובץ index.html.

המתודה ask() מקבלת מידע מהטופס ב-POST. כולל: מאמר, אינדקס ושאלה. המתודה מאחסנת את המאמר במנוע החיפוש תחת אינדקס ייחודי. הופכת אותו לייצוג וקטורי באמצעות retriever, מאתרת חלקים של הטקסט שעשויים להכיל את התשובה ומחזירה את התוצאות כפי שהסברתי במדריך קודם מערכת שאלות ותשובות.

@app.route('/ask', methods=['POST'])
def ask():
    # get the inputs
    index = request.form['index']
    article = request.form['article']
    question = request.form['question']

    guid = uuid.uuid4().hex.upper()[0:6]
    index = index+guid
    index = index.lower()

    # split into paragraphs
    data = article.split('\n')

    data = [paragraph for paragraph in data if len(paragraph) > 0]

    # format the data
    data_json = [
        {
            'text': paragraph,
            'meta': {
                'source': index
            }
        } for paragraph in data
    ]

    # write to database
    doc_store = ElasticsearchDocumentStore(
        host = 'localhost',
        username='',
        password='',
        index=index
    )

    doc_store.write_documents(data_json)

    # retrieve
    retriever = ElasticsearchRetriever(doc_store)

    # Load a  local model or any of the QA models on
    # Hugging Face's model hub (https://huggingface.co/models)
    reader = FARMReader(model_name_or_path="deepset/roberta-base-squad2", use_gpu=False)

    # extract
    # it is extractive because we extract the answer
    # rather than generating the text
    pipe = ExtractiveQAPipeline(reader, retriever)

    # predict
    predictions = pipe.run(query=question, top_k_retriever=10, top_k_reader=5)

    predictions_list = [
        {
            'question': question,
            'answer': answer['answer'],
            'probability': answer['probability']
        } for answer in predictions['answers']
    ]

    # respond
    return jsonify(predictions_list)

 

טופס להזנת שאלה ופסקה בצד הלקוח

הטופס שאותו רואה משתמש הקצה ממוקם ב: static/index.html כי Flask דורש למקם את הקבצים הסטטיים בתוך תיקיית static.

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

<div id="theForm">
         <label>Headline:</label>
         <input type="text" id="index">
         <label>Passage:</label>
         <textarea id="article"></textarea>
         <label>Question:</label>
         <input type="text" id="question">
         <button id="ask">Ask</button>
</div>
<div id="result"></div>
<p><a href="#" id="reloadPage">Ask another question</a></p>

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

כדי להגיש את הטופס נשתמש ב-jQuery. לחיצה על כפתור השאלה בטופס יאכלס אובייקט item בתוכן השאלה והתשובה, והמידע ישלח ב-POST לצד השרת. התשובות המוחזרות יודבקו חזרה לטופס. לחיצה על קישור תאפשר לשאול שאלה נוספת.

<script type="text/javascript">
  (function($){
      var theForm = $('#theForm');
      var loaderElem = $('#loader');
      var resElem = $('#result');
      var reloadPage = $('#reloadPage');

      $('#ask').on('click', function(){
          loaderElem.show();

          // 1. collect the data from the form
          var item = {
            index: $('#index').val().replace(/ /g, '_'),
            article: $('#article').val(),
            question: $('#question').val()
          }

          // 2. ask the api
          $.post('//localhost:5001/ask', item, function(results){
              loaderElem.hide();

              var list = '<ul>';
              for(var key in results){
                  var probability = results[key].probability * 100;
                  probability = Number(probability).toFixed(2);
                  list += '<li>' + results[key].answer+' (probability: '+probability+'%)</li>';
              }
              list += '/<ul>';
              
              resElem.html(list);
              
              
              // 3. show answer
              resElem.html(list);
              theForm.hide();
              reloadPage.show();
              loaderElem.hide();
          });
      });

      reloadPage.on('click', function($event){
        $event.preventDefault();
        theForm.show();
        reloadPage.hide();
      })
  }(jQuery))
</script>

 

הרצת האפליקציה על המחשב הביתי

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

נריץ את השרת בתוך הסביבה הוירטואלית במצב דיבוג שמאפשר לנו להכניס שינויים בקוד בזמן אמת ולראות את התוצאה בלי צורך לכבות ולהדליק את השרת:

(venv) $ export FLASK_APP=main.py
(venv) $ export FLASK_DEBUG=1
(venv) $ flask run --host=0.0.0.0 --port=5001

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

התמונה של דונה גרציה מתוך ויקיפדיה

התמונה של דונה גרציה מתוך ויקיפדיה

 

אולי גם זה יעניין אותך

הטרנספורמרים משנים את עולם הבינה המלאכותית

למה ואיך לעבוד עם סביבה וירטואלית בפייתון

לכל המדריכים בנושא של למידת מכונה

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

הוסף תגובה חדשה

 

= 6 + 7