I’m trying to create a Custom GPT that would allow paid subscribers to ask questions that GPT would answer from my posts. I’m trying to add a custom action but Ghost isn’t letting me authenticate, even though it seems like I should be able to authenticate using an API Key. Have others connected a Custom GPT with Ghost?
I think you’ll need to share more info on how you’re trying authenticate and what you’re trying to do.
I was trying to have a custom GPT get my blog posts using the Admin API so I could have it answer questions based on just the dataset of my blog posts. I’ve tried different ways to add the Admin API and it has not worked. The screenshot shows my API options and I tried this schema:
openapi: 3.1.0
info:
title: "Ghost Blog API"
description: "Fetch blog posts from Ghost Admin API for the Wills, Trusts, and Estates blog."
version: "v1.0.0"
servers:
- url: "https://willstrustsestates.ghost.io"
paths:
/ghost/api/admin/posts/:
get:
description: "Retrieve all blog posts"
operationId: "fetchPosts"
parameters: []
responses:
'200':
description: "A list of blog posts"
content:
application/json:
schema:
type: object
properties:
posts:
type: array
items:
type: object
properties:
id:
type: string
title:
type: string
html:
type: string
published_at:
type: string
format: date-time
required: ["id", "title", "html", "published_at"]
'401':
description: "Unauthorized, missing or invalid API key"
components:
schemas: {}
I also ran a Python script that takes my admin key and returns a jwt token. But Ghost is refusing the headers. I tried
Authorization: Ghost {jwt-token}
The JWT token works from my Python script but I can’t figure out why Ghost is rejecting the API call from the GPT. It seems like it should be straightforward since there aren’t many options in the API dialog that is available, but it has been quite the mystery.
Try to set api key like this:
And add the following header param in schema, replace “ghost version” with your Ghost version
headers:
- name: Accept-Version
in: header
required: true
description: The version of the API to be used.
schema:
type: string
example: "ghost version"
Please note that the token expires after a few minutes by default, unless you set it to indefinite, which can be risky.
Although I’m not entirely sure, there may be a risk that users could manipulate GPT to perform actions like deleting or posting content on your blog. It would be better to add a middleware layer between your blog and GPT to limit its actions.
Thank you. That worked.
How do I set the JWT to indefinite? I tried the follwoing and it still defaults to a few minutes.
payload = {
'iat': iat, # Issued at time
# 'exp': iat + 365 * 24 * 60 * 60, 1-year expiration
'aud': '/admin/' # Audience (admin API)
}
Also, how do I filter posts so only published posts are retrieved?
I tried this:
https://willstrustsestates.ghost.io/ghost/api/admin/posts/?filter=status:published
I also tried adding this with and without the quotation marks in the schema:
- name: filter
in: query
description: Filter for retrieving only published posts
schema:
type: string
example: 'status:published'
You need to encode that query string. Try it with
?filter=status%3Apublished
I tried it with this and it didn’t work:
https://willstrustsestates.ghost.io/ghost/api/admin/posts/?filter=status%3Apublished
I got this explanation:
It seems there are no published posts available at the moment from the willstrustsestates.ghost.io API. Let me know if you need further assistance or if you'd like me to try something else.
I have over 240 posts published.
I think I need to rethink my workflow. I got the Custom GPT to work, even though the filter isn’t working. But I have to paginate the payload from Ghost. So, GPT only sees a few posts at a time. I can ask it to get more posts, but this is quite inefficient and not what I had in mind.
It seems like I need to get the data from Ghost, create embeddings through the OpenAI API, store the embeddings in a vector database (like Pinecone), and write a client-facing script that allows users to ask GPT questions (which then queries the database).