Skip to content

Latest commit

 

History

History
442 lines (350 loc) · 15.1 KB

File metadata and controls

442 lines (350 loc) · 15.1 KB

Technical Implementation Summary: app.py

Overview

app.py is a Gradio-based web application that provides AI-powered hints for Hitman game walkthroughs. It uses OpenAI's GPT models to process game transcripts and generate contextual, spoiler-free hints for players. The system currently supports 1,034 walkthrough transcripts loaded at startup, covering a comprehensive library of Hitman missions and challenges.


Architecture

Core Technologies

  • Framework: Gradio 3.50.2 (web UI framework)
  • LLM Provider: OpenAI API
  • Language: Python 3.9+
  • State Management: Gradio State with custom ConversationState class

Design Pattern

  • Two-stage conversation flow: Mission selection → Hint generation
  • Stateful chatbot: Maintains conversation context across interactions
  • Lazy loading: Transcripts loaded once at startup, processed on-demand

Key Components

1. Transcript Management

load_transcripts() (Lines 22-48)

  • Purpose: Recursively loads all game walkthrough transcripts from the transcripts/ directory
  • Implementation:
    • Uses Path.rglob("*.txt") for recursive file discovery
    • Filters out files starting with underscore (_)
    • Stores as dict: {filename_stem: file_content}
    • Executes at module load time (line 51)
  • Error Handling: Catches and logs file read errors, continues loading other files

get_all_transcripts() (Lines 53-55)

  • Returns list of available transcript keys for UI display

clean_mission_name() (Lines 57-93)

  • Purpose: Transforms verbose filenames into user-friendly display names
  • Transformations:
    • Removes "HITMAN 2" prefix
    • Strips suffixes: "ChallengeFeat", "Walkthrough", "Feat"
    • Fixes spacing: "AssassinSuit" → "Assassin Suit"
    • Normalizes whitespace
  • Example: "HITMAN 2 Mumbai Memoirs ChallengeFeat Walkthrough""Mumbai Memoirs Challenge"

2. Fuzzy Matching System

find_best_match() (Lines 95-119)

  • Purpose: Matches user input to available transcripts without requiring exact names
  • Algorithm:
    1. Exact substring match: Returns immediately if found (lines 108-109)
    2. Word overlap scoring: Counts common words between input and transcript names
    3. Best match selection: Returns transcript with highest overlap score
  • Input normalization: Case-insensitive, tokenizes on whitespace
  • Threshold: Returns None if no common words found

3. AI Processing Pipeline

chunk_transcript_with_llm() (Lines 129-176)

Purpose: Converts raw walkthrough transcripts into structured, actionable steps

Configuration (Optimized from extensive testing):

  • Model: gpt-4.1-nano-2025-04-14
  • Temperature: 0.3 (deterministic, consistent output)
  • System Prompt: Gameplay extraction expert persona
    • Filters commentary/filler
    • Recognizes Hitman mechanics (disguises, weapons, objectives)
    • Maintains logical progression

User Prompt Strategy:

  • Explicit instructions for segmentation (timestamps, area changes, objective completion)
  • Requests numbered step format: "Step 1: ...", "Step 2: ..."
  • Emphasizes removal of fluff, commentary, jokes

Output: Numbered list of concise gameplay actions

generate_hint() (Lines 178-256)

Purpose: Generates clear, actionable hints that reveal ONE step at a time

Configuration (Optimized from extensive testing):

  • Model: gpt-4.1-mini-2025-04-14
  • Temperature: 0.8 (creative, varied hints)
  • System Prompt: Expert hint system persona
    • Provides clear, actionable hints one step at a time
    • Reveals ONE step from solution without spoiling what comes next
    • Balances concrete guidance with maintaining discovery satisfaction

User Prompt Features:

  • Core Principle: Reveal ONE step at a time, but reveal it clearly
  • Step Analysis: Determines where player is in the solution based on their question
  • Single-Step Revelation:
    • ✅ DO reveal: Specific locations, items, actions for current step
    • ✅ DO use: Concrete nouns, room names, specific disguise types
    • ❌ DON'T reveal: What to do AFTER completing this step
    • ❌ DON'T reveal: Multiple sequential steps
  • Hint Structure: [Direct instruction for ONE step] + [Optional: Why this helps] + [Encouragement]
  • Few-shot examples: Good vs. bad hint demonstrations with multi-step warnings
  • Output Format: 1-3 sentences that reveal exactly ONE step with enough detail to be actionable

Input: Chunked steps, user's question (transcript parameter removed in latest version) Output: Single actionable hint revealing one step (1-3 sentences)


4. State Management

ConversationState Class (Lines 122-127)

Tracks conversation progress through mission selection and hint generation.

Attributes:

  • stage: Current conversation phase ("select_mission" | "ready_for_hints")
  • selected_mission: Transcript key (filename stem)
  • transcript: Full transcript text
  • chunked_steps: LLM-processed step list

Lifecycle:

  1. Initialize → stage="select_mission"
  2. User provides keywords → Fuzzy match → Load transcript
  3. LLM chunks transcript → stage="ready_for_hints"
  4. User asks questions → Generate hints from chunked steps
  5. User types /new → Reset to step 1

respond() Function (Lines 308-328)

Purpose: Bridge between Gradio's dict-based state and ConversationState object

Flow:

  1. Convert incoming state_dict to ConversationState object
  2. Call chatbot_response() with object state
  3. Convert updated state back to dict for Gradio
  4. Return response text and updated state dict

5. Conversation Flow Logic

chatbot_response() (Lines 258-306)

Purpose: Core chatbot logic handling the two-stage conversation flow

Stage 1: Mission Selection (Lines 261-289)

  • Calls find_best_match() with user input
  • If match found:
    • Load transcript and update state
    • Call chunk_transcript_with_llm() to process
    • Display cleaned mission name with clean_mission_name()
    • Transition to "ready_for_hints" stage
  • If no match:
    • Display error message
    • List available missions (cleaned names)

Stage 2: Hint Generation (Lines 291-304)

  • Special command: /new resets to mission selection
  • Normal flow:
    • Pass user question + chunked steps to generate_hint() (transcript no longer passed)
    • Return hint to user
    • Maintain "ready_for_hints" stage for follow-up questions

6. Gradio UI Layer

Interface Configuration (Lines 330-438)

Theme: Red primary hue (gr.themes.Base(primary_hue="red"))

Components:

  1. Header Markdown (Lines 332-340): Title and instructions
  2. State Container (Lines 342-347): Persists conversation state across interactions
  3. Chatbot Display (Lines 369-372): Chat history with welcome message
  4. Input Row (Lines 374-381):
    • Text input with placeholder (scale=4)
    • Submit button (primary variant, scale=1)
    • Clear button (scale=1) - clears both message box and chatbot history
  5. Examples Component (Lines 383-393): Clickable example messages
    • Mission examples: "Mumbai Memoirs", "Dubai Silent Assassin Suit Only"
    • Question examples: "How do I start?", "Where can I find a disguise?", "I'm at the beach, what should I do?"
  6. Tips Markdown (Lines 395-405): Usage instructions

Event Handlers (Lines 407-429)

user_send() (Lines 407-409):

  • Clears input box
  • Appends user message to chat history with placeholder None for bot response
  • Returns updated history

bot_respond() (Lines 411-416):

  • Extracts latest user message
  • Calls respond() to get bot response
  • Updates placeholder with actual response
  • Returns updated history and state

reset_chat() (Lines 418-424):

  • Resets chatbot to welcome message
  • Clears conversation state (stage, mission, transcript, chunked steps)
  • Returns user to initial "select_mission" stage
  • Triggered by Clear button click

Event Chaining:

  • msg.submituser_sendbot_respond
  • submit.clickuser_sendbot_respond
  • clear.clickreset_chat
  • Uses Gradio's .then() for sequential execution

Data Flow

Complete User Interaction Flow

1. User opens app
   ↓
2. Gradio loads → load_transcripts() → TRANSCRIPTS dict populated
   ↓
3. UI displays welcome message with available missions
   ↓
4. User types mission keywords (e.g., "Mumbai Memoirs")
   ↓
5. user_send() → Adds message to chat history
   ↓
6. bot_respond() → respond() → chatbot_response()
   ↓
7. find_best_match() → Returns "HITMAN 2 Mumbai Memoirs ChallengeFeat Walkthrough"
   ↓
8. Load transcript from TRANSCRIPTS dict
   ↓
9. chunk_transcript_with_llm() → OpenAI API call
   ↓
10. Display cleaned name: "Mumbai Memoirs Challenge"
    ↓
11. State transitions to "ready_for_hints"
    ↓
12. User asks: "How do I start?"
    ↓
13. generate_hint() → OpenAI API call with chunked steps + question (no transcript)
    ↓
14. Display clear, actionable hint revealing ONE step
    ↓
15. Loop: User asks more questions → More hints generated
    ↓
16. User types "/new" → Reset to step 4

API Integration

OpenAI Client (Line 17)

  • Initialized with environment variable: OPENAI_API_KEY
  • Reused across all LLM calls (chunking + hint generation)

API Call Pattern

response = client.chat.completions.create(
    model="<model-name>",
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt}
    ],
    temperature=<temp-value>
)
return response.choices[0].message.content

Error Handling

  • Try-except blocks around all API calls
  • Returns error messages to user
  • Suggests checking OPENAI_API_KEY for chunking errors

Optimization Decisions

Model Selection (Based on Testing)

  1. Chunking: gpt-4.1-nano @ temp 0.3

    • Cost-effective for structured extraction
    • Low temperature ensures consistency
  2. Hints: gpt-4.1-mini @ temp 0.8

    • Better reasoning for contextual hints
    • Higher temperature adds variety
    • Capable of analyzing player position in solution

Hint Philosophy Evolution

  • Previous approach: Vague, directional hints that avoided specifics
  • Current approach: Clear, actionable hints that reveal ONE step at a time
  • Key insight: Players need specific guidance for the current step, but not future steps
  • Result: Hints are helpful enough to make progress, but don't spoil the solution path

Performance Considerations

  • One-time transcript loading: All 1,034 files loaded at startup, not per-request
    • Average startup time: ~2-3 seconds for full transcript library
    • Stored in memory for instant fuzzy matching
  • Chunking once per mission: Results cached in state, reused for all hints
  • Fuzzy matching: O(n) string operations over 1,034 transcripts, no external dependencies
    • Fast execution due to simple word overlap algorithm
  • Minimal API calls: Only on mission selection (chunking) and hint requests
  • UI Examples: Pre-populated examples reduce user typing and improve UX

Security & Configuration

Environment Variables

  • OPENAI_API_KEY: Required for LLM functionality
  • Read via os.environ.get() with empty string fallback

File System Access

  • Read-only access to transcripts/ directory
  • No user file uploads or writes
  • UTF-8 encoding for international character support

Entry Point

Launch Configuration (Lines 437-438)

if __name__ == "__main__":
    demo.launch(share=True)
  • share=True: Creates public Gradio link (tunneling)
  • Enables external access without deployment
  • Alternative: share=False for localhost-only access

Code Style & Documentation

Comments

  • Function-level documentation using # comments (not docstrings)
  • Inline comments for complex logic
  • Configuration details documented at function level

String Conventions

  • Multi-line strings (""") reserved for:
    • LLM prompts (actual data sent to API)
    • Gradio Markdown content (UI text)
  • Single-line comments (#) for all documentation
  • Important: Triple quotes inside f-strings must be escaped (\"\"\") to avoid premature string closure
    • Example: f"""Prompt with \"\"\" {variable} \"\"\" inside"""

Dependencies

Core Requirements

gradio==3.50.2
openai (latest compatible with Python 3.9)
pathlib (built-in)
re (built-in)
os (built-in)

Python Version

  • Target: Python 3.9+
  • Compatible with macOS/Linux/Windows

UI/UX Enhancements

Clear Button Feature

  • Purpose: Allows users to reset conversation and start fresh
  • Functionality: Clears both chat history and conversation state
  • Implementation: gr.ClearButton component + custom reset_chat() handler
  • Benefits:
    • No page refresh needed
    • Instant reset to welcome screen
    • Preserves transcript library in memory

Examples Component

  • Purpose: Guide users with clickable example inputs
  • Implementation: gr.Examples component with 5 pre-populated examples
  • Benefits:
    • Reduces friction for first-time users
    • Shows expected input formats
    • Demonstrates both mission selection and hint-asking patterns
  • Examples Provided:
    • Mission selection: "Mumbai Memoirs", "Dubai Silent Assassin Suit Only"
    • Hint questions: "How do I start?", "Where can I find a disguise?", "I'm at the beach, what should I do?"

Extensibility Points

Easy to Extend

  1. Add new transcripts: Drop .txt files in transcripts/ folder (system handles 1,000+ files efficiently)
  2. Modify prompts: Edit system/user prompts in chunking/hint functions
  3. Adjust hint style: Change temperature or model configuration
  4. UI customization: Modify Gradio theme or add components
  5. Update examples: Edit the examples list in the gr.Examples component

Requires Code Changes

  1. Different LLM provider: Replace OpenAI client with alternative API
  2. Multi-language support: Add translation layer
  3. User accounts: Integrate authentication system
  4. Persistent history: Add database for conversation storage
  5. Advanced filtering: Add transcript categorization by game version or difficulty

Testing & Validation

Optimization Process

  • Extensive testing documented in lines 3-9
  • Compared multiple models: gpt-4.1-nano, gpt-4.1-mini, gpt-5-nano
  • Tested system prompts (3 variations)
  • Tested user prompts (3 variations)
  • Temperature tuning (6 values: 0.3, 0.5, 0.7, 0.8, 1.0, 1.2)
  • Iterative refinement of hint generation approach (vague → one-step-at-a-time)

Companion Scripts

  • model_comparison.py: Model/prompt testing
  • temperature_comparison.py: Temperature optimization

Summary Statistics

  • Total Lines: 438
  • Functions: 9 (including reset_chat())
  • Classes: 1 (ConversationState)
  • API Calls: 2 types (chunking + hints)
  • Conversation Stages: 2 (select_mission, ready_for_hints)
  • UI Components: 7
    • Markdown header
    • Chatbot display
    • Textbox (message input)
    • Submit button
    • Clear button (new!)
    • Examples component (new!)
    • Tips markdown
  • Special Commands: 1 (/new to reset mission selection)
  • Available Transcripts: 1,034 Hitman walkthrough files loaded at startup