Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/smart-npc/.gcloudignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Python Environment
.venv/
__pycache__/
run.log

# NodeJS
node_modules/

# Dev
test/
25 changes: 25 additions & 0 deletions examples/smart-npc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Secrets
config-secret.toml

# Terraform
.terraform
terraform.tfstate
terraform.tfstate.backup
variables.tfvars

# Python Environment
.venv/
__pycache__/
run.log

# NodeJS
node_modules/

# Smart NPC
# the following files is generated by Terraform.
**/config.yaml.template
**/config.yaml
**/config.toml
test/
k8s.yaml
skaffold.yaml
28 changes: 28 additions & 0 deletions examples/smart-npc/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM python:3.11-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True

WORKDIR /app

COPY src /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY ./config.toml /app/

EXPOSE 8080

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
56 changes: 56 additions & 0 deletions examples/smart-npc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

# Smart NPC

The Smart NPC demonstrates using Gemini-1.5-Flash to
generate NPC dialogues while maintaining the character personality,
storyline and scene settings thorughout the conversation.

Players are expected to achieve an objective of the scene, Gemini simulate
involving NPCs to respond to the player while implicitly guiding the player
toward the objective.

## Baseball simulation demo game

This example using the concept of LLM powered Smart NPC in a baseball simulation game,
where the player plays the coach of a baseball team. The `NPC` which powered by the LLM
provides tactics suggestions to the player.

## Applicaiton Flow

[Smart NPC API flow](./docs/0-SmartNPC-API-Flow.md)

[Game flow](./docs/1-Game-Flow.md)

## Database Tables

[Database Tables](./docs/3-Database.md)

## Configurations

* [config.app.toml.template](./config.app.toml.template) contains the SQL queries for
game logics in the `baseball` section.

It also holds SQL queries for the framework itself in `sql` section.

* [const.py](./src/utils/const.py) determines if the game uses Google for Games Quick Start
as the LLM backend. Update the `USE_QUICK_START` to `False` to invoke Gemini 2.0 API directly.

## Deploy the Application

* Deploy the application

```
cd $CUR_DIR/examples/smart-npc

export PROJECT_ID=$(gcloud config list --format 'value(core.project)' 2>/dev/null)

find . -type f -name "*.template.yaml" -exec \
bash -c "template_path={}; sed \"s:your-unique-project-id:${PROJECT_ID:?}:g\" < \${template_path} > \${template_path/%.template.yaml/.yaml} " \;

skaffold run
```

* Create database and ingest data

Use your PostgreSQL client of choice, execute [SQL scripts](./example/baseball/sql/) to create
database tables and insert data to the tables.
189 changes: 189 additions & 0 deletions examples/smart-npc/config.app.toml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@

[game]
game_id = "baseball"
enable_validator = "False"

[npc]
RESPONSE_LANGUAGE = "en-US"

[sql]
QUERY_SCENE = """
select scene_id, scene, status, goal, npcs, knowledge, game_id from smartnpc.scene
where scene_id=:scene_id and game_id=:game_id
"""

QUERY_NPC_BY_ID = """
select npc_id, game_id, background, name, class, class_level, status, lore_level from smartnpc.npc
where npc_id=:npc_id and game_id=:game_id
"""

QUERY_NPC_KNOWLEDGE = """
select background_id,
background_name,
content,
lore_level,
background,
(1 - (background_embeddings <=> :query_embeddings)) as score
from games.world_background
where lore_level <= :lore_level
order by score desc
limit 5
"""

QUERY_SEARCH_QUESTS_ALL = """
select
game_id,
quest_id,
quest_story,
min_level,
metadata,
quest_name,
provider_id
from games.quests
where provider_id = :provider_id and game_id=:game_id
limit 5
"""

QUERY_SEARCH_QUESTS = """
select
game_id,
quest_id,
quest_story,
min_level,
metadata,
quest_name,
provider_id,
(1 - (quest_embeddings <=> :query_embeddings)) as score
from games.quests
where provider_id = :provider_id and game_id=:game_id
order by (1 - (quest_embeddings <=> :query_embeddings)) desc
limit 5
"""

QUERY_PROMPT_TEMPLATE = """

SELECT prompt_id,
scene_id,
game_id,
prompt_template,
is_activate
FROM smartnpc.prompt_template
WHERE
is_activate = True and
prompt_id=:prompt_id and
game_id=:game_id and
CASE
WHEN scene_id = :scene_id THEN scene_id
ELSE 'default'
END = scene_id;
"""

QUERY_CONV_EXAMPLE = """
select
example_id,
game_id,
scene_id,
conversation_example,
is_activate
from smartnpc.conversation_examples
where
game_id=:game_id and
CASE
WHEN scene_id = :scene_id THEN scene_id
ELSE 'default'
END = scene_id
and
CASE
WHEN example_id = :example_id THEN example_id
ELSE 'default'
END = example_id;

"""

[baseball]
QUERY_TEAM = """
select team_id,
team_name,
team_year,
description,
roster,
default_lineup
from smartnpc.teams
where team_id=:team_id
"""

QUERY_TEAMS = """
select team_id,
team_name,
team_year,
description,
roster,
default_lineup
from smartnpc.teams
"""

QUERY_TEAM_ROSTER = """
select team_id,
session_id,
player_id,
roster
from smartnpc.rosters
where
team_id=:team_id And
session_id=:session_id And
player_id=:player_id
"""

QUERY_TEAM_LINEUP = """
select
team_id,
player_id,
session_id,
lineup
from smartnpc.lineup
where
team_id=:team_id And
session_id=:session_id And
player_id=:player_id
"""

UPSERT_TEAM_LINEUP = """
INSERT INTO smartnpc.lineup(
team_id,
player_id,
session_id,
lineup
)
values(
:team_id,
:player_id,
:session_id,
:lineup
)
ON CONFLICT(team_id, player_id)
DO UPDATE SET
session_id = :session_id,
lineup = :lineup;
"""


UPSERT_TEAM_ROSTER = """
INSERT INTO smartnpc.rosters(
team_id,
session_id,
player_id,
roster
)
values(
:team_id,
:session_id,
:player_id,
:roster
)
ON CONFLICT(team_id, session_id)
DO UPDATE SET
player_id = :player_id,
team_id=:team_id,
session_id=:session_id,
roster = :roster;
"""
13 changes: 13 additions & 0 deletions examples/smart-npc/config.gcp.toml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
["gcp"]
database_private_ip_address=""
database_public_ip_address=""
postgres_instance_connection_name=""
database_user_name="llmuser"
database_password_key="pgvector-password"
image_upload_gcs_bucket=""
google-project-id=""
cache-server-host = ""
cache-server-port = 6379
use-cache-server = "True" # "False" if running locally
google-default-region = "us-central1"
api-key = ""
Loading