ShubhamSetia commited on
Commit
2f1910b
·
1 Parent(s): 7fdbbb5

fix: harden OpenBMB backend runtime

Browse files
app.py CHANGED
@@ -8,10 +8,12 @@ from puppet_theater import (
8
  DEFAULT_OPENBMB_MODEL_ID,
9
  TheaterSession,
10
  create_show_from_premise,
 
11
  request_finale,
12
  run_one_beat,
13
  summon_actor,
14
  throw_prop,
 
15
  )
16
 
17
 
@@ -29,9 +31,16 @@ EMPTY_STAGE = """
29
  EMPTY_TRANSCRIPT = "No show yet. The transcript will appear here."
30
  EMPTY_DIRECTOR_LOG = "No director notes yet."
31
  EMPTY_TRACE = "No trace events yet."
32
- EMPTY_BACKEND = "Active backend: deterministic\nFallback: deterministic safety path enabled"
 
 
 
 
 
33
  BACKEND_CHOICES = ["deterministic", "openbmb"]
34
  OPENBMB_MODEL_ID = os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
 
 
35
  PLAYBACK_DELAY_SECONDS = 0.75
36
  PROP_EMOJI = {
37
  "rubber duck": "🐤",
@@ -920,24 +929,63 @@ def normalize_backend_name(backend_name: str | None) -> str:
920
  return backend_name if backend_name in BACKEND_CHOICES else "deterministic"
921
 
922
 
923
- def apply_backend_selection(session: TheaterSession | None, backend_name: str | None) -> TheaterSession | None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
924
  if session is None:
925
  return None
926
  session.backend_name = normalize_backend_name(backend_name)
927
  session.backend_model_id = OPENBMB_MODEL_ID if session.backend_name == "openbmb" else None
 
 
928
  return session
929
 
930
 
931
- def render_backend_settings(session: TheaterSession | None, backend_name: str | None = None) -> str:
 
 
 
 
 
932
  selected_backend = normalize_backend_name(backend_name)
933
  active_backend = session.backend_name if session is not None else selected_backend
934
  model_id = session.backend_model_id if session is not None else None
935
  if active_backend == "openbmb":
936
  model_id = model_id or OPENBMB_MODEL_ID
 
 
 
 
 
 
 
 
 
 
937
  return (
938
  f"Active backend: {active_backend}\n"
939
  "Available backends: deterministic, openbmb\n"
940
  f"OpenBMB model id: {model_id or 'not selected'}\n"
 
 
 
 
 
941
  "Fallback behavior: invalid model output falls back to deterministic actor lines"
942
  )
943
 
@@ -952,9 +1000,17 @@ def render_outputs(session: TheaterSession | None):
952
  )
953
 
954
 
955
- def create_show(premise: str, session: TheaterSession | None, backend_name: str):
 
 
 
 
 
 
956
  premise = premise.strip()
957
  selected_backend = normalize_backend_name(backend_name)
 
 
958
  if not premise:
959
  return (
960
  None,
@@ -962,13 +1018,15 @@ def create_show(premise: str, session: TheaterSession | None, backend_name: str)
962
  "No premise yet. Add a premise to raise the curtain.",
963
  EMPTY_DIRECTOR_LOG,
964
  EMPTY_TRACE,
965
- render_backend_settings(None, selected_backend),
966
  )
967
 
968
  session = create_show_from_premise(
969
  premise,
970
  backend_name=selected_backend,
971
  backend_model_id=OPENBMB_MODEL_ID if selected_backend == "openbmb" else None,
 
 
972
  )
973
  return session, *render_outputs(session)
974
 
@@ -984,11 +1042,19 @@ def reset_show():
984
  EMPTY_DIRECTOR_LOG,
985
  EMPTY_TRACE,
986
  "deterministic",
 
 
 
987
  EMPTY_BACKEND,
988
  )
989
 
990
 
991
- def advance_one_beat(session: TheaterSession | None, backend_name: str):
 
 
 
 
 
992
  if session is None:
993
  return (
994
  None,
@@ -996,15 +1062,21 @@ def advance_one_beat(session: TheaterSession | None, backend_name: str):
996
  "Create a show before running a beat.",
997
  EMPTY_DIRECTOR_LOG,
998
  EMPTY_TRACE,
999
- render_backend_settings(None, backend_name),
1000
  )
1001
 
1002
- session = apply_backend_selection(session, backend_name)
1003
  session = run_one_beat(session)
1004
  return session, *render_outputs(session)
1005
 
1006
 
1007
- def advance_full_act(session: TheaterSession | None, backend_name: str):
 
 
 
 
 
 
1008
  if session is None:
1009
  yield (
1010
  None,
@@ -1012,24 +1084,46 @@ def advance_full_act(session: TheaterSession | None, backend_name: str):
1012
  "Create a show before running the full act.",
1013
  EMPTY_DIRECTOR_LOG,
1014
  EMPTY_TRACE,
1015
- render_backend_settings(None, backend_name),
1016
  )
1017
  return
1018
 
1019
- session = apply_backend_selection(session, backend_name)
 
 
 
 
 
 
 
 
1020
  if session.beat_index >= session.max_beats:
 
 
1021
  session = run_one_beat(session)
 
 
1022
  yield session, *render_outputs(session)
1023
  return
1024
 
1025
  while session.beat_index < session.max_beats:
 
 
1026
  session = run_one_beat(session)
 
 
1027
  yield session, *render_outputs(session)
1028
  if session.beat_index < session.max_beats:
1029
  sleep(PLAYBACK_DELAY_SECONDS)
1030
 
1031
 
1032
- def throw_audience_prop(session: TheaterSession | None, prop_name: str, backend_name: str):
 
 
 
 
 
 
1033
  if session is None:
1034
  return (
1035
  None,
@@ -1037,15 +1131,21 @@ def throw_audience_prop(session: TheaterSession | None, prop_name: str, backend_
1037
  "Create a show before throwing a prop.",
1038
  EMPTY_DIRECTOR_LOG,
1039
  EMPTY_TRACE,
1040
- render_backend_settings(None, backend_name),
1041
  )
1042
 
1043
- session = apply_backend_selection(session, backend_name)
1044
  session = throw_prop(session, prop_name)
1045
  return session, *render_outputs(session)
1046
 
1047
 
1048
- def summon_audience_actor(session: TheaterSession | None, actor_name: str, backend_name: str):
 
 
 
 
 
 
1049
  if session is None:
1050
  return (
1051
  None,
@@ -1053,15 +1153,20 @@ def summon_audience_actor(session: TheaterSession | None, actor_name: str, backe
1053
  "Create a show before summoning an actor.",
1054
  EMPTY_DIRECTOR_LOG,
1055
  EMPTY_TRACE,
1056
- render_backend_settings(None, backend_name),
1057
  )
1058
 
1059
- session = apply_backend_selection(session, backend_name)
1060
  session = summon_actor(session, actor_name)
1061
  return session, *render_outputs(session)
1062
 
1063
 
1064
- def request_audience_finale(session: TheaterSession | None, backend_name: str):
 
 
 
 
 
1065
  if session is None:
1066
  return (
1067
  None,
@@ -1069,14 +1174,43 @@ def request_audience_finale(session: TheaterSession | None, backend_name: str):
1069
  "Create a show before requesting a finale.",
1070
  EMPTY_DIRECTOR_LOG,
1071
  EMPTY_TRACE,
1072
- render_backend_settings(None, backend_name),
1073
  )
1074
 
1075
- session = apply_backend_selection(session, backend_name)
1076
  session = request_finale(session)
1077
  return session, *render_outputs(session)
1078
 
1079
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
  with gr.Blocks(title="AI Puppet Theater") as app:
1081
  session_state = gr.State(None)
1082
 
@@ -1163,43 +1297,77 @@ with gr.Blocks(title="AI Puppet Theater") as app:
1163
  label="Actor Line Backend",
1164
  interactive=True,
1165
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1166
  backend_output = gr.Textbox(
1167
  value=EMPTY_BACKEND,
1168
  label="Model Settings",
1169
- lines=4,
1170
  interactive=False,
1171
  )
1172
 
1173
  create_button.click(
1174
  create_show,
1175
- inputs=[premise_input, session_state, backend_select],
1176
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1177
  )
1178
  run_one_button.click(
1179
  advance_one_beat,
1180
- inputs=[session_state, backend_select],
1181
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1182
  )
1183
  run_full_button.click(
1184
  advance_full_act,
1185
- inputs=[session_state, backend_select],
 
 
 
 
 
 
1186
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1187
  )
1188
  throw_prop_button.click(
1189
  throw_audience_prop,
1190
- inputs=[session_state, prop_input, backend_select],
1191
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1192
  )
1193
  summon_actor_button.click(
1194
  summon_audience_actor,
1195
- inputs=[session_state, actor_input, backend_select],
1196
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1197
  )
1198
  request_finale_button.click(
1199
  request_audience_finale,
1200
- inputs=[session_state, backend_select],
1201
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1202
  )
 
 
 
 
 
1203
  reset_button.click(
1204
  reset_show,
1205
  outputs=[
@@ -1212,6 +1380,9 @@ with gr.Blocks(title="AI Puppet Theater") as app:
1212
  director_output,
1213
  trace_output,
1214
  backend_select,
 
 
 
1215
  backend_output,
1216
  ],
1217
  )
 
8
  DEFAULT_OPENBMB_MODEL_ID,
9
  TheaterSession,
10
  create_show_from_premise,
11
+ get_backend_status,
12
  request_finale,
13
  run_one_beat,
14
  summon_actor,
15
  throw_prop,
16
+ warm_up_openbmb,
17
  )
18
 
19
 
 
31
  EMPTY_TRANSCRIPT = "No show yet. The transcript will appear here."
32
  EMPTY_DIRECTOR_LOG = "No director notes yet."
33
  EMPTY_TRACE = "No trace events yet."
34
+ EMPTY_BACKEND = (
35
+ "Active backend: deterministic\n"
36
+ "OpenBMB model id: openbmb/MiniCPM5-1B\n"
37
+ "Model status: unloaded\n"
38
+ "Fallback: deterministic safety path enabled"
39
+ )
40
  BACKEND_CHOICES = ["deterministic", "openbmb"]
41
  OPENBMB_MODEL_ID = os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
42
+ DEFAULT_MAX_NEW_TOKENS = 80
43
+ DEFAULT_TEMPERATURE = 0.8
44
  PLAYBACK_DELAY_SECONDS = 0.75
45
  PROP_EMOJI = {
46
  "rubber duck": "🐤",
 
929
  return backend_name if backend_name in BACKEND_CHOICES else "deterministic"
930
 
931
 
932
+ def normalize_max_new_tokens(max_new_tokens: int | float | None) -> int:
933
+ if max_new_tokens is None:
934
+ return DEFAULT_MAX_NEW_TOKENS
935
+ return max(16, min(160, int(max_new_tokens)))
936
+
937
+
938
+ def normalize_temperature(temperature: int | float | None) -> float:
939
+ if temperature is None:
940
+ return DEFAULT_TEMPERATURE
941
+ return max(0.0, min(1.5, float(temperature)))
942
+
943
+
944
+ def apply_backend_selection(
945
+ session: TheaterSession | None,
946
+ backend_name: str | None,
947
+ max_new_tokens: int | float | None = None,
948
+ temperature: int | float | None = None,
949
+ ) -> TheaterSession | None:
950
  if session is None:
951
  return None
952
  session.backend_name = normalize_backend_name(backend_name)
953
  session.backend_model_id = OPENBMB_MODEL_ID if session.backend_name == "openbmb" else None
954
+ session.backend_max_new_tokens = normalize_max_new_tokens(max_new_tokens)
955
+ session.backend_temperature = normalize_temperature(temperature)
956
  return session
957
 
958
 
959
+ def render_backend_settings(
960
+ session: TheaterSession | None,
961
+ backend_name: str | None = None,
962
+ max_new_tokens: int | float | None = None,
963
+ temperature: int | float | None = None,
964
+ ) -> str:
965
  selected_backend = normalize_backend_name(backend_name)
966
  active_backend = session.backend_name if session is not None else selected_backend
967
  model_id = session.backend_model_id if session is not None else None
968
  if active_backend == "openbmb":
969
  model_id = model_id or OPENBMB_MODEL_ID
970
+ status = get_backend_status(active_backend)
971
+ openbmb_status = get_backend_status("openbmb")
972
+ configured_max_new_tokens = (
973
+ session.backend_max_new_tokens if session is not None else normalize_max_new_tokens(max_new_tokens)
974
+ )
975
+ configured_temperature = (
976
+ session.backend_temperature if session is not None else normalize_temperature(temperature)
977
+ )
978
+ latency = f"{status.latest_latency_ms}ms" if status.latest_latency_ms is not None else "none yet"
979
+ fallback_reason = status.latest_fallback_reason or "none"
980
  return (
981
  f"Active backend: {active_backend}\n"
982
  "Available backends: deterministic, openbmb\n"
983
  f"OpenBMB model id: {model_id or 'not selected'}\n"
984
+ f"Model status: {status.load_status}\n"
985
+ f"OpenBMB status: {openbmb_status.load_status}\n"
986
+ f"Latest latency: {latency}\n"
987
+ f"Latest fallback reason: {fallback_reason}\n"
988
+ f"Generation: max_new_tokens={configured_max_new_tokens}, temperature={configured_temperature:.2f}\n"
989
  "Fallback behavior: invalid model output falls back to deterministic actor lines"
990
  )
991
 
 
1000
  )
1001
 
1002
 
1003
+ def create_show(
1004
+ premise: str,
1005
+ session: TheaterSession | None,
1006
+ backend_name: str,
1007
+ max_new_tokens: int | float,
1008
+ temperature: int | float,
1009
+ ):
1010
  premise = premise.strip()
1011
  selected_backend = normalize_backend_name(backend_name)
1012
+ selected_max_new_tokens = normalize_max_new_tokens(max_new_tokens)
1013
+ selected_temperature = normalize_temperature(temperature)
1014
  if not premise:
1015
  return (
1016
  None,
 
1018
  "No premise yet. Add a premise to raise the curtain.",
1019
  EMPTY_DIRECTOR_LOG,
1020
  EMPTY_TRACE,
1021
+ render_backend_settings(None, selected_backend, selected_max_new_tokens, selected_temperature),
1022
  )
1023
 
1024
  session = create_show_from_premise(
1025
  premise,
1026
  backend_name=selected_backend,
1027
  backend_model_id=OPENBMB_MODEL_ID if selected_backend == "openbmb" else None,
1028
+ backend_max_new_tokens=selected_max_new_tokens,
1029
+ backend_temperature=selected_temperature,
1030
  )
1031
  return session, *render_outputs(session)
1032
 
 
1042
  EMPTY_DIRECTOR_LOG,
1043
  EMPTY_TRACE,
1044
  "deterministic",
1045
+ DEFAULT_MAX_NEW_TOKENS,
1046
+ DEFAULT_TEMPERATURE,
1047
+ True,
1048
  EMPTY_BACKEND,
1049
  )
1050
 
1051
 
1052
+ def advance_one_beat(
1053
+ session: TheaterSession | None,
1054
+ backend_name: str,
1055
+ max_new_tokens: int | float,
1056
+ temperature: int | float,
1057
+ ):
1058
  if session is None:
1059
  return (
1060
  None,
 
1062
  "Create a show before running a beat.",
1063
  EMPTY_DIRECTOR_LOG,
1064
  EMPTY_TRACE,
1065
+ render_backend_settings(None, backend_name, max_new_tokens, temperature),
1066
  )
1067
 
1068
+ session = apply_backend_selection(session, backend_name, max_new_tokens, temperature)
1069
  session = run_one_beat(session)
1070
  return session, *render_outputs(session)
1071
 
1072
 
1073
+ def advance_full_act(
1074
+ session: TheaterSession | None,
1075
+ backend_name: str,
1076
+ max_new_tokens: int | float,
1077
+ temperature: int | float,
1078
+ use_deterministic_full_act: bool,
1079
+ ):
1080
  if session is None:
1081
  yield (
1082
  None,
 
1084
  "Create a show before running the full act.",
1085
  EMPTY_DIRECTOR_LOG,
1086
  EMPTY_TRACE,
1087
+ render_backend_settings(None, backend_name, max_new_tokens, temperature),
1088
  )
1089
  return
1090
 
1091
+ session = apply_backend_selection(session, backend_name, max_new_tokens, temperature)
1092
+ selected_backend = session.backend_name
1093
+ deterministic_full_act = selected_backend == "openbmb" and use_deterministic_full_act
1094
+ if deterministic_full_act:
1095
+ session.director_log.append(
1096
+ "OpenBMB is selected, so Run Full Act will use deterministic actor lines for this playback."
1097
+ )
1098
+ session.trace_events.append("full_act_openbmb_deterministic_playback")
1099
+
1100
  if session.beat_index >= session.max_beats:
1101
+ if deterministic_full_act:
1102
+ session.backend_name = "deterministic"
1103
  session = run_one_beat(session)
1104
+ if deterministic_full_act:
1105
+ session.backend_name = selected_backend
1106
  yield session, *render_outputs(session)
1107
  return
1108
 
1109
  while session.beat_index < session.max_beats:
1110
+ if deterministic_full_act:
1111
+ session.backend_name = "deterministic"
1112
  session = run_one_beat(session)
1113
+ if deterministic_full_act:
1114
+ session.backend_name = selected_backend
1115
  yield session, *render_outputs(session)
1116
  if session.beat_index < session.max_beats:
1117
  sleep(PLAYBACK_DELAY_SECONDS)
1118
 
1119
 
1120
+ def throw_audience_prop(
1121
+ session: TheaterSession | None,
1122
+ prop_name: str,
1123
+ backend_name: str,
1124
+ max_new_tokens: int | float,
1125
+ temperature: int | float,
1126
+ ):
1127
  if session is None:
1128
  return (
1129
  None,
 
1131
  "Create a show before throwing a prop.",
1132
  EMPTY_DIRECTOR_LOG,
1133
  EMPTY_TRACE,
1134
+ render_backend_settings(None, backend_name, max_new_tokens, temperature),
1135
  )
1136
 
1137
+ session = apply_backend_selection(session, backend_name, max_new_tokens, temperature)
1138
  session = throw_prop(session, prop_name)
1139
  return session, *render_outputs(session)
1140
 
1141
 
1142
+ def summon_audience_actor(
1143
+ session: TheaterSession | None,
1144
+ actor_name: str,
1145
+ backend_name: str,
1146
+ max_new_tokens: int | float,
1147
+ temperature: int | float,
1148
+ ):
1149
  if session is None:
1150
  return (
1151
  None,
 
1153
  "Create a show before summoning an actor.",
1154
  EMPTY_DIRECTOR_LOG,
1155
  EMPTY_TRACE,
1156
+ render_backend_settings(None, backend_name, max_new_tokens, temperature),
1157
  )
1158
 
1159
+ session = apply_backend_selection(session, backend_name, max_new_tokens, temperature)
1160
  session = summon_actor(session, actor_name)
1161
  return session, *render_outputs(session)
1162
 
1163
 
1164
+ def request_audience_finale(
1165
+ session: TheaterSession | None,
1166
+ backend_name: str,
1167
+ max_new_tokens: int | float,
1168
+ temperature: int | float,
1169
+ ):
1170
  if session is None:
1171
  return (
1172
  None,
 
1174
  "Create a show before requesting a finale.",
1175
  EMPTY_DIRECTOR_LOG,
1176
  EMPTY_TRACE,
1177
+ render_backend_settings(None, backend_name, max_new_tokens, temperature),
1178
  )
1179
 
1180
+ session = apply_backend_selection(session, backend_name, max_new_tokens, temperature)
1181
  session = request_finale(session)
1182
  return session, *render_outputs(session)
1183
 
1184
 
1185
+ def warm_up_backend(
1186
+ session: TheaterSession | None,
1187
+ max_new_tokens: int | float,
1188
+ temperature: int | float,
1189
+ ):
1190
+ selected_max_new_tokens = normalize_max_new_tokens(max_new_tokens)
1191
+ selected_temperature = normalize_temperature(temperature)
1192
+ status = warm_up_openbmb(
1193
+ max_new_tokens=selected_max_new_tokens,
1194
+ temperature=selected_temperature,
1195
+ )
1196
+ if session is not None:
1197
+ session.backend_max_new_tokens = selected_max_new_tokens
1198
+ session.backend_temperature = selected_temperature
1199
+ if status.load_status == "loaded":
1200
+ session.director_log.append(f"OpenBMB warm-up loaded {status.model_id}.")
1201
+ session.trace_events.append(f"openbmb_warmup_loaded:{status.model_id}:latency_ms={status.latest_latency_ms}")
1202
+ else:
1203
+ reason = status.latest_fallback_reason or "unknown error"
1204
+ session.director_log.append(f"OpenBMB warm-up failed: {reason}.")
1205
+ session.trace_events.append(f"openbmb_warmup_failed:{status.model_id}:{reason}")
1206
+ return (
1207
+ session,
1208
+ render_director_log(session),
1209
+ render_trace(session),
1210
+ render_backend_settings(session, "openbmb", selected_max_new_tokens, selected_temperature),
1211
+ )
1212
+
1213
+
1214
  with gr.Blocks(title="AI Puppet Theater") as app:
1215
  session_state = gr.State(None)
1216
 
 
1297
  label="Actor Line Backend",
1298
  interactive=True,
1299
  )
1300
+ with gr.Row():
1301
+ max_new_tokens_input = gr.Slider(
1302
+ minimum=16,
1303
+ maximum=160,
1304
+ value=DEFAULT_MAX_NEW_TOKENS,
1305
+ step=8,
1306
+ label="Max New Tokens",
1307
+ interactive=True,
1308
+ )
1309
+ temperature_input = gr.Slider(
1310
+ minimum=0.0,
1311
+ maximum=1.5,
1312
+ value=DEFAULT_TEMPERATURE,
1313
+ step=0.1,
1314
+ label="Temperature",
1315
+ interactive=True,
1316
+ )
1317
+ deterministic_full_act_input = gr.Checkbox(
1318
+ value=True,
1319
+ label="Use deterministic actor lines for OpenBMB full-act playback",
1320
+ interactive=True,
1321
+ )
1322
+ warm_up_button = gr.Button("Warm up OpenBMB", elem_classes=["secondary-action"])
1323
  backend_output = gr.Textbox(
1324
  value=EMPTY_BACKEND,
1325
  label="Model Settings",
1326
+ lines=8,
1327
  interactive=False,
1328
  )
1329
 
1330
  create_button.click(
1331
  create_show,
1332
+ inputs=[premise_input, session_state, backend_select, max_new_tokens_input, temperature_input],
1333
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1334
  )
1335
  run_one_button.click(
1336
  advance_one_beat,
1337
+ inputs=[session_state, backend_select, max_new_tokens_input, temperature_input],
1338
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1339
  )
1340
  run_full_button.click(
1341
  advance_full_act,
1342
+ inputs=[
1343
+ session_state,
1344
+ backend_select,
1345
+ max_new_tokens_input,
1346
+ temperature_input,
1347
+ deterministic_full_act_input,
1348
+ ],
1349
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1350
  )
1351
  throw_prop_button.click(
1352
  throw_audience_prop,
1353
+ inputs=[session_state, prop_input, backend_select, max_new_tokens_input, temperature_input],
1354
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1355
  )
1356
  summon_actor_button.click(
1357
  summon_audience_actor,
1358
+ inputs=[session_state, actor_input, backend_select, max_new_tokens_input, temperature_input],
1359
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1360
  )
1361
  request_finale_button.click(
1362
  request_audience_finale,
1363
+ inputs=[session_state, backend_select, max_new_tokens_input, temperature_input],
1364
  outputs=[session_state, stage_output, transcript_output, director_output, trace_output, backend_output],
1365
  )
1366
+ warm_up_button.click(
1367
+ warm_up_backend,
1368
+ inputs=[session_state, max_new_tokens_input, temperature_input],
1369
+ outputs=[session_state, director_output, trace_output, backend_output],
1370
+ )
1371
  reset_button.click(
1372
  reset_show,
1373
  outputs=[
 
1380
  director_output,
1381
  trace_output,
1382
  backend_select,
1383
+ max_new_tokens_input,
1384
+ temperature_input,
1385
+ deterministic_full_act_input,
1386
  backend_output,
1387
  ],
1388
  )
puppet_theater/__init__.py CHANGED
@@ -5,7 +5,9 @@ from puppet_theater.backends import (
5
  ModelBackend,
6
  OpenBMBTransformersBackend,
7
  generate_actor_response,
 
8
  parse_actor_output,
 
9
  )
10
  from puppet_theater.director import BEAT_ARC, run_full_act, run_one_beat
11
  from puppet_theater.models import Actor, ActorResponse, Beat, TheaterSession
@@ -23,10 +25,12 @@ __all__ = [
23
  "TheaterSession",
24
  "create_show_from_premise",
25
  "generate_actor_response",
 
26
  "parse_actor_output",
27
  "request_finale",
28
  "run_full_act",
29
  "run_one_beat",
30
  "summon_actor",
31
  "throw_prop",
 
32
  ]
 
5
  ModelBackend,
6
  OpenBMBTransformersBackend,
7
  generate_actor_response,
8
+ get_backend_status,
9
  parse_actor_output,
10
+ warm_up_openbmb,
11
  )
12
  from puppet_theater.director import BEAT_ARC, run_full_act, run_one_beat
13
  from puppet_theater.models import Actor, ActorResponse, Beat, TheaterSession
 
25
  "TheaterSession",
26
  "create_show_from_premise",
27
  "generate_actor_response",
28
+ "get_backend_status",
29
  "parse_actor_output",
30
  "request_finale",
31
  "run_full_act",
32
  "run_one_beat",
33
  "summon_actor",
34
  "throw_prop",
35
+ "warm_up_openbmb",
36
  ]
puppet_theater/backends.py CHANGED
@@ -13,7 +13,8 @@ from puppet_theater.prompts import ACTOR_LINE_PROMPT
13
 
14
  MAX_ACTOR_LINE_CHARS = 220
15
  DEFAULT_OPENBMB_MODEL_ID = "openbmb/MiniCPM5-1B"
16
- OPENBMB_MAX_NEW_TOKENS = 112
 
17
 
18
 
19
  @dataclass(frozen=True)
@@ -23,10 +24,24 @@ class BackendGeneration:
23
  model_id: str | None
24
  fallback_used: bool
25
  validation_status: str
 
26
  latency_ms: int | None = None
27
  error: str | None = None
28
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  class ModelBackend(ABC):
31
  name: str = "base"
32
  model_id: str | None = None
@@ -55,6 +70,7 @@ class ModelBackend(ABC):
55
 
56
  class DeterministicBackend(ModelBackend):
57
  name = "deterministic"
 
58
 
59
  def generate_actor_response(
60
  self,
@@ -69,13 +85,30 @@ class DeterministicBackend(ModelBackend):
69
  class OpenBMBTransformersBackend(ModelBackend):
70
  name = "openbmb"
71
 
72
- def __init__(self, model_id: str | None = None, max_new_tokens: int = OPENBMB_MAX_NEW_TOKENS) -> None:
 
 
 
 
 
73
  self.model_id = model_id or os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
74
  self.max_new_tokens = max_new_tokens
 
 
 
 
 
 
75
  self._tokenizer = None
76
  self._model = None
77
  self._torch = None
78
 
 
 
 
 
 
 
79
  def generate_actor_response(
80
  self,
81
  session: TheaterSession,
@@ -105,22 +138,35 @@ class OpenBMBTransformersBackend(ModelBackend):
105
 
106
  def _load(self) -> None:
107
  if self._tokenizer is not None and self._model is not None:
 
108
  return
109
 
 
110
  try:
111
  import torch
112
  from transformers import AutoModelForCausalLM, AutoTokenizer
113
  except ImportError as exc:
 
 
114
  raise RuntimeError("OpenBMB backend dependencies are not installed") from exc
115
 
116
- self._torch = torch
117
- self._tokenizer = AutoTokenizer.from_pretrained(self.model_id)
118
- self._model = AutoModelForCausalLM.from_pretrained(
119
- self.model_id,
120
- torch_dtype="auto",
121
- device_map="auto",
122
- )
123
- self._model.eval()
 
 
 
 
 
 
 
 
 
124
 
125
  def _generate_text(self, prompt: str) -> str:
126
  self._load()
@@ -149,14 +195,17 @@ class OpenBMBTransformersBackend(ModelBackend):
149
  inputs = inputs.to(model.device)
150
  eos_token_id = tokenizer.eos_token_id
151
  pad_token_id = tokenizer.pad_token_id or eos_token_id
 
 
 
 
 
 
 
 
 
152
  with self._torch.inference_mode():
153
- outputs = model.generate(
154
- **inputs,
155
- max_new_tokens=self.max_new_tokens,
156
- do_sample=False,
157
- pad_token_id=pad_token_id,
158
- eos_token_id=eos_token_id,
159
- )
160
  new_tokens = outputs[0][inputs["input_ids"].shape[-1] :]
161
  return tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
162
 
@@ -183,7 +232,11 @@ def generate_actor_response(
183
  prop: str | None,
184
  backend: ModelBackend | None = None,
185
  ) -> BackendGeneration:
186
- active_backend = backend or get_backend(session.backend_name)
 
 
 
 
187
  start_time = time.perf_counter()
188
  raw_output: ActorResponse | dict[str, Any] | str | None = None
189
  try:
@@ -203,14 +256,17 @@ def generate_actor_response(
203
 
204
  response, validation_status = parse_actor_output(raw_output)
205
  if response is not None:
206
- return BackendGeneration(
207
  response=response,
208
  backend_name=active_backend.name,
209
  model_id=active_backend.model_id,
210
  fallback_used=False,
211
  validation_status=validation_status,
 
212
  latency_ms=_elapsed_ms(start_time),
213
  )
 
 
214
 
215
  try:
216
  repair_output = active_backend.repair_actor_response(
@@ -235,14 +291,17 @@ def generate_actor_response(
235
  if repair_output is not None:
236
  response, repair_status = parse_actor_output(repair_output)
237
  if response is not None:
238
- return BackendGeneration(
239
  response=response,
240
  backend_name=active_backend.name,
241
  model_id=active_backend.model_id,
242
  fallback_used=False,
243
  validation_status=f"repair_{repair_status}",
 
244
  latency_ms=_elapsed_ms(start_time),
245
  )
 
 
246
  validation_status = f"{validation_status};repair_{repair_status}"
247
 
248
  return _fallback_generation(
@@ -256,17 +315,64 @@ def generate_actor_response(
256
  )
257
 
258
 
259
- def get_backend(backend_name: str | None) -> ModelBackend:
 
 
 
 
260
  normalized_name = (backend_name or "deterministic").strip().lower()
261
  if normalized_name == "openbmb":
262
  model_id = os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
263
  cache_key = f"openbmb:{model_id}"
264
  if cache_key not in _BACKEND_CACHE:
265
- _BACKEND_CACHE[cache_key] = OpenBMBTransformersBackend(model_id=model_id)
266
- return _BACKEND_CACHE[cache_key]
 
 
 
 
 
 
 
267
  return _BACKEND_CACHE["deterministic"]
268
 
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  def build_actor_line_prompt(
271
  session: TheaterSession,
272
  beat_type: str,
@@ -304,15 +410,18 @@ def _fallback_generation(
304
  error: str | None = None,
305
  ) -> BackendGeneration:
306
  fallback_response = deterministic_actor_response(session, beat_type, speaker, prop)
307
- return BackendGeneration(
308
  response=fallback_response,
309
  backend_name=backend.name,
310
  model_id=backend.model_id,
311
  fallback_used=True,
312
  validation_status=validation_status,
 
313
  latency_ms=latency_ms,
314
  error=error,
315
  )
 
 
316
 
317
 
318
  def parse_actor_output(raw_output: ActorResponse | dict[str, Any] | str) -> tuple[ActorResponse | None, str]:
@@ -364,6 +473,39 @@ def _summarize_error(exc: Exception) -> str:
364
  return message[:180]
365
 
366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  def _line_for_beat(
368
  session: TheaterSession,
369
  beat_type: str,
 
13
 
14
  MAX_ACTOR_LINE_CHARS = 220
15
  DEFAULT_OPENBMB_MODEL_ID = "openbmb/MiniCPM5-1B"
16
+ OPENBMB_MAX_NEW_TOKENS = 80
17
+ OPENBMB_TEMPERATURE = 0.8
18
 
19
 
20
  @dataclass(frozen=True)
 
24
  model_id: str | None
25
  fallback_used: bool
26
  validation_status: str
27
+ load_status: str
28
  latency_ms: int | None = None
29
  error: str | None = None
30
 
31
 
32
+ @dataclass(frozen=True)
33
+ class BackendRuntimeStatus:
34
+ backend_name: str
35
+ model_id: str | None
36
+ load_status: str
37
+ latest_latency_ms: int | None = None
38
+ latest_validation_status: str | None = None
39
+ latest_fallback_used: bool | None = None
40
+ latest_fallback_reason: str | None = None
41
+ max_new_tokens: int | None = None
42
+ temperature: float | None = None
43
+
44
+
45
  class ModelBackend(ABC):
46
  name: str = "base"
47
  model_id: str | None = None
 
70
 
71
  class DeterministicBackend(ModelBackend):
72
  name = "deterministic"
73
+ load_status = "loaded"
74
 
75
  def generate_actor_response(
76
  self,
 
85
  class OpenBMBTransformersBackend(ModelBackend):
86
  name = "openbmb"
87
 
88
+ def __init__(
89
+ self,
90
+ model_id: str | None = None,
91
+ max_new_tokens: int = OPENBMB_MAX_NEW_TOKENS,
92
+ temperature: float = OPENBMB_TEMPERATURE,
93
+ ) -> None:
94
  self.model_id = model_id or os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
95
  self.max_new_tokens = max_new_tokens
96
+ self.temperature = temperature
97
+ self.load_status = "unloaded"
98
+ self.latest_latency_ms: int | None = None
99
+ self.latest_validation_status: str | None = None
100
+ self.latest_fallback_used: bool | None = None
101
+ self.latest_fallback_reason: str | None = None
102
  self._tokenizer = None
103
  self._model = None
104
  self._torch = None
105
 
106
+ def configure(self, max_new_tokens: int | None = None, temperature: float | None = None) -> None:
107
+ if max_new_tokens is not None:
108
+ self.max_new_tokens = _clamp_int(max_new_tokens, 16, 160)
109
+ if temperature is not None:
110
+ self.temperature = _clamp_float(temperature, 0.0, 1.5)
111
+
112
  def generate_actor_response(
113
  self,
114
  session: TheaterSession,
 
138
 
139
  def _load(self) -> None:
140
  if self._tokenizer is not None and self._model is not None:
141
+ self.load_status = "loaded"
142
  return
143
 
144
+ self.load_status = "loading"
145
  try:
146
  import torch
147
  from transformers import AutoModelForCausalLM, AutoTokenizer
148
  except ImportError as exc:
149
+ self.load_status = "error"
150
+ self.latest_fallback_reason = "OpenBMB backend dependencies are not installed"
151
  raise RuntimeError("OpenBMB backend dependencies are not installed") from exc
152
 
153
+ try:
154
+ self._torch = torch
155
+ self._tokenizer = AutoTokenizer.from_pretrained(self.model_id)
156
+ self._model = AutoModelForCausalLM.from_pretrained(
157
+ self.model_id,
158
+ torch_dtype="auto",
159
+ device_map="auto",
160
+ )
161
+ self._model.eval()
162
+ except Exception as exc:
163
+ self._tokenizer = None
164
+ self._model = None
165
+ self.load_status = "error"
166
+ self.latest_fallback_reason = _summarize_error(exc)
167
+ raise
168
+
169
+ self.load_status = "loaded"
170
 
171
  def _generate_text(self, prompt: str) -> str:
172
  self._load()
 
195
  inputs = inputs.to(model.device)
196
  eos_token_id = tokenizer.eos_token_id
197
  pad_token_id = tokenizer.pad_token_id or eos_token_id
198
+ do_sample = self.temperature > 0
199
+ generation_kwargs = {
200
+ "max_new_tokens": self.max_new_tokens,
201
+ "do_sample": do_sample,
202
+ "pad_token_id": pad_token_id,
203
+ "eos_token_id": eos_token_id,
204
+ }
205
+ if do_sample:
206
+ generation_kwargs["temperature"] = self.temperature
207
  with self._torch.inference_mode():
208
+ outputs = model.generate(**inputs, **generation_kwargs)
 
 
 
 
 
 
209
  new_tokens = outputs[0][inputs["input_ids"].shape[-1] :]
210
  return tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
211
 
 
232
  prop: str | None,
233
  backend: ModelBackend | None = None,
234
  ) -> BackendGeneration:
235
+ active_backend = backend or get_backend(
236
+ session.backend_name,
237
+ max_new_tokens=session.backend_max_new_tokens,
238
+ temperature=session.backend_temperature,
239
+ )
240
  start_time = time.perf_counter()
241
  raw_output: ActorResponse | dict[str, Any] | str | None = None
242
  try:
 
256
 
257
  response, validation_status = parse_actor_output(raw_output)
258
  if response is not None:
259
+ generation = BackendGeneration(
260
  response=response,
261
  backend_name=active_backend.name,
262
  model_id=active_backend.model_id,
263
  fallback_used=False,
264
  validation_status=validation_status,
265
+ load_status=getattr(active_backend, "load_status", "loaded"),
266
  latency_ms=_elapsed_ms(start_time),
267
  )
268
+ _record_generation_status(active_backend, generation)
269
+ return generation
270
 
271
  try:
272
  repair_output = active_backend.repair_actor_response(
 
291
  if repair_output is not None:
292
  response, repair_status = parse_actor_output(repair_output)
293
  if response is not None:
294
+ generation = BackendGeneration(
295
  response=response,
296
  backend_name=active_backend.name,
297
  model_id=active_backend.model_id,
298
  fallback_used=False,
299
  validation_status=f"repair_{repair_status}",
300
+ load_status=getattr(active_backend, "load_status", "loaded"),
301
  latency_ms=_elapsed_ms(start_time),
302
  )
303
+ _record_generation_status(active_backend, generation)
304
+ return generation
305
  validation_status = f"{validation_status};repair_{repair_status}"
306
 
307
  return _fallback_generation(
 
315
  )
316
 
317
 
318
+ def get_backend(
319
+ backend_name: str | None,
320
+ max_new_tokens: int | None = None,
321
+ temperature: float | None = None,
322
+ ) -> ModelBackend:
323
  normalized_name = (backend_name or "deterministic").strip().lower()
324
  if normalized_name == "openbmb":
325
  model_id = os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
326
  cache_key = f"openbmb:{model_id}"
327
  if cache_key not in _BACKEND_CACHE:
328
+ _BACKEND_CACHE[cache_key] = OpenBMBTransformersBackend(
329
+ model_id=model_id,
330
+ max_new_tokens=max_new_tokens or OPENBMB_MAX_NEW_TOKENS,
331
+ temperature=temperature if temperature is not None else OPENBMB_TEMPERATURE,
332
+ )
333
+ backend = _BACKEND_CACHE[cache_key]
334
+ if isinstance(backend, OpenBMBTransformersBackend):
335
+ backend.configure(max_new_tokens=max_new_tokens, temperature=temperature)
336
+ return backend
337
  return _BACKEND_CACHE["deterministic"]
338
 
339
 
340
+ def warm_up_openbmb(
341
+ max_new_tokens: int = OPENBMB_MAX_NEW_TOKENS,
342
+ temperature: float = OPENBMB_TEMPERATURE,
343
+ ) -> BackendRuntimeStatus:
344
+ backend = get_backend("openbmb", max_new_tokens=max_new_tokens, temperature=temperature)
345
+ if not isinstance(backend, OpenBMBTransformersBackend):
346
+ return get_backend_status("deterministic")
347
+
348
+ start_time = time.perf_counter()
349
+ try:
350
+ backend._load()
351
+ backend.latest_latency_ms = _elapsed_ms(start_time)
352
+ backend.latest_fallback_reason = None
353
+ except Exception as exc:
354
+ backend.latest_latency_ms = _elapsed_ms(start_time)
355
+ backend.latest_fallback_reason = _summarize_error(exc)
356
+ return get_backend_status("openbmb")
357
+
358
+
359
+ def get_backend_status(backend_name: str | None = None) -> BackendRuntimeStatus:
360
+ normalized_name = (backend_name or "deterministic").strip().lower()
361
+ if normalized_name == "openbmb":
362
+ model_id = os.getenv("OPENBMB_MODEL_ID", DEFAULT_OPENBMB_MODEL_ID)
363
+ backend = _BACKEND_CACHE.get(f"openbmb:{model_id}")
364
+ if backend is None:
365
+ return BackendRuntimeStatus(
366
+ backend_name="openbmb",
367
+ model_id=model_id,
368
+ load_status="unloaded",
369
+ max_new_tokens=OPENBMB_MAX_NEW_TOKENS,
370
+ temperature=OPENBMB_TEMPERATURE,
371
+ )
372
+ return _runtime_status_from_backend(backend)
373
+ return _runtime_status_from_backend(_BACKEND_CACHE["deterministic"])
374
+
375
+
376
  def build_actor_line_prompt(
377
  session: TheaterSession,
378
  beat_type: str,
 
410
  error: str | None = None,
411
  ) -> BackendGeneration:
412
  fallback_response = deterministic_actor_response(session, beat_type, speaker, prop)
413
+ generation = BackendGeneration(
414
  response=fallback_response,
415
  backend_name=backend.name,
416
  model_id=backend.model_id,
417
  fallback_used=True,
418
  validation_status=validation_status,
419
+ load_status=getattr(backend, "load_status", "loaded"),
420
  latency_ms=latency_ms,
421
  error=error,
422
  )
423
+ _record_generation_status(backend, generation)
424
+ return generation
425
 
426
 
427
  def parse_actor_output(raw_output: ActorResponse | dict[str, Any] | str) -> tuple[ActorResponse | None, str]:
 
473
  return message[:180]
474
 
475
 
476
+ def _clamp_int(value: int, minimum: int, maximum: int) -> int:
477
+ return max(minimum, min(maximum, int(value)))
478
+
479
+
480
+ def _clamp_float(value: float, minimum: float, maximum: float) -> float:
481
+ return max(minimum, min(maximum, float(value)))
482
+
483
+
484
+ def _record_generation_status(backend: ModelBackend, generation: BackendGeneration) -> None:
485
+ if hasattr(backend, "latest_latency_ms"):
486
+ backend.latest_latency_ms = generation.latency_ms
487
+ if hasattr(backend, "latest_validation_status"):
488
+ backend.latest_validation_status = generation.validation_status
489
+ if hasattr(backend, "latest_fallback_used"):
490
+ backend.latest_fallback_used = generation.fallback_used
491
+ if hasattr(backend, "latest_fallback_reason"):
492
+ backend.latest_fallback_reason = generation.error
493
+
494
+
495
+ def _runtime_status_from_backend(backend: ModelBackend) -> BackendRuntimeStatus:
496
+ return BackendRuntimeStatus(
497
+ backend_name=backend.name,
498
+ model_id=backend.model_id,
499
+ load_status=getattr(backend, "load_status", "loaded"),
500
+ latest_latency_ms=getattr(backend, "latest_latency_ms", None),
501
+ latest_validation_status=getattr(backend, "latest_validation_status", None),
502
+ latest_fallback_used=getattr(backend, "latest_fallback_used", None),
503
+ latest_fallback_reason=getattr(backend, "latest_fallback_reason", None),
504
+ max_new_tokens=getattr(backend, "max_new_tokens", None),
505
+ temperature=getattr(backend, "temperature", None),
506
+ )
507
+
508
+
509
  def _line_for_beat(
510
  session: TheaterSession,
511
  beat_type: str,
puppet_theater/director.py CHANGED
@@ -50,7 +50,7 @@ def run_one_beat(session: TheaterSession | None) -> TheaterSession | None:
50
  "Backend "
51
  f"{backend_generation.backend_name} returned actor output "
52
  f"({backend_generation.validation_status}, fallback={backend_generation.fallback_used}"
53
- f", latency={backend_generation.latency_ms}ms)."
54
  )
55
  if backend_generation.model_id:
56
  session.director_log.append(f"Model id: {backend_generation.model_id}.")
@@ -61,6 +61,7 @@ def run_one_beat(session: TheaterSession | None) -> TheaterSession | None:
61
  "backend_result:"
62
  f"{backend_generation.backend_name}:"
63
  f"model={backend_generation.model_id or 'none'}:"
 
64
  f"fallback={backend_generation.fallback_used}:"
65
  f"validation={backend_generation.validation_status}:"
66
  f"latency_ms={backend_generation.latency_ms}"
 
50
  "Backend "
51
  f"{backend_generation.backend_name} returned actor output "
52
  f"({backend_generation.validation_status}, fallback={backend_generation.fallback_used}"
53
+ f", load_status={backend_generation.load_status}, latency={backend_generation.latency_ms}ms)."
54
  )
55
  if backend_generation.model_id:
56
  session.director_log.append(f"Model id: {backend_generation.model_id}.")
 
61
  "backend_result:"
62
  f"{backend_generation.backend_name}:"
63
  f"model={backend_generation.model_id or 'none'}:"
64
+ f"load_status={backend_generation.load_status}:"
65
  f"fallback={backend_generation.fallback_used}:"
66
  f"validation={backend_generation.validation_status}:"
67
  f"latency_ms={backend_generation.latency_ms}"
puppet_theater/models.py CHANGED
@@ -65,3 +65,5 @@ class TheaterSession:
65
  finale_requested: bool = False
66
  backend_name: str = "deterministic"
67
  backend_model_id: str | None = None
 
 
 
65
  finale_requested: bool = False
66
  backend_name: str = "deterministic"
67
  backend_model_id: str | None = None
68
+ backend_max_new_tokens: int = 80
69
+ backend_temperature: float = 0.8
puppet_theater/session.py CHANGED
@@ -27,7 +27,13 @@ def _setting_from_premise(premise: str) -> str:
27
  return "a pocket-sized improv stage with painted flats and a wobbly spotlight"
28
 
29
 
30
- def create_show_from_premise(premise: str, backend_name: str = "deterministic", backend_model_id: str | None = None) -> TheaterSession:
 
 
 
 
 
 
31
  cleaned_premise = _clean_premise(premise)
32
  show_title = _title_from_premise(cleaned_premise)
33
  setting = _setting_from_premise(cleaned_premise)
@@ -90,4 +96,6 @@ def create_show_from_premise(premise: str, backend_name: str = "deterministic",
90
  finale_requested=False,
91
  backend_name=active_backend,
92
  backend_model_id=backend_model_id,
 
 
93
  )
 
27
  return "a pocket-sized improv stage with painted flats and a wobbly spotlight"
28
 
29
 
30
+ def create_show_from_premise(
31
+ premise: str,
32
+ backend_name: str = "deterministic",
33
+ backend_model_id: str | None = None,
34
+ backend_max_new_tokens: int = 80,
35
+ backend_temperature: float = 0.8,
36
+ ) -> TheaterSession:
37
  cleaned_premise = _clean_premise(premise)
38
  show_title = _title_from_premise(cleaned_premise)
39
  setting = _setting_from_premise(cleaned_premise)
 
96
  finale_requested=False,
97
  backend_name=active_backend,
98
  backend_model_id=backend_model_id,
99
+ backend_max_new_tokens=backend_max_new_tokens,
100
+ backend_temperature=backend_temperature,
101
  )