Spaces:
No application file
No application file
integrating twitter chatbot to a django server
Browse files- app.py +46 -0
- {src β backend/TwitterChatBot}/chat.py +10 -7
- {src β backend/TwitterChatBot}/gpt_3_manager.py +0 -0
- {src β backend/TwitterChatBot}/index.py +1 -1
- backend/TwitterChatBot/main.py +28 -0
- {src β backend/TwitterChatBot}/prompt.py +0 -0
- {src β backend/TwitterChatBot}/tests/chat_test.py +0 -0
- {src β backend/TwitterChatBot}/tests/gpt_3_manager_test.py +0 -0
- {src β backend/TwitterChatBot}/tests/index_test.py +0 -0
- {src β backend/TwitterChatBot}/tests/prompt_test.py +0 -0
- {src β backend/TwitterChatBot}/tests/utils_test.py +0 -0
- {src β backend/TwitterChatBot}/utils.py +0 -0
- {src/tests β backend/backend}/__init__.py +0 -0
- backend/backend/asgi.py +16 -0
- backend/backend/settings.py +125 -0
- backend/backend/urls.py +7 -0
- backend/backend/wsgi.py +16 -0
- backend/chatbot/__init__.py +0 -0
- backend/chatbot/admin.py +3 -0
- backend/chatbot/apps.py +6 -0
- backend/chatbot/migrations/__init__.py +0 -0
- backend/chatbot/models.py +3 -0
- backend/chatbot/tests.py +3 -0
- backend/chatbot/urls.py +7 -0
- backend/chatbot/views.py +15 -0
- backend/manage.py +22 -0
- conftest.py +0 -0
- requirements.txt +4 -1
- src/main.py +0 -29
app.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import random
|
3 |
+
import string
|
4 |
+
import requests
|
5 |
+
|
6 |
+
|
7 |
+
def get_random_string(length=6):
|
8 |
+
letters = string.ascii_lowercase
|
9 |
+
result_str = "".join(random.choice(letters) for i in range(length))
|
10 |
+
return result_str
|
11 |
+
|
12 |
+
|
13 |
+
def get_answer(question):
|
14 |
+
try:
|
15 |
+
answer = requests.get(
|
16 |
+
"http://127.0.0.1:8000/api/",
|
17 |
+
json={"question": question},
|
18 |
+
)
|
19 |
+
except Exception as err:
|
20 |
+
return f"Sorry there was a problem with {err}, please check your connection and try again."
|
21 |
+
|
22 |
+
if answer.status_code == 200:
|
23 |
+
return answer.json()["answer"]
|
24 |
+
|
25 |
+
return "Sorry, We have a problem with our server"
|
26 |
+
|
27 |
+
|
28 |
+
def predict(input, history=[]):
|
29 |
+
answer = get_answer(input)
|
30 |
+
history.append((input, answer))
|
31 |
+
response = history
|
32 |
+
return response, history
|
33 |
+
|
34 |
+
|
35 |
+
with gr.Blocks() as demo:
|
36 |
+
chatbot = gr.Chatbot()
|
37 |
+
state = gr.State([])
|
38 |
+
|
39 |
+
with gr.Row():
|
40 |
+
txt = gr.Textbox(
|
41 |
+
show_label=False, placeholder="Enter text and press enter"
|
42 |
+
).style(container=False)
|
43 |
+
|
44 |
+
txt.submit(predict, [txt, state], [chatbot, state])
|
45 |
+
|
46 |
+
demo.launch()
|
{src β backend/TwitterChatBot}/chat.py
RENAMED
@@ -1,10 +1,14 @@
|
|
1 |
import os
|
2 |
import openai
|
3 |
-
from dotenv import load_dotenv
|
4 |
-
from index import IndexSearchEngine
|
5 |
-
from gpt_3_manager import Gpt3Manager
|
6 |
-
from prompt import QuestionAnsweringPrompt, PassageSummarizationPrompt, TextPromptLoader
|
7 |
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
|
10 |
load_dotenv()
|
@@ -27,12 +31,11 @@ class ChatBot:
|
|
27 |
|
28 |
answers = []
|
29 |
for result in search_result:
|
30 |
-
print("iterating over answering questions")
|
31 |
question_answering_prompt = QuestionAnsweringPrompt(
|
32 |
passage=result, question=question, prompt_loader=self.prompet_loader
|
33 |
)
|
34 |
prompt = question_answering_prompt.load(
|
35 |
-
Path("prompts") / "question_answering.txt"
|
36 |
)
|
37 |
|
38 |
answer = self.gpt_manager.get_completion(
|
@@ -45,7 +48,7 @@ class ChatBot:
|
|
45 |
)
|
46 |
|
47 |
prompt = passage_summarization_prompt.load(
|
48 |
-
Path("prompts") / "passage_summarization.txt"
|
49 |
)
|
50 |
|
51 |
final_answer = self.gpt_manager.get_completion(prompt=prompt)
|
|
|
1 |
import os
|
2 |
import openai
|
|
|
|
|
|
|
|
|
3 |
from pathlib import Path
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
|
6 |
+
from TwitterChatBot.index import IndexSearchEngine
|
7 |
+
from TwitterChatBot.prompt import (
|
8 |
+
QuestionAnsweringPrompt,
|
9 |
+
PassageSummarizationPrompt,
|
10 |
+
TextPromptLoader,
|
11 |
+
)
|
12 |
|
13 |
|
14 |
load_dotenv()
|
|
|
31 |
|
32 |
answers = []
|
33 |
for result in search_result:
|
|
|
34 |
question_answering_prompt = QuestionAnsweringPrompt(
|
35 |
passage=result, question=question, prompt_loader=self.prompet_loader
|
36 |
)
|
37 |
prompt = question_answering_prompt.load(
|
38 |
+
Path("../prompts") / "question_answering.txt"
|
39 |
)
|
40 |
|
41 |
answer = self.gpt_manager.get_completion(
|
|
|
48 |
)
|
49 |
|
50 |
prompt = passage_summarization_prompt.load(
|
51 |
+
Path("../prompts") / "passage_summarization.txt"
|
52 |
)
|
53 |
|
54 |
final_answer = self.gpt_manager.get_completion(prompt=prompt)
|
{src β backend/TwitterChatBot}/gpt_3_manager.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/index.py
RENAMED
@@ -1,6 +1,6 @@
|
|
1 |
from abc import ABC, abstractmethod
|
2 |
import jsonlines
|
3 |
-
from utils import dot_similarity
|
4 |
|
5 |
|
6 |
class Index(ABC):
|
|
|
1 |
from abc import ABC, abstractmethod
|
2 |
import jsonlines
|
3 |
+
from TwitterChatBot.utils import dot_similarity
|
4 |
|
5 |
|
6 |
class Index(ABC):
|
backend/TwitterChatBot/main.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from pathlib import Path
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
from TwitterChatBot.index import IndexSearchEngine
|
6 |
+
from TwitterChatBot.gpt_3_manager import Gpt3Manager
|
7 |
+
from TwitterChatBot.chat import ChatBot
|
8 |
+
from TwitterChatBot.index import JsonLinesIndex
|
9 |
+
from TwitterChatBot.prompt import TextPromptLoader
|
10 |
+
|
11 |
+
load_dotenv()
|
12 |
+
|
13 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
14 |
+
|
15 |
+
path = Path("../index") / "index.jsonl"
|
16 |
+
|
17 |
+
|
18 |
+
def ask(question):
|
19 |
+
index = JsonLinesIndex()
|
20 |
+
loaded = index.load(path)
|
21 |
+
gpt_manager = Gpt3Manager(api_key=OPENAI_API_KEY)
|
22 |
+
|
23 |
+
engine = IndexSearchEngine(loaded, gpt_manager=gpt_manager)
|
24 |
+
loader = TextPromptLoader()
|
25 |
+
chatbot = ChatBot(engine, prompt_loader=loader, gpt_manager=gpt_manager)
|
26 |
+
|
27 |
+
answer = chatbot.ask(question)
|
28 |
+
return answer
|
{src β backend/TwitterChatBot}/prompt.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/tests/chat_test.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/tests/gpt_3_manager_test.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/tests/index_test.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/tests/prompt_test.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/tests/utils_test.py
RENAMED
File without changes
|
{src β backend/TwitterChatBot}/utils.py
RENAMED
File without changes
|
{src/tests β backend/backend}/__init__.py
RENAMED
File without changes
|
backend/backend/asgi.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
ASGI config for backend project.
|
3 |
+
|
4 |
+
It exposes the ASGI callable as a module-level variable named ``application``.
|
5 |
+
|
6 |
+
For more information on this file, see
|
7 |
+
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
8 |
+
"""
|
9 |
+
|
10 |
+
import os
|
11 |
+
|
12 |
+
from django.core.asgi import get_asgi_application
|
13 |
+
|
14 |
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
|
15 |
+
|
16 |
+
application = get_asgi_application()
|
backend/backend/settings.py
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Django settings for backend project.
|
3 |
+
|
4 |
+
Generated by 'django-admin startproject' using Django 4.1.7.
|
5 |
+
|
6 |
+
For more information on this file, see
|
7 |
+
https://docs.djangoproject.com/en/4.1/topics/settings/
|
8 |
+
|
9 |
+
For the full list of settings and their values, see
|
10 |
+
https://docs.djangoproject.com/en/4.1/ref/settings/
|
11 |
+
"""
|
12 |
+
|
13 |
+
from pathlib import Path
|
14 |
+
|
15 |
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
16 |
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
17 |
+
|
18 |
+
|
19 |
+
# Quick-start development settings - unsuitable for production
|
20 |
+
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
21 |
+
|
22 |
+
# SECURITY WARNING: keep the secret key used in production secret!
|
23 |
+
SECRET_KEY = "django-insecure-@0lshx3*e(q@2
olq=%ak0-)-%_!xux^a&70@p1=x_o^(=g"
|
24 |
+
|
25 |
+
# SECURITY WARNING: don't run with debug turned on in production!
|
26 |
+
DEBUG = True
|
27 |
+
|
28 |
+
ALLOWED_HOSTS = []
|
29 |
+
|
30 |
+
|
31 |
+
# Application definition
|
32 |
+
|
33 |
+
INSTALLED_APPS = [
|
34 |
+
"django.contrib.admin",
|
35 |
+
"django.contrib.auth",
|
36 |
+
"django.contrib.contenttypes",
|
37 |
+
"django.contrib.sessions",
|
38 |
+
"django.contrib.messages",
|
39 |
+
"django.contrib.staticfiles",
|
40 |
+
"rest_framework",
|
41 |
+
"chatbot",
|
42 |
+
]
|
43 |
+
|
44 |
+
MIDDLEWARE = [
|
45 |
+
"django.middleware.security.SecurityMiddleware",
|
46 |
+
"django.contrib.sessions.middleware.SessionMiddleware",
|
47 |
+
"django.middleware.common.CommonMiddleware",
|
48 |
+
"django.middleware.csrf.CsrfViewMiddleware",
|
49 |
+
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
50 |
+
"django.contrib.messages.middleware.MessageMiddleware",
|
51 |
+
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
52 |
+
]
|
53 |
+
|
54 |
+
ROOT_URLCONF = "backend.urls"
|
55 |
+
|
56 |
+
TEMPLATES = [
|
57 |
+
{
|
58 |
+
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
59 |
+
"DIRS": [],
|
60 |
+
"APP_DIRS": True,
|
61 |
+
"OPTIONS": {
|
62 |
+
"context_processors": [
|
63 |
+
"django.template.context_processors.debug",
|
64 |
+
"django.template.context_processors.request",
|
65 |
+
"django.contrib.auth.context_processors.auth",
|
66 |
+
"django.contrib.messages.context_processors.messages",
|
67 |
+
],
|
68 |
+
},
|
69 |
+
},
|
70 |
+
]
|
71 |
+
|
72 |
+
WSGI_APPLICATION = "backend.wsgi.application"
|
73 |
+
|
74 |
+
|
75 |
+
# Database
|
76 |
+
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
77 |
+
|
78 |
+
DATABASES = {
|
79 |
+
"default": {
|
80 |
+
"ENGINE": "django.db.backends.sqlite3",
|
81 |
+
"NAME": BASE_DIR / "db.sqlite3",
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
|
86 |
+
# Password validation
|
87 |
+
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
|
88 |
+
|
89 |
+
AUTH_PASSWORD_VALIDATORS = [
|
90 |
+
{
|
91 |
+
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
92 |
+
},
|
93 |
+
{
|
94 |
+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
98 |
+
},
|
99 |
+
{
|
100 |
+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
101 |
+
},
|
102 |
+
]
|
103 |
+
|
104 |
+
|
105 |
+
# Internationalization
|
106 |
+
# https://docs.djangoproject.com/en/4.1/topics/i18n/
|
107 |
+
|
108 |
+
LANGUAGE_CODE = "en-us"
|
109 |
+
|
110 |
+
TIME_ZONE = "UTC"
|
111 |
+
|
112 |
+
USE_I18N = True
|
113 |
+
|
114 |
+
USE_TZ = True
|
115 |
+
|
116 |
+
|
117 |
+
# Static files (CSS, JavaScript, Images)
|
118 |
+
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
119 |
+
|
120 |
+
STATIC_URL = "static/"
|
121 |
+
|
122 |
+
# Default primary key field type
|
123 |
+
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
124 |
+
|
125 |
+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
backend/backend/urls.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.contrib import admin
|
2 |
+
from django.urls import path, include
|
3 |
+
|
4 |
+
urlpatterns = [
|
5 |
+
path("admin/", admin.site.urls),
|
6 |
+
path("api/", include("chatbot.urls")),
|
7 |
+
]
|
backend/backend/wsgi.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
WSGI config for backend project.
|
3 |
+
|
4 |
+
It exposes the WSGI callable as a module-level variable named ``application``.
|
5 |
+
|
6 |
+
For more information on this file, see
|
7 |
+
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
8 |
+
"""
|
9 |
+
|
10 |
+
import os
|
11 |
+
|
12 |
+
from django.core.wsgi import get_wsgi_application
|
13 |
+
|
14 |
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
|
15 |
+
|
16 |
+
application = get_wsgi_application()
|
backend/chatbot/__init__.py
ADDED
File without changes
|
backend/chatbot/admin.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from django.contrib import admin
|
2 |
+
|
3 |
+
# Register your models here.
|
backend/chatbot/apps.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.apps import AppConfig
|
2 |
+
|
3 |
+
|
4 |
+
class ChatbotConfig(AppConfig):
|
5 |
+
default_auto_field = 'django.db.models.BigAutoField'
|
6 |
+
name = 'chatbot'
|
backend/chatbot/migrations/__init__.py
ADDED
File without changes
|
backend/chatbot/models.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from django.db import models
|
2 |
+
|
3 |
+
# Create your models here.
|
backend/chatbot/tests.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from django.test import TestCase
|
2 |
+
|
3 |
+
# Create your tests here.
|
backend/chatbot/urls.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.urls import path
|
2 |
+
|
3 |
+
from . import views
|
4 |
+
|
5 |
+
urlpatterns = [
|
6 |
+
path("", views.AskChatBot.as_view()),
|
7 |
+
]
|
backend/chatbot/views.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from rest_framework.views import APIView
|
2 |
+
from django.http import JsonResponse
|
3 |
+
from TwitterChatBot.main import ask
|
4 |
+
|
5 |
+
|
6 |
+
class AskChatBot(APIView):
|
7 |
+
"""
|
8 |
+
let you ask a question to the twitter chatbot
|
9 |
+
"""
|
10 |
+
|
11 |
+
def get(self, request, format=None):
|
12 |
+
question = request.data["question"]
|
13 |
+
answer = ask(question=question)
|
14 |
+
|
15 |
+
return JsonResponse({"answer": answer.strip()})
|
backend/manage.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
"""Django's command-line utility for administrative tasks."""
|
3 |
+
import os
|
4 |
+
import sys
|
5 |
+
|
6 |
+
|
7 |
+
def main():
|
8 |
+
"""Run administrative tasks."""
|
9 |
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
|
10 |
+
try:
|
11 |
+
from django.core.management import execute_from_command_line
|
12 |
+
except ImportError as exc:
|
13 |
+
raise ImportError(
|
14 |
+
"Couldn't import Django. Are you sure it's installed and "
|
15 |
+
"available on your PYTHONPATH environment variable? Did you "
|
16 |
+
"forget to activate a virtual environment?"
|
17 |
+
) from exc
|
18 |
+
execute_from_command_line(sys.argv)
|
19 |
+
|
20 |
+
|
21 |
+
if __name__ == '__main__':
|
22 |
+
main()
|
conftest.py
ADDED
File without changes
|
requirements.txt
CHANGED
@@ -4,4 +4,7 @@ openai
|
|
4 |
python-dotenv
|
5 |
jsonlines
|
6 |
pytest
|
7 |
-
numpy
|
|
|
|
|
|
|
|
4 |
python-dotenv
|
5 |
jsonlines
|
6 |
pytest
|
7 |
+
numpy
|
8 |
+
django
|
9 |
+
djangorestframework
|
10 |
+
gradio
|
src/main.py
DELETED
@@ -1,29 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
from pathlib import Path
|
3 |
-
|
4 |
-
from index import IndexSearchEngine
|
5 |
-
from gpt_3_manager import Gpt3Manager
|
6 |
-
|
7 |
-
from dotenv import load_dotenv
|
8 |
-
from chat import ChatBot
|
9 |
-
from index import JsonLinesIndex
|
10 |
-
|
11 |
-
from prompt import TextPromptLoader
|
12 |
-
|
13 |
-
load_dotenv()
|
14 |
-
|
15 |
-
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
16 |
-
|
17 |
-
|
18 |
-
path = Path("index") / "index.jsonl"
|
19 |
-
|
20 |
-
index = JsonLinesIndex()
|
21 |
-
loaded = index.load(path)
|
22 |
-
gpt_manager = Gpt3Manager(api_key=OPENAI_API_KEY)
|
23 |
-
|
24 |
-
engine = IndexSearchEngine(loaded, gpt_manager=gpt_manager)
|
25 |
-
loader = TextPromptLoader()
|
26 |
-
chatbot = ChatBot(engine, prompt_loader=loader, gpt_manager=gpt_manager)
|
27 |
-
|
28 |
-
answer = chatbot.ask("What does the twitter terms of service does")
|
29 |
-
print(answer)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|