Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

out api request method #39

Merged
merged 4 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 74 additions & 19 deletions api_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import io
from functools import partial
import xml.etree.ElementTree as ET
from urllib.parse import urlparse
from urllib.parse import urlparse, urlencode
import threading

from sc_logging import logger
from text_detection_target import TextDetectionTargetWithResult
from storage import fetch_data, subscribe_to_data

out_api_url = fetch_data("scoresight.json", "out_api_url", None)
out_api_encoding = fetch_data("scoresight.json", "out_api_encoding", "JSON")
out_api_encoding = fetch_data("scoresight.json", "out_api_encoding", "JSON (Full)")
out_api_method = fetch_data("scoresight.json", "out_api_method", "POST")


def is_valid_url_urllib(url):
Expand All @@ -33,13 +34,21 @@ def setup_out_api_encoding(encoding):
out_api_encoding = encoding


def setup_out_api_method(method):
global out_api_method
out_api_method = method


subscribe_to_data("scoresight.json", "out_api_url", setup_out_api_url)
subscribe_to_data("scoresight.json", "out_api_encoding", setup_out_api_encoding)
subscribe_to_data("scoresight.json", "out_api_method", setup_out_api_method)


def update_out_api(data: list[TextDetectionTargetWithResult]):
if out_api_url is None or out_api_encoding is None:
logger.error(f"Output API not set up: {out_api_url}, {out_api_encoding}")
if out_api_url is None or out_api_encoding is None or out_api_method is None:
logger.error(
f"Output API not set up: {out_api_url}, {out_api_encoding}, {out_api_method}"
)
return

# validate the URL
Expand All @@ -51,14 +60,20 @@ def update_out_api(data: list[TextDetectionTargetWithResult]):

def send_data():
try:
if out_api_encoding == "JSON":
response = send_json(data)
elif out_api_encoding == "XML":
response = send_xml(data)
elif out_api_encoding == "CSV":
response = send_csv(data)
if out_api_method == "GET":
response = send_get(data)
else:
logger.error("Invalid encoding: %s", out_api_encoding)
if out_api_encoding.startswith("JSON"):
response = send_json(data, out_api_encoding)
elif out_api_encoding == "XML":
response = send_xml(data)
elif out_api_encoding == "CSV":
response = send_csv(data)
else:
logger.error("Invalid encoding: %s", out_api_encoding)
return

if response is None:
return

if response.status_code != 200:
Expand All @@ -72,13 +87,41 @@ def send_data():
thread.start()


def send_json(data: list[TextDetectionTargetWithResult]):
def send_get(data: list[TextDetectionTargetWithResult]):
out_api_url_copy = out_api_url
# add the data to the URL as query parameters
# check if the URL already has query parameters
if "?" in out_api_url_copy:
out_api_url_copy += "&"
else:
out_api_url_copy += "?"
out_api_url_copy += urlencode({result.name: result.result for result in data})
logger.debug(f"GET URL: {out_api_url_copy}")
response = requests.get(out_api_url_copy)
return response


def send_json(data: list[TextDetectionTargetWithResult], encoding: str):
headers = {"Content-Type": "application/json"}
response = requests.post(
out_api_url,
headers=headers,
data=json.dumps([result.to_dict() for result in data]),
)
if encoding == "JSON (Full)":
json_data_dump = json.dumps([result.to_dict() for result in data])
elif encoding == "JSON (Simple key-value)":
json_data_dump = json.dumps({result.name: result.result for result in data})
if out_api_method == "POST":
response = requests.post(
out_api_url,
headers=headers,
data=json_data_dump,
)
elif out_api_method == "PUT":
response = requests.put(
out_api_url,
headers=headers,
data=json_data_dump,
)
else:
logger.error(f"Invalid method: {out_api_method}")
return None
return response


Expand All @@ -95,7 +138,13 @@ def send_xml(data: list[TextDetectionTargetWithResult]):
resultEl.set("width", str(targetWithResult.width()))
resultEl.set("height", str(targetWithResult.height()))
xml_data = ET.tostring(root, encoding="utf-8")
response = requests.post(out_api_url, headers=headers, data=xml_data)
if out_api_method == "POST":
response = requests.post(out_api_url, headers=headers, data=xml_data)
elif out_api_method == "PUT":
response = requests.put(out_api_url, headers=headers, data=xml_data)
else:
logger.error(f"Invalid method: {out_api_method}")
return None
return response


Expand All @@ -116,5 +165,11 @@ def send_csv(data: list[TextDetectionTargetWithResult]):
result.height(),
]
)
response = requests.post(out_api_url, headers=headers, data=output.getvalue())
if out_api_method == "POST":
response = requests.post(out_api_url, headers=headers, data=output.getvalue())
elif out_api_method == "PUT":
response = requests.put(out_api_url, headers=headers, data=output.getvalue())
else:
logger.error(f"Invalid method: {out_api_method}")
return None
return response
Binary file added docs/image-29.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/image-30.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 37 additions & 17 deletions docs/out_api.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# ScoreSight Outboud API Integration Tutorial
# ScoreSight Outbound API Integration Tutorial

ScoreSight now offers the ability to send OCR-extracted scoreboard data to external APIs. This tutorial will guide you through setting up the feature and provide a simple Python script to receive the data.

## Enabling API Requests in ScoreSight

1. Open ScoreSight and navigate to the "API" tab in the bottom left corner.

![alt text](image-21.png)
![alt text](image-29.png)

2. Check the box labeled "Send out API requests to external services".
3. Enter the URL where you want to send the data in the provided box.
4. Select the encoding format for the data: JSON, XML, or CSV.
4. Select the encoding format for the data: JSON (Full), Json (Simple key-value) XML, or CSV.

![alt text](image-22.png)
![alt text](image-30.png)

5. Choose the HTTP method for the API request: POST, PUT, or GET.

## Troubleshooting

Expand All @@ -35,13 +37,17 @@ If you encounter issues with the API integration, follow these steps to troubles
3. Encoding Format:
- Verify that the encoding format selected in ScoreSight (JSON, XML, or CSV) matches the format your receiving script or API expects.

4. Server Availability and Authentication:
4. HTTP Method:
- Ensure that the selected HTTP method (POST, PUT, or GET) is supported by your receiving API.
- Verify that your API is configured to handle the chosen method correctly.

5. Server Availability and Authentication:
- If using the provided Python script, make sure it's running before attempting to send data from ScoreSight.
- For external APIs, check if the service is up and accessible.
- If your external API requires an API key or authentication, ensure these details are correctly included in the URL or headers.
- If testing locally, check that your firewall isn't blocking the connection.

5. Test with a Simple Server:
6. Test with a Simple Server:
- Use the provided Python script below as a test server to isolate whether the issue is with ScoreSight or the receiving end.

If problems persist after trying these steps, consider reaching out to ScoreSight support for further assistance.
Expand All @@ -56,16 +62,30 @@ import json

class RequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)

print("Received data:")
try:
# Assuming JSON format, adjust if using XML or CSV
data = json.loads(post_data.decode('utf-8'))
print(json.dumps(data, indent=2))
except json.JSONDecodeError:
print(post_data.decode('utf-8'))
self.handle_request()

def do_PUT(self):
self.handle_request()

def do_GET(self):
self.handle_request()

def handle_request(self):
if self.command in ['POST', 'PUT']:
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)

print(f"Received {self.command} data:")
try:
# Assuming JSON format, adjust if using XML or CSV
data = json.loads(post_data.decode('utf-8'))
print(json.dumps(data, indent=2))
except json.JSONDecodeError:
print(post_data.decode('utf-8'))
elif self.command == 'GET':
print("Received GET request")
print(f"Path: {self.path}")
print(f"Headers: {self.headers}")

self.send_response(200)
self.end_headers()
Expand Down Expand Up @@ -100,7 +120,7 @@ You may see in the console an output similar to:

```
127.0.0.1 - - [nn/nn/nnnn 10:57:03] "POST / HTTP/1.1" 200 -
Received data: Name,Text,State,X,Y,Width,Height
Received POST data: Name,Text,State,X,Y,Width,Height
Time,0:52,SameNoChange,843.656319861826,663.0215827338131,359.13669064748206,207.19424460431662
Home Score,35,SameNoChange,525.969716884406,638.4370727628325,214.62426933453253,175.27648662320166
```
Expand Down
8 changes: 8 additions & 0 deletions mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ def __init__(self, translator: QTranslator, parent: QObject):
fetch_data("scoresight.json", "out_api_encoding", "JSON")
)
)
self.ui.comboBox_outApiMethod.currentTextChanged.connect(
partial(self.globalSettingsChanged, "out_api_method")
)
self.ui.comboBox_outApiMethod.setCurrentIndex(
self.ui.comboBox_outApiMethod.findText(
fetch_data("scoresight.json", "out_api_method", "POST")
)
)

self.obs_websocket_client = None

Expand Down
37 changes: 27 additions & 10 deletions mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,12 @@
<widget class="QComboBox" name="comboBox_api_encode">
<item>
<property name="text">
<string>JSON</string>
<string>JSON (Full)</string>
</property>
</item>
<item>
<property name="text">
<string>JSON (Simple key-value)</string>
</property>
</item>
<item>
Expand Down Expand Up @@ -1511,16 +1516,28 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_is_websocket">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Not implemented yet.</string>
</property>
<property name="text">
<string>Websocket</string>
<widget class="QComboBox" name="comboBox_outApiMethod">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>POST</string>
</property>
</item>
<item>
<property name="text">
<string>PUT</string>
</property>
</item>
<item>
<property name="text">
<string>GET</string>
</property>
</item>
</widget>
</item>
</layout>
Expand Down
Loading