Initial commit of Python client for GumYum NPC
This commit is contained in:
commit
b9a3ba56ca
43 changed files with 9174 additions and 0 deletions
393
gumyum_models.py
Normal file
393
gumyum_models.py
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
"""
|
||||
GumYum NPC API Shared Data Models and Exceptions
|
||||
Cross-engine AI-powered NPC dialogue and quest system
|
||||
|
||||
This module contains shared data models and exceptions used by both sync and async clients.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional, Any, Union
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from pydantic import BaseModel, Field
|
||||
except ImportError:
|
||||
BaseModel = None
|
||||
Field = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# EXCEPTIONS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class GumYumError(Exception):
|
||||
"""Base exception for all GumYum SDK errors"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
status_code: Optional[int] = None,
|
||||
response_data: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
super().__init__(message)
|
||||
self.message = message
|
||||
self.status_code = status_code
|
||||
self.response_data = response_data or {}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}({self.message!r}, status_code={self.status_code})"
|
||||
|
||||
|
||||
class GumYumAPIError(GumYumError):
|
||||
"""General API error from the server"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumAuthError(GumYumError):
|
||||
"""Authentication or authorization error (401, 403)"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumNotFoundError(GumYumError):
|
||||
"""Resource not found error (404)"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumValidationError(GumYumError):
|
||||
"""Request validation error (400, 422)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
status_code: Optional[int] = None,
|
||||
response_data: Optional[Dict[str, Any]] = None,
|
||||
validation_errors: Optional[list] = None,
|
||||
):
|
||||
super().__init__(message, status_code, response_data)
|
||||
self.validation_errors = validation_errors or []
|
||||
|
||||
|
||||
class GumYumServerError(GumYumError):
|
||||
"""Server error (5xx)"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumNetworkError(GumYumError):
|
||||
"""Network connectivity error"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumTimeoutError(GumYumNetworkError):
|
||||
"""Request timeout error"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GumYumRateLimitError(GumYumAPIError):
|
||||
"""Rate limit exceeded (429)"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
status_code: Optional[int] = None,
|
||||
response_data: Optional[Dict[str, Any]] = None,
|
||||
retry_after: Optional[int] = None,
|
||||
):
|
||||
super().__init__(message, status_code, response_data)
|
||||
self.retry_after = retry_after # Seconds to wait before retry
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# ENUMS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ChatRole(str, Enum):
|
||||
"""Chat message roles"""
|
||||
|
||||
USER = "user"
|
||||
ASSISTANT = "assistant"
|
||||
SYSTEM = "system"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# CHAT MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class ChatMessage(BaseModel):
|
||||
"""Chat message with role and content"""
|
||||
|
||||
role: Union[ChatRole, str]
|
||||
content: str
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to API-compatible dictionary"""
|
||||
return {"role": self.role, "content": self.content}
|
||||
|
||||
|
||||
class ChatChoice(BaseModel):
|
||||
"""Chat completion choice"""
|
||||
|
||||
index: int
|
||||
message: ChatMessage
|
||||
finish_reason: Optional[str] = None
|
||||
|
||||
|
||||
class Usage(BaseModel):
|
||||
"""Token usage information"""
|
||||
|
||||
prompt_tokens: int
|
||||
completion_tokens: int
|
||||
total_tokens: int
|
||||
# Optional fields that may be None
|
||||
prompt_tokens_details: Optional[Dict[str, Any]] = None
|
||||
completion_tokens_details: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
class ChatCompletion(BaseModel):
|
||||
"""OpenAI-compatible chat completion response"""
|
||||
|
||||
id: str
|
||||
object: str = "chat.completion"
|
||||
created: int
|
||||
model: str
|
||||
choices: List[ChatChoice]
|
||||
usage: Optional[Usage] = None
|
||||
npc_context: Optional[Dict[str, Any]] = None
|
||||
mood_transition: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# NPC MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class SpawnedData(BaseModel):
|
||||
"""Data determined at spawn time"""
|
||||
|
||||
location: str
|
||||
mood: str
|
||||
stress_level: int # 1-10
|
||||
|
||||
|
||||
class NPCProfile(BaseModel):
|
||||
"""Full NPC profile data returned from save/update operations"""
|
||||
|
||||
npc_id: str
|
||||
name: str
|
||||
profession: str
|
||||
age: Optional[int] = None
|
||||
sex: Optional[str] = None # "male", "female", "neutral"
|
||||
personality_type: int # Enneagram type (1-9)
|
||||
wing: Optional[int] = None
|
||||
stress_level: Optional[int] = None
|
||||
mood: Optional[str] = None
|
||||
likes: List[str] = Field(default_factory=list)
|
||||
dislikes: List[str] = Field(default_factory=list)
|
||||
motivations: List[str] = Field(default_factory=list)
|
||||
fears: List[str] = Field(default_factory=list)
|
||||
relationships: List[Dict[str, Any]] = Field(default_factory=list)
|
||||
background: Optional[str] = None
|
||||
location: Optional[str] = None
|
||||
purpose: Optional[str] = None
|
||||
spawned: SpawnedData
|
||||
created_at: Optional[str] = None
|
||||
updated_at: Optional[str] = None
|
||||
custom_name: Optional[str] = None
|
||||
inventory: List[Dict[str, Any]] = Field(default_factory=list)
|
||||
stats: Dict[str, Any] = Field(default_factory=dict)
|
||||
skills: List[str] = Field(default_factory=list)
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
metadata: Dict[str, Any] = Field(default_factory=dict)
|
||||
universe_id: Optional[str] = None
|
||||
seed: Optional[int] = None
|
||||
cached: Optional[bool] = None
|
||||
cache_url: Optional[str] = None
|
||||
|
||||
|
||||
class NPC(BaseModel):
|
||||
"""NPC instance with chat capabilities"""
|
||||
|
||||
npc_id: int
|
||||
name: str
|
||||
profession: str
|
||||
personality_type: int # Enneagram type (1-9)
|
||||
mood: Optional[str] = None
|
||||
spawned: Optional[SpawnedData] = None
|
||||
universe_id: Optional[str] = None
|
||||
seed: Optional[int] = None
|
||||
cached: bool = False
|
||||
cache_url: Optional[str] = None
|
||||
chat_history: List[dict] = Field(default_factory=list)
|
||||
age: Optional[int] = None
|
||||
sex: Optional[str] = None # "male", "female", "neutral"
|
||||
wing: Optional[int] = None
|
||||
stress_level: Optional[int] = None
|
||||
likes: List[str] = Field(default_factory=list)
|
||||
dislikes: List[str] = Field(default_factory=list)
|
||||
motivations: List[str] = Field(default_factory=list)
|
||||
fears: List[str] = Field(default_factory=list)
|
||||
relationships: List[Dict[str, Any]] = Field(default_factory=list)
|
||||
background: Optional[str] = None
|
||||
location: Optional[str] = None
|
||||
purpose: Optional[str] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# UNIVERSE MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class UniverseThemeInfo(BaseModel):
|
||||
"""Universe theme information"""
|
||||
|
||||
id: str
|
||||
title: str
|
||||
description: Optional[str] = None
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
mood_id: Optional[str] = None
|
||||
|
||||
|
||||
class UniverseListItem(BaseModel):
|
||||
"""Universe list item for listing endpoints"""
|
||||
|
||||
universe_id: str
|
||||
name: str
|
||||
hash: str
|
||||
custom_name: Optional[str] = None
|
||||
theme_id: Optional[str] = None
|
||||
mood_id: Optional[str] = None
|
||||
mood_name: Optional[str] = None
|
||||
|
||||
|
||||
class UniverseData(BaseModel):
|
||||
"""Full universe data structure"""
|
||||
|
||||
universe_id: str
|
||||
name: str
|
||||
hash: str
|
||||
custom_name: Optional[str] = None
|
||||
theme_data: Optional[UniverseThemeInfo] = None
|
||||
data: Dict[str, Any] = Field(default_factory=dict)
|
||||
mood_id: Optional[str] = None
|
||||
mood_name: Optional[str] = None
|
||||
|
||||
|
||||
class PublicUniverse(BaseModel):
|
||||
"""Public universe information"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
hash: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
tags: List[str] = Field(default_factory=list)
|
||||
mood_id: Optional[str] = None
|
||||
mood_name: Optional[str] = None
|
||||
npc_count: int = 0
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# AUTH MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class AuthToken(BaseModel):
|
||||
"""Authentication token response"""
|
||||
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
token_type: str = "Bearer"
|
||||
expires_in: int
|
||||
user_id: str
|
||||
username: str
|
||||
|
||||
|
||||
class UserProfile(BaseModel):
|
||||
"""User profile information"""
|
||||
|
||||
user_id: str
|
||||
username: str
|
||||
email: str
|
||||
created_at: str
|
||||
universes_count: int = 0
|
||||
npcs_count: int = 0
|
||||
|
||||
|
||||
class ApiKey(BaseModel):
|
||||
"""API key information (without secret)"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
public_key: str
|
||||
scopes: List[str]
|
||||
created_at: str
|
||||
last_used_at: Optional[str] = None
|
||||
expires_at: Optional[str] = None
|
||||
|
||||
|
||||
class ApiKeyPair(BaseModel):
|
||||
"""API key pair with secret (only returned on creation)"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
public_key: str
|
||||
secret_key: str
|
||||
scopes: List[str]
|
||||
created_at: str
|
||||
expires_at: Optional[str] = None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# STATS MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class APIUsage(BaseModel):
|
||||
"""API usage statistics"""
|
||||
|
||||
requests_today: int
|
||||
requests_month: int
|
||||
rate_limit: int
|
||||
|
||||
|
||||
class NPCStats(BaseModel):
|
||||
"""User's NPC statistics"""
|
||||
|
||||
total_npcs: int
|
||||
total_messages: int
|
||||
unique_universes: int
|
||||
api_usage: APIUsage
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# MOOD MODELS
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class MoodData(BaseModel):
|
||||
"""Mood data structure"""
|
||||
|
||||
categories: Dict[str, Dict[str, Dict[str, str]]]
|
||||
|
||||
|
||||
class MoodItem(BaseModel):
|
||||
"""Mood list item"""
|
||||
|
||||
mood_id: str
|
||||
categories_count: int
|
||||
filename: str
|
||||
|
||||
|
||||
class MoodUploadResponse(BaseModel):
|
||||
"""Mood upload response"""
|
||||
|
||||
success: bool
|
||||
mood_id: str
|
||||
categories_count: int
|
||||
Loading…
Add table
Add a link
Reference in a new issue