unitysvc-services 0.1.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.
- unitysvc_services/__init__.py +4 -0
- unitysvc_services/cli.py +21 -0
- unitysvc_services/format_data.py +145 -0
- unitysvc_services/list.py +245 -0
- unitysvc_services/models/__init__.py +6 -0
- unitysvc_services/models/base.py +352 -0
- unitysvc_services/models/listing_v1.py +72 -0
- unitysvc_services/models/provider_v1.py +53 -0
- unitysvc_services/models/seller_v1.py +110 -0
- unitysvc_services/models/service_v1.py +80 -0
- unitysvc_services/populate.py +186 -0
- unitysvc_services/publisher.py +925 -0
- unitysvc_services/query.py +471 -0
- unitysvc_services/scaffold.py +1039 -0
- unitysvc_services/update.py +293 -0
- unitysvc_services/utils.py +240 -0
- unitysvc_services/validator.py +515 -0
- unitysvc_services-0.1.0.dist-info/METADATA +172 -0
- unitysvc_services-0.1.0.dist-info/RECORD +23 -0
- unitysvc_services-0.1.0.dist-info/WHEEL +5 -0
- unitysvc_services-0.1.0.dist-info/entry_points.txt +2 -0
- unitysvc_services-0.1.0.dist-info/licenses/LICENSE +21 -0
- unitysvc_services-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,352 @@
|
|
1
|
+
from enum import StrEnum
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
5
|
+
|
6
|
+
|
7
|
+
class AccessMethodEnum(StrEnum):
|
8
|
+
http = "http"
|
9
|
+
websocket = "websocket"
|
10
|
+
grpc = "grpc"
|
11
|
+
|
12
|
+
|
13
|
+
class AuthMethodEnum(StrEnum):
|
14
|
+
api_key = "api_key"
|
15
|
+
oauth = "oauth"
|
16
|
+
jwt = "jwt"
|
17
|
+
bearer_token = "bearer_token"
|
18
|
+
basic_auth = "basic_auth"
|
19
|
+
|
20
|
+
|
21
|
+
class ContentFilterEnum(StrEnum):
|
22
|
+
adult = "adult"
|
23
|
+
violence = "violence"
|
24
|
+
hate_speech = "hate_speech"
|
25
|
+
profanity = "profanity"
|
26
|
+
pii = "pii" # Personally Identifiable Information
|
27
|
+
|
28
|
+
|
29
|
+
class DocumentContextEnum(StrEnum):
|
30
|
+
access_interface = "access_interface" # Documents belong to AccessInterface
|
31
|
+
service_definition = "service_definition" # Documents belong to ServiceDefinition
|
32
|
+
service_offering = "service_offering" # Documents belong to ServiceOffering
|
33
|
+
service_listing = "service_listing" # Documents belong to ServiceListing
|
34
|
+
user = "user" # can be for seller, subscriber, consumer
|
35
|
+
|
36
|
+
|
37
|
+
class DocumentCategoryEnum(StrEnum):
|
38
|
+
getting_started = "getting_started"
|
39
|
+
api_reference = "api_reference"
|
40
|
+
tutorials = "tutorials"
|
41
|
+
code_examples = "code_examples"
|
42
|
+
use_cases = "use_cases"
|
43
|
+
troubleshooting = "troubleshooting"
|
44
|
+
changelog = "changelog"
|
45
|
+
best_practices = "best_practices"
|
46
|
+
specification = "specification"
|
47
|
+
service_level_agreement = "service_level_agreement"
|
48
|
+
terms_of_service = "terms_of_service"
|
49
|
+
invoice = "invoice"
|
50
|
+
logo = "logo"
|
51
|
+
avatar = "avatar"
|
52
|
+
other = "other"
|
53
|
+
|
54
|
+
|
55
|
+
class MimeTypeEnum(StrEnum):
|
56
|
+
markdown = "markdown"
|
57
|
+
python = "python"
|
58
|
+
javascript = "javascript"
|
59
|
+
bash = "bash"
|
60
|
+
html = "html"
|
61
|
+
text = "text"
|
62
|
+
pdf = "pdf"
|
63
|
+
jpeg = "jpeg"
|
64
|
+
png = "png"
|
65
|
+
svg = "svg"
|
66
|
+
url = "url"
|
67
|
+
|
68
|
+
|
69
|
+
class InterfaceContextTypeEnum(StrEnum):
|
70
|
+
service_offering = "service_offering" # Pricing from upstream provider
|
71
|
+
service_listing = "service_listing" # Pricing shown to end users
|
72
|
+
|
73
|
+
|
74
|
+
class SellerTypeEnum(StrEnum):
|
75
|
+
individual = "individual"
|
76
|
+
organization = "organization"
|
77
|
+
partnership = "partnership"
|
78
|
+
corporation = "corporation"
|
79
|
+
|
80
|
+
|
81
|
+
class ListingStatusEnum(StrEnum):
|
82
|
+
# Not yet determined
|
83
|
+
unknown = "unknown"
|
84
|
+
# step 1: upstream is ready to be used
|
85
|
+
upstream_ready = "upstream_ready"
|
86
|
+
# step 2: downstream is ready, with proper routing, logging, and billing
|
87
|
+
downstream_ready = "downstream_ready"
|
88
|
+
# step 3: service is operationally ready (with proper documentation and initial
|
89
|
+
# performance metrics, and pricing strategy)
|
90
|
+
ready = "ready"
|
91
|
+
# step 4: service is in service
|
92
|
+
in_service = "in_service"
|
93
|
+
# step 5.1: service is deprecated from upstream
|
94
|
+
upstream_deprecated = "upstream_deprecated"
|
95
|
+
# step 5.2: service is no longer offered to users (due to business reasons)
|
96
|
+
deprecated = "deprecated"
|
97
|
+
|
98
|
+
|
99
|
+
class OveragePolicyEnum(StrEnum):
|
100
|
+
block = "block" # Block requests when quota exceeded
|
101
|
+
throttle = "throttle" # Reduce rate when quota exceeded
|
102
|
+
charge = "charge" # Allow with additional charges
|
103
|
+
queue = "queue" # Queue requests until quota resets
|
104
|
+
|
105
|
+
|
106
|
+
class PricingTypeEnum(StrEnum):
|
107
|
+
upstream = "upstream" # Pricing from upstream provider
|
108
|
+
user_facing = "user_facing" # Pricing shown to end users
|
109
|
+
|
110
|
+
|
111
|
+
class PricingUnitEnum(StrEnum):
|
112
|
+
one_million_tokens = "one_million_tokens"
|
113
|
+
one_second = "one_second"
|
114
|
+
image = "image"
|
115
|
+
step = "step"
|
116
|
+
|
117
|
+
|
118
|
+
class QuotaResetCycleEnum(StrEnum):
|
119
|
+
daily = "daily"
|
120
|
+
weekly = "weekly"
|
121
|
+
monthly = "monthly"
|
122
|
+
yearly = "yearly"
|
123
|
+
|
124
|
+
|
125
|
+
class RateLimitUnitEnum(StrEnum):
|
126
|
+
requests = "requests"
|
127
|
+
tokens = "tokens"
|
128
|
+
input_tokens = "input_tokens"
|
129
|
+
output_tokens = "output_tokens"
|
130
|
+
bytes = "bytes"
|
131
|
+
concurrent = "concurrent"
|
132
|
+
|
133
|
+
|
134
|
+
class RequestTransformEnum(StrEnum):
|
135
|
+
# https://docs.api7.ai/hub/proxy-rewrite
|
136
|
+
proxy_rewrite = "proxy_rewrite"
|
137
|
+
# https://docs.api7.ai/hub/body-transformer
|
138
|
+
body_transformer = "body_transformer"
|
139
|
+
|
140
|
+
|
141
|
+
class ServiceTypeEnum(StrEnum):
|
142
|
+
llm = "llm"
|
143
|
+
# generate embedding from texts
|
144
|
+
embedding = "embedding"
|
145
|
+
# generation of images from prompts
|
146
|
+
image_generation = "image_generation"
|
147
|
+
# streaming trancription needs websocket connection forwarding, and cannot
|
148
|
+
# be provided for now.
|
149
|
+
streaming_transcription = "streaming_transcription"
|
150
|
+
# prerecorded transcription
|
151
|
+
prerecorded_transcription = "prerecorded_transcription"
|
152
|
+
# prerecorded translation
|
153
|
+
prerecorded_translation = "prerecorded_translation"
|
154
|
+
# describe images
|
155
|
+
vision_language_model = "vision_language_model"
|
156
|
+
#
|
157
|
+
speech_to_text = "speech_to_text"
|
158
|
+
#
|
159
|
+
text_to_speech = "text_to_speech"
|
160
|
+
#
|
161
|
+
video_generation = "video_generation"
|
162
|
+
#
|
163
|
+
text_to_image = "text_to_image"
|
164
|
+
#
|
165
|
+
undetermined = "undetermined"
|
166
|
+
#
|
167
|
+
text_to_3d = "text_to_3d"
|
168
|
+
|
169
|
+
|
170
|
+
class SubscriptionStatusEnum(StrEnum):
|
171
|
+
active = "active"
|
172
|
+
cancelled = "cancelled"
|
173
|
+
expired = "expired"
|
174
|
+
pending = "pending"
|
175
|
+
trialing = "trialing"
|
176
|
+
failed = "failed"
|
177
|
+
paused = "paused"
|
178
|
+
incomplete = "incomplete"
|
179
|
+
incomplete_expired = "incomplete_expired"
|
180
|
+
unpaid = "unpaid"
|
181
|
+
|
182
|
+
|
183
|
+
class TagEnum(StrEnum):
|
184
|
+
"""
|
185
|
+
Allowed enums, currently not enforced.
|
186
|
+
"""
|
187
|
+
|
188
|
+
# Service requires users to provide their own API key for access.
|
189
|
+
byop = "byop"
|
190
|
+
|
191
|
+
|
192
|
+
class TimeWindowEnum(StrEnum):
|
193
|
+
second = "second"
|
194
|
+
minute = "minute"
|
195
|
+
hour = "hour"
|
196
|
+
day = "day"
|
197
|
+
month = "month"
|
198
|
+
|
199
|
+
|
200
|
+
class UpstreamStatusEnum(StrEnum):
|
201
|
+
# uploading (not ready)
|
202
|
+
uploading = "uploading"
|
203
|
+
# upstream is ready to be used
|
204
|
+
ready = "ready"
|
205
|
+
# service is deprecated from upstream
|
206
|
+
deprecated = "deprecated"
|
207
|
+
|
208
|
+
|
209
|
+
class Document(BaseModel):
|
210
|
+
model_config = ConfigDict(extra="forbid")
|
211
|
+
|
212
|
+
# fields that will be stored in backend database
|
213
|
+
#
|
214
|
+
title: str = Field(min_length=5, max_length=255, description="Document title")
|
215
|
+
description: str | None = Field(default=None, max_length=500, description="Document description")
|
216
|
+
mime_type: MimeTypeEnum = Field(description="Document MIME type")
|
217
|
+
version: str | None = Field(default=None, max_length=50, description="Document version")
|
218
|
+
category: DocumentCategoryEnum = Field(description="Document category for organization and filtering")
|
219
|
+
meta: dict[str, Any] | None = Field(
|
220
|
+
default=None,
|
221
|
+
description="JSON containing operation stats",
|
222
|
+
)
|
223
|
+
file_path: str | None = Field(
|
224
|
+
default=None,
|
225
|
+
max_length=1000,
|
226
|
+
description="Path to file to upload (mutually exclusive with external_url)",
|
227
|
+
)
|
228
|
+
external_url: str | None = Field(
|
229
|
+
default=None,
|
230
|
+
max_length=1000,
|
231
|
+
description="External URL for the document (mutually exclusive with object_key)",
|
232
|
+
)
|
233
|
+
sort_order: int = Field(default=0, description="Sort order within category")
|
234
|
+
is_active: bool = Field(default=True, description="Whether document is active")
|
235
|
+
is_public: bool = Field(
|
236
|
+
default=False,
|
237
|
+
description="Whether document is publicly accessible without authentication",
|
238
|
+
)
|
239
|
+
|
240
|
+
|
241
|
+
class RateLimit(BaseModel):
|
242
|
+
"""Store rate limiting rules for services."""
|
243
|
+
|
244
|
+
model_config = ConfigDict(extra="forbid")
|
245
|
+
|
246
|
+
# Core rate limit definition
|
247
|
+
limit: int = Field(description="Maximum allowed in the time window")
|
248
|
+
unit: RateLimitUnitEnum = Field(description="What is being limited")
|
249
|
+
window: TimeWindowEnum = Field(description="Time window for the limit")
|
250
|
+
|
251
|
+
# Optional additional info
|
252
|
+
description: str | None = Field(default=None, max_length=255, description="Human-readable description")
|
253
|
+
burst_limit: int | None = Field(default=None, description="Short-term burst allowance")
|
254
|
+
|
255
|
+
# Status
|
256
|
+
is_active: bool = Field(default=True, description="Whether rate limit is active")
|
257
|
+
|
258
|
+
|
259
|
+
class ServiceConstraints(BaseModel):
|
260
|
+
model_config = ConfigDict(extra="forbid")
|
261
|
+
|
262
|
+
# Usage Quotas & Billing
|
263
|
+
monthly_quota: int | None = Field(default=None, description="Monthly usage quota (requests, tokens, etc.)")
|
264
|
+
daily_quota: int | None = Field(default=None, description="Daily usage quota (requests, tokens, etc.)")
|
265
|
+
quota_unit: RateLimitUnitEnum | None = Field(default=None, description="Unit for quota limits")
|
266
|
+
quota_reset_cycle: QuotaResetCycleEnum | None = Field(default=None, description="How often quotas reset")
|
267
|
+
overage_policy: OveragePolicyEnum | None = Field(default=None, description="What happens when quota is exceeded")
|
268
|
+
|
269
|
+
# Authentication & Security
|
270
|
+
auth_methods: list[AuthMethodEnum] | None = Field(default=None, description="Supported authentication methods")
|
271
|
+
ip_whitelist_required: bool | None = Field(default=None, description="Whether IP whitelisting is required")
|
272
|
+
tls_version_min: str | None = Field(default=None, description="Minimum TLS version required")
|
273
|
+
|
274
|
+
# Request/Response Constraints
|
275
|
+
max_request_size_bytes: int | None = Field(default=None, description="Maximum request payload size in bytes")
|
276
|
+
max_response_size_bytes: int | None = Field(default=None, description="Maximum response payload size in bytes")
|
277
|
+
timeout_seconds: int | None = Field(default=None, description="Request timeout in seconds")
|
278
|
+
max_batch_size: int | None = Field(default=None, description="Maximum number of items in batch requests")
|
279
|
+
|
280
|
+
# Content & Model Restrictions
|
281
|
+
content_filters: list[ContentFilterEnum] | None = Field(
|
282
|
+
default=None, description="Active content filtering policies"
|
283
|
+
)
|
284
|
+
input_languages: list[str] | None = Field(default=None, description="Supported input languages (ISO 639-1 codes)")
|
285
|
+
output_languages: list[str] | None = Field(default=None, description="Supported output languages (ISO 639-1 codes)")
|
286
|
+
max_context_length: int | None = Field(default=None, description="Maximum context length in tokens")
|
287
|
+
region_restrictions: list[str] | None = Field(
|
288
|
+
default=None, description="Geographic restrictions (ISO country codes)"
|
289
|
+
)
|
290
|
+
|
291
|
+
# Availability & SLA
|
292
|
+
uptime_sla_percent: float | None = Field(default=None, description="Uptime SLA percentage (e.g., 99.9)")
|
293
|
+
response_time_sla_ms: int | None = Field(default=None, description="Response time SLA in milliseconds")
|
294
|
+
maintenance_windows: list[str] | None = Field(default=None, description="Scheduled maintenance windows")
|
295
|
+
|
296
|
+
# Concurrency & Connection Limits
|
297
|
+
max_concurrent_requests: int | None = Field(default=None, description="Maximum concurrent requests allowed")
|
298
|
+
connection_timeout_seconds: int | None = Field(default=None, description="Connection timeout in seconds")
|
299
|
+
max_connections_per_ip: int | None = Field(default=None, description="Maximum connections per IP address")
|
300
|
+
|
301
|
+
|
302
|
+
class AccessInterface(BaseModel):
|
303
|
+
model_config = ConfigDict(extra="allow")
|
304
|
+
|
305
|
+
access_method: AccessMethodEnum = Field(default=AccessMethodEnum.http, description="Type of access method")
|
306
|
+
|
307
|
+
api_endpoint: str = Field(max_length=500, description="API endpoint URL")
|
308
|
+
|
309
|
+
api_key: str | None = Field(default=None, max_length=2000, description="API key if required")
|
310
|
+
|
311
|
+
name: str | None = Field(default=None, max_length=100, description="Interface name")
|
312
|
+
|
313
|
+
description: str | None = Field(default=None, max_length=500, description="Interface description")
|
314
|
+
|
315
|
+
request_transformer: dict[RequestTransformEnum, dict[str, Any]] | None = Field(
|
316
|
+
default=None, description="Request transformation configuration"
|
317
|
+
)
|
318
|
+
|
319
|
+
documents: list[Document] | None = Field(
|
320
|
+
default=None, description="List of documents associated with the interface"
|
321
|
+
)
|
322
|
+
|
323
|
+
rate_limits: list[RateLimit] | None = Field(
|
324
|
+
default=None,
|
325
|
+
description="Rate limit",
|
326
|
+
)
|
327
|
+
constraint: ServiceConstraints | None = Field(default=None, description="Service constraints and conditions")
|
328
|
+
is_active: bool = Field(default=True, description="Whether interface is active")
|
329
|
+
is_primary: bool = Field(default=False, description="Whether this is the primary interface")
|
330
|
+
sort_order: int = Field(default=0, description="Display order")
|
331
|
+
|
332
|
+
|
333
|
+
class Pricing(BaseModel):
|
334
|
+
model_config = ConfigDict(extra="forbid")
|
335
|
+
|
336
|
+
# Pricing tier name (Basic, Pro, Enterprise, etc.)
|
337
|
+
name: str | None = Field(default=None, description="Pricing tier name (e.g., Basic, Pro, Enterprise)")
|
338
|
+
|
339
|
+
description: str | None = Field(default=None, description="Pricing model description")
|
340
|
+
|
341
|
+
# Currency and description
|
342
|
+
currency: str | None = Field(default=None, description="Currency code (e.g., USD)")
|
343
|
+
|
344
|
+
unit: PricingUnitEnum = Field(description="Unit of pricing")
|
345
|
+
|
346
|
+
# Store price as JSON - flexible structure for different pricing models
|
347
|
+
price_data: dict[str, Any] = Field(
|
348
|
+
description="JSON containing price data (single price, tiered, usage-based, etc.)",
|
349
|
+
)
|
350
|
+
|
351
|
+
# Optional reference to upstream pricing
|
352
|
+
reference: str | None = Field(default=None, description="Reference URL to upstream pricing")
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
5
|
+
|
6
|
+
from unitysvc_services.models.base import (
|
7
|
+
AccessInterface,
|
8
|
+
Document,
|
9
|
+
ListingStatusEnum,
|
10
|
+
Pricing,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
class ListingV1(BaseModel):
|
15
|
+
model_config = ConfigDict(extra="forbid")
|
16
|
+
|
17
|
+
#
|
18
|
+
# fields for business data collection and maintenance
|
19
|
+
#
|
20
|
+
schema_version: str = Field(default="listing_v1", description="Schema identifier", alias="schema")
|
21
|
+
time_created: datetime
|
22
|
+
|
23
|
+
#
|
24
|
+
# fields that will be stored in backend database
|
25
|
+
#
|
26
|
+
service_name: str | None = Field(
|
27
|
+
default=None,
|
28
|
+
description=(
|
29
|
+
"Name of the service (ServiceV1.name), optional if only one service is defined under the same directory."
|
30
|
+
),
|
31
|
+
)
|
32
|
+
|
33
|
+
seller_name: str = Field(
|
34
|
+
description="Name of the seller offering this service listing"
|
35
|
+
)
|
36
|
+
|
37
|
+
# unique name for each provider, usually following upstream naming convention
|
38
|
+
# status of the service, public, deprecated etc
|
39
|
+
listing_status: ListingStatusEnum = Field(
|
40
|
+
default=ListingStatusEnum.unknown,
|
41
|
+
description="Operation status of the service",
|
42
|
+
)
|
43
|
+
|
44
|
+
#
|
45
|
+
# how to users access the service from upstream, which can include
|
46
|
+
# - endpoint
|
47
|
+
# - access_method
|
48
|
+
# - code_examples
|
49
|
+
# multiple access interfaces can be provided, for example, if the service
|
50
|
+
# is available through multiple interfaces or service groups
|
51
|
+
user_access_interfaces: list[AccessInterface] = Field(description="Dictionary of user access interfaces")
|
52
|
+
|
53
|
+
#
|
54
|
+
# how upstream charges for their services, which can include
|
55
|
+
# a list of pricing models
|
56
|
+
#
|
57
|
+
user_price: Pricing | None = Field(description="Dictionary of pricing information")
|
58
|
+
|
59
|
+
documents: list[Document] | None = Field(
|
60
|
+
default=None,
|
61
|
+
description="List of documents associated with the listing (e.g. service level agreements)",
|
62
|
+
)
|
63
|
+
#
|
64
|
+
# schema for accepting user parameters for the service
|
65
|
+
#
|
66
|
+
user_parameters_schema: dict[str, Any] | None = Field(
|
67
|
+
default=None, description="Dictionary of user parameters schema"
|
68
|
+
)
|
69
|
+
|
70
|
+
user_parameters_ui_schema: dict[str, Any] | None = Field(
|
71
|
+
default=None, description="Dictionary of user parameters UI schema"
|
72
|
+
)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, EmailStr, Field, HttpUrl
|
5
|
+
|
6
|
+
from unitysvc_services.models.base import AccessInterface, Document
|
7
|
+
|
8
|
+
|
9
|
+
class ProviderV1(BaseModel):
|
10
|
+
model_config = ConfigDict(extra="forbid")
|
11
|
+
|
12
|
+
#
|
13
|
+
# fields for business data collection and maintenance
|
14
|
+
#
|
15
|
+
schema_version: str = Field(default="provider_v1", description="Schema identifier", alias="schema")
|
16
|
+
time_created: datetime
|
17
|
+
# how to automatically populate service data, if available
|
18
|
+
services_populator: dict[str, Any] | None = None
|
19
|
+
# parameters for accessing service provider, which typically
|
20
|
+
# include "api_endpoint" and "api_key"
|
21
|
+
provider_access_info: AccessInterface = Field(description="Dictionary of upstream access interface")
|
22
|
+
#
|
23
|
+
# fields that will be stored in backend database
|
24
|
+
#
|
25
|
+
|
26
|
+
# name of the provider should be the same as directory name
|
27
|
+
name: str
|
28
|
+
|
29
|
+
# this field is added for convenience. It will be converted to
|
30
|
+
# documents during importing.
|
31
|
+
logo: str | HttpUrl | None = None
|
32
|
+
|
33
|
+
# this field is added for convenience. It will be converted to
|
34
|
+
# documents during importing.
|
35
|
+
terms_of_service: None | str | HttpUrl = Field(
|
36
|
+
default=None,
|
37
|
+
description="Either a path to a .md file or a URL to terms of service",
|
38
|
+
)
|
39
|
+
|
40
|
+
documents: list[Document] | None = Field(
|
41
|
+
default=None,
|
42
|
+
description="List of documents associated with the provider (e.g. logo)",
|
43
|
+
)
|
44
|
+
#
|
45
|
+
# fields for business operation purposes, not stored in backend database
|
46
|
+
#
|
47
|
+
|
48
|
+
# internal business data, usually not expose to users, and may not store
|
49
|
+
# in database
|
50
|
+
description: str | None = None
|
51
|
+
homepage: HttpUrl
|
52
|
+
contact_email: EmailStr
|
53
|
+
secondary_contact_email: EmailStr | None = None
|
@@ -0,0 +1,110 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
from pydantic import BaseModel, ConfigDict, EmailStr, Field, HttpUrl
|
4
|
+
|
5
|
+
from unitysvc_services.models.base import Document, SellerTypeEnum
|
6
|
+
|
7
|
+
|
8
|
+
class SellerV1(BaseModel):
|
9
|
+
"""
|
10
|
+
Seller information for marketplace sellers.
|
11
|
+
|
12
|
+
Each repository can only have one seller.json file at the root of the data directory.
|
13
|
+
"""
|
14
|
+
|
15
|
+
model_config = ConfigDict(extra="forbid")
|
16
|
+
|
17
|
+
#
|
18
|
+
# fields for business data collection and maintenance
|
19
|
+
#
|
20
|
+
schema_version: str = Field(default="seller_v1", description="Schema identifier", alias="schema")
|
21
|
+
time_created: datetime
|
22
|
+
|
23
|
+
#
|
24
|
+
# fields that will be stored in backend database
|
25
|
+
#
|
26
|
+
|
27
|
+
# Seller name must be unique and URL-friendly (lowercase, hyphens)
|
28
|
+
name: str = Field(
|
29
|
+
description="Unique seller identifier (URL-friendly, e.g., 'acme-corp', 'john-doe')",
|
30
|
+
min_length=2,
|
31
|
+
max_length=100,
|
32
|
+
)
|
33
|
+
|
34
|
+
# Display name for UI
|
35
|
+
display_name: str | None = Field(
|
36
|
+
default=None,
|
37
|
+
max_length=200,
|
38
|
+
description="Human-readable seller name (e.g., 'ACME Corporation', 'John Doe')",
|
39
|
+
)
|
40
|
+
|
41
|
+
# Seller type
|
42
|
+
seller_type: SellerTypeEnum = Field(
|
43
|
+
default=SellerTypeEnum.individual,
|
44
|
+
description="Type of seller entity",
|
45
|
+
)
|
46
|
+
|
47
|
+
# Contact information
|
48
|
+
contact_email: EmailStr = Field(description="Primary contact email for the seller")
|
49
|
+
|
50
|
+
secondary_contact_email: EmailStr | None = Field(default=None, description="Secondary contact email")
|
51
|
+
|
52
|
+
# Account manager
|
53
|
+
account_manager: str | None = Field(
|
54
|
+
default=None,
|
55
|
+
max_length=100,
|
56
|
+
description="Email or username of the user managing this seller account",
|
57
|
+
)
|
58
|
+
|
59
|
+
homepage: HttpUrl | None = Field(default=None, description="Seller's homepage URL")
|
60
|
+
|
61
|
+
# Business information
|
62
|
+
description: str | None = Field(
|
63
|
+
default=None,
|
64
|
+
max_length=1000,
|
65
|
+
description="Brief description of the seller",
|
66
|
+
)
|
67
|
+
|
68
|
+
business_registration: str | None = Field(
|
69
|
+
default=None,
|
70
|
+
max_length=100,
|
71
|
+
description="Business registration number (if organization)",
|
72
|
+
)
|
73
|
+
|
74
|
+
tax_id: str | None = Field(
|
75
|
+
default=None,
|
76
|
+
max_length=100,
|
77
|
+
description="Tax identification number (EIN, VAT, etc.)",
|
78
|
+
)
|
79
|
+
|
80
|
+
# Stripe Connect integration
|
81
|
+
stripe_connect_id: str | None = Field(
|
82
|
+
default=None,
|
83
|
+
max_length=255,
|
84
|
+
description="Stripe Connect account ID for payment processing",
|
85
|
+
)
|
86
|
+
|
87
|
+
# Documents (logo, business docs, etc.)
|
88
|
+
# This field is added for convenience. It will be converted to
|
89
|
+
# documents during importing.
|
90
|
+
logo: str | HttpUrl | None = None
|
91
|
+
|
92
|
+
documents: list[Document] | None = Field(
|
93
|
+
default=None,
|
94
|
+
description="List of documents associated with the seller (e.g. business registration, tax documents)",
|
95
|
+
)
|
96
|
+
|
97
|
+
#
|
98
|
+
# fields for business operation purposes
|
99
|
+
#
|
100
|
+
|
101
|
+
# Status flags - these would typically be set by the backend
|
102
|
+
is_active: bool = Field(
|
103
|
+
default=True,
|
104
|
+
description="Whether the seller is active on the marketplace",
|
105
|
+
)
|
106
|
+
|
107
|
+
is_verified: bool = Field(
|
108
|
+
default=False,
|
109
|
+
description="Whether the seller has been verified (KYC/business verification)",
|
110
|
+
)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field, HttpUrl
|
5
|
+
|
6
|
+
from unitysvc_services.models.base import (
|
7
|
+
AccessInterface,
|
8
|
+
Document,
|
9
|
+
Pricing,
|
10
|
+
ServiceTypeEnum,
|
11
|
+
TagEnum,
|
12
|
+
UpstreamStatusEnum,
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
class ServiceV1(BaseModel):
|
17
|
+
model_config = ConfigDict(extra="forbid")
|
18
|
+
|
19
|
+
#
|
20
|
+
# fields for business data collection and maintenance
|
21
|
+
#
|
22
|
+
schema_version: str = Field(default="service_v1", description="Schema identifier", alias="schema")
|
23
|
+
time_created: datetime
|
24
|
+
|
25
|
+
#
|
26
|
+
# fields that will be stored in backend database
|
27
|
+
#
|
28
|
+
# unique name for each provider, usually following upstream naming convention
|
29
|
+
name: str
|
30
|
+
# type of service to group services
|
31
|
+
service_type: ServiceTypeEnum
|
32
|
+
# common display name for the service, allowing across provider linking
|
33
|
+
display_name: str
|
34
|
+
# version of the service, this, combined with display_name, allowing across provider linking
|
35
|
+
# of specific services, despite of provider internal naming conventions. Note that
|
36
|
+
# same display_name and version does not guarantee the same service (e.g. context window
|
37
|
+
# can be different)
|
38
|
+
version: str | None
|
39
|
+
|
40
|
+
# description of service, mandatory
|
41
|
+
description: str
|
42
|
+
|
43
|
+
# this field is added for convenience. It will be converted to
|
44
|
+
# documents during importing.
|
45
|
+
logo: str | HttpUrl | None = None
|
46
|
+
|
47
|
+
# Short elevator pitch or description for the service
|
48
|
+
tagline: str | None = None
|
49
|
+
|
50
|
+
# Tags for the service, e.g., bring your own API key
|
51
|
+
tags: list[TagEnum] | None = Field(
|
52
|
+
default=None,
|
53
|
+
description="List of tags for the service, e.g., bring your own API key",
|
54
|
+
)
|
55
|
+
|
56
|
+
# status of the service, public, deprecated etc
|
57
|
+
upstream_status: UpstreamStatusEnum = Field(
|
58
|
+
default=UpstreamStatusEnum.ready,
|
59
|
+
description="Status of the service from upstream service provider",
|
60
|
+
)
|
61
|
+
|
62
|
+
# static information from upstream, each service_type will have a
|
63
|
+
# set of mandatory fields
|
64
|
+
details: dict[str, Any] = Field(description="Dictionary of static features and information")
|
65
|
+
|
66
|
+
documents: list[Document] | None = Field(
|
67
|
+
default=None,
|
68
|
+
description="List of documents associated with the service (e.g. tech spec.)",
|
69
|
+
)
|
70
|
+
#
|
71
|
+
# how to access the service from upstream, which can include
|
72
|
+
# - endpoint
|
73
|
+
# - apikey
|
74
|
+
# - access_method
|
75
|
+
upstream_access_interface: AccessInterface = Field(description="Dictionary of upstream access interface")
|
76
|
+
#
|
77
|
+
# how upstream charges for their services, which can include
|
78
|
+
# a list of pricing models
|
79
|
+
#
|
80
|
+
upstream_price: Pricing | None = Field(description="List of pricing information")
|