Added new exception classes for API error handling including APIError, AuthenticationError, InvalidRequestError, APIConnectionError, RateLimitError, and ServerError to improve error handling and debugging capabilities in the SecureCompletionClient. These changes enhance the robustness of the API client by providing specific error types for different failure scenarios. |
||
|---|---|---|
| nomyo | ||
| .gitignore | ||
| LICENSE | ||
| MANIFEST.in | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
| SECURITY.md | ||
| test.py | ||
NOMYO Secure Python Chat Client
OpenAI-compatible secure chat client with end-to-end encryption with NOMYO Inference Endpoints
🔒 All prompts and responses are automatically encrypted and decrypted 🔑 Uses hybrid encryption (AES-256-GCM + RSA-OAEP with 4096-bit keys) 🔄 Drop-in replacement for OpenAI's ChatCompletion API
🚀 Quick Start
1. Install dependencies
pip install -r requirements.txt
2. Use the client (same API as OpenAI)
import asyncio
from nomyo import SecureChatCompletion
async def main():
# Initialize client (defaults to http://api.nomyo.ai:12434)
client = SecureChatCompletion(base_url="http://api.nomyo.ai:12434")
# Simple chat completion
response = await client.create(
model="Qwen/Qwen3-0.6B",
messages=[
{"role": "user", "content": "Hello! How are you today?"}
],
temperature=0.7
)
print(response['choices'][0]['message']['content'])
# Run the async function
asyncio.run(main())
3. Run tests
python3 test.py
🔐 Security Features
Hybrid Encryption
- Payload encryption: AES-256-GCM (authenticated encryption)
- Key exchange: RSA-OAEP with SHA-256
- Key size: 4096-bit RSA keys
- All communication: End-to-end encrypted
Key Management
- Automatic key generation and management
- Keys stored with restricted permissions (600 for private key)
- Optional password protection for private keys
- Key persistence across sessions
🔄 OpenAI Compatibility
The SecureChatCompletion class provides exact API compatibility with OpenAI's ChatCompletion.create() method.
Supported Parameters
All standard OpenAI parameters are supported:
model: Model identifiermessages: List of message objectstemperature: Sampling temperature (0-2)max_tokens: Maximum tokens to generatetop_p: Nucleus samplingfrequency_penalty: Frequency penaltypresence_penalty: Presence penaltystop: Stop sequencesn: Number of completionsstream: Streaming (not yet implemented)tools: Tool definitionstool_choice: Tool selection strategyuser: User identifier- And more...
Response Format
Responses follow the OpenAI format exactly, with an additional _metadata field for debugging and security information:
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1234567890,
"model": "Qwen/Qwen3-0.6B",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! I'm doing well, thank you for asking.",
"tool_calls": [...] # if tools were used
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 20,
"total_tokens": 30
},
"_metadata": {
"payload_id": "openai-compat-abc123", # Unique identifier for this request
"processed_at": 1765250382, # Timestamp when server processed the request
"is_encrypted": True, # Indicates this response was decrypted
"encryption_algorithm": "hybrid-aes256-rsa4096", # Encryption method used
"response_status": "success" # Status of the decryption/processing
}
}
The _metadata field contains security-related information about the encrypted communication and is automatically added to all responses.
🛠️ Usage Examples
Basic Chat
import asyncio
from nomyo import SecureChatCompletion
async def main():
client = SecureChatCompletion(base_url="http://api.nomyo.ai:12434")
response = await client.create(
model="Qwen/Qwen3-0.6B",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
temperature=0.7
)
print(response['choices'][0]['message']['content'])
asyncio.run(main())
With Tools
import asyncio
from nomyo import SecureChatCompletion
async def main():
client = SecureChatCompletion(base_url="http://api.nomyo.ai:12434")
response = await client.create(
model="Qwen/Qwen3-0.6B",
messages=[
{"role": "user", "content": "What's the weather in Paris?"}
],
tools=[
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather information",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
}
],
temperature=0.7
)
print(response['choices'][0]['message']['content'])
asyncio.run(main())
Using acreate() Alias
import asyncio
from nomyo import SecureChatCompletion
async def main():
client = SecureChatCompletion(base_url="http://api.nomyo.ai:12434")
response = await client.acreate(
model="Qwen/Qwen3-0.6B",
messages=[
{"role": "user", "content": "Hello!"}
],
temperature=0.7
)
print(response['choices'][0]['message']['content'])
asyncio.run(main())
📦 Dependencies
See requirements.txt for the complete list:
cryptography: Cryptographic primitives (RSA, AES, etc.)httpx: Async HTTP clientanyio: Async compatibility layer
🔧 Configuration
Custom Base URL
import asyncio
from nomyo import SecureChatCompletion
async def main():
client = SecureChatCompletion(base_url="http://NOMYO-Pro-Router:12434")
# ... rest of your code
asyncio.run(main())
Key Management
Keys are automatically generated on first use and stored in client_keys/ directory.
Generate Keys Manually
import asyncio
from nomyo.SecureCompletionClient import SecureCompletionClient
async def main():
client = SecureCompletionClient()
await client.generate_keys(save_to_file=True, password="your-password")
asyncio.run(main())
Load Existing Keys
import asyncio
from nomyo.SecureCompletionClient import SecureCompletionClient
async def main():
client = SecureCompletionClient()
await client.load_keys("client_keys/private_key.pem", "client_keys/public_key.pem", password="your-password")
asyncio.run(main())
🧪 Testing
Run the comprehensive test suite:
python3 test.py
Tests verify:
- ✅ OpenAI API compatibility
- ✅ Basic chat completion
- ✅ Tool usage
- ✅ All OpenAI parameters
- ✅ Async methods
- ✅ Error handling
📚 API Reference
SecureChatCompletion
Constructor
SecureChatCompletion(base_url: str = "http://api.nomyo.ai:12434")
Methods
create(model, messages, **kwargs): Create a chat completionacreate(model, messages, **kwargs): Async alias for create()
SecureCompletionClient
Constructor
SecureCompletionClient(router_url: str = "http://api.nomyo.ai:12434")
Methods
generate_keys(save_to_file=False, key_dir="client_keys", password=None): Generate RSA key pairload_keys(private_key_path, public_key_path=None, password=None): Load keys from filesfetch_server_public_key(): Fetch server's public keyencrypt_payload(payload): Encrypt a payloaddecrypt_response(encrypted_response, payload_id): Decrypt a responsesend_secure_request(payload, payload_id): Send encrypted request and receive decrypted response
📝 Notes
Security Best Practices
- Always use password protection for private keys in production
- Keep private keys secure (permissions set to 600)
- Never share your private key
- Verify server's public key fingerprint before first use
Performance
- Key generation takes ~1-2 seconds (one-time operation)
- Encryption/decryption adds minimal overhead (~10-20ms per request)
Compatibility
- Works with any OpenAI-compatible code
- No changes needed to existing OpenAI client code
- Simply replace
openai.ChatCompletion.create()withSecureChatCompletion.create()
🤝 Contributing
Contributions are welcome! Please open issues or pull requests on the project repository.
📄 License
See LICENSE file for licensing information.
📞 Support
For questions or issues, please refer to the project documentation or open an issue.