diff --git a/examples/treasure-hunt/Dockerfile b/examples/treasure-hunt/Dockerfile new file mode 100644 index 00000000..c20b1310 --- /dev/null +++ b/examples/treasure-hunt/Dockerfile @@ -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"] diff --git a/examples/treasure-hunt/README.md b/examples/treasure-hunt/README.md new file mode 100644 index 00000000..129698ed --- /dev/null +++ b/examples/treasure-hunt/README.md @@ -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. diff --git a/examples/treasure-hunt/app.py b/examples/treasure-hunt/app.py new file mode 100644 index 00000000..edad495d --- /dev/null +++ b/examples/treasure-hunt/app.py @@ -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') diff --git a/examples/treasure-hunt/package.json b/examples/treasure-hunt/package.json new file mode 100644 index 00000000..0774935a --- /dev/null +++ b/examples/treasure-hunt/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "marked": "^12.0.1" + } +} diff --git a/examples/treasure-hunt/requirements.txt b/examples/treasure-hunt/requirements.txt new file mode 100644 index 00000000..22a041a0 --- /dev/null +++ b/examples/treasure-hunt/requirements.txt @@ -0,0 +1,3 @@ +Flask==2.0.1 +gptscript==0.4.1 +Werkzeug==2.2.2 diff --git a/examples/treasure-hunt/static/css/style.css b/examples/treasure-hunt/static/css/style.css new file mode 100644 index 00000000..089f2e1c --- /dev/null +++ b/examples/treasure-hunt/static/css/style.css @@ -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%; +} diff --git a/examples/treasure-hunt/static/js/app.js b/examples/treasure-hunt/static/js/app.js new file mode 100644 index 00000000..1b3b78d5 --- /dev/null +++ b/examples/treasure-hunt/static/js/app.js @@ -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 +}); + diff --git a/examples/treasure-hunt/static/made-with-gptscript.png b/examples/treasure-hunt/static/made-with-gptscript.png new file mode 100644 index 00000000..01fbff4c Binary files /dev/null and b/examples/treasure-hunt/static/made-with-gptscript.png differ diff --git a/examples/treasure-hunt/templates/index.html b/examples/treasure-hunt/templates/index.html new file mode 100644 index 00000000..9544c085 --- /dev/null +++ b/examples/treasure-hunt/templates/index.html @@ -0,0 +1,44 @@ + + + +
+