Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
app.py
CHANGED
@@ -1,10 +1,7 @@
|
|
1 |
# app.py
|
2 |
-
#
|
3 |
-
|
4 |
-
|
5 |
-
# - Auto-sizes pentachora banks to match checkpoints (across Beeper v1..v4)
|
6 |
-
# - Generation uses same knobs & penalties as training script
|
7 |
-
# --------------------------------------------------------------------------------------------------
|
8 |
import gradio as gr
|
9 |
import torch
|
10 |
from tokenizers import Tokenizer
|
@@ -13,9 +10,6 @@ from safetensors.torch import load_file as load_safetensors
|
|
13 |
|
14 |
from beeper_model import BeeperRoseGPT, generate, prepare_model_for_state_dict
|
15 |
|
16 |
-
# ----------------------------
|
17 |
-
# 🔧 Model versions configuration
|
18 |
-
# ----------------------------
|
19 |
MODEL_VERSIONS = {
|
20 |
"Beeper v4 (Advanced)": {
|
21 |
"repo_id": "AbstractPhil/beeper-rose-v4",
|
@@ -39,7 +33,6 @@ MODEL_VERSIONS = {
|
|
39 |
},
|
40 |
}
|
41 |
|
42 |
-
# Base configuration (matches training defaults)
|
43 |
CONFIG = {
|
44 |
"context": 512,
|
45 |
"vocab_size": 8192,
|
@@ -56,196 +49,182 @@ CONFIG = {
|
|
56 |
"resid_dropout": 0.1,
|
57 |
"dropout": 0.0,
|
58 |
"grad_checkpoint": False,
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
}
|
61 |
|
62 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
63 |
-
|
64 |
-
# Globals (kept simple for a single process Gradio app)
|
65 |
infer: BeeperRoseGPT | None = None
|
66 |
tok: Tokenizer | None = None
|
67 |
current_version: str | None = None
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
def load_model_version(version_name: str) -> str:
|
71 |
-
|
72 |
-
Download the checkpoint and tokenizer, build model, ensure pentachora sizes match,
|
73 |
-
then strictly load weights. Robust to v1/v2 (no pentas) and v3/v4 (with pentas).
|
74 |
-
"""
|
75 |
-
global infer, tok, current_version
|
76 |
-
|
77 |
if current_version == version_name and infer is not None and tok is not None:
|
78 |
return f"Already loaded: {version_name}"
|
79 |
|
80 |
-
|
81 |
-
|
82 |
try:
|
83 |
-
|
84 |
-
|
85 |
-
repo_id=version_info["repo_id"],
|
86 |
-
filename=version_info["model_file"]
|
87 |
-
)
|
88 |
-
tokenizer_file = hf_hub_download(
|
89 |
-
repo_id=version_info["repo_id"],
|
90 |
-
filename="tokenizer.json"
|
91 |
-
)
|
92 |
-
|
93 |
-
# Load state dict on CPU, inspect pentachora shapes if present
|
94 |
-
state_dict = load_safetensors(model_file, device="cpu")
|
95 |
|
96 |
-
|
97 |
m = BeeperRoseGPT(CONFIG).to(device)
|
98 |
-
prepare_model_for_state_dict(m,
|
99 |
|
100 |
-
# Try strict load first; if shapes drift (rare), fallback to non-strict
|
101 |
try:
|
102 |
-
missing, unexpected = m.load_state_dict(
|
103 |
-
# PyTorch returns NamedTuple; report counts
|
104 |
_msg = f"strict load ok | missing={len(missing)} unexpected={len(unexpected)}"
|
105 |
except Exception as e:
|
106 |
-
_msg = f"strict load failed ({e});
|
107 |
-
|
108 |
-
m.load_state_dict(state_dict, strict=False)
|
109 |
|
110 |
m.eval()
|
111 |
-
|
112 |
-
# Tokenizer
|
113 |
t = Tokenizer.from_file(tokenizer_file)
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
|
|
|
|
|
|
119 |
|
|
|
120 |
except Exception as e:
|
121 |
-
infer = None
|
122 |
-
|
123 |
-
current_version = None
|
124 |
return f"Error loading {version_name}: {str(e)}"
|
125 |
|
126 |
-
|
127 |
-
# Load default on startup — prefer v4, fallback to v3
|
128 |
try:
|
129 |
-
|
130 |
-
if "Error" in
|
131 |
-
print(
|
132 |
-
|
133 |
-
except Exception
|
134 |
-
|
135 |
-
print(
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
temperature: float | None,
|
146 |
-
top_k: int | None,
|
147 |
-
top_p: float | None,
|
148 |
-
max_new_tokens: int = 80
|
149 |
-
) -> str:
|
150 |
global infer, tok, current_version
|
151 |
-
|
152 |
-
# Hot-swap versions if the dropdown changed
|
153 |
if model_version != current_version:
|
154 |
-
|
155 |
-
if "Error" in
|
156 |
-
return f"⚠️ {
|
157 |
|
158 |
if infer is None or tok is None:
|
159 |
return "⚠️ Model not loaded. Please select a version and try again."
|
160 |
|
161 |
-
#
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
tok=tok,
|
176 |
-
cfg=CONFIG,
|
177 |
-
prompt=prompt,
|
178 |
max_new_tokens=int(max_new_tokens),
|
179 |
temperature=float(temperature) if temperature is not None else None,
|
180 |
top_k=int(top_k) if top_k is not None else None,
|
181 |
top_p=float(top_p) if top_p is not None else None,
|
182 |
-
repetition_penalty=1.10,
|
183 |
-
|
184 |
-
frequency_penalty=0.1,
|
185 |
-
device=device,
|
186 |
-
detokenize=True,
|
187 |
)
|
188 |
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
lines = [ln.strip() for ln in text.splitlines() if ln.strip()]
|
195 |
-
if lines:
|
196 |
-
text = lines[0]
|
197 |
-
|
198 |
-
# If user message echoed at head, trim after first occurrence
|
199 |
-
head = m[:20].lower()
|
200 |
-
if text.lower().startswith(head):
|
201 |
-
idx = text.lower().find(head)
|
202 |
-
text = text[idx + len(head):].strip() or text
|
203 |
-
|
204 |
-
for artifact in ("User:", "Beeper:", "U ser:", "Beep er:", "User ", "Beeper "):
|
205 |
-
text = text.replace(artifact, "")
|
206 |
|
207 |
-
|
208 |
-
if not text or len(text) < 3:
|
209 |
-
text = "I like robots and stories!"
|
210 |
-
|
211 |
-
if text[-1:] not in ".!?”\"'":
|
212 |
-
text += "."
|
213 |
-
|
214 |
-
return text[:200]
|
215 |
-
|
216 |
-
|
217 |
-
# ----------------------------
|
218 |
-
# 🖼️ Interface
|
219 |
-
# ----------------------------
|
220 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
221 |
-
gr.Markdown(
|
222 |
-
"""
|
223 |
-
# 🤖 Beeper — A Rose-based Tiny Language Model
|
224 |
-
Hello! I'm Beeper, a small language model trained with love and care. Please be patient with me — I'm still learning! 💕
|
225 |
-
"""
|
226 |
-
)
|
227 |
|
228 |
with gr.Row():
|
229 |
with gr.Column(scale=3):
|
230 |
model_dropdown = gr.Dropdown(
|
231 |
choices=list(MODEL_VERSIONS.keys()),
|
232 |
-
value="Beeper v3 (Multi-Concept)",
|
233 |
-
label="Select Beeper Version"
|
234 |
-
info="Choose which version of Beeper to chat with",
|
235 |
)
|
236 |
with gr.Column(scale=7):
|
237 |
version_info = gr.Markdown("**Current:** " + MODEL_VERSIONS["Beeper v3 (Multi-Concept)"]["description"])
|
238 |
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
chatbot = gr.Chatbot(label="Chat with Beeper", height=
|
249 |
msg = gr.Textbox(label="Message", placeholder="Type your message here...")
|
250 |
|
251 |
with gr.Row():
|
@@ -262,34 +241,38 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
262 |
submit = gr.Button("Send", variant="primary")
|
263 |
clear = gr.Button("Clear")
|
264 |
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
)
|
275 |
|
276 |
-
def respond(message, chat_history, model_version, temperature, top_k, top_p, max_new_tokens
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
|
|
281 |
return "", chat_history
|
282 |
|
283 |
-
msg
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
)
|
288 |
-
submit.click(
|
289 |
-
respond,
|
290 |
-
[msg, chatbot, model_dropdown, temperature_slider, top_k_slider, top_p_slider, max_new_tokens_slider],
|
291 |
-
[msg, chatbot],
|
292 |
-
)
|
293 |
clear.click(lambda: None, None, chatbot, queue=False)
|
294 |
|
295 |
if __name__ == "__main__":
|
|
|
1 |
# app.py
|
2 |
+
# Gradio app exposing full Corpus (coarse) and Capoera (topic/mood) selections
|
3 |
+
|
4 |
+
import json
|
|
|
|
|
|
|
5 |
import gradio as gr
|
6 |
import torch
|
7 |
from tokenizers import Tokenizer
|
|
|
10 |
|
11 |
from beeper_model import BeeperRoseGPT, generate, prepare_model_for_state_dict
|
12 |
|
|
|
|
|
|
|
13 |
MODEL_VERSIONS = {
|
14 |
"Beeper v4 (Advanced)": {
|
15 |
"repo_id": "AbstractPhil/beeper-rose-v4",
|
|
|
33 |
},
|
34 |
}
|
35 |
|
|
|
36 |
CONFIG = {
|
37 |
"context": 512,
|
38 |
"vocab_size": 8192,
|
|
|
49 |
"resid_dropout": 0.1,
|
50 |
"dropout": 0.0,
|
51 |
"grad_checkpoint": False,
|
52 |
+
"runtime_pentachora": {
|
53 |
+
"enable": True,
|
54 |
+
"pool": "mean",
|
55 |
+
"temp": 0.10,
|
56 |
+
"coarse_alpha": 0.25,
|
57 |
+
"topic_alpha": 0.15,
|
58 |
+
"mood_alpha": 0.10,
|
59 |
+
},
|
60 |
}
|
61 |
|
62 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
|
|
|
|
63 |
infer: BeeperRoseGPT | None = None
|
64 |
tok: Tokenizer | None = None
|
65 |
current_version: str | None = None
|
66 |
|
67 |
+
# Metadata for selectors
|
68 |
+
CORPUS_CHOICES: list[str] = []
|
69 |
+
CORPUS_INDEX: dict[str, int] = {}
|
70 |
+
TOPIC_CHOICES: list[str] = []
|
71 |
+
MOOD_CHOICES: list[str] = []
|
72 |
+
|
73 |
+
def _mood_labels(mood_bins: int) -> list[str]:
|
74 |
+
center = mood_bins // 2
|
75 |
+
labels = []
|
76 |
+
for i in range(mood_bins):
|
77 |
+
v = i - center
|
78 |
+
name = { -3:"Very Negative", -2:"Negative", -1:"Slightly Negative",
|
79 |
+
0:"Neutral", 1:"Slightly Positive", 2:"Positive", 3:"Very Positive" }.get(v, f"Valence {v:+d}")
|
80 |
+
labels.append(f"{i} ({name} {v:+d})")
|
81 |
+
return labels
|
82 |
+
|
83 |
+
def _build_choices_from_config(repo_id: str, coarse_C: int, topic_C: int, mood_C: int):
|
84 |
+
global CORPUS_CHOICES, CORPUS_INDEX, TOPIC_CHOICES, MOOD_CHOICES
|
85 |
+
CORPUS_CHOICES, CORPUS_INDEX = [], {}
|
86 |
+
# Try to load training config.json (exported alongside weights)
|
87 |
+
names = []
|
88 |
+
try:
|
89 |
+
cfg_path = hf_hub_download(repo_id, "config.json")
|
90 |
+
with open(cfg_path, "r", encoding="utf-8") as f:
|
91 |
+
train_cfg = json.load(f)
|
92 |
+
alive = train_cfg.get("_alive_entries")
|
93 |
+
if isinstance(alive, list) and all(isinstance(e, dict) for e in alive):
|
94 |
+
names = [str(e.get("name", f"Class {i}")) for i, e in enumerate(alive)]
|
95 |
+
elif isinstance(train_cfg.get("corpus"), list):
|
96 |
+
# fallback: use corpus list if length matches bank size
|
97 |
+
maybe = [str(e.get("name", f"Class {i}")) for i, e in enumerate(train_cfg["corpus"])]
|
98 |
+
if len(maybe) == coarse_C:
|
99 |
+
names = maybe
|
100 |
+
except Exception:
|
101 |
+
names = []
|
102 |
+
|
103 |
+
if len(names) != coarse_C:
|
104 |
+
names = [f"Class {i}" for i in range(coarse_C)]
|
105 |
+
|
106 |
+
CORPUS_CHOICES = names
|
107 |
+
CORPUS_INDEX = {name: i for i, name in enumerate(names)}
|
108 |
+
TOPIC_CHOICES = [str(i) for i in range(topic_C)]
|
109 |
+
MOOD_CHOICES = _mood_labels(mood_C)
|
110 |
|
111 |
def load_model_version(version_name: str) -> str:
|
112 |
+
global infer, tok, current_version, CORPUS_CHOICES, TOPIC_CHOICES, MOOD_CHOICES
|
|
|
|
|
|
|
|
|
|
|
113 |
if current_version == version_name and infer is not None and tok is not None:
|
114 |
return f"Already loaded: {version_name}"
|
115 |
|
116 |
+
info = MODEL_VERSIONS[version_name]
|
|
|
117 |
try:
|
118 |
+
model_file = hf_hub_download(info["repo_id"], info["model_file"])
|
119 |
+
tokenizer_file = hf_hub_download(info["repo_id"], "tokenizer.json")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
|
121 |
+
state = load_safetensors(model_file, device="cpu")
|
122 |
m = BeeperRoseGPT(CONFIG).to(device)
|
123 |
+
prepare_model_for_state_dict(m, state, device=device)
|
124 |
|
|
|
125 |
try:
|
126 |
+
missing, unexpected = m.load_state_dict(state, strict=True)
|
|
|
127 |
_msg = f"strict load ok | missing={len(missing)} unexpected={len(unexpected)}"
|
128 |
except Exception as e:
|
129 |
+
_msg = f"strict load failed ({e}); non-strict fallback"
|
130 |
+
m.load_state_dict(state, strict=False)
|
|
|
131 |
|
132 |
m.eval()
|
|
|
|
|
133 |
t = Tokenizer.from_file(tokenizer_file)
|
134 |
|
135 |
+
infer, tok, current_version = m, t, version_name
|
136 |
+
|
137 |
+
# Build UI choices from bank sizes + training config (for names)
|
138 |
+
coarse_C = infer.penta_coarse.size(0) if infer.penta_coarse is not None else 0
|
139 |
+
topic_C = infer.penta_medium.size(0) if infer.penta_medium is not None else 512
|
140 |
+
mood_C = infer.penta_fine.size(0) if infer.penta_fine is not None else 7
|
141 |
+
_build_choices_from_config(info["repo_id"], coarse_C, topic_C, mood_C)
|
142 |
|
143 |
+
return f"Successfully loaded: {version_name} ({_msg})"
|
144 |
except Exception as e:
|
145 |
+
infer = None; tok = None; current_version = None
|
146 |
+
CORPUS_CHOICES, TOPIC_CHOICES, MOOD_CHOICES = [], [], []
|
|
|
147 |
return f"Error loading {version_name}: {str(e)}"
|
148 |
|
149 |
+
# Initial load: prefer v4, fallback to v3
|
|
|
150 |
try:
|
151 |
+
status = load_model_version("Beeper v4 (Advanced)")
|
152 |
+
if "Error" in status:
|
153 |
+
print(status)
|
154 |
+
status = load_model_version("Beeper v3 (Multi-Concept)")
|
155 |
+
except Exception:
|
156 |
+
status = load_model_version("Beeper v3 (Multi-Concept)")
|
157 |
+
print(status)
|
158 |
+
|
159 |
+
def _parse_selected_indices(values: list[str] | None, mapping: dict[str,int] | None = None) -> list[int] | None:
|
160 |
+
if not values: return None
|
161 |
+
if mapping is None:
|
162 |
+
return [int(v.split()[0]) if isinstance(v, str) else int(v) for v in values]
|
163 |
+
return [mapping[v] for v in values if v in mapping]
|
164 |
+
|
165 |
+
def beeper_reply(message, history, model_version, temperature, top_k, top_p, max_new_tokens,
|
166 |
+
corpus_selected, topic_selected, mood_selected):
|
|
|
|
|
|
|
|
|
|
|
167 |
global infer, tok, current_version
|
|
|
|
|
168 |
if model_version != current_version:
|
169 |
+
s = load_model_version(model_version)
|
170 |
+
if "Error" in s:
|
171 |
+
return f"⚠️ {s}"
|
172 |
|
173 |
if infer is None or tok is None:
|
174 |
return "⚠️ Model not loaded. Please select a version and try again."
|
175 |
|
176 |
+
# Build runtime pull config with user selections
|
177 |
+
rt = dict(CONFIG.get("runtime_pentachora", {}))
|
178 |
+
# Convert selections -> index lists
|
179 |
+
rt["coarse_select"] = _parse_selected_indices(corpus_selected, CORPUS_INDEX) # names -> indices
|
180 |
+
rt["topic_select"] = _parse_selected_indices(topic_selected, None) # numeric strings -> ints
|
181 |
+
rt["mood_select"] = _parse_selected_indices(mood_selected, None) # numeric strings -> ints
|
182 |
+
|
183 |
+
m = (message or "").strip()
|
184 |
+
if "?" in m: prompt = f"Q: {m}\nA:"
|
185 |
+
elif m.lower() in {"hi","hello","hey"}: prompt = 'The little robot said hello. She said, "'
|
186 |
+
elif "story" in m.lower(): prompt = "Once upon a time, there was a robot. "
|
187 |
+
else: prompt = m + ". "
|
188 |
+
|
189 |
+
out = generate(
|
190 |
+
model=infer, tok=tok, cfg=CONFIG, prompt=prompt,
|
|
|
|
|
191 |
max_new_tokens=int(max_new_tokens),
|
192 |
temperature=float(temperature) if temperature is not None else None,
|
193 |
top_k=int(top_k) if top_k is not None else None,
|
194 |
top_p=float(top_p) if top_p is not None else None,
|
195 |
+
repetition_penalty=1.10, presence_penalty=0.8, frequency_penalty=0.1,
|
196 |
+
device=device, detokenize=True, runtime_cfg=rt,
|
|
|
|
|
|
|
197 |
)
|
198 |
|
199 |
+
if out.startswith(prompt): out = out[len(prompt):]
|
200 |
+
out = out.replace("Q:","").replace("A:","").strip()
|
201 |
+
if out and out[-1] not in ".!?”\"'": out += "."
|
202 |
+
return out[:200]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
|
204 |
+
# ---------------- UI ----------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
206 |
+
gr.Markdown("# 🤖 Beeper — Corpus & Capoera–aware Chat")
|
|
|
|
|
|
|
|
|
|
|
207 |
|
208 |
with gr.Row():
|
209 |
with gr.Column(scale=3):
|
210 |
model_dropdown = gr.Dropdown(
|
211 |
choices=list(MODEL_VERSIONS.keys()),
|
212 |
+
value="Beeper v3 (Multi-Concept)",
|
213 |
+
label="Select Beeper Version"
|
|
|
214 |
)
|
215 |
with gr.Column(scale=7):
|
216 |
version_info = gr.Markdown("**Current:** " + MODEL_VERSIONS["Beeper v3 (Multi-Concept)"]["description"])
|
217 |
|
218 |
+
# Runtime pentachora selectors
|
219 |
+
with gr.Row():
|
220 |
+
with gr.Column():
|
221 |
+
corpus_select = gr.Dropdown(choices=CORPUS_CHOICES, multiselect=True, label="Corpus (Coarse classes)")
|
222 |
+
with gr.Column():
|
223 |
+
topic_select = gr.Dropdown(choices=TOPIC_CHOICES, multiselect=True, label="Capoera Topics (IDs)")
|
224 |
+
with gr.Column():
|
225 |
+
mood_select = gr.Dropdown(choices=MOOD_CHOICES, multiselect=True, label="Capoera Moods (valence)")
|
226 |
+
|
227 |
+
chatbot = gr.Chatbot(label="Chat with Beeper", height=420)
|
228 |
msg = gr.Textbox(label="Message", placeholder="Type your message here...")
|
229 |
|
230 |
with gr.Row():
|
|
|
241 |
submit = gr.Button("Send", variant="primary")
|
242 |
clear = gr.Button("Clear")
|
243 |
|
244 |
+
# On version change: load model + update selectors
|
245 |
+
def on_change_version(version_name: str):
|
246 |
+
status = load_model_version(version_name)
|
247 |
+
info = f"**Current:** {MODEL_VERSIONS[version_name]['description']} \n{status}"
|
248 |
+
# refresh selector choices
|
249 |
+
return (
|
250 |
+
info,
|
251 |
+
gr.update(choices=CORPUS_CHOICES, value=[]),
|
252 |
+
gr.update(choices=TOPIC_CHOICES, value=[]),
|
253 |
+
gr.update(choices=MOOD_CHOICES, value=[]),
|
254 |
+
)
|
255 |
+
|
256 |
+
model_dropdown.change(
|
257 |
+
on_change_version,
|
258 |
+
inputs=[model_dropdown],
|
259 |
+
outputs=[version_info, corpus_select, topic_select, mood_select],
|
260 |
)
|
261 |
|
262 |
+
def respond(message, chat_history, model_version, temperature, top_k, top_p, max_new_tokens,
|
263 |
+
corpus_selected, topic_selected, mood_selected):
|
264 |
+
if chat_history is None: chat_history = []
|
265 |
+
resp = beeper_reply(message, chat_history, model_version, temperature, top_k, top_p, max_new_tokens,
|
266 |
+
corpus_selected, topic_selected, mood_selected)
|
267 |
+
chat_history.append((message, resp))
|
268 |
return "", chat_history
|
269 |
|
270 |
+
inputs_all = [msg, chatbot, model_dropdown, temperature_slider, top_k_slider, top_p_slider, max_new_tokens_slider,
|
271 |
+
corpus_select, topic_select, mood_select]
|
272 |
+
outputs_all = [msg, chatbot]
|
273 |
+
|
274 |
+
msg.submit(respond, inputs_all, outputs_all)
|
275 |
+
submit.click(respond, inputs_all, outputs_all)
|
|
|
|
|
|
|
|
|
276 |
clear.click(lambda: None, None, chatbot, queue=False)
|
277 |
|
278 |
if __name__ == "__main__":
|