mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 17:31:56 +03:00
Docs: Create a Python version of our ET Recipe for Content Moderation [Fixes #9909]
GITHUB_PR_NUMBER: 9931 GITHUB_PR_URL: https://github.com/hasura/graphql-engine/pull/9931 PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10384 Co-authored-by: Rutam Prita Mishra <47860497+Rutam21@users.noreply.github.com> GitOrigin-RevId: f8a96186ad2c10e7a9c237f146298f4167debf08
This commit is contained in:
parent
26f33bec0e
commit
9db5cb3075
@ -134,6 +134,15 @@ Below, we've written an example of webhook in JavaScript that uses `body-parser`
|
|||||||
earlier, this runs on port `4000`. If you're attempting to run this locally, follow the instructions below. If you're
|
earlier, this runs on port `4000`. If you're attempting to run this locally, follow the instructions below. If you're
|
||||||
running this in a hosted environment, use this code as a guide to write your own webhook.
|
running this in a hosted environment, use this code as a guide to write your own webhook.
|
||||||
|
|
||||||
|
<Tabs
|
||||||
|
defaultValue="javascript"
|
||||||
|
values={[
|
||||||
|
{ label: 'JavaScript', value: 'javascript' },
|
||||||
|
{ label: 'Python', value: 'python' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<TabItem value="javascript">
|
||||||
|
|
||||||
Init a new project with `npm init` and install the following dependencies:
|
Init a new project with `npm init` and install the following dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -279,8 +288,175 @@ app.listen(4000, () => {
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
You can run the server by running `node index.js` in your terminal. If you see the message
|
You can run the server by running `node index.js` in your terminal.
|
||||||
`Webhook server is running on port 4000`, you're good to go!
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="python">
|
||||||
|
|
||||||
|
Make sure you have the necessary dependencies installed. You can use pip to install them:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install Flask[async] openai requests
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
Then, create a new file called <code>index.py</code> and add the following code:
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
```python
|
||||||
|
from flask import Flask, request, jsonify
|
||||||
|
import openai
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# Hasura and OpenAI config
|
||||||
|
config = {
|
||||||
|
'url': '<YOUR_PROJECT_ENDPOINT>',
|
||||||
|
'secret': '<YOUR_ADMIN_SECRET>',
|
||||||
|
'openAIKey': '<YOUR_OPENAI_KEY>',
|
||||||
|
}
|
||||||
|
|
||||||
|
# OpenAI API config and client
|
||||||
|
openai.api_key = config["openAIKey"]
|
||||||
|
|
||||||
|
prompt = (
|
||||||
|
"You are a content moderator for SuperStore.com. A customer has left a review for a product they purchased. "
|
||||||
|
'Your response should only be a JSON object with two properties: "feedback" and "is_appropriate". '
|
||||||
|
'The "feedback" property should be a string containing your response to the customer only if the review "is_appropriate" value is false. '
|
||||||
|
"The feedback should be on why their review was flagged as inappropriate, not a response to their review. "
|
||||||
|
'The "is_appropriate" property should be a boolean indicating whether or not the review contains inappropriate content and it should be set by you.'
|
||||||
|
'"is_appropriate" is set to TRUE for appropriate content and to FALSE for inappropriate content.'
|
||||||
|
"The review is as follows:"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Send a request to ChatGPT to see if the review contains inappropriate content
|
||||||
|
def check_review_with_chat_gpt(review_text):
|
||||||
|
try:
|
||||||
|
response = openai.ChatCompletion.create(
|
||||||
|
model="gpt-3.5-turbo",
|
||||||
|
messages=[
|
||||||
|
{"role": "system", "content": prompt},
|
||||||
|
{"role": "user", "content": review_text},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
response_content = response["choices"][0]["message"]["content"]
|
||||||
|
return json.loads(response_content)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error evaluating content: {review_text}")
|
||||||
|
print(str(e))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# Mark their review as visible if there's no feedback
|
||||||
|
async def mark_review_as_visible(user_review, review_id):
|
||||||
|
response = requests.post(
|
||||||
|
config["url"],
|
||||||
|
json={
|
||||||
|
"query": """
|
||||||
|
mutation UpdateReviewToVisible($review_id: uuid!) {
|
||||||
|
update_reviews_by_pk(pk_columns: {id: $review_id}, _set: {is_visible: true}) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"variables": {
|
||||||
|
"review_id": review_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-hasura-admin-secret": config["secret"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
print(f"🎉 Review approved: {user_review}")
|
||||||
|
data = response.json()
|
||||||
|
return data.get("update_reviews_by_pk", None)
|
||||||
|
|
||||||
|
|
||||||
|
# Send a notification to the user if their review is flagged
|
||||||
|
def send_notification(user_review, user_id, review_feedback):
|
||||||
|
query = """
|
||||||
|
mutation InsertNotification($user_id: uuid!, $review_feedback: String!) {
|
||||||
|
insert_notifications_one(object: {user_id: $user_id, message: $review_feedback}) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
variables = {"user_id": user_id, "review_feedback": review_feedback}
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-hasura-admin-secret": config["secret"],
|
||||||
|
}
|
||||||
|
url = config["url"]
|
||||||
|
|
||||||
|
request_body = {"query": query, "variables": variables}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, json=request_body, headers=headers)
|
||||||
|
# Raise an error for bad responses
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
response_json = response.json()
|
||||||
|
if "errors" in response_json:
|
||||||
|
# Handle the case where there are errors in the response
|
||||||
|
print(f"Failed to send a notification for: {user_review}")
|
||||||
|
print(response_json)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Extract the updated data from the response
|
||||||
|
data = response_json.get("data", {})
|
||||||
|
notification = data.get("insert_notifications_one", {})
|
||||||
|
print(
|
||||||
|
f"🚩 Review flagged. This is not visible to users: {user_review}\n🔔 The user has received the following notification: {review_feedback}"
|
||||||
|
)
|
||||||
|
return notification
|
||||||
|
except Exception as e:
|
||||||
|
# Handle exceptions or network errors
|
||||||
|
print(f"Error sending a notification for: {user_review}")
|
||||||
|
print(str(e))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/check-review", methods=["POST"])
|
||||||
|
async def check_review():
|
||||||
|
auth_header = request.headers.get("secret-authorization-string")
|
||||||
|
if auth_header != "super_secret_string_123":
|
||||||
|
return jsonify({"message": "Unauthorized"}), 401
|
||||||
|
|
||||||
|
# Parse the review from the event payload
|
||||||
|
data = request.get_json()
|
||||||
|
user_review = data["event"]["data"]["new"]["text"]
|
||||||
|
user_id = data["event"]["data"]["new"]["user_id"]
|
||||||
|
review_id = data["event"]["data"]["new"]["id"]
|
||||||
|
|
||||||
|
# Check the review with ChatGPT
|
||||||
|
moderation_report = check_review_with_chat_gpt(user_review)
|
||||||
|
|
||||||
|
# If the review is appropriate, mark it as visible; if not, send a notification to the user
|
||||||
|
if moderation_report["is_appropriate"]:
|
||||||
|
await mark_review_as_visible(user_review, review_id)
|
||||||
|
else:
|
||||||
|
send_notification(user_review, user_id, moderation_report["feedback"])
|
||||||
|
|
||||||
|
return jsonify({"GPTResponse": moderation_report})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(port=4000)
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
You can run the server by running `python3 index.py` in your terminal.
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
If you see the message `Webhook server is running on port 4000`, you're good to go!
|
||||||
|
|
||||||
## Step 4: Test the setup
|
## Step 4: Test the setup
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user