Hermes Bot commited on
Commit
f5ed009
·
unverified ·
2 Parent(s): 1420fd31a9d5be

Merge branch 'develop'

Browse files

# Conflicts:
# shared/inference_client.py

projects/tinybard/app.py CHANGED
@@ -191,9 +191,12 @@ def generate_procedural_step(genre: str, step: int, health: int, choice: str = "
191
  def _parse_messages(genre: str, history: List[Dict[str, str]], next_instruction: str) -> list[Dict[str, str]]:
192
  """Translate internal history into OpenAI-style chat messages."""
193
  system = (
194
- "You are the narrator of an interactive text adventure game. "
 
195
  f"Genre: {genre}. Write in the second person ('You...'). "
196
- "Keep descriptions highly atmospheric but short (under 3 sentences). "
 
 
197
  "Focus on action, mystery, and choice. Do not offer numbered choices unless asked."
198
  )
199
  msgs: List[Dict[str, str]] = [{"role": "system", "content": system}]
@@ -213,9 +216,8 @@ def generate_llm_story(
213
  max_tokens: int = 180,
214
  ) -> str:
215
  """Generate story text via HF Inference API (with cooldown)."""
216
- if cooldown_active("tinybard"):
217
- log.info("tinybard inference skipped (cooldown active)")
218
- return ""
219
  try:
220
  msgs = _parse_messages(genre, history, next_instruction)
221
  result = inference_generate(
@@ -226,7 +228,6 @@ def generate_llm_story(
226
  )
227
  return result.text
228
  except RuntimeError:
229
- # Cooldown — let caller fall back
230
  return ""
231
  except Exception as e:
232
  log.warning(f"HF Inference error (fallback to procedural): {e}")
@@ -235,8 +236,9 @@ def generate_llm_story(
235
 
236
  def generate_llm_choices(genre: str, story_context: str) -> List[str]:
237
  """Ask the LLM to produce 3 short distinct choices for the player."""
238
- if cooldown_active("tinybard"):
239
- return []
 
240
  system = (
241
  "You generate 3 short, distinct player choices for an interactive text adventure. "
242
  "Output exactly in the format: 1. <choice> | 2. <choice> | 3. <choice>"
@@ -806,27 +808,12 @@ def create_gradio_app() -> gr.Blocks:
806
  story, choices, h, s, go, hist = api_start_game(genre)
807
  return story, choices, h, s, go, hist, "", gr.update(choices=choices or [], value=None)
808
 
809
- # API endpoints (preserved for MCP)
810
- start_btn.click(
811
- fn=api_start_game,
812
- inputs=[genre_input],
813
- outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output],
814
- api_name="start_game",
815
- )
816
-
817
  # UI start game button: also updates choices radio and clears text
818
  start_btn.click(
819
  fn=handle_start_game,
820
  inputs=[genre_input],
821
  outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output, choice_text_input, choice_radio],
822
- )
823
-
824
- # API make_choice endpoint (preserved for MCP)
825
- choice_btn.click(
826
- fn=api_make_choice,
827
- inputs=[choice_text_input, genre_input, step_input, health_input, history_input],
828
- outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output],
829
- api_name="make_choice",
830
  )
831
 
832
  # UI make choice button: resolves radio/text, updates choices radio
@@ -834,6 +821,7 @@ def create_gradio_app() -> gr.Blocks:
834
  fn=handle_make_choice,
835
  inputs=[choice_text_input, choice_radio, genre_input, step_input, health_input, history_input],
836
  outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output, choice_text_input, choice_radio],
 
837
  )
838
 
839
  # Save game handler
@@ -961,14 +949,7 @@ def _run_turn(choice: str, genre: str, step: int, health: int, history: List[Dic
961
  Returns a dict the frontend can consume directly. Used by both the
962
  FastAPI /api/game/* endpoints and the Gradio MCP tools.
963
  """
964
- # Cooldown short-circuit: if active, the game just uses the procedural
965
- # engine for this turn. This protects your HF/Modal credit budget.
966
- in_cooldown = cooldown_active("tinybard")
967
-
968
  if step == 0:
969
- # New game
970
- if in_cooldown:
971
- return generate_procedural_step(genre, 0, 100)
972
  instruction = "Narrate the beginning of the adventure. What happens first? Do not offer choices yet."
973
  story = generate_llm_story(genre, [], instruction)
974
  if not story:
@@ -983,10 +964,6 @@ def _run_turn(choice: str, genre: str, step: int, health: int, history: List[Dic
983
  "genre": genre,
984
  }
985
 
986
- # Subsequent turn
987
- if in_cooldown:
988
- return generate_procedural_step(genre, step, health, choice)
989
-
990
  history.append({"role": "player", "text": choice})
991
  health_delta = random.choice([-15, 0, 10])
992
  new_health = max(0, min(100, health + health_delta))
 
191
  def _parse_messages(genre: str, history: List[Dict[str, str]], next_instruction: str) -> list[Dict[str, str]]:
192
  """Translate internal history into OpenAI-style chat messages."""
193
  system = (
194
+ "You are Nanaboozhoo, the trickster storyteller of Anishinaabe tradition. "
195
+ "You spin interactive text adventures with wit, mischief, and wonder. "
196
  f"Genre: {genre}. Write in the second person ('You...'). "
197
+ "Keep descriptions atmospheric but concise (2-3 sentences). "
198
+ "Be unpredictable — every story beat should surprise. "
199
+ "Never repeat the same scene twice. "
200
  "Focus on action, mystery, and choice. Do not offer numbered choices unless asked."
201
  )
202
  msgs: List[Dict[str, str]] = [{"role": "system", "content": system}]
 
216
  max_tokens: int = 180,
217
  ) -> str:
218
  """Generate story text via HF Inference API (with cooldown)."""
219
+ from shared.inference_client import force_clear_cooldown
220
+ force_clear_cooldown("tinybard")
 
221
  try:
222
  msgs = _parse_messages(genre, history, next_instruction)
223
  result = inference_generate(
 
228
  )
229
  return result.text
230
  except RuntimeError:
 
231
  return ""
232
  except Exception as e:
233
  log.warning(f"HF Inference error (fallback to procedural): {e}")
 
236
 
237
  def generate_llm_choices(genre: str, story_context: str) -> List[str]:
238
  """Ask the LLM to produce 3 short distinct choices for the player."""
239
+ # Always clear cooldown for choices — they follow a story call in the same turn
240
+ from shared.inference_client import force_clear_cooldown
241
+ force_clear_cooldown("tinybard")
242
  system = (
243
  "You generate 3 short, distinct player choices for an interactive text adventure. "
244
  "Output exactly in the format: 1. <choice> | 2. <choice> | 3. <choice>"
 
808
  story, choices, h, s, go, hist = api_start_game(genre)
809
  return story, choices, h, s, go, hist, "", gr.update(choices=choices or [], value=None)
810
 
 
 
 
 
 
 
 
 
811
  # UI start game button: also updates choices radio and clears text
812
  start_btn.click(
813
  fn=handle_start_game,
814
  inputs=[genre_input],
815
  outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output, choice_text_input, choice_radio],
816
+ api_name="start_game",
 
 
 
 
 
 
 
817
  )
818
 
819
  # UI make choice button: resolves radio/text, updates choices radio
 
821
  fn=handle_make_choice,
822
  inputs=[choice_text_input, choice_radio, genre_input, step_input, health_input, history_input],
823
  outputs=[story_output, choices_output, health_output, step_output, game_over_output, history_output, choice_text_input, choice_radio],
824
+ api_name="make_choice",
825
  )
826
 
827
  # Save game handler
 
949
  Returns a dict the frontend can consume directly. Used by both the
950
  FastAPI /api/game/* endpoints and the Gradio MCP tools.
951
  """
 
 
 
 
952
  if step == 0:
 
 
 
953
  instruction = "Narrate the beginning of the adventure. What happens first? Do not offer choices yet."
954
  story = generate_llm_story(genre, [], instruction)
955
  if not story:
 
964
  "genre": genre,
965
  }
966
 
 
 
 
 
967
  history.append({"role": "player", "text": choice})
968
  health_delta = random.choice([-15, 0, 10])
969
  new_health = max(0, min(100, health + health_delta))
shared/inference_client.py CHANGED
@@ -34,9 +34,9 @@ INFERENCE_MODEL = os.environ.get(
34
  "meta-llama/Llama-3.2-1B-Instruct", # 1B, free-tier, great prose
35
  )
36
 
37
- # Provider: "hf-inference" (free serverless), "together", "fal-ai", "replicate"
38
  # Free HF inference works for many small models; otherwise use a paid provider.
39
- INFERENCE_PROVIDER = os.environ.get("INFERENCE_PROVIDER", None)
40
 
41
  # Token — read from HF Space secrets at runtime.
42
  HF_TOKEN = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACEHUB_API_TOKEN")
 
34
  "meta-llama/Llama-3.2-1B-Instruct", # 1B, free-tier, great prose
35
  )
36
 
37
+ # Provider: "featherless-ai" (supports small instruct models), "hf-inference" (free serverless), "together", "fal-ai", "replicate"
38
  # Free HF inference works for many small models; otherwise use a paid provider.
39
+ INFERENCE_PROVIDER = os.environ.get("INFERENCE_PROVIDER", "featherless-ai")
40
 
41
  # Token — read from HF Space secrets at runtime.
42
  HF_TOKEN = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACEHUB_API_TOKEN")