Skip to content

Commit

Permalink
Merge pull request #13 from Riminder/feat/asking-unfolding-apis
Browse files Browse the repository at this point in the history
feat: asking, authentication, and unfolding APIs; and test suite
  • Loading branch information
corentin-hrflow authored Dec 22, 2023
2 parents 2f71beb + a741f47 commit 65c9d2a
Show file tree
Hide file tree
Showing 53 changed files with 3,496 additions and 474 deletions.
11 changes: 10 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
HRFLOW_API_KEY="___FILL_ME___"
HRFLOW_USER_EMAIL="___FILL_ME___"
HRFLOW_API_KEY_READ="___FILL_ME___"
HRFLOW_USER_EMAIL="___FILL_ME___"
HRFLOW_ALGORITHM_KEY="___FILL_ME___"
HRFLOW_BOARD_KEY="___FILL_ME___"
HRFLOW_JOB_KEY="___JOB_KEY_IN_BOARD___"
HRFLOW_PROFILE_KEY="___PROFILE_KEY_IN_SOURCE_QUICKSILVER_SYNC___"
HRFLOW_SOURCE_KEY_HAWK_SYNC="___FILL_ME___"
HRFLOW_SOURCE_KEY_QUICKSILVER_SYNC="___FILL_ME___"
HRFLOW_SOURCE_KEY_QUICKSILVER_ASYNC="___FILL_ME___"
HRFLOW_SOURCE_KEY_MOZART_ASYNC="___FILL_ME___"
6 changes: 6 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[flake8]
max-line-length = 88
exclude = .pytest_cache, __pycache__, .env, .venv
black-config = pyproject.toml
per-file-ignores = __init__.py:F401
ignore = E731, W503, E203
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ credentials
credentials_seg
test/*
test_assets/*
tests/assets
.htpasswd

docker/dependencies/libs/*
Expand Down
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ ARGS :=
clean:
rm -rf build dist *.egg-info

clean_cache:
find . -type d \( -name '__pycache__' -o -name '.pytest_cache' \) -exec rm -rf {} +
rm -rf tests/assets

build:
poetry build

Expand All @@ -14,4 +18,13 @@ deploy-test:
poetry publish -r test-pypi --build

deploy:
poetry publish --build
poetry publish --build

flake8:
poetry run flake8 --config=./.flake8

style:
poetry run isort . && poetry run black --config=./pyproject.toml .

check:
bash ./check.sh
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Install using `pip install -U hrflow` or `conda install hrflow -c conda-forge`.

```py
from hrflow import Hrflow
client = Hrflow(api_secret="YOUR_API_KEY"; api_user="YOU_USER_EMAIL")
client = Hrflow(api_secret="YOUR_API_KEY", api_user="YOU_USER_EMAIL")

# read file from directory (in binary mode)
with open("path_to_file.pdf", "rb") as f:
Expand Down
13 changes: 13 additions & 0 deletions check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

PYTEST_RUN="poetry run pytest"
PYTEST_OPTIONS=(--verbose --tb=long --strict-markers --durations=0 --datefmt "%Y-%m-%d %H:%M:%S.%f%z")
PYTEST_DIR=tests/

if [ "$#" -gt 0 ]; then
for marker in "$@"; do
$PYTEST_RUN "${PYTEST_OPTIONS[@]}" "$PYTEST_DIR" -m "$marker"
done
else
$PYTEST_RUN "${PYTEST_OPTIONS[@]}" "$PYTEST_DIR"
fi
12 changes: 9 additions & 3 deletions hrflow/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
from .__version__ import (
__author__,
__author_email__,
__description__,
__license__,
__title__,
__url__,
__version__,
)
from .hrflow.hrflow import Hrflow

from .__version__ import __title__, __description__, __url__, __version__
from .__version__ import __author__, __author_email__, __license__
2 changes: 1 addition & 1 deletion hrflow/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
__version__ = importlib.metadata.version("hrflow")
__author__ = "HrFlow.ai"
__author_email__ = "contact@hrflow.ai"
__license__ = "MIT"
__license__ = "MIT"
35 changes: 35 additions & 0 deletions hrflow/hrflow/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import typing as t

from ..utils import validate_key, validate_response

API_SECRET_REGEX = r"^ask[rw]?_[0-9a-f]{32}$"


class Auth:
def __init__(self, api):
self.client = api

def get(self) -> t.Dict[str, t.Any]:
"""
Try your API Keys. This endpoint allows you to learn how to add the right
information to your API calls, so you can make them.
Args:
api_user: <str>
Your HrFlow.ai account's email.
api_secret: <str>
Your API Key.
Returns:
`/auth` response
"""

validate_key(
"api_secret",
self.client.auth_header.get("X-API-KEY"),
regex=API_SECRET_REGEX,
)

response = self.client.get("auth")

return validate_response(response)
60 changes: 32 additions & 28 deletions hrflow/hrflow/board/__init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
from ..utils import validate_key, validate_page, validate_limit, validate_value, validate_response

from ..utils import ORDER_BY_VALUES
from ..utils import (
ORDER_BY_VALUES,
validate_key,
validate_limit,
validate_page,
validate_response,
validate_value,
)


class Board(object):

def __init__(self, client):
self.client = client

def list(self, name=None, page=1, limit=30, sort_by='date', order_by='desc'):
def list(self, name=None, page=1, limit=30, sort_by="date", order_by="desc"):
"""
Search boards for given filters.
Args:
name: <string>
name
page: <integer>
page
limit: <integer>
limit
sort_by: <string>
sort_by
order_by: <string>
order_by
Returns
Result of source's search
Search boards for given filters.
Args:
name: <string>
name
page: <integer>
page
limit: <integer>
limit
sort_by: <string>
sort_by
order_by: <string>
order_by
Returns
Result of source's search
"""
query_params = {}
Expand All @@ -40,15 +44,15 @@ def list(self, name=None, page=1, limit=30, sort_by='date', order_by='desc'):

def get(self, key=None):
"""
Get source given a board key.
Get source given a board key.
Args:
key: <string>
board_key
Returns
Board if exists
Args:
key: <string>
board_key
Returns
Board if exists
"""
query_params = {"key": validate_key("Board", key)}
response = self.client.get('board', query_params)
response = self.client.get("board", query_params)
return validate_response(response)
51 changes: 32 additions & 19 deletions hrflow/hrflow/hrflow.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import requests as req
import json

import requests as req

from .auth import Auth
from .board import Board
from .job import Job
from .text import Text
from .profile import Profile
from .webhook import Webhook
from .rating import Rating
from .source import Source
from .text import Text
from .tracking import Tracking
from .rating import Rating

from .webhook import Webhook

CLIENT_API_URL = "https://api.hrflow.ai/v1/"

Expand All @@ -32,10 +33,12 @@ def __init__(
The API URL. Defaults to https://api.hrflow.ai/v1/
api_secret: <string>
The API secret key. You can find it in your Hrflow.ai account.
The API secret key. You can find it in your
Hrflow.ai account.
api_user: <string>
The API user email. You can find it in your Hrflow.ai account.
The API user email. You can find it in your
Hrflow.ai account.
webhook_secret: <string>
Expand All @@ -45,6 +48,7 @@ def __init__(
self.api_url = api_url
self.auth_header = {"X-API-KEY": api_secret, "X-USER-EMAIL": api_user}
self.webhook_secret = webhook_secret
self.auth = Auth(self)
self.job = Job(self)
self.profile = Profile(self)
self.text = Text(self)
Expand Down Expand Up @@ -81,10 +85,12 @@ def get(self, resource_endpoint, query_params={}):
The resource endpoint. For example: "job/indexing"
query_params: <dict>
The query parameters to be sent to the API. It must be a dictionary.
The query parameters to be sent to the API. It
must be a dictionary.
Returns
Make the corresponding GET request to the Hrflow API and returns the response object.
Make the corresponding GET request to the Hrflow API and returns the
response object.
"""
url = self._create_request_url(resource_endpoint)
if query_params:
Expand All @@ -104,16 +110,21 @@ def post(self, resource_endpoint, data={}, json={}, files=None):
The resource endpoint. For example: "job/indexing"
data: <dict>
The data payload (for multipart/formdata) to be sent to the API. It must be a dictionary.
The data payload (for multipart/formdata) to be
sent to the API. It must be a dictionary.
json: <dict>
The json payload to be sent to the API. It must be a dictionary.
The json payload to be sent to the API. It must
be a dictionary.
files: <dict>
The files payload to be sent to the API. It must be a dictionary. (ie. {"file": open("file.pdf", "rb")}
The files payload to be sent to the API. It must
be a dictionary. (ie. {"file": open("file.pdf",
"rb")}
Returns:
Makes the corresponding POST request to the Hrflow API and returns the response object.
Makes the corresponding POST request to the Hrflow API and returns the
response object.
"""
url = self._create_request_url(resource_endpoint)
if files:
Expand All @@ -133,11 +144,12 @@ def patch(self, resource_endpoint, json={}):
The resource endpoint. For example: "job/indexing"
json: <dict>
The json payload to be sent to the API. It must be a dictionary.
The json payload to be sent to the API. It must
be a dictionary.
Returns:
Makes the corresponding PATCH request to the Hrflow API and returns the response object.
Makes the corresponding PATCH request to the Hrflow API and returns the
response object.
"""
url = self._create_request_url(resource_endpoint)
data = self._validate_args(json)
Expand All @@ -154,11 +166,12 @@ def put(self, resource_endpoint, json={}):
The resource endpoint. For example: "job/indexing"
json: <dict>
The json payload to be sent to the API. It must be a dictionary.
The json payload to be sent to the API. It must
be a dictionary.
Returns:
Makes the corresponding PUT request to the Hrflow API and returns the response object.
Makes the corresponding PUT request to the Hrflow API and returns the
response object.
"""
url = self._create_request_url(resource_endpoint)
return req.put(url, headers=self.auth_header, json=json)
8 changes: 5 additions & 3 deletions hrflow/hrflow/job/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from .parsing import JobParsing
from .asking import JobAsking
from .embedding import JobEmbedding
from .searching import JobSearching
from .scoring import JobScoring
from .parsing import JobParsing
from .reasoning import JobReasoning
from .scoring import JobScoring
from .searching import JobSearching
from .storing import JobStoring


class Job:
def __init__(self, client):
self.client = client
self.asking = JobAsking(self.client)
self.parsing = JobParsing(self.client)
self.embedding = JobEmbedding(self.client)
self.searching = JobSearching(self.client)
Expand Down
Loading

0 comments on commit 65c9d2a

Please sign in to comment.