snowleopard 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
snowleopard/__init__.py CHANGED
@@ -2,12 +2,12 @@
2
2
  # copyright 2025 Snow Leopard, Inc
3
3
  # released under the MIT license - see LICENSE file
4
4
 
5
- from snowleopard.async_client import AsyncSnowLeopardPlaygroundClient
6
- from snowleopard.client import SnowLeopardPlaygroundClient
5
+ from snowleopard.async_client import AsyncSnowLeopardClient
6
+ from snowleopard.client import SnowLeopardClient
7
7
 
8
- __version__ = "0.1.1"
8
+ __version__ = "0.2.0"
9
9
 
10
10
  __all__ = [
11
- "SnowLeopardPlaygroundClient",
12
- "AsyncSnowLeopardPlaygroundClient",
11
+ "SnowLeopardClient",
12
+ "AsyncSnowLeopardClient",
13
13
  ]
@@ -10,7 +10,7 @@ from snowleopard.client_base import SLClientBase
10
10
  from snowleopard.models import ResponseDataObjects, RetrieveResponseObjects, parse
11
11
 
12
12
 
13
- class AsyncSnowLeopardPlaygroundClient(SLClientBase):
13
+ class AsyncSnowLeopardClient(SLClientBase):
14
14
  client: httpx.AsyncClient
15
15
 
16
16
  def __init__(
@@ -26,9 +26,10 @@ class AsyncSnowLeopardPlaygroundClient(SLClientBase):
26
26
 
27
27
  async def retrieve(
28
28
  self,
29
- datafile_id: str,
29
+ *,
30
30
  user_query: str,
31
31
  known_data: Optional[Dict[str, Any]] = None,
32
+ datafile_id: Optional[str] = None,
32
33
  ) -> RetrieveResponseObjects:
33
34
  resp = await self.client.post(
34
35
  url=self._build_path(datafile_id, "retrieve"),
@@ -38,9 +39,10 @@ class AsyncSnowLeopardPlaygroundClient(SLClientBase):
38
39
 
39
40
  async def response(
40
41
  self,
41
- datafile_id: str,
42
- user_query: str,
42
+ *,
43
43
  known_data: Optional[Dict[str, Any]] = None,
44
+ user_query: str,
45
+ datafile_id: Optional[str] = None,
44
46
  ) -> AsyncGenerator[ResponseDataObjects, None]:
45
47
  async with self.client.stream(
46
48
  "POST",
snowleopard/cli.py CHANGED
@@ -9,7 +9,7 @@ import argparse
9
9
  from typing import List, Optional, Dict, Any
10
10
 
11
11
  from httpx import HTTPStatusError
12
- from snowleopard import __version__, SnowLeopardPlaygroundClient
12
+ from snowleopard import __version__, SnowLeopardClient
13
13
  from snowleopard.models import RetrieveResponseError
14
14
 
15
15
 
@@ -41,13 +41,15 @@ def _create_parser() -> argparse.ArgumentParser:
41
41
  response.set_defaults(command_func=_response)
42
42
 
43
43
  for subparser in (retrieve, response):
44
+ subparser.add_argument(
45
+ "--datafile", "-df", type=str, help="ID for playground datafile to query"
46
+ )
44
47
  subparser.add_argument(
45
48
  "--knownData",
46
49
  "-d",
47
50
  action="append",
48
51
  help="Known data in key=value format (can be specified multiple times)",
49
52
  )
50
- subparser.add_argument("datafile", type=str, help="ID for Datafile to query")
51
53
  subparser.add_argument("question", type=str, help="Natural language query")
52
54
 
53
55
  return parser
@@ -60,7 +62,10 @@ def _parse_known_data(known_data_list: Optional[List[str]]) -> Optional[Dict[str
60
62
  result = {}
61
63
  for item in known_data_list:
62
64
  if "=" not in item:
63
- print(f"Error: Invalid knownData format '{item}'. Expected key=value", file=sys.stderr)
65
+ print(
66
+ f"Error: Invalid knownData format '{item}'. Expected key=value",
67
+ file=sys.stderr,
68
+ )
64
69
  sys.exit(1)
65
70
  key, value = item.split("=", 1)
66
71
  result[key] = value
@@ -69,7 +74,7 @@ def _parse_known_data(known_data_list: Optional[List[str]]) -> Optional[Dict[str
69
74
 
70
75
  def _get_client(parsed_args):
71
76
  try:
72
- client = SnowLeopardPlaygroundClient(api_key=parsed_args.apikey, loc=parsed_args.loc)
77
+ client = SnowLeopardClient(api_key=parsed_args.apikey, loc=parsed_args.loc)
73
78
  except Exception as e:
74
79
  print(str(e), file=sys.stderr)
75
80
  sys.exit(1)
@@ -80,7 +85,11 @@ def _retrieve(parsed_args):
80
85
  try:
81
86
  known_data = _parse_known_data(parsed_args.knownData)
82
87
  with _get_client(parsed_args) as client:
83
- resp = client.retrieve(parsed_args.datafile, parsed_args.question, known_data)
88
+ resp = client.retrieve(
89
+ user_query=parsed_args.question,
90
+ known_data=known_data,
91
+ datafile_id=parsed_args.datafile,
92
+ )
84
93
  print(json.dumps(dataclasses.asdict(resp)))
85
94
  if isinstance(resp, RetrieveResponseError):
86
95
  sys.exit(1)
@@ -93,7 +102,11 @@ def _response(parsed_args):
93
102
  try:
94
103
  known_data = _parse_known_data(parsed_args.knownData)
95
104
  with _get_client(parsed_args) as client:
96
- for chunk in client.response(parsed_args.datafile, parsed_args.question, known_data):
105
+ for chunk in client.response(
106
+ known_data=known_data,
107
+ user_query=parsed_args.question,
108
+ datafile_id=parsed_args.datafile,
109
+ ):
97
110
  print(json.dumps(dataclasses.asdict(chunk)))
98
111
  except HTTPStatusError as e:
99
112
  print(str(e), file=sys.stderr)
snowleopard/client.py CHANGED
@@ -10,7 +10,7 @@ from snowleopard.client_base import SLClientBase
10
10
  from snowleopard.models import parse, RetrieveResponseObjects, ResponseDataObjects
11
11
 
12
12
 
13
- class SnowLeopardPlaygroundClient(SLClientBase):
13
+ class SnowLeopardClient(SLClientBase):
14
14
  client: httpx.Client
15
15
 
16
16
  def __init__(
@@ -26,9 +26,10 @@ class SnowLeopardPlaygroundClient(SLClientBase):
26
26
 
27
27
  def retrieve(
28
28
  self,
29
- datafile_id: str,
29
+ *,
30
30
  user_query: str,
31
31
  known_data: Optional[Dict[str, Any]] = None,
32
+ datafile_id: Optional[str] = None,
32
33
  ) -> RetrieveResponseObjects:
33
34
  resp = self.client.post(
34
35
  url=self._build_path(datafile_id, "retrieve"),
@@ -40,9 +41,10 @@ class SnowLeopardPlaygroundClient(SLClientBase):
40
41
 
41
42
  def response(
42
43
  self,
43
- datafile_id: str,
44
- user_query: str,
44
+ *,
45
45
  known_data: Optional[Dict[str, Any]] = None,
46
+ user_query: str,
47
+ datafile_id: Optional[str] = None,
46
48
  ) -> Generator[ResponseDataObjects, None, None]:
47
49
  with self.client.stream(
48
50
  "POST",
@@ -3,6 +3,7 @@
3
3
  # released under the MIT license - see LICENSE file
4
4
 
5
5
  import os
6
+ from abc import abstractmethod
6
7
  from dataclasses import dataclass
7
8
  from typing import Optional, Dict, Any
8
9
 
@@ -25,6 +26,44 @@ class SLConfig:
25
26
 
26
27
 
27
28
  class SLClientBase:
29
+ @abstractmethod
30
+ def retrieve(
31
+ self,
32
+ *,
33
+ user_query: str,
34
+ known_data: Optional[Dict[str, Any]] = None,
35
+ datafile_id: Optional[str] = None,
36
+ ):
37
+ """
38
+ The primary for developers building AI agents that needs to retrieve data from a database directly.
39
+
40
+ Takes a natural language question (usually from the user or the agent) and returns the data required to answer
41
+ the query in an LLM-friendly object.
42
+
43
+ :param datafile_id: (optional) The playground datafile-id if hitting a Snow Leopard api directly
44
+ :param user_query: Natural language query to execute against the Playground datafile
45
+ :param known_data: Additional context about the user_query
46
+ """
47
+ ...
48
+
49
+ @abstractmethod
50
+ def response(
51
+ self,
52
+ *,
53
+ known_data: Optional[Dict[str, Any]] = None,
54
+ user_query: str,
55
+ datafile_id: Optional[str] = None,
56
+ ):
57
+ """
58
+ Takes a natural language question (usually from the user or the agent) and returns the data required to answer
59
+ the query as well as a LLM summary of the returned data.
60
+
61
+ :param datafile_id: (optional) The playground datafile-id if hitting a Snow Leopard api directly
62
+ :param user_query: Natural language query to execute against the Playground datafile
63
+ :param known_data: (optional) Additional context about the user_query
64
+ """
65
+ ...
66
+
28
67
  @staticmethod
29
68
  def _config(
30
69
  api_key: Optional[str], timeout: Optional[httpx.Timeout], loc: Optional[str]
@@ -46,7 +85,10 @@ class SLClientBase:
46
85
 
47
86
  @staticmethod
48
87
  def _build_path(datafile_id: str, endpoint: str) -> str:
49
- return f"datafiles/{datafile_id}/{endpoint}"
88
+ if datafile_id is None:
89
+ return endpoint
90
+ else:
91
+ return f"datafiles/{datafile_id}/{endpoint}"
50
92
 
51
93
  @staticmethod
52
94
  def _build_request_body(
snowleopard/models.py CHANGED
@@ -11,6 +11,7 @@ from typing import Any, Dict, List, Optional, Union
11
11
 
12
12
  class StrEnum(str, Enum):
13
13
  """String enum compatible with Python 3.8"""
14
+
14
15
  pass
15
16
 
16
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: snowleopard
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: snowleopard.ai client library
5
5
  Author-email: Snowy <hello@snowleopard.ai>
6
6
  License: MIT License
@@ -34,7 +34,9 @@ Description-Content-Type: text/markdown
34
34
 
35
35
  # Snow Leopard SDK for Python
36
36
 
37
- Python client library for [Snow Leopard Playground](https://try.snowleopard.ai) APIs.
37
+ This repo contains the Python client library for [Snow Leopard Playground](https://try.snowleopard.ai) APIs.
38
+
39
+ See our [API documentation](https://docs.snowleopard.ai/#api-documentation) for more details.
38
40
 
39
41
  ## Installation
40
42
 
@@ -45,16 +47,13 @@ pip install snowleopard
45
47
  ## Quick Start
46
48
 
47
49
  ```python
48
- from snowleopard import SnowLeopardPlaygroundClient
50
+ from snowleopard import SnowLeopardClient
49
51
 
50
- # Initialize the client (or AsyncSnowLeopardPlaygroundClient)
51
- client = SnowLeopardPlaygroundClient(api_key="your-api-key")
52
+ # Initialize the client (or AsyncSnowLeopardClient)
53
+ client = SnowLeopardClient(api_key="your-api-key")
52
54
 
53
55
  # Query your data in natural language
54
- response = client.retrieve(
55
- datafile_id="your-datafile-id",
56
- user_query="How many users signed up last month?"
57
- )
56
+ response = client.retrieve(user_query="How many users signed up last month?", datafile_id="your-datafile-id")
58
57
  ```
59
58
 
60
59
  ## Getting Started
@@ -69,7 +68,7 @@ response = client.retrieve(
69
68
  Or pass it directly to the client:
70
69
 
71
70
  ```python
72
- SnowLeopardPlaygroundClient(api_key="your-api-key")
71
+ SnowLeopardClient(api_key="your-api-key")
73
72
  ```
74
73
 
75
74
  ## Usage
@@ -77,31 +76,31 @@ response = client.retrieve(
77
76
  ### Synchronous Client
78
77
 
79
78
  ```python
80
- from snowleopard import SnowLeopardPlaygroundClient
79
+ from snowleopard import SnowLeopardClient
81
80
 
82
- with SnowLeopardPlaygroundClient() as client:
83
- # Get data directly from a natural language query
84
- response = client.retrieve("datafile-id", "What's the total revenue?")
85
- print(response.data)
86
-
87
- # Stream natural language summary of live data
88
- for chunk in client.response("datafile-id", "Show me top 10 customers"):
89
- print(chunk)
81
+ with SnowLeopardClient() as client:
82
+ # Get data directly from a natural language query
83
+ response = client.retrieve(user_query="How many superheroes are there?")
84
+ print(response.data)
85
+
86
+ # Stream natural language summary of live data
87
+ for chunk in client.response(user_query="How many superheroes are there?"):
88
+ print(chunk)
90
89
  ```
91
90
 
92
91
  ### Async Client
93
92
 
94
93
  ```python
95
- from snowleopard import AsyncSnowLeopardPlaygroundClient
94
+ from snowleopard import AsyncSnowLeopardClient
96
95
 
97
- async with AsyncSnowLeopardPlaygroundClient() as client:
98
- # Get complete results
99
- response = await client.retrieve("datafile-id", "What's the total revenue?")
100
- print(response.data)
96
+ async with AsyncSnowLeopardClient() as client:
97
+ # Get complete results
98
+ response = await client.retrieve(user_query="How many superheroes are there?")
99
+ print(response.data)
101
100
 
102
- # Get streaming results
103
- async for chunk in client.response("datafile-id", "Show me top 10 customers"):
104
- print(chunk)
101
+ # Get streaming results
102
+ async for chunk in client.response(user_query="How many superheroes are there?"):
103
+ print(chunk)
105
104
  ```
106
105
 
107
106
  ### CLI
@@ -110,10 +109,22 @@ The SDK includes a command-line interface:
110
109
 
111
110
  ```bash
112
111
  pip install snowleopard
113
- snowy retrieve <datafile-id> "How many records are there?"
114
- snowy response <datafile-id> "Summarize the data"
112
+ snowy retrieve --datafile <datafile-id> "How many records are there?"
113
+ snowy response --datafile <datafile-id> "Summarize the data"
115
114
  ```
116
115
 
116
+ ### On Premise Customers
117
+
118
+ For our customers who have a separate deployment per dataset, you should declare <url> explicitly when creating a
119
+ client and omit <datafile id> when querying.
120
+
121
+ Example:
122
+ ```python
123
+ client = SnowLeopardClient(url="https://{your-vm-ip}:{port}", api_key="your-api-key")
124
+ response = client.retrieve(user_query="How many users signed up last month?")
125
+ ```
126
+
127
+
117
128
  ## Contributing
118
129
 
119
130
  For SDK developer docs and how to contribute, see [CONTRIBUTING.md](CONTRIBUTING.md)
@@ -0,0 +1,11 @@
1
+ snowleopard/__init__.py,sha256=q2PBrFC6njiGSnk2apaohSpWbvTFFoiV5Aup9D3u3_U,314
2
+ snowleopard/async_client.py,sha256=IqWpv5CCYwGtuWAGMHFE4dInP6l643WePTEWvytSCsg,1994
3
+ snowleopard/cli.py,sha256=0fXljUETy2RhC2kfuvhk-DKORvWYz0Zm_AUWuqrf1EY,3968
4
+ snowleopard/client.py,sha256=YnnCkAdPzumckxhm_DiL2uVsUP9RF_P8ILMZDUF-tlY,1990
5
+ snowleopard/client_base.py,sha256=hLmtd6W_wuHp-oh5dTAzpEyRkniyuyho_qJy4-k6cdE,3468
6
+ snowleopard/models.py,sha256=A3dFN4X9h31rK-OObvBYJklCgrOdiLpgWZH0L_liak0,2859
7
+ snowleopard-0.2.0.dist-info/METADATA,sha256=rlQZtSsoKk9BtKcTsAAHbIUIZr7h5LWakXyv84sPTBc,4223
8
+ snowleopard-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
9
+ snowleopard-0.2.0.dist-info/entry_points.txt,sha256=KoByMlsBKmDB6_iwkrTCFyl2BT9bjBuKUZth40aXx70,47
10
+ snowleopard-0.2.0.dist-info/licenses/LICENSE,sha256=Lw8Ah-T2MngQlqtV8GCML7qD1OPJ5QnccfJBB_U3f2A,1072
11
+ snowleopard-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,11 +0,0 @@
1
- snowleopard/__init__.py,sha256=bN7CK0iAiVg6get_gDBW47JWYzwJ83AZzeVf1bTc_II,354
2
- snowleopard/async_client.py,sha256=ybTkgqO5SUHq8K0QJbrsvyzZQxlmecjExfacOF4PR2U,1948
3
- snowleopard/cli.py,sha256=xb1DlP2nm-pkiH4I4U0fHko06yaQZnOwIhjn2tIvc7Y,3705
4
- snowleopard/client.py,sha256=-oVa7yegfVgJ2p7DVCZhTdA6DOs_Rs69mryCNsH9p6I,1944
5
- snowleopard/client_base.py,sha256=7hoFmnCfeC1fcBMoOYKVmniSUqsWhe5moGUhlhqf_lo,1903
6
- snowleopard/models.py,sha256=5kFRjfwe79Cx6tYneLMWKloyGQylYc2pPHoFcwO3GlU,2858
7
- snowleopard-0.1.1.dist-info/METADATA,sha256=01OaSIIMjzC8jSY-x6yMKNhsOQAPyA3nVuae58mARQY,3804
8
- snowleopard-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
- snowleopard-0.1.1.dist-info/entry_points.txt,sha256=KoByMlsBKmDB6_iwkrTCFyl2BT9bjBuKUZth40aXx70,47
10
- snowleopard-0.1.1.dist-info/licenses/LICENSE,sha256=Lw8Ah-T2MngQlqtV8GCML7qD1OPJ5QnccfJBB_U3f2A,1072
11
- snowleopard-0.1.1.dist-info/RECORD,,