Skip to content

Commit c619ec8

Browse files
authored
GEN-1140 add billing capabilities (#8)
* Squashed 'protos/' changes from a643df8..8c94d7c 8c94d7c Merge pull request #10 from macrocosm-os/gen-1140_add_billing_to_const_api 066033c GEN-1140 Add billing to Const API b22028b GEN-1154: Add endpoint for validating reddit topics (#104) git-subtree-dir: protos git-subtree-split: 8c94d7c4b6b814e417e9070369916e03eeb13231 * added billing capabilities * version 1.0.0
1 parent b09aed9 commit c619ec8

22 files changed

+704
-31
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
Example of using the async Apex Chat API to stream a chat completion using the Macrocosmos SDK.
3+
"""
4+
5+
import asyncio
6+
import os
7+
import time
8+
9+
import macrocosmos as mc
10+
11+
12+
async def demo_deep_research():
13+
"""Demo deep research."""
14+
15+
messages = [
16+
mc.ChatMessage(
17+
role="user",
18+
content="How do you design a federated LLM training pipeline that shards the model across remote systems across untrusted nodes?",
19+
)
20+
]
21+
api_key = os.environ.get("APEX_API_KEY", os.environ.get("MACROCOSMOS_API_KEY"))
22+
23+
sampling_params = mc.SamplingParameters(
24+
temperature=0.6,
25+
top_p=0.95,
26+
max_new_tokens=8192,
27+
do_sample=False,
28+
)
29+
30+
client = mc.AsyncApexClient(
31+
max_retries=0,
32+
timeout=21000,
33+
api_key=api_key,
34+
app_name="examples/apex_chat_deep_research",
35+
)
36+
37+
try:
38+
start_time = time.time()
39+
response_stream = await client.chat.completions.create(
40+
model="mrfakename/mistral-small-3.1-24b-instruct-2503-hf",
41+
messages=messages,
42+
inference_mode="Chain-of-Thought",
43+
sampling_parameters=sampling_params,
44+
stream=True,
45+
)
46+
47+
print("Streaming response:")
48+
full_content = ""
49+
50+
chunk: mc.ChatCompletionChunkResponse
51+
async for chunk in response_stream:
52+
if chunk.choices and chunk.choices[0].delta.content:
53+
content = chunk.choices[0].delta.content
54+
full_content += content
55+
print(content, end="", flush=True)
56+
57+
except Exception as e:
58+
print(f"Unexpected Error: {e}")
59+
raise e
60+
finally:
61+
print(f"\nTotal time taken: {time.time() - start_time:.2f} seconds")
62+
63+
64+
if __name__ == "__main__":
65+
print("Testing streaming ChatCompletion:")
66+
asyncio.run(demo_deep_research())

examples/billing_usage_example.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import macrocosmos as mc
2+
import os
3+
4+
5+
def main():
6+
# Initialize the client
7+
client = mc.BillingClient(api_key=os.environ.get("MACROCOSMOS_API_KEY"))
8+
9+
# Get usage information for gravity
10+
response = client.billing.GetUsage()
11+
12+
# Print the response
13+
print(f"Available credits: {response.available_credits}")
14+
print(f"Used credits: {response.used_credits}")
15+
print(f"Remaining credits: {response.remaining_credits}")
16+
print("\nBilling rates:")
17+
for rate in response.billing_rates:
18+
print(f" - Rate type: {rate.rate_type}")
19+
print(f" Unit size: {rate.unit_size}")
20+
print(f" Unit type: {rate.unit_type}")
21+
print(f" Price per unit: {rate.price_per_unit} {rate.currency}")
22+
23+
24+
if __name__ == "__main__":
25+
main()

protos/billing/v1/billing.proto

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
syntax = "proto3";
2+
3+
package billing.v1;
4+
5+
option go_package = "macrocosm-os/rift/constellation_api/gen/billing/v1";
6+
7+
service BillingService {
8+
// Get the usage of the user's credits
9+
rpc GetUsage(GetUsageRequest) returns (GetUsageResponse);
10+
}
11+
12+
// GetUsageRequest is the request message for getting the usage of the user's credits
13+
message GetUsageRequest {
14+
// product_type: the type of the product (i.e. "gravity")
15+
string product_type = 1;
16+
}
17+
18+
// ProductPlan is details of the subscription plan for a product
19+
message BillingRate {
20+
// product_type: the type of the product (i.e. "gravity")
21+
string rate_type = 1;
22+
// unit_size: the size of the unit of the subscription (e.g. 1000, 10000, 100000)
23+
int64 unit_size = 2;
24+
// unit_type: the type of the unit of the subscription (i.e. "rows")
25+
string unit_type = 3;
26+
// price_per_unit: the price per unit of the subscription
27+
float price_per_unit = 4;
28+
// currency: the currency of the subscription
29+
string currency = 5;
30+
}
31+
32+
// GetUsageResponse is the response message for getting the usage of the user's credits
33+
message GetUsageResponse {
34+
// available_credits: the number of credits available to the user
35+
float available_credits = 1;
36+
// used_credits: the number of credits used by the user
37+
float used_credits = 2;
38+
// remaining_credits: the number of credits remaining to the user
39+
float remaining_credits = 3;
40+
// subscription: the subscription that the user has
41+
repeated BillingRate billing_rates = 4;
42+
}

protos/gravity/v1/gravity.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ message BuildDatasetRequest {
181181
string crawler_id = 1;
182182
// notification_requests: the details of the notification to be sent to the user when the dataset is ready to download (optional)
183183
repeated NotificationRequest notification_requests = 2;
184+
// max_rows: the maximum number of rows to include in the dataset (optional, defaults to 500)
185+
int64 max_rows = 3;
184186
}
185187

186188
// BuildDatasetResponse is the response message for manually requesting the building of a dataset for a single crawler

protos/sn13/v1/sn13_validator.proto

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ option go_package = "macrocosm-os/rift/constellation_api/gen/sn13/v1";
99
service Sn13Service {
1010
// ListTopics is the RPC method for getting the top topics
1111
rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse);
12+
rpc ValidateRedditTopic(ValidateRedditTopicRequest) returns (ValidateRedditTopicResponse);
1213
}
1314

1415
// ListTopicsRequest is the request message for getting the top topics
@@ -32,3 +33,23 @@ message ListTopicsResponse {
3233
// message: the response message
3334
repeated ListTopicsResponseDetail details = 1;
3435
}
36+
37+
// ValidateTopicRequest is the request message for validating a reddit topic
38+
message ValidateRedditTopicRequest {
39+
// topic: the topic to validate
40+
string topic = 1;
41+
}
42+
43+
// ValidateTopicResponse is the response message for validating a topic
44+
message ValidateRedditTopicResponse {
45+
// platform: i.e. reddit
46+
string platform = 1;
47+
// topic: the topic to validate
48+
string topic = 2;
49+
// exists: whether the topic exists
50+
bool exists = 3;
51+
// over18: whether the topic is NSFW
52+
bool over18 = 4;
53+
// quarantine: whether the topic is quarantined
54+
bool quarantine = 5;
55+
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "macrocosmos"
3-
version = "0.1.4"
3+
version = "1.0.0"
44
description = "The official Python SDK for Macrocosmos"
55
readme = "README.md"
66
license = "Apache-2.0"

src/macrocosmos/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@
1818
__version__ = "unknown"
1919

2020
# Import client and types
21-
from .client import ApexClient, AsyncApexClient, AsyncGravityClient, GravityClient
21+
from .client import (
22+
ApexClient,
23+
AsyncApexClient,
24+
AsyncGravityClient,
25+
GravityClient,
26+
BillingClient,
27+
AsyncBillingClient,
28+
)
2229
from .types import (
2330
ChatCompletionChunkResponse,
2431
ChatCompletionResponse,
@@ -33,6 +40,8 @@
3340
"ApexClient",
3441
"AsyncGravityClient",
3542
"GravityClient",
43+
"BillingClient",
44+
"AsyncBillingClient",
3645
"ChatMessage",
3746
"ChatCompletionResponse",
3847
"ChatCompletionChunkResponse",

src/macrocosmos/client.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
)
1010
from macrocosmos.resources.gravity import AsyncGravity, SyncGravity
1111
from macrocosmos.resources.web_search import AsyncWebSearch, SyncWebSearch
12+
from macrocosmos.resources.billing import AsyncBilling, SyncBilling
1213
from macrocosmos.resources._client import BaseClient
1314

1415

@@ -181,3 +182,86 @@ def __init__(
181182
)
182183

183184
self.gravity = SyncGravity(self)
185+
186+
187+
class AsyncBillingClient(BaseClient):
188+
"""
189+
Asynchronous client for the Billing API.
190+
"""
191+
192+
def __init__(
193+
self,
194+
api_key: Optional[str] = None,
195+
base_url: Optional[str] = None,
196+
timeout: Optional[int] = None,
197+
max_retries: int = 0,
198+
compress: bool = True,
199+
secure: Optional[bool] = None,
200+
app_name: Optional[str] = None,
201+
):
202+
"""
203+
Initialize the asynchronous Billing client.
204+
205+
Args:
206+
api_key: The API key.
207+
base_url: The base URL for the API.
208+
timeout: Time to wait for a response in seconds. (default: None)
209+
max_retries: The maximum number of retries. (default: 0)
210+
compress: Whether to compress the request using gzip (default: True).
211+
secure: Whether to use HTTPS (default: True).
212+
app_name: The name of the application using the client.
213+
"""
214+
if not api_key:
215+
api_key = os.environ.get("BILLING_API_KEY")
216+
217+
super().__init__(
218+
api_key=api_key,
219+
base_url=base_url,
220+
timeout=timeout,
221+
max_retries=max_retries,
222+
secure=secure,
223+
compress=compress,
224+
app_name=app_name,
225+
)
226+
227+
self.billing = AsyncBilling(self)
228+
229+
230+
class BillingClient(BaseClient):
231+
"""
232+
Synchronous client for the Billing API.
233+
"""
234+
235+
def __init__(
236+
self,
237+
api_key: Optional[str] = None,
238+
base_url: Optional[str] = None,
239+
timeout: Optional[int] = None,
240+
max_retries: int = 0,
241+
secure: Optional[bool] = None,
242+
app_name: Optional[str] = None,
243+
):
244+
"""
245+
Initialize the synchronous Billing client.
246+
247+
Args:
248+
api_key: The API key.
249+
base_url: The base URL for the API.
250+
timeout: Time to wait for a response in seconds. (default: None)
251+
max_retries: The maximum number of retries. (default: 0)
252+
secure: Whether to use HTTPS (default: True).
253+
app_name: The name of the application using the client.
254+
"""
255+
if not api_key:
256+
api_key = os.environ.get("BILLING_API_KEY")
257+
258+
super().__init__(
259+
api_key=api_key,
260+
base_url=base_url,
261+
timeout=timeout,
262+
max_retries=max_retries,
263+
secure=secure,
264+
app_name=app_name,
265+
)
266+
267+
self.billing = SyncBilling(self)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# This is an automatically generated file, please do not change
2+
# gen by protobuf_to_pydantic[v0.3.1.1](https://github.com/so1n/protobuf_to_pydantic)
3+
# Protobuf Version: 5.29.4
4+
# Pydantic Version: 2.11.0
5+
from google.protobuf.message import Message # type: ignore
6+
from pydantic import BaseModel
7+
from pydantic import Field
8+
import typing
9+
10+
11+
class GetUsageRequest(BaseModel):
12+
"""
13+
GetUsageRequest is the request message for getting the usage of the user's credits
14+
"""
15+
16+
# product_type: the type of the product (i.e. "gravity")
17+
product_type: str = Field(default="")
18+
19+
class BillingRate(BaseModel):
20+
"""
21+
ProductPlan is details of the subscription plan for a product
22+
"""
23+
24+
# product_type: the type of the product (i.e. "gravity")
25+
rate_type: str = Field(default="")
26+
# unit_size: the size of the unit of the subscription (e.g. 1000, 10000, 100000)
27+
unit_size: int = Field(default=0)
28+
# unit_type: the type of the unit of the subscription (i.e. "rows")
29+
unit_type: str = Field(default="")
30+
# price_per_unit: the price per unit of the subscription
31+
price_per_unit: float = Field(default=0.0)
32+
# currency: the currency of the subscription
33+
currency: str = Field(default="")
34+
35+
class GetUsageResponse(BaseModel):
36+
"""
37+
GetUsageResponse is the response message for getting the usage of the user's credits
38+
"""
39+
40+
# available_credits: the number of credits available to the user
41+
available_credits: float = Field(default=0.0)
42+
# used_credits: the number of credits used by the user
43+
used_credits: float = Field(default=0.0)
44+
# remaining_credits: the number of credits remaining to the user
45+
remaining_credits: float = Field(default=0.0)
46+
# subscription: the subscription that the user has
47+
billing_rates: typing.List[BillingRate] = Field(default_factory=list)

src/macrocosmos/generated/billing/v1/billing_pb2.py

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)