eai_answers_lib 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: eai_answers_lib
3
+ Version: 0.1.0
4
+ Summary: Library to interact with Expert AI Answers engine
5
+ Author: Simone Martin
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: loguru>=0.7.3
9
+ Requires-Dist: pydantic>=2.13.3
10
+ Requires-Dist: requests>=2.33.1
11
+ Provides-Extra: dev
12
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
13
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
14
+ Requires-Dist: responses>=0.25.0; extra == "dev"
15
+
16
+ # Answers Lib
17
+
18
+ Library to interact with Expert AI Answers engine.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install eai-answers-lib
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```python
29
+ from eai_answers_lib import Answers
30
+
31
+ a = Answers()
32
+ result = a.get_answers(query="Your question")
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ ```python
38
+ a = Answers(
39
+ enable_auth=True,
40
+ client_id="your-client-id",
41
+ client_secret="your-client-secret"
42
+ )
43
+ ```
44
+
45
+ ## Environment Variables
46
+
47
+ - `ANSWERS_ENDPOINT` - API endpoint URL
48
+ - `ANSWERS_CLIENT_ID` - Client ID for authentication
49
+ - `ANSWERS_CLIENT_SECRET` - Client secret for authentication
@@ -0,0 +1,34 @@
1
+ # Answers Lib
2
+
3
+ Library to interact with Expert AI Answers engine.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install eai-answers-lib
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from eai_answers_lib import Answers
15
+
16
+ a = Answers()
17
+ result = a.get_answers(query="Your question")
18
+ ```
19
+
20
+ ## Authentication
21
+
22
+ ```python
23
+ a = Answers(
24
+ enable_auth=True,
25
+ client_id="your-client-id",
26
+ client_secret="your-client-secret"
27
+ )
28
+ ```
29
+
30
+ ## Environment Variables
31
+
32
+ - `ANSWERS_ENDPOINT` - API endpoint URL
33
+ - `ANSWERS_CLIENT_ID` - Client ID for authentication
34
+ - `ANSWERS_CLIENT_SECRET` - Client secret for authentication
@@ -0,0 +1,40 @@
1
+ [project]
2
+ name = "eai_answers_lib"
3
+ version = "0.1.0"
4
+ description = "Library to interact with Expert AI Answers engine"
5
+ authors = [{name = "Simone Martin"}]
6
+ readme = "README.md"
7
+ requires-python = ">=3.12"
8
+ dependencies = [
9
+ "loguru>=0.7.3",
10
+ "pydantic>=2.13.3",
11
+ "requests>=2.33.1",
12
+ ]
13
+
14
+ [project.optional-dependencies]
15
+ dev = [
16
+ "ruff>=0.9.0",
17
+ "pytest>=8.0.0",
18
+ "responses>=0.25.0",
19
+ ]
20
+
21
+ [tool.uv]
22
+ dev-dependencies = [
23
+ "ruff>=0.9.0",
24
+ "pytest>=8.0.0",
25
+ "responses>=0.25.0",
26
+ ]
27
+
28
+ [tool.ruff]
29
+ target-version = "py312"
30
+
31
+ [tool.ruff.format]
32
+ quote-style = "double"
33
+
34
+ [tool.pytest.ini_options]
35
+ testpaths = ["tests"]
36
+ python_files = ["test_*.py", "*_test.py"]
37
+ python_functions = ["test_*"]
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: eai_answers_lib
3
+ Version: 0.1.0
4
+ Summary: Library to interact with Expert AI Answers engine
5
+ Author: Simone Martin
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: loguru>=0.7.3
9
+ Requires-Dist: pydantic>=2.13.3
10
+ Requires-Dist: requests>=2.33.1
11
+ Provides-Extra: dev
12
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
13
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
14
+ Requires-Dist: responses>=0.25.0; extra == "dev"
15
+
16
+ # Answers Lib
17
+
18
+ Library to interact with Expert AI Answers engine.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install eai-answers-lib
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```python
29
+ from eai_answers_lib import Answers
30
+
31
+ a = Answers()
32
+ result = a.get_answers(query="Your question")
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ ```python
38
+ a = Answers(
39
+ enable_auth=True,
40
+ client_id="your-client-id",
41
+ client_secret="your-client-secret"
42
+ )
43
+ ```
44
+
45
+ ## Environment Variables
46
+
47
+ - `ANSWERS_ENDPOINT` - API endpoint URL
48
+ - `ANSWERS_CLIENT_ID` - Client ID for authentication
49
+ - `ANSWERS_CLIENT_SECRET` - Client secret for authentication
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/eai_answers_lib.egg-info/PKG-INFO
4
+ src/eai_answers_lib.egg-info/SOURCES.txt
5
+ src/eai_answers_lib.egg-info/dependency_links.txt
6
+ src/eai_answers_lib.egg-info/requires.txt
7
+ src/eai_answers_lib.egg-info/top_level.txt
8
+ src/schemas/__init__.py
9
+ src/schemas/answers_schemas.py
10
+ src/services/__init__.py
11
+ src/services/logger.py
12
+ tests/test_answers.py
@@ -0,0 +1,8 @@
1
+ loguru>=0.7.3
2
+ pydantic>=2.13.3
3
+ requests>=2.33.1
4
+
5
+ [dev]
6
+ ruff>=0.9.0
7
+ pytest>=8.0.0
8
+ responses>=0.25.0
@@ -0,0 +1,2 @@
1
+ schemas
2
+ services
File without changes
@@ -0,0 +1,35 @@
1
+
2
+ from typing import Any, Dict, Optional, Union, List, Literal
3
+ from pydantic import BaseModel
4
+
5
+
6
+
7
+
8
+ class PackageAndCollection(BaseModel):
9
+ kb: str
10
+ description: str # collection description
11
+ id: str # collection id
12
+
13
+ class CollectionDocument(BaseModel):
14
+ data: str
15
+ dataAnnotation: Optional[str] = None
16
+ dataXml: Optional[str] = None
17
+ dataJson: Optional[Dict[Any, Any]] = None
18
+ size: Optional[int] = None
19
+ name: str
20
+
21
+ class AddCollectionRequest(BaseModel):
22
+ cogitoAnalysisMode: Optional[str] = None
23
+ removeAnnotations: Optional[bool] = True
24
+ ocr: Optional[bool] = False
25
+ doubleColumn: Optional[bool] = False
26
+ pageImages: Optional[bool] = False
27
+ indexStrategies: List[str]
28
+ engine: str
29
+ analyzer: Optional[str] = None
30
+ status: Optional[str] = None
31
+ messages: Optional[List[Dict[str, str]]] = None
32
+ documents: List[CollectionDocument]
33
+ pkg: str
34
+ collection: str
35
+
File without changes
@@ -0,0 +1,16 @@
1
+ from pathlib import Path
2
+ from loguru import logger
3
+
4
+ logs_path = Path(".logs")
5
+ logs_path.mkdir(parents=True, exist_ok=True)
6
+
7
+ #logger.remove() # Remove the default console logger
8
+ logger.add(
9
+ logs_path / "log_{time:YYYY-MM-DD}.log", # File name with date
10
+ rotation="1 day",
11
+ retention="2 months", # Keep 7 days of logs
12
+ # compression="zip", # Compress old logs
13
+ level="INFO", # Only log INFO and above
14
+ enqueue=True # Thread-safe logging
15
+ )
16
+
@@ -0,0 +1,156 @@
1
+ import pytest
2
+ import responses
3
+ from src import Answers
4
+
5
+
6
+ responses.mock.start()
7
+ responses.mock.register_uri(
8
+ responses.POST,
9
+ "https://api.example.com/auth/realms/test-realm/protocol/openid-connect/token",
10
+ json={"access_token": "test-token", "expires_in": 3600},
11
+ status=200,
12
+ )
13
+
14
+
15
+ @pytest.fixture
16
+ def mock_endpoint():
17
+ return "https://api.example.com"
18
+
19
+
20
+ @pytest.fixture
21
+ def answers(mock_endpoint):
22
+ return Answers(endpoint=mock_endpoint, enable_auth=False)
23
+
24
+
25
+ @pytest.fixture
26
+ def answers_with_auth(mock_endpoint):
27
+ return Answers(
28
+ endpoint=mock_endpoint,
29
+ enable_auth=True,
30
+ auth_path="auth",
31
+ realm="test-realm",
32
+ client_id="test-client",
33
+ client_secret="test-secret",
34
+ )
35
+
36
+
37
+ class TestInit:
38
+ def test_init_success(self, mock_endpoint):
39
+ answers = Answers(endpoint=mock_endpoint)
40
+ assert answers.endpoint == mock_endpoint
41
+
42
+ def test_init_missing_endpoint_raises(self):
43
+ with pytest.raises(ValueError, match="endpoint must be provided"):
44
+ Answers(endpoint=None)
45
+
46
+ def test_init_with_auth(self, mock_endpoint):
47
+ answers = Answers(
48
+ endpoint=mock_endpoint,
49
+ enable_auth=True,
50
+ auth_path="auth",
51
+ realm="test-realm",
52
+ client_id="client",
53
+ client_secret="secret",
54
+ )
55
+ assert answers.enable_auth is True
56
+ assert answers.auth_path == "auth"
57
+ assert answers.realm == "test-realm"
58
+
59
+ def test_init_default_paths(self, mock_endpoint):
60
+ answers = Answers(endpoint=mock_endpoint)
61
+ assert answers.query_path == "v1/query"
62
+ assert answers.status_path == "v1/status"
63
+
64
+
65
+ def test_refresh_bearer_success(answers_with_auth):
66
+ responses.mock.register_uri(
67
+ responses.POST,
68
+ "https://api.example.com/auth/realms/test-realm/protocol/openid-connect/token",
69
+ json={"access_token": "new-token", "expires_in": 3600},
70
+ status=200,
71
+ )
72
+ answers_with_auth.refresh_bearer()
73
+ assert answers_with_auth.bearer == "new-token"
74
+ assert answers_with_auth.token_expiration > 0
75
+
76
+
77
+ def test_refresh_bearer_failure(answers_with_auth):
78
+ responses.mock.register_uri(
79
+ responses.POST,
80
+ "https://api.example.com/auth/realms/test-realm/protocol/openid-connect/token",
81
+ status=401,
82
+ )
83
+ with pytest.raises(Exception, match="Error Refreshing authentication Bearer"):
84
+ answers_with_auth.refresh_bearer()
85
+
86
+
87
+ def test_get_auth_header_no_auth(answers):
88
+ headers = answers.get_auth_header()
89
+ assert headers == {}
90
+
91
+
92
+ def test_get_auth_header_with_auth(answers_with_auth):
93
+ headers = answers_with_auth.get_auth_header()
94
+ assert headers == {"Authorization": "Bearer test-token"}
95
+
96
+
97
+ @responses.activate
98
+ def test_start_query_task_success(answers):
99
+ responses.post(
100
+ "https://api.example.com/v1/query/pkg/collection",
101
+ json={"success": True, "data": {"task_id": "task-123"}},
102
+ status=200,
103
+ )
104
+ task_id = answers.start_query_task(payload={}, headers={}, pkg="pkg", collection="collection")
105
+ assert task_id == "task-123"
106
+
107
+
108
+ @responses.activate
109
+ def test_start_query_task_failure(answers):
110
+ responses.post(
111
+ "https://api.example.com/v1/query/pkg/collection",
112
+ json={"success": False, "data": {"error": "failed"}},
113
+ status=200,
114
+ )
115
+ with pytest.raises(Exception):
116
+ answers.start_query_task(payload={}, headers={}, pkg="pkg", collection="collection")
117
+
118
+
119
+ @responses.activate
120
+ def test_poll_query_status_success(answers):
121
+ responses.get(
122
+ "https://api.example.com/v1/status/task-123",
123
+ json={"success": True, "data": {"completed": True, "query_tasks": ["t1"], "completed_tasks": ["t1"]}},
124
+ status=200,
125
+ )
126
+ status = answers.poll_query_status(task_id="task-123", headers={})
127
+ assert status["success"] is True
128
+ assert status["data"]["completed"] is True
129
+
130
+
131
+ @responses.activate
132
+ def test_poll_query_status_failure(answers):
133
+ responses.get(
134
+ "https://api.example.com/v1/status/task-123",
135
+ json={"success": False, "messages": ["error"]},
136
+ status=200,
137
+ )
138
+ status = answers.poll_query_status(task_id="task-123", headers={})
139
+ assert status["success"] is False
140
+
141
+
142
+ @responses.activate
143
+ def test_call_full_flow(answers):
144
+ responses.post(
145
+ "https://api.example.com/v1/query/pkg/collection",
146
+ json={"success": True, "data": {"task_id": "task-456"}},
147
+ status=200,
148
+ )
149
+ responses.get(
150
+ "https://api.example.com/v1/status/task-456",
151
+ json={"success": True, "data": {"completed": True}},
152
+ status=200,
153
+ )
154
+ result = answers(payload={}, pkg="pkg", collection="collection")
155
+ assert result["success"] is True
156
+ assert result["data"]["completed"] is True