Skip to content

Add Treasure Hunt #262

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 9, 2024
Merged
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
24 changes: 24 additions & 0 deletions examples/treasure-hunt/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Use the official Python image as the base image
FROM python:3.9-slim

# Set the working directory
WORKDIR /app

# Copy the requirements file
COPY requirements.txt .

# Install the Python dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Flask app code
COPY . .

# Expose the port
EXPOSE 5000

# Set the environment variable
ENV FLASK_APP=app.py
ENV FLASK_DEBUG=False # Set this to True/False to enable/disable debugging.

# Run app
CMD ["flask", "run", "--host=0.0.0.0"]
46 changes: 46 additions & 0 deletions examples/treasure-hunt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Treasure Hunt

## Overview

This Flask application leverages GPTScript to generate clues for a real world treasure hunt game. The user needs to provide a list of locations within a city and the application will generate fun and interesting clues for them.

## Installation

### Prerequisites

- Python 3.8 or later
- Node.js and npm
- Flask
- Other Python and Node.js dependencies listed in `requirements.txt` and `package.json` respectively.

### Steps

1. Clone the repository:

``` bash
git clone https://github.com/gptscript-ai/gptscript.git
```

2. Navigate to the `examples/treasure-hunt` directory and install the dependencies:

Python:

```bash
pip install -r requirements.txt
```

Node:

```bash
npm install
```

3. Setup `OPENAI_API_KEY` (Eg: `export OPENAI_API_KEY="yourapikey123456"`). You can get your [API key here](https://platform.openai.com/api-keys).

4. Run the Flask application using `flask run` or `python app.py`

## Usage

1. Open your web browser and navigate to `http://127.0.0.1:5000/`.
2. Use the interface to provide a comma-separated list of locations within a city. For eg: Statue of Liberty, Hudson Yards, Central Park, Grand Central Station.
3. The application will generate fun and witty clues for all these locations.
51 changes: 51 additions & 0 deletions examples/treasure-hunt/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from gptscript.command import stream_exec_file
from flask import Flask, render_template, request, jsonify
import os
import uuid

app = Flask(__name__)

# Setting the base directory
base_dir = os.path.dirname(os.path.abspath(__file__))
app.config['PWD'] = base_dir
SCRIPT_PATH = os.path.join(base_dir, 'treasure-hunt.gpt')

def print_output(out, err):
# Error stream has the debug info that is useful to see
for line in err:
print(line)
for line in out:
print(line)

@app.route('/')
def index():
return render_template('index.html')

@app.route('/get-clues', methods=['POST'])
def get_clues():
try:
code = request.json['code']

# Generate a unique request ID
request_id = str(uuid.uuid4())

# Generate an output file name based on the request ID
output_file_name = f"{request_id}_treasure-hunt.md"
output_file_path = os.path.join(app.config['PWD'], output_file_name)

# Execute the script to generate the clues
out, err, wait = stream_exec_file(SCRIPT_PATH, "--locations " + code + " --outputfile "+output_file_name)
print_output(out, err)
wait()

# Read the output file
with open(output_file_path, 'r') as output_file:
summary = output_file.read()

# Return clues
return summary
except Exception as e:
return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG', True), host='0.0.0.0')
5 changes: 5 additions & 0 deletions examples/treasure-hunt/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"marked": "^12.0.1"
}
}
3 changes: 3 additions & 0 deletions examples/treasure-hunt/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Flask==2.0.1
gptscript==0.4.1
Werkzeug==2.2.2
46 changes: 46 additions & 0 deletions examples/treasure-hunt/static/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* style.css */
body {
background-color: #f5f5f5;
font-family: 'Roboto', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}

.container {
max-width: 500px;
width: 60%;
padding: 0 10px;
}

.input, .button {
border-radius: 0 !important;
}

.box {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
border-radius: 0;
padding: 30px;
}

.markdown-body {
box-sizing: border-box;
background-color: #f5f5f5;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
border-radius: 0;
padding: 30px;
}

.gpt-logo {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.gpt-logo img {
width: 15%;
height: 15%;
}
50 changes: 50 additions & 0 deletions examples/treasure-hunt/static/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// app.js
new Vue({
el: '#app',
data: {
code: '',
showClues: false,
cluesMarkdown: '',
renderedMarkdown: '',
isLoading: false
},
methods: {
getClues() {
this.isLoading = true;
axios.post('/get-clues', { code: this.code })
.then(response => {
this.cluesMarkdown = response.data;
this.renderedMarkdown = marked.parse(this.cluesMarkdown)
this.showClues = true;
})
.catch(error => {
if (error.response && error.response.data && error.response.data.error) {
alert('Error: ' + error.response.data.error);
} else {
alert('An unexpected error occurred. Please try again later.');
}
})
.finally(() => {
this.isLoading = false;
});
}
}
});

// Initialize the marked library
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function(code, language) {
const hljs = require('highlight.js');
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';
return hljs.highlight(validLanguage, code).value;
},
pedantic: false,
gfm: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
});

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions examples/treasure-hunt/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Treasure Hunt</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div id="app" class="container is-fluid">
<section class="hero is-primary is-medium is-bold" style="background-image: linear-gradient(to right, #140aa2, #b91b0d);">
<div class="hero-body">
<h1 class="title">Treasure Hunt</h1>
<h2 class="subtitle">How about a real treasure hunt experience? Enter locations for which you want the clues and get hunting!</h2>
</div>
</section>

<div class="box">
<div class="field">
<label class="label">Locations</label>
<div class="control">
<input class="input is-focused" type="text" placeholder="Central Park, Hudson Yards, Times Square..." v-model="code">
</div>
</div>
<button class="button is-primary is-medium" style="background-color: #140aa2;" @click="getClues" :disabled="isLoading">
<span v-if="isLoading" class="icon is-medium">
<i class="fas fa-spinner fa-spin"></i>
</span>
<span v-else>Get Clues</span>
</button>
</div>

<div class="box markdown-body" v-if="showClues" v-html="renderedMarkdown"></div>
<div class="gpt-logo"><a href="https://gptscript.ai" target="_blank"><img src="{{url_for('static', filename='made-with-gptscript.png')}}"/></a></div>
</div>

<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<script defer src="https://use.fontawesome.com/releases/v5.15.4/js/all.js"></script>
</body>
</html>
27 changes: 27 additions & 0 deletions examples/treasure-hunt/treasure-hunt.gpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
tools: sys.find, sys.read, sys.write, search
args: locations: List of locations
args: outputfile: Name of the output file.

You are an expert in generating treasure hunt clues. You have to create a list of clues for an amazing race-type game in which people go on a scavenger hunt across a city, hopping from one spot to the other.

Do the following things in order without showing, using, or writing the location provided by the user:

1. Generate a clue in the format "Your next location is a/the..." without including the location's name or address. Try to use interesting trivia, facts, historical information, noteworthy personalities, or events that took place at that location.
2. For the first clue, start with "Your journey starts with/Your first location is..."
3. Be witty or funny when you give a clue, and ensure it has at least three hints for every location to help the user.
4. The clue should also lead the user to the next location, with fun trivia, suggested modes of transport, and the distance.
5. For the last clue, mention that it's the final one and that the user will find their final reward here.
6. Do not show, write, or display the name of the specific location or the word "clue" anywhere in the output.
7. Create a new md file named $(outputfile) with all the clues in order of the locations provided, along with a short welcome note to the player welcoming them to the city. Mention the name of the city where these locations are before listing the clues.
8. Beautify the md file neatly with logical line breaks, paragraphs, bold, and italics. For each clue, use a bold subheading with a witty one-liner related to that clue without mentioning the location.


---
name: search
description: Searches the internet for content
args: query: The query to search for
tools: sys.http.html2text?

1. For each of the location in $(locations), open Google Maps at the URL: "https://www.google.com/maps/search/?api=1&query=${locations}".
2. Find the shortest route between the locations provided based on the order of places provided.
3. Return the best mode of transport to reach from one location to another for each location in the order provided.