Skip to content

Commit

Permalink
Merge branch 'release/2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
megastruktur committed May 17, 2023
2 parents ea00ff7 + 4f1c676 commit 4483d8f
Show file tree
Hide file tree
Showing 16 changed files with 494 additions and 149 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
releases
5 changes: 5 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
2.0
- Global refactoring
- Adds a new "Dummy" GPT provider with test data instead of a checkbox.
- Adds support for other languages generated by the GPT provider.

1.0
- The module is born.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The Place is created as Journal entry by default but additionally can be added a
## Installation

### ChatGPT
0. Make sure to get familiar with their pricing first at https://openai.com/api/pricing/
1. Install and enable the module
2. Create account at openai.com (or use an existing one)
3. Go to https://platform.openai.com/account/api-keys and create a new API key
Expand Down
12 changes: 11 additions & 1 deletion ai-classes/ai-manager.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { ChatGPT } from "./chatgpt.js";
import {Dummy} from "./dummy.js";
import {ChatGPTTD} from "./chatgpt-temporary-demo.js";

export const ai_providers = {
0: {
"name": "chatgpt",
"class": ChatGPT,
}
},
1: {
"name": "dummy",
"class": Dummy,
},
2: {
"name": "chatgpt-temporary-demo",
"class": ChatGPTTD,
},
}

export class AiManager {
Expand Down
68 changes: 68 additions & 0 deletions ai-classes/chatgpt-temporary-demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
export class ChatGPTTD {

get name() {
return 'ChatGPT Temporary Demo';
}

/**
* Get a response from ChatGPT
* @param prompt
* @param full_or_sections
* @returns {Promise<any|null>}
*/
async getCompletion(prompt, full_or_sections = "section") {

if (!game.settings.get('place-gpt', 'openaiAPIToken')) {
ui.notifications.error(game.i18n.localize('place-gpt.error.no_api_token'));
return null;
}

const apiUrl = 'https://api.openai.com/v1/chat/completions';

let full_or_sections_prompt = game.i18n.localize("place-gpt.prompt_section");
if (full_or_sections === "full") {
full_or_sections_prompt = game.i18n.localize("place-gpt.prompt_full")
}

const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer OPENAITEMPDEMO'
};

const body = {
'model': 'gpt-3.5-turbo-0301',
'temperature': 0.2,
'messages': [
{'role': 'system', 'content': full_or_sections_prompt},
{'role': 'system', 'content': "Answer in the language of user request but keep the JSON valid."},
{'role': 'user', 'content': prompt}
]
};

const requestOptions = {
method: 'POST',
headers: headers,
body: JSON.stringify(body)
};

try {
// @todo add different http error handling e.g. 429 is out of credits.
const response = await fetch(apiUrl, requestOptions);
const data = await response.json();

// Retrieve the assistant's reply from the API response
// Try to decode JSON (if the response is JSON)
try {
return JSON.parse(data.choices[0].message.content);
}
catch {
// If the response is not JSON, return the raw string
return null;
}
} catch (error) {
console.error('Error:', error);
// Handle error
return null;
}
}
}
23 changes: 13 additions & 10 deletions ai-classes/chatgpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,30 @@ Hooks.on('init', () => {

export class ChatGPT {

get name() {
return 'ChatGPT';
}

/**
* Get a response from ChatGPT
* @param prompt
* @param full_or_sections
* @returns {Promise<any|null>}
*/
async getCompletion(prompt) {
async getCompletion(prompt, full_or_sections = "section") {

if (!game.settings.get('place-gpt', 'openaiAPIToken')) {
ui.notifications.error(game.i18n.localize('place-gpt.error.no_api_token'));
return null;
}

// Test data
if (game.settings.get("place-gpt", "dummyMode") === true) {
let dummyJson = game.i18n.localize('place-gpt.dummy_completion');
const apiUrl = 'https://api.openai.com/v1/chat/completions';

// wait 2 secs to emulate the call to the API
await new Promise(r => setTimeout(r, 2000));
return JSON.parse(dummyJson);
let full_or_sections_prompt = game.i18n.localize("place-gpt.prompt_section");
if (full_or_sections === "full") {
full_or_sections_prompt = game.i18n.localize("place-gpt.prompt_full")
}

const apiUrl = 'https://api.openai.com/v1/chat/completions';

const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + game.settings.get('place-gpt', 'openaiAPIToken')
Expand All @@ -43,7 +44,8 @@ export class ChatGPT {
'model': 'gpt-3.5-turbo-0301',
'temperature': 0.2,
'messages': [
{'role': 'system', 'content': game.i18n.localize("place-gpt.prompt")},
{'role': 'system', 'content': full_or_sections_prompt},
{'role': 'system', 'content': "Answer in the language of user request but keep the JSON valid."},
{'role': 'user', 'content': prompt}
]
};
Expand All @@ -55,6 +57,7 @@ export class ChatGPT {
};

try {
// @todo add different http error handling e.g. 429 is out of credits.
const response = await fetch(apiUrl, requestOptions);
const data = await response.json();

Expand Down
53 changes: 53 additions & 0 deletions ai-classes/dummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export class Dummy {

get name() {
return 'Dummy';
}

/**
* Get a response from ChatGPT
* @param prompt
* @param full_or_sections
* @returns {Promise<any|null>}
*/
async getCompletion(prompt, full_or_sections= "section") {

console.log(full_or_sections);
let apiUrl = '/modules/place-gpt/assets/dummy_section.json';
if (full_or_sections === "full") {
apiUrl = '/modules/place-gpt/assets/dummy_full.json';
}

const headers = {
'Content-Type': 'application/json',
};

const requestOptions = {
method: 'GET',
headers: headers
};

try {

await new Promise(r => setTimeout(r, 2000));

const response = await fetch(apiUrl, requestOptions);
const data = await response.json();

// Retrieve the assistant's reply from the API response
// Try to decode JSON (if the response is JSON)
try {
return data;
}
catch(error) {
// If the response is not JSON, return the raw string
console.error('place-gpt Error:', error);
return null;
}
} catch (error) {
console.error('place-gpt Error:', error);
// Handle error
return null;
}
}
}
35 changes: 35 additions & 0 deletions assets/dummy2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[{
"name": "Entrance",
"exits": {
"north": "Storage Room",
"east": "Weapons Section",
"south": "Food Section"
}
}, {
"name": "Storage Room",
"exits": {
"south": "Entrance"
}
}, {
"name": "Weapons Section",
"exits": {
"west": "Entrance",
"north": "Armor Section"
}
}, {
"name": "Armor Section",
"exits": {
"south": "Weapons Section"
}
}, {
"name": "Food Section",
"exits": {
"north": "Entrance",
"east": "Drink Section"
}
}, {
"name": "Drink Section",
"exits": {
"west": "Food Section"
}
}]
48 changes: 48 additions & 0 deletions assets/dummy_full.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[
{
"name": "Living Room",
"description": "The living room is cozy and inviting, with a plush sofa and armchair arranged around a coffee table. A TV sits on a stand against one wall, and a bookshelf lines another. A large window lets in plenty of natural light, and there is a door leading to the front porch.",
"exits": {
"east": "Kitchen",
"south": "Main Hallway"
}
},
{
"name": "Kitchen",
"description": "The kitchen is small but functional, with a stove, refrigerator, and sink. There is a small table with two chairs for dining. A window above the sink looks out onto the backyard, and there is a door leading to the back porch.",
"exits": {
"west": "Living Room"
}
},
{
"name": "Main Hallway",
"description": "The main hallway runs the length of the house, with doors leading to the various rooms. There is a coat closet by the front door, and a staircase leading to the second floor.",
"exits": {
"north": "Living Room",
"east": "Bathroom",
"south": "Bedroom 1",
"west": "Bedroom 2"
}
},
{
"name": "Bathroom",
"description": "The bathroom is small but functional, with a sink, toilet, and shower/tub combo. There is a small window for ventilation.",
"exits": {
"west": "Main Hallway"
}
},
{
"name": "Bedroom 1",
"description": "This bedroom is cozy and comfortable, with a double bed, dresser, and closet. A window looks out onto the front yard.",
"exits": {
"north": "Main Hallway"
}
},
{
"name": "Bedroom 2",
"description": "This bedroom is slightly larger than the other, with a queen bed, dresser, and closet. A window looks out onto the backyard.",
"exits": {
"east": "Main Hallway"
}
}
]
42 changes: 42 additions & 0 deletions assets/dummy_section.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[
{
"name": "Living Room",
"exits": {
"east": "Kitchen",
"south": "Main Hallway"
}
},
{
"name": "Kitchen",
"exits": {
"west": "Living Room"
}
},
{
"name": "Main Hallway",
"exits": {
"north": "Living Room",
"east": "Bathroom",
"south": "Bedroom 1",
"west": "Bedroom 2"
}
},
{
"name": "Bathroom",
"exits": {
"west": "Main Hallway"
}
},
{
"name": "Bedroom 1",
"exits": {
"north": "Main Hallway"
}
},
{
"name": "Bedroom 2",
"exits": {
"east": "Main Hallway"
}
}
]
11 changes: 9 additions & 2 deletions lang/en.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"place-gpt.prompt": "Generate the text description of the map and its every room for Tabletop RPG by The Description below. Format your answer in a valid JSON array of objects, where every object is a room. E.g.: [{ \"name\": \"Bridge\", \"description\": \"This is the command center of the spaceship. The walls are lined with screens displaying various readings and data. The captain's chair sits at the center of the room, facing the main viewscreen. There are doors leading to the rest of the ship.\", \"exits\": { \"north\": \"Captain's Quarters\", \"east\": \"Navigation Room\", \"south\": \"Main Corridor\" }] Keep response under 1000 tokens.",
"place-gpt.prompt_full": "Generate text description of the map and its every room for Tabletop RPG by The Description below. Format your answer in a valid JSON array of objects where every object is a room. E.g. [{ \"name\": \"Bridge\", \"description\": \"This is the command center of the spaceship. The walls are lined with screens. There are doors leading to the rest of the ship.\", \"exits\": { \"north\": \"Captain's Quarters\", \"east\": \"Navigation Room\", \"south\": \"Main Corridor\" }] Keep response under 1000 tokens.",
"place-gpt.prompt_sections": "Take The Description below and generate the names for map's every room for Tabletop RPG. Format your answer in a valid JSON array of objects, where every object is a room. E.g.: [{ \"name\": \"Bridge\", \"exits\": { \"north\": \"Captain's Quarters\", \"east\": \"Navigation Room\", \"south\": \"Main Corridor\" }] Keep response under 200 tokens.",
"place-gpt.prompt_description": "Take The Room Name and Place Name below and generate the names for map's every room for Tabletop RPG. Format your answer in a valid JSON object. E.g.: { \"description\": \"This room is filled with barrels\"} Keep response under 200 tokens.",
"place-gpt.dialog.generate_full": "Full",
"place-gpt.dialog.generate_sections": "Sections (slightly faster)",
"place-gpt.Generate": "Generate",
"place-gpt.Generating": "Generating...",
"place-gpt.generating_the_place": "Generating the place",
Expand All @@ -12,8 +16,11 @@
"place-gpt.settings.outputTo.chat": "Chat",
"place-gpt.settings.outputTo.both": "Journal and Chat",
"place-gpt.dummy_completion": "[ { \"name\": \"Living Room\", \"description\": \"The living room is cozy and inviting, with a plush sofa and armchair arranged around a coffee table. A TV sits on a stand against one wall, and a bookshelf lines another. A large window lets in plenty of natural light, and there is a door leading to the front porch.\", \"exits\": { \"east\": \"Kitchen\", \"south\": \"Main Hallway\" } }, { \"name\": \"Kitchen\", \"description\": \"The kitchen is small but functional, with a stove, refrigerator, and sink. There is a small table with two chairs for dining. A window above the sink looks out onto the backyard, and there is a door leading to the back porch.\", \"exits\": { \"west\": \"Living Room\" } }, { \"name\": \"Main Hallway\", \"description\": \"The main hallway runs the length of the house, with doors leading to the various rooms. There is a coat closet by the front door, and a staircase leading to the second floor.\", \"exits\": { \"north\": \"Living Room\", \"east\": \"Bathroom\", \"south\": \"Bedroom 1\", \"west\": \"Bedroom 2\" } }, { \"name\": \"Bathroom\", \"description\": \"The bathroom is small but functional, with a sink, toilet, and shower/tub combo. There is a small window for ventilation.\", \"exits\": { \"west\": \"Main Hallway\" } }, { \"name\": \"Bedroom 1\", \"description\": \"This bedroom is cozy and comfortable, with a double bed, dresser, and closet. A window looks out onto the front yard.\", \"exits\": { \"north\": \"Main Hallway\" } }, { \"name\": \"Bedroom 2\", \"description\": \"This bedroom is slightly larger than the other, with a queen bed, dresser, and closet. A window looks out onto the backyard.\", \"exits\": { \"east\": \"Main Hallway\" } } ]",
"place-gpt.generate-room-description": "Generate room description",
"place-gpt.error.no_api_token": "No API token provided. Please set it in the module settings.",
"place-gpt.error.prompt_required": "Prompt is required",
"place-gpt.error.error_generating_place": "Error generating place",
"place-gpt.success.success_generating_place": "Place generated successfully",
"place-gpt.settings.ai_selector.name": "Select the AI module",
"place-gpt.settings.ai_selector.hint": "Select the AI module"
"place-gpt.settings.ai_selector.hint": "WARNING: RELOAD the page after changing this setting"
}
5 changes: 3 additions & 2 deletions module.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
{
"title": "Place GPT",
"description": "Generate a description for your locations using GPT-3",
"version": "1.1",
"version": "2.0",
"url": "https://github.com/megastruktur/foundryvtt-place-gpt/",
"manifest": "https://raw.githubusercontent.com/megastruktur/foundryvtt-place-gpt/master/module.json",
"download": "https://github.com/megastruktur/foundryvtt-place-gpt/releases/download/1.1/place-gpt-1.1.zip",
"download": "https://github.com/megastruktur/foundryvtt-place-gpt/releases/download/2.0/place-gpt-2.0.zip",
"scripts": [
],
"esmodules": [
"place-gpt.js",
"scripts/config.js",
"ai-classes/chatgpt.js",
"ai-classes/dummy.js",
"ai-classes/ai-manager.js"
],
"id": "place-gpt",
Expand Down
Loading

0 comments on commit 4483d8f

Please sign in to comment.