Spaces:
Build error
Build error
Add first commit
Browse files- LICENSE +21 -0
- README.md +2 -37
- app/SessionState.py +107 -0
- app/__pycache__/SessionState.cpython-37.pyc +0 -0
- app/__pycache__/prompts.cpython-37.pyc +0 -0
- app/app.py +176 -0
- app/chatbot.html +134 -0
- app/css/main.css +109 -0
- app/js/main.js +122 -0
- app/prompts.py +20 -0
- requirements.txt +10 -0
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2021 indonesian-nlp
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,37 +1,2 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
emoji: 🏢
|
4 |
-
colorFrom: gray
|
5 |
-
colorTo: gray
|
6 |
-
sdk: streamlit
|
7 |
-
app_file: app.py
|
8 |
-
pinned: false
|
9 |
-
---
|
10 |
-
|
11 |
-
# Configuration
|
12 |
-
|
13 |
-
`title`: _string_
|
14 |
-
Display title for the Space
|
15 |
-
|
16 |
-
`emoji`: _string_
|
17 |
-
Space emoji (emoji-only character allowed)
|
18 |
-
|
19 |
-
`colorFrom`: _string_
|
20 |
-
Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
|
21 |
-
|
22 |
-
`colorTo`: _string_
|
23 |
-
Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
|
24 |
-
|
25 |
-
`sdk`: _string_
|
26 |
-
Can be either `gradio` or `streamlit`
|
27 |
-
|
28 |
-
`sdk_version` : _string_
|
29 |
-
Only applicable for `streamlit` SDK.
|
30 |
-
See [doc](https://hf.co/docs/hub/spaces) for more info on supported versions.
|
31 |
-
|
32 |
-
`app_file`: _string_
|
33 |
-
Path to your main application file (which contains either `gradio` or `streamlit` Python code).
|
34 |
-
Path is relative to the root of the repository.
|
35 |
-
|
36 |
-
`pinned`: _boolean_
|
37 |
-
Whether the Space stays on top of your list.
|
|
|
1 |
+
# gpt2-app
|
2 |
+
Streamlit app showing some Indonesian GPT-2 models
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/SessionState.py
ADDED
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Hack to add per-session state to Streamlit.
|
2 |
+
Usage
|
3 |
+
-----
|
4 |
+
>>> import SessionState
|
5 |
+
>>>
|
6 |
+
>>> session_state = SessionState.get(user_name='', favorite_color='black')
|
7 |
+
>>> session_state.user_name
|
8 |
+
''
|
9 |
+
>>> session_state.user_name = 'Mary'
|
10 |
+
>>> session_state.favorite_color
|
11 |
+
'black'
|
12 |
+
Since you set user_name above, next time your script runs this will be the
|
13 |
+
result:
|
14 |
+
>>> session_state = get(user_name='', favorite_color='black')
|
15 |
+
>>> session_state.user_name
|
16 |
+
'Mary'
|
17 |
+
"""
|
18 |
+
try:
|
19 |
+
import streamlit.ReportThread as ReportThread
|
20 |
+
from streamlit.server.Server import Server
|
21 |
+
except Exception:
|
22 |
+
# Streamlit >= 0.65.0
|
23 |
+
import streamlit.report_thread as ReportThread
|
24 |
+
from streamlit.server.server import Server
|
25 |
+
|
26 |
+
|
27 |
+
class SessionState(object):
|
28 |
+
def __init__(self, **kwargs):
|
29 |
+
"""A new SessionState object.
|
30 |
+
Parameters
|
31 |
+
----------
|
32 |
+
**kwargs : any
|
33 |
+
Default values for the session state.
|
34 |
+
Example
|
35 |
+
-------
|
36 |
+
>>> session_state = SessionState(user_name='', favorite_color='black')
|
37 |
+
>>> session_state.user_name = 'Mary'
|
38 |
+
''
|
39 |
+
>>> session_state.favorite_color
|
40 |
+
'black'
|
41 |
+
"""
|
42 |
+
for key, val in kwargs.items():
|
43 |
+
setattr(self, key, val)
|
44 |
+
|
45 |
+
|
46 |
+
def get(**kwargs):
|
47 |
+
"""Gets a SessionState object for the current session.
|
48 |
+
Creates a new object if necessary.
|
49 |
+
Parameters
|
50 |
+
----------
|
51 |
+
**kwargs : any
|
52 |
+
Default values you want to add to the session state, if we're creating a
|
53 |
+
new one.
|
54 |
+
Example
|
55 |
+
-------
|
56 |
+
>>> session_state = get(user_name='', favorite_color='black')
|
57 |
+
>>> session_state.user_name
|
58 |
+
''
|
59 |
+
>>> session_state.user_name = 'Mary'
|
60 |
+
>>> session_state.favorite_color
|
61 |
+
'black'
|
62 |
+
Since you set user_name above, next time your script runs this will be the
|
63 |
+
result:
|
64 |
+
>>> session_state = get(user_name='', favorite_color='black')
|
65 |
+
>>> session_state.user_name
|
66 |
+
'Mary'
|
67 |
+
"""
|
68 |
+
# Hack to get the session object from Streamlit.
|
69 |
+
|
70 |
+
ctx = ReportThread.get_report_ctx()
|
71 |
+
|
72 |
+
this_session = None
|
73 |
+
|
74 |
+
current_server = Server.get_current()
|
75 |
+
if hasattr(current_server, '_session_infos'):
|
76 |
+
# Streamlit < 0.56
|
77 |
+
session_infos = Server.get_current()._session_infos.values()
|
78 |
+
else:
|
79 |
+
session_infos = Server.get_current()._session_info_by_id.values()
|
80 |
+
|
81 |
+
for session_info in session_infos:
|
82 |
+
s = session_info.session
|
83 |
+
if (
|
84 |
+
# Streamlit < 0.54.0
|
85 |
+
(hasattr(s, '_main_dg') and s._main_dg == ctx.main_dg)
|
86 |
+
or
|
87 |
+
# Streamlit >= 0.54.0
|
88 |
+
(not hasattr(s, '_main_dg') and s.enqueue == ctx.enqueue)
|
89 |
+
or
|
90 |
+
# Streamlit >= 0.65.2
|
91 |
+
(not hasattr(s, '_main_dg') and s._uploaded_file_mgr == ctx.uploaded_file_mgr)
|
92 |
+
):
|
93 |
+
this_session = s
|
94 |
+
|
95 |
+
if this_session is None:
|
96 |
+
raise RuntimeError(
|
97 |
+
"Oh noes. Couldn't get your Streamlit Session object. "
|
98 |
+
'Are you doing something fancy with threads?')
|
99 |
+
|
100 |
+
# Got the session object! Now let's attach some state into it.
|
101 |
+
|
102 |
+
if not hasattr(this_session, '_custom_session_state'):
|
103 |
+
this_session._custom_session_state = SessionState(**kwargs)
|
104 |
+
|
105 |
+
return this_session._custom_session_state
|
106 |
+
|
107 |
+
__all__ = ['get']
|
app/__pycache__/SessionState.cpython-37.pyc
ADDED
Binary file (2.93 kB). View file
|
|
app/__pycache__/prompts.cpython-37.pyc
ADDED
Binary file (1.36 kB). View file
|
|
app/app.py
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import SessionState
|
3 |
+
from mtranslate import translate
|
4 |
+
from prompts import PROMPT_LIST
|
5 |
+
import random
|
6 |
+
import time
|
7 |
+
from transformers import pipeline, set_seed
|
8 |
+
import psutil
|
9 |
+
import codecs
|
10 |
+
import streamlit.components.v1 as stc
|
11 |
+
import shutil
|
12 |
+
import pathlib
|
13 |
+
|
14 |
+
# st.set_page_config(page_title="Indonesian Story Generator")
|
15 |
+
|
16 |
+
MODELS = {
|
17 |
+
"Indonesian Literature - GPT-2 Small": {
|
18 |
+
"name": "cahya/gpt2-small-indonesian-story",
|
19 |
+
"text_generator": None
|
20 |
+
},
|
21 |
+
"Indonesian Literature - GPT-2 Medium": {
|
22 |
+
"name": "cahya/gpt2-medium-indonesian-story",
|
23 |
+
"text_generator": None
|
24 |
+
},
|
25 |
+
"Indonesian Persona Chatbot": {
|
26 |
+
"name": "",
|
27 |
+
"text_generator": None
|
28 |
+
},
|
29 |
+
}
|
30 |
+
|
31 |
+
|
32 |
+
def stc_chatbot(html_file, width=700, height=900):
|
33 |
+
html = codecs.open(html_file, "r")
|
34 |
+
page = html.read()
|
35 |
+
stc.html(page, width=width, height=height, scrolling=True)
|
36 |
+
|
37 |
+
|
38 |
+
model = st.sidebar.selectbox('Model', (MODELS.keys()))
|
39 |
+
|
40 |
+
|
41 |
+
@st.cache(suppress_st_warning=True, allow_output_mutation=True)
|
42 |
+
def get_generator(model_name: str):
|
43 |
+
st.write(f"Loading the GPT2 model {model_name}, please wait...")
|
44 |
+
text_generator = pipeline('text-generation', model=model_name)
|
45 |
+
return text_generator
|
46 |
+
|
47 |
+
|
48 |
+
# Disable the st.cache for this function due to issue on newer version of streamlit
|
49 |
+
# @st.cache(suppress_st_warning=True, hash_funcs={tokenizers.Tokenizer: id})
|
50 |
+
def process(text_generator, text: str, max_length: int = 100, do_sample: bool = True, top_k: int = 50, top_p: float = 0.95,
|
51 |
+
temperature: float = 1.0, max_time: float = 60.0, seed=42):
|
52 |
+
# st.write("Cache miss: process")
|
53 |
+
set_seed(seed)
|
54 |
+
result = text_generator(text, max_length=max_length, do_sample=do_sample,
|
55 |
+
top_k=top_k, top_p=top_p, temperature=temperature,
|
56 |
+
max_time=max_time)
|
57 |
+
return result
|
58 |
+
|
59 |
+
|
60 |
+
st.title("Indonesian GPT-2 Applications")
|
61 |
+
prompt_group_name = ""
|
62 |
+
if model.find("Indonesian Literature") != -1:
|
63 |
+
st.subheader("Indonesian Literature")
|
64 |
+
prompt_group_name = "Indonesian Literature"
|
65 |
+
st.markdown(
|
66 |
+
"""
|
67 |
+
This application is a demo for Indonesian Literature Generator using GPT2.
|
68 |
+
"""
|
69 |
+
)
|
70 |
+
session_state = SessionState.get(prompt=None, prompt_box=None, text=None)
|
71 |
+
ALL_PROMPTS = list(PROMPT_LIST[prompt_group_name].keys())+["Custom"]
|
72 |
+
|
73 |
+
prompt = st.selectbox('Prompt', ALL_PROMPTS, index=len(ALL_PROMPTS)-1)
|
74 |
+
|
75 |
+
# Update prompt
|
76 |
+
if session_state.prompt is None:
|
77 |
+
session_state.prompt = prompt
|
78 |
+
elif session_state.prompt is not None and (prompt != session_state.prompt):
|
79 |
+
session_state.prompt = prompt
|
80 |
+
session_state.prompt_box = None
|
81 |
+
session_state.text = None
|
82 |
+
else:
|
83 |
+
session_state.prompt = prompt
|
84 |
+
|
85 |
+
# Update prompt box
|
86 |
+
if session_state.prompt == "Custom":
|
87 |
+
session_state.prompt_box = "Enter your text here"
|
88 |
+
else:
|
89 |
+
print(f"# prompt: {session_state.prompt}")
|
90 |
+
print(f"# prompt_box: {session_state.prompt_box}")
|
91 |
+
if session_state.prompt is not None and session_state.prompt_box is None:
|
92 |
+
session_state.prompt_box = random.choice(PROMPT_LIST[prompt_group_name][session_state.prompt])
|
93 |
+
|
94 |
+
session_state.text = st.text_area("Enter text", session_state.prompt_box)
|
95 |
+
|
96 |
+
max_length = st.sidebar.number_input(
|
97 |
+
"Maximum length",
|
98 |
+
value=100,
|
99 |
+
max_value=512,
|
100 |
+
help="The maximum length of the sequence to be generated."
|
101 |
+
)
|
102 |
+
|
103 |
+
temperature = st.sidebar.slider(
|
104 |
+
"Temperature",
|
105 |
+
value=1.0,
|
106 |
+
min_value=0.0,
|
107 |
+
max_value=10.0
|
108 |
+
)
|
109 |
+
|
110 |
+
do_sample = st.sidebar.checkbox(
|
111 |
+
"Use sampling",
|
112 |
+
value=True
|
113 |
+
)
|
114 |
+
|
115 |
+
top_k = 40
|
116 |
+
top_p = 0.95
|
117 |
+
|
118 |
+
if do_sample:
|
119 |
+
top_k = st.sidebar.number_input(
|
120 |
+
"Top k",
|
121 |
+
value=top_k
|
122 |
+
)
|
123 |
+
top_p = st.sidebar.number_input(
|
124 |
+
"Top p",
|
125 |
+
value=top_p
|
126 |
+
)
|
127 |
+
|
128 |
+
seed = st.sidebar.number_input(
|
129 |
+
"Random Seed",
|
130 |
+
value=25,
|
131 |
+
help="The number used to initialize a pseudorandom number generator"
|
132 |
+
)
|
133 |
+
|
134 |
+
for group_name in MODELS:
|
135 |
+
if group_name.find("Indonesian Literature") != -1:
|
136 |
+
MODELS[group_name]["text_generator"] = get_generator(MODELS[group_name]["name"])
|
137 |
+
# text_generator = get_generator()
|
138 |
+
if st.button("Run"):
|
139 |
+
with st.spinner(text="Getting results..."):
|
140 |
+
memory = psutil.virtual_memory()
|
141 |
+
st.subheader("Result")
|
142 |
+
time_start = time.time()
|
143 |
+
# text_generator = MODELS[model]["text_generator"]
|
144 |
+
result = process(MODELS[model]["text_generator"], text=session_state.text, max_length=int(max_length),
|
145 |
+
temperature=temperature, do_sample=do_sample,
|
146 |
+
top_k=int(top_k), top_p=float(top_p), seed=seed)
|
147 |
+
time_end = time.time()
|
148 |
+
time_diff = time_end-time_start
|
149 |
+
result = result[0]["generated_text"]
|
150 |
+
st.write(result.replace("\n", " \n"))
|
151 |
+
st.text("Translation")
|
152 |
+
translation = translate(result, "en", "id")
|
153 |
+
st.write(translation.replace("\n", " \n"))
|
154 |
+
# st.write(f"*do_sample: {do_sample}, top_k: {top_k}, top_p: {top_p}, seed: {seed}*")
|
155 |
+
info = f"""
|
156 |
+
*Memory: {memory.total/(1024*1024*1024):.2f}GB, used: {memory.percent}%, available: {memory.available/(1024*1024*1024):.2f}GB*
|
157 |
+
*Text generated in {time_diff:.5} seconds*
|
158 |
+
"""
|
159 |
+
st.write(info)
|
160 |
+
|
161 |
+
# Reset state
|
162 |
+
session_state.prompt = None
|
163 |
+
session_state.prompt_box = None
|
164 |
+
session_state.text = None
|
165 |
+
elif model == "Indonesian Persona Chatbot":
|
166 |
+
st.subheader("Indonesian GPT-2 Persona Chatbot")
|
167 |
+
STREAMLIT_STATIC_PATH = pathlib.Path(st.__path__[0]) / 'static'
|
168 |
+
# We create a videos directory within the streamlit static asset directory
|
169 |
+
# and we write output files to it
|
170 |
+
ASSETS_PATH = STREAMLIT_STATIC_PATH/"gpt2-app"
|
171 |
+
if not ASSETS_PATH.is_dir():
|
172 |
+
ASSETS_PATH.mkdir()
|
173 |
+
shutil.copytree("app/css", ASSETS_PATH/"css")
|
174 |
+
shutil.copytree("app/js", ASSETS_PATH/"js")
|
175 |
+
|
176 |
+
stc_chatbot("app/chatbot.html")
|
app/chatbot.html
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<!-- Required meta tags -->
|
5 |
+
<meta charset="utf-8">
|
6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7 |
+
|
8 |
+
<!-- Bootstrap CSS -->
|
9 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
10 |
+
|
11 |
+
<title>Indonesian GPT2 Chatbot</title>
|
12 |
+
<link rel="stylesheet" href="gpt2-app/css/main.css">
|
13 |
+
<script src="gpt2-app/js/main.js"></script>
|
14 |
+
</head>
|
15 |
+
<body onload="pageSetup();">
|
16 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script>
|
17 |
+
|
18 |
+
<div class="buttons" style="display: none">
|
19 |
+
<div class="minus button">-</div>
|
20 |
+
<div class="value">?</div>
|
21 |
+
<div class="plus button">+</div>
|
22 |
+
</div>
|
23 |
+
<div class="state" style="display: none">
|
24 |
+
<span class="users"></span>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<div class="container">
|
28 |
+
<div class="chat-container">
|
29 |
+
<div class="chat-messages">
|
30 |
+
<div class="messages">
|
31 |
+
</div>
|
32 |
+
</div>
|
33 |
+
</div>
|
34 |
+
<div class="chat-input input-group mb-3">
|
35 |
+
<input type="text" class="form-control user-input" placeholder="Type a message..." aria-label="User message" aria-describedby="basic-addon2">
|
36 |
+
<span class="input-group-text btn btn-primary user-input-button" id="basic-addon2">Send</span>
|
37 |
+
</div>
|
38 |
+
<!--
|
39 |
+
<div class="chat-suggestion">
|
40 |
+
Suggestion: <span class="js-loading">Loading…</span> <a class="js-suggestion hide">Kenapa kamu sedih?</a>
|
41 |
+
</div>
|
42 |
+
-->
|
43 |
+
<div class="server-message">
|
44 |
+
<span class="server-message-value"></span>
|
45 |
+
</div>
|
46 |
+
<div class="accordion" id="accordionExample">
|
47 |
+
<div class="accordion-item">
|
48 |
+
<h2 class="accordion-header" id="headingOne">
|
49 |
+
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
50 |
+
Bots Personalities
|
51 |
+
</button>
|
52 |
+
</h2>
|
53 |
+
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
|
54 |
+
<form class="bot-personality">
|
55 |
+
<div class="mb-3">
|
56 |
+
<div class="row g-2 align-items-center">
|
57 |
+
<div class="col-auto">
|
58 |
+
<label for="inputPersonality1" class="col-form-label">Personality 1:</label>
|
59 |
+
</div>
|
60 |
+
<div class="col-auto">
|
61 |
+
<input type="text" class="form-control" id="inputPersonality1">
|
62 |
+
</div>
|
63 |
+
</div>
|
64 |
+
<div class="row g-2 align-items-center">
|
65 |
+
<div class="col-auto">
|
66 |
+
<label for="inputPersonality2" class="col-form-label">Personality 2:</label>
|
67 |
+
</div>
|
68 |
+
<div class="col-auto">
|
69 |
+
<input type="text" class="form-control" id="inputPersonality2">
|
70 |
+
</div>
|
71 |
+
</div>
|
72 |
+
<div class="row g-2 align-items-center">
|
73 |
+
<div class="col-auto">
|
74 |
+
<label for="inputPersonality3" class="col-form-label">Personality 3:</label>
|
75 |
+
</div>
|
76 |
+
<div class="col-auto">
|
77 |
+
<input type="text" class="form-control" id="inputPersonality3">
|
78 |
+
</div>
|
79 |
+
</div>
|
80 |
+
<div class="row g-2 align-items-center">
|
81 |
+
<div class="col-auto">
|
82 |
+
<label for="inputPersonality4" class="col-form-label">Personality 4:</label>
|
83 |
+
</div>
|
84 |
+
<div class="col-auto">
|
85 |
+
<input type="text" class="form-control" id="inputPersonality4">
|
86 |
+
</div>
|
87 |
+
</div>
|
88 |
+
<div class="row g-2 align-items-center">
|
89 |
+
<div class="col-auto">
|
90 |
+
<label for="inputPersonality5" class="col-form-label">Personality 5:</label>
|
91 |
+
</div>
|
92 |
+
<div class="col-auto">
|
93 |
+
<input type="text" class="form-control" id="inputPersonality5">
|
94 |
+
</div>
|
95 |
+
</div>
|
96 |
+
</div>
|
97 |
+
<button id="updatePersonality" class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
|
98 |
+
Update Personality
|
99 |
+
</button>
|
100 |
+
</form>
|
101 |
+
</div>
|
102 |
+
</div>
|
103 |
+
<div class="accordion-item">
|
104 |
+
<h2 class="accordion-header" id="headingThree">
|
105 |
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
106 |
+
Parameters
|
107 |
+
</button>
|
108 |
+
</h2>
|
109 |
+
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
|
110 |
+
|
111 |
+
<div class="chat-parameter card card-body">
|
112 |
+
<div class="form-check">
|
113 |
+
<input class="form-check-input" type="checkbox" value="" id="doSample" checked>
|
114 |
+
<label class="form-check-label" for="doSample">
|
115 |
+
Do Sample
|
116 |
+
</label>
|
117 |
+
</div>
|
118 |
+
<label for="minLength" class="form-label">Minimal Length: <span id="minLengthValue">1</span></label>
|
119 |
+
<input type="range" class="form-range" min="1" max="10" value="1" id="minLength" onmousemove="updateValue('minLengthValue', this.value);">
|
120 |
+
<label for="maxLength" class="form-label">Maximal Length: <span id="maxLengthValue">20</span></label>
|
121 |
+
<input type="range" class="form-range" min="20" max="50" value="20" id="maxLength" onmousemove="updateValue('maxLengthValue', this.value);">
|
122 |
+
<label for="temperature" class="form-label">Temperature: <span id="temperatureValue">0.7</span></label>
|
123 |
+
<input type="range" class="form-range" min="0.5" max="10" value="0.7" step="0.1" id="temperature" onmousemove="updateValue('temperatureValue', this.value);">
|
124 |
+
<label for="topK" class="form-label">Top k: <span id="topKValue">0</span></label>
|
125 |
+
<input type="range" class="form-range" min="0" max="50" value="0" id="topK" onmousemove="updateValue('topKValue', this.value);">
|
126 |
+
<label for="topP" class="form-label">Top p: <span id="topPValue">0.9</span></label>
|
127 |
+
<input type="range" class="form-range" min="0.1" max="1.0" value="0.9" step="0.01" id="topP" onmousemove="updateValue('topPValue', this.value);">
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
</div>
|
131 |
+
</div>
|
132 |
+
</div>
|
133 |
+
</body>
|
134 |
+
</html>
|
app/css/main.css
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family: "Arial, Courier New", sans-serif;
|
3 |
+
text-align: center;
|
4 |
+
}
|
5 |
+
|
6 |
+
h1 {
|
7 |
+
margin: 10px 10px;
|
8 |
+
}
|
9 |
+
|
10 |
+
.buttons {
|
11 |
+
font-size: 2em;
|
12 |
+
display: flex;
|
13 |
+
justify-content: center;
|
14 |
+
}
|
15 |
+
|
16 |
+
.button, .value {
|
17 |
+
line-height: 1;
|
18 |
+
padding: 1rem;
|
19 |
+
margin: 1rem;
|
20 |
+
border: medium solid;
|
21 |
+
min-height: 1em;
|
22 |
+
min-width: 1em;
|
23 |
+
}
|
24 |
+
|
25 |
+
.button {
|
26 |
+
cursor: pointer;
|
27 |
+
user-select: none;
|
28 |
+
}
|
29 |
+
|
30 |
+
.minus {
|
31 |
+
color: red;
|
32 |
+
}
|
33 |
+
|
34 |
+
.plus {
|
35 |
+
color: green;
|
36 |
+
}
|
37 |
+
|
38 |
+
.value {
|
39 |
+
min-width: 2em;
|
40 |
+
}
|
41 |
+
|
42 |
+
.state {
|
43 |
+
font-size: 2em;
|
44 |
+
}
|
45 |
+
|
46 |
+
.container {
|
47 |
+
min-width: 30em;
|
48 |
+
max-width: 40em;
|
49 |
+
}
|
50 |
+
|
51 |
+
.accordion-collapse {
|
52 |
+
padding: 5px 5px 0 5px;
|
53 |
+
}
|
54 |
+
|
55 |
+
.chat-container {
|
56 |
+
margin: 10px 0;
|
57 |
+
min-height: 300px;
|
58 |
+
max-height: 600px;
|
59 |
+
overflow: auto;
|
60 |
+
}
|
61 |
+
|
62 |
+
.bot-personality {
|
63 |
+
text-align: left;
|
64 |
+
margin: 0 0 5px 0;
|
65 |
+
}
|
66 |
+
|
67 |
+
.chat-parameter {
|
68 |
+
text-align: left;
|
69 |
+
margin: 5px 0 5px 0;
|
70 |
+
}
|
71 |
+
|
72 |
+
.bot-personality input {
|
73 |
+
margin: 5px 0 0 0;
|
74 |
+
min-width: 20em;
|
75 |
+
}
|
76 |
+
|
77 |
+
.message {
|
78 |
+
margin: 5px 0;
|
79 |
+
}
|
80 |
+
|
81 |
+
.message-inner {
|
82 |
+
font-size: 16px;
|
83 |
+
}
|
84 |
+
|
85 |
+
.outgoing {
|
86 |
+
text-align: right;
|
87 |
+
}
|
88 |
+
|
89 |
+
.outgoing .badge {
|
90 |
+
text-align: right;
|
91 |
+
}
|
92 |
+
|
93 |
+
.botPersonality, .incoming, .incoming .badge, .chat-suggestion, .server-message, .parameters {
|
94 |
+
text-align: left;
|
95 |
+
}
|
96 |
+
|
97 |
+
.chat-suggestion, .server-message
|
98 |
+
{
|
99 |
+
padding-left: 5px;
|
100 |
+
}
|
101 |
+
|
102 |
+
.server-message-value {
|
103 |
+
font-style: italic;
|
104 |
+
}
|
105 |
+
|
106 |
+
#collapseParameter {
|
107 |
+
width: 300px;
|
108 |
+
margin: 8px 0px;
|
109 |
+
}
|
app/js/main.js
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
updateValue = function(id, value) {
|
2 |
+
document.getElementById(id).innerText = value;
|
3 |
+
}
|
4 |
+
|
5 |
+
htmlToElement = function(html) {
|
6 |
+
let template = document.createElement('template');
|
7 |
+
html = html.trim(); // Never return a text node of whitespace as the result
|
8 |
+
template.innerHTML = html;
|
9 |
+
return template.content.firstChild;
|
10 |
+
}
|
11 |
+
|
12 |
+
pageSetup = function() {
|
13 |
+
const minus = document.querySelector('.minus');
|
14 |
+
const plus = document.querySelector('.plus');
|
15 |
+
const value = document.querySelector('.value');
|
16 |
+
// const users = document.querySelector('.users');
|
17 |
+
const userInput = document.querySelector('.user-input');
|
18 |
+
const userInputButton = document.querySelector('.user-input-button');
|
19 |
+
const serverMessageValue = document.querySelector('.server-message-value');
|
20 |
+
const messages = document.querySelector('.messages');
|
21 |
+
const updatePersonality = document.getElementById("updatePersonality")
|
22 |
+
const websocket = new WebSocket("wss://gpt2-chat.ai-research.id/");
|
23 |
+
//const websocket = new WebSocket("ws://localhost:8502/");
|
24 |
+
|
25 |
+
minus.onclick = function () {
|
26 |
+
websocket.send(JSON.stringify({action: 'minus'}));
|
27 |
+
}
|
28 |
+
|
29 |
+
plus.onclick = function () {
|
30 |
+
websocket.send(JSON.stringify({action: 'plus'}));
|
31 |
+
}
|
32 |
+
|
33 |
+
updatePersonality.onclick = function () {
|
34 |
+
const elements = document.querySelectorAll(".bot-personality input")
|
35 |
+
let data = {
|
36 |
+
"action": "personality",
|
37 |
+
"message": []
|
38 |
+
}
|
39 |
+
for (let i = 0; i < Math.min(elements.length, 5); i++) {
|
40 |
+
if(elements[i].value.length >0)
|
41 |
+
data.message.push(elements[i].value);
|
42 |
+
}
|
43 |
+
websocket.send(JSON.stringify(data));
|
44 |
+
}
|
45 |
+
|
46 |
+
let getParameters = function() {
|
47 |
+
return {
|
48 |
+
"do_sample": document.getElementById("doSample").checked,
|
49 |
+
"min_length": parseInt(document.getElementById("minLength").value),
|
50 |
+
"max_length": parseInt(document.getElementById("maxLength").value),
|
51 |
+
"temperature": parseFloat(document.getElementById("temperature").value),
|
52 |
+
"top_k": parseInt(document.getElementById("topK").value),
|
53 |
+
"top_p": parseFloat(document.getElementById("topP").value),
|
54 |
+
};
|
55 |
+
}
|
56 |
+
|
57 |
+
let processUserInput = function (userInput) {
|
58 |
+
let parameters = getParameters();
|
59 |
+
parameters["action"] = "talk";
|
60 |
+
parameters["utterance"] = userInput.value;
|
61 |
+
websocket.send(JSON.stringify(parameters));
|
62 |
+
const element = htmlToElement("<div class=\"message outgoing\"><div class=\"message-inner badge bg-primary text-wrap\">"
|
63 |
+
+ userInput.value + "</div></div>");
|
64 |
+
userInput.value = "";
|
65 |
+
messages.appendChild(element);
|
66 |
+
messages.scrollIntoView(false)
|
67 |
+
}
|
68 |
+
|
69 |
+
userInputButton.onclick = function () {
|
70 |
+
processUserInput(userInput);
|
71 |
+
}
|
72 |
+
|
73 |
+
userInput.addEventListener("keyup", function(event) {
|
74 |
+
if (event.keyCode === 13) {
|
75 |
+
// Cancel the default action, if needed
|
76 |
+
event.preventDefault();
|
77 |
+
processUserInput(userInput);
|
78 |
+
}
|
79 |
+
});
|
80 |
+
|
81 |
+
websocket.onmessage = function (event) {
|
82 |
+
let data = JSON.parse(event.data);
|
83 |
+
switch (data.type) {
|
84 |
+
case 'connection':
|
85 |
+
console.log(data.value)
|
86 |
+
websocket.send(JSON.stringify({action: 'dialog', personality: []}));
|
87 |
+
break;
|
88 |
+
case 'state':
|
89 |
+
value.textContent = data.value;
|
90 |
+
break;
|
91 |
+
case 'users':
|
92 |
+
serverMessageValue.textContent = (
|
93 |
+
data.count.toString() + " user" +
|
94 |
+
(data.count === 1 ? "" : "s") + " online");
|
95 |
+
break;
|
96 |
+
case 'dialog':
|
97 |
+
console.log(data.message)
|
98 |
+
break;
|
99 |
+
case 'talk':
|
100 |
+
const element = htmlToElement("<div class=\"message incoming\"><div class=\"message-inner badge bg-success text-wrap\">"
|
101 |
+
+ data.message+ "</div></div>");
|
102 |
+
messages.appendChild(element);
|
103 |
+
messages.scrollIntoView(false)
|
104 |
+
break;
|
105 |
+
case 'personality':
|
106 |
+
const elements = document.querySelectorAll(".bot-personality input")
|
107 |
+
for (let i = 0; i < Math.min(elements.length, data.message.length); i++) {
|
108 |
+
elements[i].value = data.message[i];
|
109 |
+
}
|
110 |
+
break;
|
111 |
+
case 'personality_reply':
|
112 |
+
serverMessageValue.textContent = data.message
|
113 |
+
setTimeout(function() {
|
114 |
+
websocket.send(JSON.stringify({action: 'get_users'}));
|
115 |
+
}, 3000);
|
116 |
+
break;
|
117 |
+
default:
|
118 |
+
console.error(
|
119 |
+
"unsupported event", data);
|
120 |
+
}
|
121 |
+
};
|
122 |
+
}
|
app/prompts.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
PROMPT_LIST = {
|
2 |
+
"Indonesian Literature": {
|
3 |
+
"Adult Romance": [
|
4 |
+
"Ini adalah kisah tentang seorang laki-laki yang berusaha memperjuangkan cintanya",
|
5 |
+
"Alunan musik terdengar memenuhi ruangan kantor, cowok itu duduk di balik meja kerjanya sambil memejamkan mata. Berusaha meresapi nada per nada",
|
6 |
+
"Aku mencari dan terus mencari\nDimana bahagia akan kutemui\nKumencari terus mencari\nHingga ku tak mengerti arti hari-hari",
|
7 |
+
"Gadis itu mengharuskan dirinya tegar, dan kuat dalam menghadapi masalah. Menahan air matanya jatuh setiap kali ingin menangis"
|
8 |
+
],
|
9 |
+
"Horror": [
|
10 |
+
"Ditengah-tengah perbincangan mereka berdua, datanglah sesosok mahluk tinggi hitam dan besar",
|
11 |
+
"Sesosok hantu perempuan seperti kuntilanak yang melayang keluar dan bergerak perlahan dari pintu kamar kecil tadi yang tertutup.",
|
12 |
+
"Sejak pertemuannya dengan leak, yang ternyata tinggal satu atap dengannya, hidupnya terus dihantui oleh berbagai sosok seram."
|
13 |
+
],
|
14 |
+
"Poetry": [
|
15 |
+
"Aku ingin menulis sajak\nyang melesat dalam kejap\nmenembus hati yang pejam\nmemaksa mimpimu terjaga\ndari semu",
|
16 |
+
"Malam ini langitku lengang\ntiada hujan yang membasuh rindu\npun awan yang biasanya temani seruput kopimu",
|
17 |
+
"Di sisimu waktu menjelma\nsetangkai kembang api\ngelora membakar tanpa jeda\nmemercik pijar binar kita."
|
18 |
+
]
|
19 |
+
}
|
20 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy
|
2 |
+
torch
|
3 |
+
tokenizers
|
4 |
+
transformers
|
5 |
+
datasets
|
6 |
+
mtranslate
|
7 |
+
# streamlit version 0.67.1 is needed due to issue with caching
|
8 |
+
# streamlit==0.67.1
|
9 |
+
streamlit
|
10 |
+
psutil
|