https://github.com/dankinsoid/openaimacros
Macros for OpenAI repo
https://github.com/dankinsoid/openaimacros
Last synced: 10 months ago
JSON representation
Macros for OpenAI repo
- Host: GitHub
- URL: https://github.com/dankinsoid/openaimacros
- Owner: dankinsoid
- Created: 2025-07-09T16:44:17.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-07-09T19:28:27.000Z (11 months ago)
- Last Synced: 2025-07-10T03:33:55.940Z (11 months ago)
- Language: Swift
- Size: 25.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# OpenAI Macros
A Swift package that provides macros for seamless integration with OpenAI's function calling API. Instead of manually creating `FunctionDeclaration` structs, simply annotate your Swift functions with `@openAIFunction` and let the macro generate everything automatically.
## Installation
Add this package to your Swift project:
```swift
dependencies: [
.package(url: "https://github.com/yourusername/OpenAIMacros", from: "1.0.0")
]
```
## Quick Start
### 1. Define Your Functions
```swift
import OpenAIMacros
struct WeatherService {
/// Get the current weather for a given location
/// - Parameters:
/// - location: The city and state, e.g. San Francisco, CA
/// - unit: Temperature unit (celsius or fahrenheit)
@openAIFunction
func getCurrentWeather(location: String, unit: TemperatureUnit = .celsius) async throws -> WeatherResponse {
// Your implementation here
return WeatherResponse(temperature: 22.5, unit: unit, description: "Sunny")
}
}
enum TemperatureUnit: String, CaseIterable, Codable {
case celsius
case fahrenheit
}
struct WeatherResponse: Codable {
let temperature: Double
let unit: TemperatureUnit
let description: String
}
```
### 2. Use with OpenAI
```swift
import OpenAI
import OpenAIMacros
let openAI = OpenAI(apiToken: "your-api-key")
let weatherService = WeatherService()
// The macro automatically generates getCurrentWeatherCall
let result = try await openAI.chatsWith(
functions: [weatherService.getCurrentWeatherCall],
query: ChatQuery(
messages: [.user(.init(content: .string("What's the weather like in Boston?")))],
model: "gpt-4o"
)
)
// prints "The current temperature in Boston is 22.5°C."
print(result.choices[0].message.content ?? "No response")
```
## What the Macro Generates
The `@openAIFunction` macro automatically generates:
1. **Parameter Struct**: `GetCurrentWeatherParameters` with proper `Codable` support
2. **Function Wrapper**: `getCurrentWeatherCall` that bridges OpenAI ↔ Swift
3. **JSON Schema**: Complete parameter validation with types and descriptions
4. **Custom Decoder**: Handles default values (e.g., `unit` parameter is optional in JSON)
### Generated Code Example
```swift
// Generated by @openAIFunction
struct GetCurrentWeatherParameters: Decodable {
let location: String
let unit: TemperatureUnit
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.location = try container.decode(String.self, forKey: .location)
self.unit = try container.decodeIfPresent(TemperatureUnit.self, forKey: .unit) ?? .celsius
}
private enum CodingKeys: String, CodingKey {
case location
case unit
}
}
var getCurrentWeatherCall: OpenAIFunctionWrapper {
OpenAIFunctionWrapper(
difinition: ChatQuery.ChatCompletionToolParam.FunctionDefinition(
name: "getCurrentWeather",
description: "Get the current weather for a given location",
parameters: AnyJSONSchema(fields: [
.type(.object),
.properties([
"location": AnyJSONSchema.forType(String.self, description: "The city and state, e.g. San Francisco, CA"),
"unit": AnyJSONSchema.forType(TemperatureUnit.self, description: "Temperature unit (celsius or fahrenheit)")
]),
.required(["location"])
])
)
) { [self] decoder, data, encoder in
let parameters = try decoder.decode(GetCurrentWeatherParameters.self, from: data)
let result = try await getCurrentWeather(location: parameters.location, unit: parameters.unit)
return try encoder.encode(result)
}
}
```
## Features
### ✅ **Automatic Code Generation**
- Parameter structs with proper `Codable` support
- JSON schema generation with type validation
- Function wrappers that handle the OpenAI ↔ Swift bridge
### ✅ **Smart Type Detection**
- **Primitives**: `String`, `Int`, `Double`, `Bool`
- **Enums**: `CaseIterable` types → JSON schema with enum values
- **Collections**: `Array`, `Dictionary`, `Set` → appropriate JSON types
- **Custom Types**: `Codable` structs/classes → JSON objects
- **Optionals**: Proper handling of optional parameters
### ✅ **Default Values Support**
- Parameters with defaults are optional in JSON
- Custom decoders handle missing values gracefully
- `nil` defaults are treated as required parameters
### ✅ **Documentation Integration**
- Function descriptions from doc comments
- Parameter descriptions from `@param` documentation
- Automatic cleanup of doc comment markers
### ✅ **Async/Throws Support**
- Detects `async` and `throws` in function signatures
- Generates appropriate `await` and `try` keywords
- Full support for async throwing functions
### ✅ **Complete Function Calling Workflow**
- `chatsWith()` method handles the entire OpenAI function calling flow
- Recursive execution of multiple function calls
- Proper error handling and result processing
## Advanced Usage
### Multiple Functions (TODO - Future Version)
```swift
// TODO: This pattern will be supported in a future version
struct MyAPI {
@openAIFunction
func getWeather(location: String) async throws -> WeatherResponse {
// Implementation
}
@openAIFunction
func searchRestaurants(location: String, cuisine: String? = nil) async throws -> [Restaurant] {
// Implementation
}
// TODO: Auto-generate this with @OpenAIFunctionsCollection macro
var allFunctions: [OpenAIFunctionWrapper] {
[getWeatherCall, searchRestaurantsCall]
}
}
// Use all functions
let api = MyAPI()
let result = try await openAI.chatsWith(
functions: api.allFunctions,
query: query
)
```
**Current workaround**: For now, you need to manually create the `allFunctions` array or call each function wrapper individually.
### Error Handling
```swift
do {
let result = try await openAI.chatsWith(functions: functions, query: query)
// Handle result
} catch let error as UnknownFunctionCall {
print("Unknown function: \(error.functionName)")
} catch let error as InvalidString {
print("String conversion error: \(error.message)")
} catch {
print("Other error: \(error)")
}
```
## Requirements
- Swift 5.9+ (for macro support)
- macOS 10.15+, iOS 13+, tvOS 13+, watchOS 6+
- [MacPaw's OpenAI Swift library](https://github.com/MacPaw/OpenAI)
## What's Next
This is the first version of OpenAI Macros. Future versions may include:
- `@OpenAIFunctionsCollection` macro for automatic function grouping
- Support for more complex parameter types
- Integration with other OpenAI Swift libraries
- Enhanced error handling and debugging
## License
MIT License - see LICENSE file for details.