# ChatGPT Plugin - A basic example using SWI-Prolog on the backend

**URL:** <https://swi-prolog.discourse.group/t/chatgpt-plugin-a-basic-example-using-swi-prolog-on-the-backend/6627>\
**Category:** Nice to know\
**Tags:** plugin, chatgpt\
**Created:** [June 10, 2023, 7:51pm UTC](https://swi-prolog.discourse.group/t/chatgpt-plugin-a-basic-example-using-swi-prolog-on-the-backend/6627 "2023-06-10T19:51:03Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [June 10, 2023, 7:51pm UTC](https://swi-prolog.discourse.group/t/chatgpt-plugin-a-basic-example-using-swi-prolog-on-the-backend/6627/1 "2023-06-10T19:51:03Z")

</div>

If you don’t know what ChatGPT is you can sign up for free at [https://chat.openai.com/](https://chat.openai.com/). Signing up does require a valid phone number that can receive SMS messages for confirmation.

The introductory documentation for ChatGPT plugins can be found at [https://platform.openai.com/docs/plugins/introduction](https://platform.openai.com/docs/plugins/introduction)

For a plugin to work it needs to communicate between two endpoints, with one endpoint being ChatGPT. To create a programming language independent API, [OpenAPI](https://www.openapis.org/l) is used. OpenAPI uses a [specification file](https://spec.openapis.org/oas/latest.html).

ChatGPT uses the OpenAPI specification file to understand how to create HTTP(S) request to send to the plugin and what expected responses exist.

The plugin is created using any programming language that can run an HTTP(S) server and communicate using REST.

Three additional files needed to create a ChatGPT plugin are

- A logo file for displaying an image along with a textual name of the plugin.
- A manifest file that contains some basic fields including the location the OpenAPI specification for the plugin.
- The code to run the HTTP(S) server.

The basic file layout of many plugins is

```prolog
C:.
| logo.png
| main.py
| openapi.yaml
\---.well-known
        ai-plugin.json

```

* * *

This example will use SWI-Prolog and have just one POST command to receive SWI-Prolog code which it will compile and then return the results.

The manifest file, named `ai-plugin.json`, is typical for most introductory plugins.

For the ChatGPT plugin - SWI-Prolog REPL this is `ai-plugin.json`

```json
{
  "schema_version": "v1",
  "name_for_human": "SWI-Prolog REPL",
  "name_for_model": "SWI_Prolog_REPL",
  "description_for_human": "Compile SWI-Prolog code and return results, success or errors.",
  "description_for_model": "Compile SWI-Prolog code and return results, success or errors.",
  "auth": {
    "type": "none"
  },
  "api": {
    "type": "openapi",
    "url": "http://localhost:5003/openapi.yaml",
    "is_user_authenticated": false
  },
  "logo_url": "http://localhost:5003/logo.png",
  "contact_email": "support@example.com",
  "legal_info_url": "https://example.com/legal"
}

```

The next file is the OpenAPI spec. It is often easier to create by just giving ChatGPT a basic description and it will often create one with little to no errors, sometimes a few changes are needed to be validated by OpenAI when installing the ChatGPT plugin.

* * *

**Prompt**  
ChatGPT May 24 Version

Create an OpenAPI specification that will post SWI-Prolog code and return the results of compiling the code, either success or the errors.

**Completion**

Sure! Here’s an example of an OpenAPI specification (using the OpenAPI 3.0 syntax) for an endpoint that accepts SWI-Prolog code as input and returns the results of compiling the code, including success or any errors encountered.

```yaml
openapi: 3.0.3
info:
  title: SWI-Prolog Compiler API
  version: 1.0.0
servers:
  - url: http://api.example.com/prolog
paths:
  /compile:
    post:
      summary: Compile SWI-Prolog code
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
                  description: SWI-Prolog code to compile
              required:
                - code
      responses:
        '200':
          description: Compilation result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    description: Indicates whether the compilation was successful
                  errors:
                    type: array
                    items:
                      type: string
                    description: Compilation errors (if any)
        '400':
          description: Invalid request
        '500':
          description: Internal server error

```

This OpenAPI specification defines a single endpoint, `/compile`, which accepts a POST request with a JSON payload containing the SWI-Prolog code to be compiled. The response will include a `success` field indicating whether the compilation was successful and an `errors` field containing any compilation errors encountered.

You can use this specification to generate API documentation, client SDKs, or server stubs using tools like Swagger UI or OpenAPI Generator.

* * *

The ChatGPT generated OpenAPI specification was close to the working version, here is the working version.

```yaml
openapi: 3.1.0
info:
  title: SWI-Prolog Compiler API
  description: A plugin to compile SWI-Prolog and return success or errors.
  version: 0.0.0.1
servers:
  - url: http://localhost:5003
paths:
  /compile:
    post:
      operationId: compileCode
      summary: Compile SWI-Prolog code
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
                  description: SWI-Prolog code to compile
              required:
                - code
      responses:
        '200':
          description: Compilation result
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    description: Indicates whether the compilation was successful
                  errors:
                    type: array
                    items:
                      type: string
                    description: Compilation errors (if any)
        '400':
          description: Invalid request
        '500':
          description: Internal server error

```

The logo is created as PNG file and uses the SWI-Prolog owl which can be found in most installation directories of SWI-Prolog.

For this example [SWI-Prolog MQI](https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/mqi.html%27)) will be used so that the HTTP server with CORS can be created using Python. Tired to create the HTTP server with CORS for this using SWI-Prolog but could never get it to work. Seems HTTP servers with CORS created with Python just work as expected with ChatGPT plugins.

To use SWI-Prolog MQI with this code ran

```prolog
pip install swiplserver

```

which created files in `C:\Users\Eric\AppData\Local\Programs\Python`

While I did not try to create a single ChatGPT prompt that would create the Python code using the OpenAPI specification and some other constraints such as using CORS, adding routes for the three static files and including SWI-Prolog MQI much of the Python code was created and refined using ChatGPT prompts.

As this example is a proof of concept rather than production quality code there are many places that optimizations can be made.

For the HTTP server with CORS created with Python to work, some additional Prolog files needed to be created, since the Prolog code is being passed as a string and the quickest way to compile it was to place the Prolog code from ChatGPT into a file, then compile it. Also when using load\_files/2 the error messages need to be captured from message\_hook/3 which was better hidden in a Prolog file, thus `compile.pl` was created to simplify the Python code.

Note: catch\_messages/2 is from [https://github.com/SWI-Prolog/packages-http/blob/010d4a0d0eb76b8f22f42ce4db7d75f7b555a8d1/test\_proxy.pl#L672-L699](https://github.com/SWI-Prolog/packages-http/blob/010d4a0d0eb76b8f22f42ce4db7d75f7b555a8d1/test_proxy.pl#L672-L699). Thanks Jan W., I knew the overall idea but once I saw this code decided not to roll my own.

FIle: `compile.pl`

```prolog
:- module(compile,[
        compile/1
    ]).

% ----------------------------------------------------------------------------

:- meta_predicate
    catch_messages(0, -).

catch_messages(Goal, Messages) :-
    nb_setval(messages, []),
    thread_self(Me),
    setup_call_cleanup(assert((user:message_hook(Term, Kind, Lines) :-
                                    catch_message(Me, message(Term,Kind,Lines))),
                            Ref),
                    once(Goal),
                    collect_messages(Messages, Ref)).

catch_message(Me, message(Term,Kind,Lines)) :-
    Kind \= silent,
    thread_self(Me),
    !,    
    nb_getval(messages, L0),
    message_to_string(Term, String),
    ( source_location(File, Line)
    -> true
    ; File = "",
        Line = 0
    ),
    nb_linkval(messages, [message(Term,Kind,Lines,File,Line,String)|L0]).

collect_messages(Messages, Ref) :-
    erase(Ref),
    nb_getval(messages, L),
    nb_delete(messages),
    reverse(L, Messages).

% ----------------------------------------------------------------------------

compile(Errors) :-
    catch_messages(
        load_files(['code.pl'],[]),
        Messages
    ),
    maplist(format_message,Messages,Errors).

format_message(message(_Term,_Kind,_Lines,_File,Line,Error),error(Line,Error)).

```

Lastly the Python HTTP server with CORS.  
FIle: `main.py`

```python
from flask import Flask, jsonify, request, send_from_directory
from flask_cors import CORS
from werkzeug.exceptions import BadRequest, InternalServerError
from swiplserver import PrologMQI, PrologThread
import json

app = Flask( __name__ )
CORS(app)

# Serve static files from the root directory
@app.route('/logo.png', methods=['GET'])
def serve_files():
    return send_from_directory('.', 'logo.png')

@app.route('/.well-known/ai-plugin.json', methods=['GET'])
def serve_ai_plugin():
    return send_from_directory('.well-known', 'ai-plugin.json')

@app.route('/openapi.yaml', methods=['GET'])
def serve_openapi():
    return send_from_directory('.', 'openapi.yaml')

@app.route('/compile', methods=['POST'])
def compile_code():
    try:
        json_reqeust = request.get_json(force=True)
        print("Request:", request.method, request.path, json_reqeust) # Print the request to the console
        
        # Extract the 'code' from the request JSON
        code = json_reqeust['code']
        print("Code: ", code)

        # Save code to file so it can be compiled.
        with open("code.pl", "w") as file:
            # Write the string to the file
            file.write(code)
        
        with PrologMQI() as mqi:
            with mqi.create_thread() as prolog_thread:  
                result = prolog_thread.query('[compile]')        
                print(result)        
                errors = prolog_thread.query('compile:compile(Errors)')             
                print(errors)
                error_message = []
                try:
                    error_message = errors[0]['Errors'][0]['args'][1]
                except (IndexError, KeyError):
                    pass
   
        # Placeholder response for demonstration purposes
        response = {
            'success': True,
            'Errors': error_message
        }
        
        return jsonify(response), 200
    
    except BadRequest:
        return jsonify({'error': 'Invalid request'}), 400
    
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == ' __main__':
    app.run(host='0.0.0.0', port=5003)

```

* * *

How to install the ChatGPT plugin - SWI-Prolog REPL.

First the HTTP server needs to be running.

From a Windows command prompt

1. Change directory to directory with `main.py`
2. python main.py

```prolog
C:\Users\Groot\SWI-Prolog REPL>python main.py
 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5003
 * Running on http://192.168.1.143:5003
Press CTRL+C to quit

```

Navigate to [https://chat.openai.com/](https://chat.openai.com/)  
Note: Many developers prefer to use Chrome at this point as it is the one OpenAI supports and fixes the bugs fastest.

Disable caching for the browser.

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/5/57b8a28161eb63d068f8b2542a2c3a7d7bb774c8.png)

Click dropdown arrow  
 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/4/465f5c1f4c443007f36aa763d714a52976901a32.png)

Click `Plugins`

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/5/5a028ab1d31d69b02742ab64f37cd69f19da8938.png)  
Click `Plugin store`

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/2/25ad1d09f4cc6c6d28efb1475c5e260c51d0997a.png)

In lower right click `Develop your own plugin`

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/7/7e93c4553a41af390ace1213c2ccad8fd1742fd8.png)

For `Domain` enter: `localhost:5003` (change port number to one server is using)  
Click `Find manifest file`

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/2/25042301244d04cf3abf79f4dde1d3844f8155e2.png)

You can click the dropdowns to see the manifest file and OpenAPI specification file found, this is handy to make sure the correct files are accessed.

Click: `Install localhost plugin`

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/0/09eb5c552773b8fccf29e144fd701378419048a7.png)

One nice debugging tool for ChatGPT is `Open plugin devtools`. This can be enabled through the ChatGPT settings.

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/3/3d4c9265816cd0ceba065c72d37dfbe4eb379fe2.png)

Notice that in the right of the ChatGPT page the `Plugin devtools` panel opened.

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/f/faa188cbc897012ed83d9857627c6994acd78adb.png)

The only thing new here is `Prompt for ChatGPT` which is TypeScript

```prolog
// Compile SWI-Prolog code and return results, success or errors.
namespace SWI_Prolog_REPL {

// Compile SWI-Prolog code
type compileCode = (_: {
// SWI-Prolog code to compile
code: string,
}) => any;

} // namespace SWI_Prolog_REPL

```

My take is that this is the API used by the ChatGPT web pages to communicate with the plugin. As can be seen it is very simple.

* * *

To use the plugin make sure it is activated, has a check mark in a green circle. It also helps during development if only one plugin at a time is activated.  
 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/7/7d136ed12082241f4f6246642df408e8c3739a06.png)

The first prompt I run is to see if ChatGPT understands what the plugin does.

* * *

**Prompt**  
ChatGPT May 24 Version

What can SWI-Prolog REPL plugin do?

**Completion**

The SWI-Prolog REPL (Read-Eval-Print Loop) plugin is a tool that allows you to compile and run SWI-Prolog code. Prolog is a logic programming language associated with artificial intelligence and computational linguistics.

Here’s what you can do with the SWI-Prolog REPL plugin:

1. **Compile and Run Prolog Code** : You can write Prolog code and have it compiled and run within the chat. This is useful for testing small snippets of code or for demonstrating how Prolog works.

2. **Debug Prolog Code** : If there are errors in your Prolog code, the REPL will provide error messages that can help you debug your code.

3. **Interactive Programming** : The REPL nature of the plugin allows for interactive programming. You can run a piece of code, see the output, then modify and rerun the code based on the output.

4. **Teaching and Learning** : The plugin can be a useful tool for teaching and learning Prolog. You can demonstrate Prolog concepts and students can practice writing Prolog code.

Remember that the plugin is a tool for running Prolog code and does not provide any Prolog-specific features beyond what is available in the SWI-Prolog system. It also does not provide features like code completion or syntax highlighting that you might find in a dedicated Prolog development environment.

* * *

* * *

The next prompt is to create some example prompts to try with the plugin, sometimes ChatGPT comes up with some interesting prompts.

**Prompt**  
ChatGPT May 24 Version

Create some simple prompts to test out SWI-Prolog REPL plugin. Do not create API calls but prompts a real person would create.

**Completion**

Sure, here are some prompts that a real person might create to test out the SWI-Prolog REPL plugin:

1. **Fact and Rule Creation** : “Can you write a Prolog program that defines a parent-child relationship? Let’s say that John is the parent of Jim, and Jim is the parent of Tim. Then, define a rule to determine if someone is a grandparent.”

2. **List Manipulation** : “Can you write a Prolog program that defines a predicate to find the last element of a list?”

3. **Recursion** : “Can you write a Prolog program that uses recursion to calculate the factorial of a number?”

4. **Path Finding** : “Can you write a Prolog program that defines a simple graph with nodes and edges, and then finds a path between two nodes?”

5. **Pattern Matching** : “Can you write a Prolog program that uses pattern matching to split a list into its head and tail?”

6. **Sorting** : “Can you write a Prolog program that sorts a list of numbers in ascending order?”

7. **Predicate Logic** : “Can you write a Prolog program that defines a predicate to determine if a number is even?”

Remember, these are prompts for testing the SWI-Prolog REPL plugin. The actual Prolog code would be written in response to these prompts.

* * *

* * *

Now to test the ChatGPT plugin - SWI-Prolog REPL.

**Prompt**  
[ChatGPT May 24 Version](https://help.openai.com/en/articles/6825453-chatgpt-release-notes)

Can you write a Prolog program that defines a parent-child relationship? Let’s say that John is the parent of Jim, and Jim is the parent of Tim. Then, define a rule to determine if someone is a grandparent.

**Completion**

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/4/4d0c1cc6f262ced60a2ae9c9ae409f4a002c7514.png)

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/0/0beba97a1cded21d5b42cf73538856d2878e8e45.png)

![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/b/b8486736e5d3ca817e4af73678437091bec1af71.png)

* * *

Notes: The first time the code passed to the SWI-Prolog plugin is not formatted correctly and returns an error. Once ChatGPT sees the error it corrects the formatting of the code and sends it to the plugin again. The second time the code does compile clean.

* * *

* * *

Next we give some invalid code.

**Prompt**  
[ChatGPT May 24 Version](https://help.openai.com/en/articles/6825453-chatgpt-release-notes)

Create some Prolog code with a syntax error to test the SWI-Prolog REPL plugin.

**Completion**

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/d/d767c71131c283a8607eaf9aea9e6d06bc0ea109.png)

 ![image](https://global.discourse-cdn.com/free1/uploads/swiprolog/original/2X/6/6ddba4eec0d58707f0ae158e5c32d8aba0310bd0.png)

* * *

Notes: The first time ChatGPT tried to create Prolog code with a syntax error it failed but it recognized that the error was not a syntax error and tried again, this time getting it correct. The use of `Used unknown plugin` is common among many plugins, still have not seen a minimal working example that can reproduce it so that OpenAI can fix the problem.

* * *

* * *

Here ia a partial listing of the Python HTTP server console.

```plaintext
127.0.0.1 - - [10/Jun/2023 15:35:42] "OPTIONS /logo.png HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:35:42] "GET /logo.png HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:40:02] "OPTIONS /compile HTTP/1.1" 200 -
Request: POST /compile {'code': 'parent(john jim).\nparent(jim, tim).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z).'}
Code: parent(john jim).
parent(jim, tim).
grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
True
[{'Errors': [{'args': [1, 'c:/users/eric/projects/chatgpt plugin/python based/eric/swi-prolog repl/code.pl:1:12: Syntax error: Operator expected'], 'functor': 'error'}]}]
127.0.0.1 - - [10/Jun/2023 15:40:03] "POST /compile HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:40:20] "OPTIONS /logo.png HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:40:20] "GET /logo.png HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:40:22] "GET /logo.png HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:40:49] "OPTIONS /compile HTTP/1.1" 200 -
Request: POST /compile {'code': 'This is not valid Prolog code.'}
Code: This is not valid Prolog code.
True
[{'Errors': [{'args': [1, 'c:/users/eric/projects/chatgpt plugin/python based/eric/swi-prolog repl/code.pl:1:12: Syntax error: Operator expected'], 'functor': 'error'}]}]
127.0.0.1 - - [10/Jun/2023 15:40:50] "POST /compile HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:41:37] "OPTIONS /compile HTTP/1.1" 200 -
Request: POST /compile {'code': 'father(john, jim).\nfather(john, ann).\nbrother(X, Y) :- father(Z, X), father(Z, Y), X \\= Y.'}
Code: father(john, jim).
father(john, ann).
brother(X, Y) :- father(Z, X), father(Z, Y), X \= Y.
True
[{'Errors': []}]
127.0.0.1 - - [10/Jun/2023 15:41:38] "POST /compile HTTP/1.1" 200 -
127.0.0.1 - - [10/Jun/2023 15:41:51] "OPTIONS /compile HTTP/1.1" 200 -
Request: POST /compile {'code': 'father(john, jim)\nfather(john, ann).\nbrother(X, Y) :- father(Z, X), father(Z, Y), X \\= Y.'}
Code: father(john, jim)
father(john, ann).
brother(X, Y) :- father(Z, X), father(Z, Y), X \= Y.
True
[{'Errors': [{'args': [1, 'c:/users/eric/projects/chatgpt plugin/python based/eric/swi-prolog repl/code.pl:1:18: Syntax error: Operator expected'], 'functor': 'error'}]}]
127.0.0.1 - - [10/Jun/2023 15:41:52] "POST /compile HTTP/1.1" 200 -

```

* * *

* * *

So there is much work to be done with this ChatGPT plugin - SWI-Prolog REPL but it does show that as a proof of concept it can be done.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [June 11, 2023, 1:11am UTC](https://swi-prolog.discourse.group/t/chatgpt-plugin-a-basic-example-using-swi-prolog-on-the-backend/6627/2 "2023-06-11T01:11:01Z")

</div>

Since the original plugin was not always passing the Prolog code from ChatGPT to the ChatGPT Plugin HTTP server in format expected, to fix first tied passing the Prolog code as `plain/text` which when used with `POST` would always generate a `Prompt for ChatGPT` with

```typescript
// Plugin to pass OpenAPI reqeust as text/plain.
namespace String_arugment_test {

// pass text
type passText = () => any;

} // namespace String_arugment_test

```

the TypeScript API created from the OpenAPI specification would never recognize the `text/plain` as an argument.

In checking every plugin OpenAPI specification listed [here](https://github.com/sisbell/chatgpt-plugin-store/tree/main/specs), they all use `application/json` for `POST`.

> **File updates and other details (click triangle to expand)**
>
> Manifest: `.well-known\ai-plugin.json`
> 
> ```plaintext
> {
> "schema_version": "v1",
> "name_for_human": "SWI-Prolog REPL",
> "name_for_model": "SWI_Prolog_REPL",
> "description_for_human": "Compile SWI-Prolog code and return results, success or errors.",
> "description_for_model": "Validate Prolog code generated by ChatGPT uisng SWI-Prolog and return results, success or errors. Transform Prolog code in prompt to application/json before sending to plugin.",
> "auth": {
> "type": "none"
> },
> "api": {
> "type": "openapi",
> "url": "http://localhost:5003/openapi.yaml",
> "is_user_authenticated": false
> },
> "logo_url": "http://localhost:5003/logo.png",
> "contact_email": "support@example.com",
> "legal_info_url": "https://example.com/legal"
> }
> 
> ```
> 
> One of the major changes was
> 
> > “description\_for\_model”: “Validate Prolog code generated by ChatGPT using SWI-Prolog and return results, success or errors. Transform Prolog code in prompt to application/json before sending to plugin.”
> 
> Thanks [duncansmothers](https://community.openai.com/u/duncansmothers) ([ref](https://community.openai.com/t/chatgpt-always-tries-to-parse-text-plain-body-as-json/145941/7?u=ericgt))
> 
> OpenAPI specification: `openapi.yaml`
> 
> ```yaml
> openapi: 3.1.0
> info:
> title: SWI-Prolog Compiler API
> description: A plugin to compile SWI-Prolog and return success or errors.
> version: 0.0.0.1
> servers:
> - url: http://localhost:5003
> paths:
> /compile:
> post:
> operationId: compileCode
> summary: compile
> requestBody:
> description: Compile SWI-Prolog code
> required: true
> content:
> application/json:
> schema:
> type: object
> properties:
> code:
> type: string
> description: SWI-Prolog code to compile
> responses:
> '200':
> description: Compilation result
> content:
> application/json:
> schema:
> type: object
> properties:
> success:
> type: boolean
> description: Indicates whether the compilation was successful
> errors:
> type: array
> items:
> type: string
> description: Compilation errors (if any)
> '400':
> description: Invalid request
> '500':
> description: Internal server error
> 
> ```
> 
> Python: `main.py`
> 
> ```python
> from flask import Flask, jsonify, request, send_from_directory
> from flask_cors import CORS
> from werkzeug.exceptions import BadRequest, InternalServerError
> from swiplserver import PrologMQI, PrologThread
> import json
> 
> app = Flask( __name__ )
> CORS(app)
> 
> # Serve static files from the root directory
> @app.route('/logo.png', methods=['GET'])
> def serve_files():
> return send_from_directory('.', 'logo.png')
> 
> @app.route('/.well-known/ai-plugin.json', methods=['GET'])
> def serve_ai_plugin():
> return send_from_directory('.well-known', 'ai-plugin.json')
> 
> @app.route('/openapi.yaml', methods=['GET'])
> def serve_openapi():
> return send_from_directory('.', 'openapi.yaml')
> 
> @app.route('/compile', methods=['POST'])
> def compile_code():
> try:
> data = request.get_json(force=True)
>         
> # Extract the 'code' from the request JSON
> code = data['code']
> 
> print("Request:", request.method, request.path, data) # Print the request to the console
> print("Code: ", code)
> 
> # Save code to file so it can be compiled.
> with open("code.pl", "w") as file:
> # Write the string to the file
> file.write(code)
>         
> with PrologMQI() as mqi:
> with mqi.create_thread() as prolog_thread:  
> result = prolog_thread.query('[compile]')        
> print(result)        
> errors = prolog_thread.query('compile:compile(Errors)')             
> print(errors)
> error_message = []
> try:
> error_message = errors[0]['Errors'][0]['args'][1]
> except (IndexError, KeyError):
> pass
>    
> response = {
> 'success': True,
> 'Errors': error_message
> }
>         
> return jsonify(response), 200
>     
> except BadRequest:
> return jsonify({'error': 'Invalid request'}), 400
>     
> except Exception as e:
> return jsonify({'error': str(e)}), 500
> 
> if __name__ == ' __main__':
> app.run(host='0.0.0.0', port=5003)
> 
> ```
> 
> The remaining files stayed the same.
> 
> Example of HTTP server console.
> 
> ```plaintext
> C:\Users\Groot\SWI-Prolog REPL>python main.py
> * Serving Flask app 'main'
> * Debug mode: off
> WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
> * Running on all addresses (0.0.0.0)
> * Running on http://127.0.0.1:5003
> * Running on http://192.168.1.143:5003
> Press CTRL+C to quit
> 127.0.0.1 - - [13/Jun/2023 07:46:16] "OPTIONS /.well-known/ai-plugin.json HTTP/1.1" 200 -
> 127.0.0.1 - - [13/Jun/2023 07:46:17] "GET /.well-known/ai-plugin.json HTTP/1.1" 304 -
> 127.0.0.1 - - [13/Jun/2023 07:46:17] "OPTIONS /openapi.yaml HTTP/1.1" 200 -
> 127.0.0.1 - - [13/Jun/2023 07:46:17] "GET /openapi.yaml HTTP/1.1" 304 -
> 127.0.0.1 - - [13/Jun/2023 07:46:52] "OPTIONS /compile HTTP/1.1" 200 -
> Request: POST /compile {'code': 'parent(john, jim).\nparent(jim, tim).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z).'}
> Code: parent(john, jim).
> parent(jim, tim).
> grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
> True
> [{'Errors': []}]
> 127.0.0.1 - - [13/Jun/2023 07:46:53] "POST /compile HTTP/1.1" 200 -
> 127.0.0.1 - - [13/Jun/2023 07:49:26] "OPTIONS /compile HTTP/1.1" 200 -
> Request: POST /compile {'code': 'parent(john, jim).\nparent(john, ann).\nparent(mary, jim).\nparent(mary, ann).\nparent(jim, tim).\nparent(jim, amy).\nparent(ann, bob).\nparent(ann, sue).\nparent(bob, dan).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z).\nsibling(X, Y) :- parent(Z, X), parent(Z, Y), X \\= Y.\naunt_uncle(X, Y) :- sibling(X, Z), parent(Z, Y).\ncousin(X, Y) :- parent(Z, X), parent(W, Y), sibling(Z, W).'}
> Code: parent(john, jim).
> parent(john, ann).
> parent(mary, jim).
> parent(mary, ann).
> parent(jim, tim).
> parent(jim, amy).
> parent(ann, bob).
> parent(ann, sue).
> parent(bob, dan).
> grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
> sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \= Y.
> aunt_uncle(X, Y) :- sibling(X, Z), parent(Z, Y).
> cousin(X, Y) :- parent(Z, X), parent(W, Y), sibling(Z, W).
> True
> [{'Errors': []}]
> 127.0.0.1 - - [13/Jun/2023 07:49:27] "POST /compile HTTP/1.1" 200 -
> 127.0.0.1 - - [13/Jun/2023 07:58:53] "OPTIONS /compile HTTP/1.1" 200 -
> Request: POST /compile {'code': 'my_list([a, b, c, d, e]).\nmember(X, [X|_]).\nmember(X, [_|T]) :- member(X, T).'}
> Code: my_list([a, b, c, d, e]).
> member(X, [X|_]).
> member(X, [_|T]) :- member(X, T).
> True
> [{'Errors': []}]
> 127.0.0.1 - - [13/Jun/2023 07:58:54] "POST /compile HTTP/1.1" 200 -
> 
> ```
> 
> **Prompt**  
> [ChatGPT May 24 Version](https://help.openai.com/en/articles/6825453-chatgpt-release-notes)
> 
> Can you write a Prolog program that defines a parent-child relationship? Let’s say that John is the parent of Jim, and Jim is the parent of Tim. Then, define a rule to determine if someone is a grandparent.
> 
> **Completion**
> 
> Sure, here is a simple Prolog program that defines the parent-child relationship and a rule to determine if someone is a grandparent.
> 
> prolog
> 
> ```prolog
> % Define parent-child relationships
> parent(john, jim).
> parent(jim, tim).
> 
> % Define grandparent rule
> grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
> 
> ```
> 
> This program defines two facts: that John is the parent of Jim, and that Jim is the parent of Tim. It also defines a rule for grandparent: a person X is a grandparent of a person Z if there is some person Y such that X is a parent of Y and Y is a parent of Z. In this case, John is the grandparent of Tim.
> 
> Let’s compile this code using the SWI-Prolog plugin to ensure it’s correct.
> 
> json
> 
> ```prolog
> {
> "code": "parent(john, jim).\nparent(jim, tim).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z)."
> }
> 
> ```
> 
> Used **SWI-Prolog REPL**
> 
> LOCALHOST
> 
> REQUEST TO SWI-PROLOG REPL
> 
> `{ "code": "parent(john, jim).\nparent(jim, tim).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z)." }`
> 
> RESPONSE FROM SWI-PROLOG REPL
> 
> `{ "Errors": [], "success": true }`
> 
> The Prolog code compiled successfully without any errors. Now, you can use this program to query the grandparent-child relationship. For example, you can ask if John is a grandparent of Tim by using the query `grandparent(john, tim).` The program should return `true` because, according to the facts we defined, John is indeed a grandparent of Tim.
> 
> * * *
> 
> **Prompt**
> 
> Create a more complex example of Prolog code.
> 
> **Completion**
> 
> Sure, let’s create a more complex family tree using Prolog. We’ll define parent-child relationships for a larger family and add rules to determine siblings, aunts/uncles, and cousins.
> 
> prolog
> 
> ```prolog
> % Define parent-child relationships
> parent(john, jim).
> parent(john, ann).
> parent(mary, jim).
> parent(mary, ann).
> parent(jim, tim).
> parent(jim, amy).
> parent(ann, bob).
> parent(ann, sue).
> parent(bob, dan).
> 
> % Define grandparent rule
> grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
> 
> % Define sibling rule
> sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \= Y.
> 
> % Define aunt/uncle rule
> aunt_uncle(X, Y) :- sibling(X, Z), parent(Z, Y).
> 
> % Define cousin rule
> cousin(X, Y) :- parent(Z, X), parent(W, Y), sibling(Z, W).
> 
> ```
> 
> This program defines a more complex family tree and rules for determining various family relationships. The `sibling` rule states that two people are siblings if they share a parent and are not the same person. The `aunt_uncle` rule states that a person is an aunt or uncle of another person if they are siblings with that person’s parent. The `cousin` rule states that two people are cousins if their parents are siblings.
> 
> Let’s compile this code using the SWI-Prolog plugin to ensure it’s correct.
> 
> json
> 
> ```prolog
> {
> "code": "parent(john, jim).\nparent(john, ann).\nparent(mary, jim).\nparent(mary, ann).\nparent(jim, tim).\nparent(jim, amy).\nparent(ann, bob).\nparent(ann, sue).\nparent(bob, dan).\ngrandparent(X, Z) :- parent(X, Y), parent(Y, Z).\nsibling(X, Y) :- parent(Z, X), parent(Z, Y), X \\= Y.\naunt_uncle(X, Y) :- sibling(X, Z), parent(Z, Y).\ncousin(X, Y) :- parent(Z, X), parent(W, Y), sibling(Z, W)."
> }
> 
> ```
> 
> Used **SWI-Prolog REPL**
> 
> LOCALHOST
> 
> The Prolog code compiled successfully without any errors. Now, you can use this program to query various family relationships. For example:
> 
> - You can ask if Jim and Ann are siblings by using the query `sibling(jim, ann).` The program should return `true` because, according to the facts we defined, Jim and Ann are indeed siblings.
> - You can ask if John is an uncle of Bob by using the query `aunt_uncle(john, bob).` The program should return `false` because John is not Bob’s uncle.
> - You can ask if Tim and Bob are cousins by using the query `cousin(tim, bob).` The program should return `true` because Tim and Bob are indeed cousins according to the facts we defined.
> 
> * * *
> 
> **Prompt**
> 
> Do a quick Prolog example.
> 
> **Completion**
> 
> Sure, here’s a quick example of a Prolog program that defines a simple list and a rule to check if an element is a member of that list.
> 
> prolog
> 
> ```prolog
> % Define a list
> my_list([a, b, c, d, e]).
> 
> % Define a rule to check if an element is a member of the list
> member(X, [X|_]).
> member(X, [_|T]) :- member(X, T).
> 
> ```
> 
> This program defines a list `my_list` with elements `a, b, c, d, e`. It also defines a rule `member` that checks if an element `X` is a member of a list. The rule works by checking if `X` is the first element of the list (the head), and if not, it recursively checks the rest of the list (the tail).
> 
> Let’s compile this code using the SWI-Prolog plugin to ensure it’s correct.
> 
> json
> 
> ```prolog
> {
> "code": "my_list([a, b, c, d, e]).\nmember(X, [X|_]).\nmember(X, [_|T]) :- member(X, T)."
> }
> 
> ```
> 
> Used **SWI-Prolog REPL**
> 
> LOCALHOST
> 
> REQUEST TO SWI-PROLOG REPL
> 
> `{ "code": "my_list([a, b, c, d, e]).\nmember(X, [X|_]).\nmember(X, [_|T]) :- member(X, T)." }`
> 
> RESPONSE FROM SWI-PROLOG REPL
> 
> `{ "Errors": [], "success": true }`
> 
> The Prolog code compiled successfully without any errors. Now, you can use this program to query if an element is a member of the list `my_list`. For example, you can ask if `b` is a member of `my_list` by using the query `member(b, my_list).` The program should return `true` because, according to the list we defined, `b` is indeed a member of `my_list`.
