-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
583 additions
and
0 deletions.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
assets/guides/formbricks-in-gpts/example_surveys_instructions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
You adhere to the following commands: | ||
|
||
/feedback [feedback] - Check if the [feedback] is an english sentence and not just nonesense. If so, call the app.formbricks.com API with the clpmo....zmqf operation and the following payload: | ||
{ | ||
"surveyId": "clpmo...ijqz", | ||
"finished": false, | ||
"ttc": { | ||
"k4fh8...nidq": 1 | ||
}, | ||
"data": { | ||
"k4fh8...nidq": {feedback} | ||
} | ||
} | ||
|
||
/vote [choice1, ...] - For each choice, check if it is one of the following choices "[latest]Vue.js GPT ", "[latest] FastAPI GPT", "[latest] TailwindCSS GPT", "All of them ❤️" or very close to it. If not, ask the user for clarification. If you can assign each choice to one of the valid choices, call the app.formbricks.com API with the clpmo....zmqf operation and the following payload: | ||
{ | ||
"surveyId": "clpmo...ijqz", | ||
"finished": false, | ||
"ttc": { | ||
"o0ynm...kob9": 1 | ||
}, | ||
"data": { | ||
"o0ynm...kob9": {choices} | ||
} | ||
} | ||
|
||
/rate [rating] - Check if the [rating] is a number between 1 and 5. If so, call the app.formbricks.com API with the clpmo....zmqf operation and the following payload: | ||
{ | ||
"surveyId": "clpmo...ijqz", | ||
"finished": false, | ||
"ttc": { | ||
"iu1kr...fzrm": 1 | ||
}, | ||
"data": { | ||
"iu1kr...fzrm": {rating} | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
assets/guides/formbricks-in-gpts/example_surveys_oapi.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
{ | ||
"openapi": "3.1.0", | ||
"info": { | ||
"title": "Formbricks API", | ||
"version": "v1.0.0" | ||
}, | ||
"servers": [ | ||
{ | ||
"url": "https://app.formbricks.com/api/v1" | ||
} | ||
], | ||
"paths": { | ||
"/client/clpmo...zmqf/responses": { | ||
"post": { | ||
"operationId": "clpmo...zmqf", | ||
"x-openai-isConsequential": false, | ||
"requestBody": { | ||
"type": "object", | ||
"content": { | ||
"application/json": { | ||
"schema": { | ||
"$ref": "#/components/schemas/FormbricksResponse" | ||
} | ||
} | ||
} | ||
}, | ||
"responses": { | ||
"200": { | ||
"description": "OK" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"components": { | ||
"schemas": { | ||
"FormbricksResponse": { | ||
"type": "object", | ||
"properties": { | ||
"surveyId": { | ||
"type": "string" | ||
}, | ||
"finished": { | ||
"type": "boolean" | ||
}, | ||
"ttc": { | ||
"type": "object", | ||
"properties": { | ||
"k4fh8...nidq": { | ||
"type": "number" | ||
}, | ||
"o0ynm...kob9": { | ||
"type": "number" | ||
}, | ||
"iu1k3...fzrm": { | ||
"type": "number" | ||
} | ||
} | ||
}, | ||
"data": { | ||
"type": "object", | ||
"properties": { | ||
"k4fh8...nidq": { | ||
"type": "string" | ||
}, | ||
"o0ynm...kob9": { | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"iu1k3...fzrm": { | ||
"type": "number" | ||
} | ||
} | ||
} | ||
}, | ||
"required": [ | ||
"surveyId", | ||
"ttc", | ||
"finished", | ||
"data" | ||
] | ||
} | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
import http.client | ||
import json | ||
|
||
|
||
def get_surveys(host: str, api_key: str) -> None: | ||
""" | ||
Get all surveys from the Formbricks API and save them to surveys.json | ||
""" | ||
surveys = [] | ||
try: | ||
conn = http.client.HTTPSConnection(host, timeout=10) | ||
headers = { | ||
'x-api-key': api_key | ||
} | ||
conn.request("GET", "/api/v1/management/surveys", headers=headers) | ||
res = conn.getresponse() | ||
data = res.read() | ||
data = json.loads(data.decode("utf-8")) | ||
finally: | ||
conn.close() | ||
json.dump(data, open("surveys.json", "w"), indent=4) | ||
|
||
|
||
def compose_openapi(surveys: dict, server: str) -> None: | ||
""" | ||
Read surveys.json and create an OpenAI Actions compatibly OpenAPI 3.0 JSON file | ||
""" | ||
added_env_ids = [] | ||
paths = {} | ||
for survey in surveys["data"]: | ||
if survey["environmentId"] not in added_env_ids: | ||
path = f"/client/{survey['environmentId']}/responses" | ||
paths[path] = { | ||
"post": { | ||
"operationId": survey['environmentId'], | ||
"x-openai-isConsequential": False, | ||
"requestBody": { | ||
"type": "object", | ||
"content": { | ||
"application/json": { | ||
"schema": { | ||
"$ref": "#/components/schemas/FormbricksResponse" | ||
} | ||
} | ||
} | ||
}, | ||
"responses": { | ||
"200": { | ||
"description": "OK" | ||
} | ||
} | ||
} | ||
} | ||
added_env_ids.append(survey["environmentId"]) | ||
for question in survey["questions"]: | ||
schema_base["components"]["schemas"]["FormbricksResponse"]["properties"]["ttc"]["properties"][question["id"]] = {"type": "number"} | ||
if question["type"] == "openText": | ||
schema_base["components"]["schemas"]["FormbricksResponse"]["properties"]["data"]["properties"][question["id"]] = {"type": "string"} | ||
elif question["type"] == "rating": | ||
schema_base["components"]["schemas"]["FormbricksResponse"]["properties"]["data"]["properties"][question["id"]] = {"type": "number"} | ||
elif question["type"] == "multipleChoiceMulti": | ||
schema_base["components"]["schemas"]["FormbricksResponse"]["properties"]["data"]["properties"][question["id"]] = {"type": "array", "items": {"type": "string"}} | ||
else: | ||
raise Exception(f"\n\nThe formbricks question type: \"{question['type']}\" is not covered by this script.\nIt should be super easy to add though.\nJust check what type/object the Formbricks API expects for \"{question['type']}\" and add a check to the 'compose_instructions' function. Then add an example command to 'question_type_to_command\nPlease create a PR to https://github.com/luona-dev/latestGPTs if you implement it.") | ||
schema_base["paths"] = paths | ||
schema_base["servers"] = [{"url": f"https://{host}/api/v1"}] | ||
json.dump(schema_base, open("surveys_oapi.json", "w"), indent=4) | ||
print("Saved OpenAPI scheme for Actions to surveys_oapi.json") | ||
|
||
|
||
def compose_instructions(surveys: dict): | ||
"""Composes the instructions for your GPT so it can handle the Formbricks endpoints""" | ||
if len(surveys["data"]) > 1: | ||
print("WARNING: You have more than one survey. This scripts logic to compose instructions is very limited and works on a per question type basis. You may take this as a starting point but will have to adjust it to your needs.") | ||
commands = [] | ||
added_question_types = [] | ||
for survey in surveys["data"]: | ||
for question in survey["questions"]: | ||
if question["type"] not in added_question_types: | ||
added_question_types.append(question["type"]) | ||
if question["type"] == "openText": | ||
commands.append(question_type_to_command[question["type"]].format(host="app.formbricks.com", | ||
operation_id=survey["environmentId"], | ||
survey_id=survey["id"], | ||
question_id=question["id"])) | ||
elif question["type"] == "rating": | ||
commands.append(question_type_to_command[question["type"]].format(host="app.formbricks.com", | ||
operation_id=survey["environmentId"], | ||
survey_id=survey["id"], | ||
question_id=question["id"], | ||
range=question["range"])) | ||
elif question["type"] == "multipleChoiceMulti": | ||
choices = ", ".join([f"\"{choice['label']}\"" for choice in question["choices"]]) | ||
commands.append(question_type_to_command[question["type"]].format(host="app.formbricks.com", | ||
operation_id=survey["environmentId"], | ||
survey_id=survey["id"], | ||
question_id=question["id"], | ||
choices=choices)) | ||
else: | ||
raise Exception(f"\n\nThe formbricks question type: \"{question['type']}\" is not covered by this script.\nIt should be super easy to add though.\nJust check what type/object the Formbricks API expects for \"{question['type']}\" and add a check to the 'compose_instructions' function. Then add an example command to 'question_type_to_command\nPlease create a PR to https://github.com/luona-dev/latestGPTs if you implement it.") | ||
else: | ||
print(f"WARNING: You have more than one question of type \"{question['type']}\". This scripts logic to compose instructions is very limited and works on a per question type basis. You may take this as a starting point but will have to adjust it to your needs.") | ||
with open("surveys_instructions.md", "w") as f: | ||
f.write(command_base) | ||
for command in commands: | ||
f.write(command) | ||
print("Saved instructions to surveys_instructions.md") | ||
|
||
schema_base = { | ||
"openapi": "3.1.0", | ||
"info": { | ||
"title": "Formbricks API", | ||
"version": "v1.0.0", | ||
}, | ||
"servers": [], | ||
"paths": {}, | ||
"components": { | ||
"schemas": { | ||
"FormbricksResponse": { | ||
"type": "object", | ||
"properties": { | ||
"surveyId": { | ||
"type": "string" | ||
}, | ||
"finished": { | ||
"type": "boolean" | ||
}, | ||
"ttc": { | ||
"type": "object", | ||
"properties": {} | ||
}, | ||
"data": { | ||
"type": "object", | ||
"properties": {} | ||
} | ||
}, | ||
"required": ["surveyId", "ttc", "finished", "data"] | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
command_base = "You adhere to the following commands:\n" | ||
|
||
|
||
question_type_to_command = dict() | ||
|
||
question_type_to_command["openText"] = """ | ||
/feedback [feedback] - Check if the [feedback] is an english sentence and not just nonesense. If so, call the {host} API with the {operation_id} operation and the following payload: | ||
{{ | ||
"surveyId": "{survey_id}", | ||
"finished": false, | ||
"ttc": {{ | ||
"{question_id}": 1 | ||
}}, | ||
"data": {{ | ||
"{question_id}": {{feedback}} | ||
}} | ||
}} | ||
""" | ||
|
||
question_type_to_command["multipleChoiceMulti"] = """ | ||
/vote [choice1, ...] - For each choice, check if it is one of the following choices {choices} or very close to it. If not, ask the user for clarification. If you can assign each choice to one of the valid choices, call the {host} API with the {operation_id} operation and the following payload: | ||
{{ | ||
"surveyId": "{survey_id}", | ||
"finished": false, | ||
"ttc": {{ | ||
"{question_id}": 1 | ||
}}, | ||
"data": {{ | ||
"{question_id}": {{choices}} | ||
}} | ||
}} | ||
""" | ||
|
||
question_type_to_command["rating"] = """ | ||
/rate [rating] - Check if the [rating] is a number between 1 and {range}. If so, call the {host} API with the {operation_id} operation and the following payload: | ||
{{ | ||
"surveyId": "{survey_id}", | ||
"finished": false, | ||
"ttc": {{ | ||
"{question_id}": 1 | ||
}}, | ||
"data": {{ | ||
"{question_id}": {{rating}} | ||
}} | ||
}} | ||
""" | ||
|
||
|
||
|
||
if __name__ == "__main__": | ||
import sys | ||
|
||
command = sys.argv[1] | ||
if command == "--help": | ||
print("Usage: python formbricks_to_gpt.py [COMMAND]") | ||
print("COMMANDS:") | ||
print(" --help: Display this help message") | ||
print(" get [API_KEY] [HOST (default: app.formbricks.com)]: Get all your surveys from the Formbricks API and save them to surveys.json") | ||
print (" oapi [PATH (default surveys.json)] [HOST (default: app.formbricks.com)]: Read surveys.json and OpenAI Actions compatibly OpenAPI 3.0 JSON file") | ||
print(" instructions [PATH (default surveys.json)]: Read surveys.json and create example instructions for your GPT so it can handle the Formbricks endpoints") | ||
exit(0) | ||
if command == "get": | ||
api_key = sys.argv[2] | ||
if not api_key: | ||
raise Exception("Please provide an API key as the first argument") | ||
if api_key == "--help": | ||
print("Usage: python formbricks_to_gpt.py get [API_KEY] [HOST (default: app.formbricks.com)]") | ||
print("API_KEY: Your Formbricks Management API key") | ||
print("HOST: The host to connect to. Default is app.formbricks.com") | ||
exit(0) | ||
host = sys.argv[3] if len(sys.argv) > 3 else "app.formbricks.com" | ||
get_surveys(host=host, api_key=api_key) | ||
print("Saved surveys to surveys.json\nRemeber to delete your Management API key and/or remove the last command from your shell history.") | ||
if command == "oapi": | ||
path = sys.argv[2] if len(sys.argv) > 2 else "surveys.json" | ||
if path == "--help": | ||
print("Usage: python formbricks_to_gpt.py oapi [PATH (default surveys.json)] [HOST (default: app.formbricks.com)]") | ||
print("PATH: The path to the surveys.json file. Default is surveys.json") | ||
print("HOST: The host to use for the required \"servers\" field in the OpenAPI scheme. Default is app.formbricks.com") | ||
exit(0) | ||
host = sys.argv[3] if len(sys.argv) > 3 else "app.formbricks.com" | ||
surveys = json.load(open(path)) | ||
compose_openapi(surveys, server=host) | ||
if command == "instructions": | ||
path = sys.argv[2] if len(sys.argv) > 2 else "surveys.json" | ||
if path == "--help": | ||
print("Usage: python formbricks_to_gpt.py instructions [PATH (default surveys.json)]") | ||
print("PATH: The path to the surveys.json file. Default is surveys.json") | ||
exit(0) | ||
surveys = json.load(open(path)) | ||
compose_instructions(surveys) |
Oops, something went wrong.