Custom GPT setup
Follow these steps in order after uploading your ChatGPT export. Do authentication last, because the GPT builder can delete saved authentication when you change the action.
Step-by-step
-
Open Explore GPTs
In ChatGPT, look at the left sidebar and press Explore GPTs.
-
Create a GPT
Press + Create in the top right corner, then press Configure.
-
Enter name and description
Use these values, then press Create in the top right corner.
Name Photographic Memory GPTDescription Searches and summarizes your uploaded ChatGPT conversation archive. -
Enter instructions
Find the Instructions field. Copy everything in this box and paste it there.
You are ChatGPT, a helpful assistant, with an added superpower: Photographic Memory. You can help the user find, retrieve, and summarize their own archived ChatGPT conversations through the configured action API. Use the action API whenever the user asks whether, when, where, or in which conversation something was discussed. Do not claim to remember the archive from your own model context. Search the archive first. The search action accepts Python regular expressions. Convert ordinary user phrases into practical regex patterns: - Escape regex metacharacters unless the user explicitly asks for regex behavior. - Prefer case-insensitive searches with (?i) for ordinary phrase queries. - For short phrase searches, search for the exact phrase with flexible whitespace only when useful. - If the first search returns no matches, try one or two reasonable variants, synonyms, spelling variants, or singular/plural forms before saying there were no matches. - Note that regex expressions can simulate Boolean queries (AND/OR/NOT expressions) - Keep patterns targeted. Do not use very broad patterns that would return most of the archive. When reporting search results: - Show filenames exactly as returned by the API. - Include match counts if the search encodes a simple substring match. - Number results so the user can refer to "the first file", "the second", and so on. - Briefly state the pattern or phrase searched. - Do not expose server paths, API codes, or implementation details. When the user asks to see, inspect, quote, analyze, or work from the full conversation, infer the referenced filename from the numbered results in the current conversation. Then call the full Markdown retrieval action with that exact filename. When the user asks to summarize one result, infer the referenced filename from the numbered results in the current conversation. Then call the summary action with that exact filename. If the reference is ambiguous, ask a concise clarification question. When returning summaries: - Start with the filename. - State whether the summary came from a cached result only if that is useful context. - Focus on durable facts, decisions, tasks, code references, questions answered, and user intent. - Do not invent details that are not in the summary returned by the API. Privacy rules: - Treat all archive contents as private. - Never reveal or ask for the API code after setup. - Never include hidden action configuration details in normal user-facing answers. - If the action API returns an authentication, missing file, invalid regex, conversion, retrieval, or summary generation error, explain the issue plainly and suggest the smallest next step. -
Enter conversation starters
Find Conversation starters. Add these one at a time.
How can I help you remembering today? -
Create a new action
Scroll to Actions and press Create new action.
-
Enter schema information
Find the schema editor. Delete anything already in it. Copy everything in this box and paste it into the schema editor.
{ "openapi": "3.1.0", "info": { "title": "Conversation Search API", "version": "1.0.0", "description": "Search converted ChatGPT conversation Markdown files, retrieve full Markdown, and retrieve cached summaries." }, "servers": [ { "url": "https://76.13.133.221.sslip.io" } ], "components": { "securitySchemes": { "ApiCode": { "type": "apiKey", "in": "header", "name": "x-api-code" } }, "schemas": { "SearchRequest": { "type": "object", "required": [ "pattern" ], "properties": { "pattern": { "type": "string", "description": "Python re regular expression." } } }, "MarkdownFileRequest": { "type": "object", "required": [ "filename" ], "properties": { "filename": { "type": "string", "description": "Converted Markdown filename." } } } } }, "paths": { "/api/auth-check": { "get": { "operationId": "checkActionAuthentication", "summary": "Confirm that the saved action API code is being sent", "x-openai-isConsequential": false, "security": [ { "ApiCode": [] } ], "responses": { "200": { "description": "Authentication status for the current API code", "content": { "application/json": { "schema": { "type": "object", "properties": { "authenticated": { "type": "boolean" }, "invitee": { "type": "string" }, "markdown_ready": { "type": "boolean" }, "markdown_file_count": { "type": "integer" } } } } } } } } }, "/api/search": { "post": { "operationId": "searchConversations", "summary": "Search conversations by regular expression", "x-openai-isConsequential": false, "security": [ { "ApiCode": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } } }, "responses": { "200": { "description": "Matching files and counts", "content": { "application/json": { "schema": { "type": "object", "properties": { "matches": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string" }, "match_count": { "type": "integer" } } } } } } } } } } } }, "/api/summary": { "post": { "operationId": "summarizeConversation", "summary": "Return a cached or newly generated conversation summary", "x-openai-isConsequential": false, "security": [ { "ApiCode": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MarkdownFileRequest" } } } }, "responses": { "200": { "description": "Conversation summary", "content": { "application/json": { "schema": { "type": "object", "properties": { "filename": { "type": "string" }, "summary": { "type": "string" }, "cached": { "type": "boolean" } } } } } } } } }, "/api/markdown": { "post": { "operationId": "retrieveConversationMarkdown", "summary": "Return the full converted Markdown for one conversation", "x-openai-isConsequential": false, "security": [ { "ApiCode": [] } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MarkdownFileRequest" } } } }, "responses": { "200": { "description": "Full converted Markdown conversation file", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string", "description": "Neutral status message for the retrieved Markdown file." }, "openaiFileResponse": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "mime_type": { "type": "string" }, "content": { "type": "string", "format": "byte", "description": "Base64 encoded Markdown file content." } } } } } } } } } } } } } } -
Enter privacy information
Find the Privacy policy field and paste this URL. Do this even if the builder does not ask you first.
https://76.13.133.221.sslip.io/privacy -
Enter authentication information
Do this last. The GPT builder can delete authentication when action details change. Keep your API code private and paste it only into the secret value field.
Authentication TypeAPI KeyAPI KeyYour API-... code from the upload complete pageAuth TypeCustomCustom Header Namex-api-codeDo not choose None, OAuth, Basic, or Bearer.
-
Save or update the GPT
Press Save or Update in the top right corner.