aip-sci 0.1.0

Affective Interaction Programming - 情感交互编程
Documentation
# FFI (Foreign Function Interface) Guide

This document describes how to use AIP from iOS and Android applications.

## Overview

AIP provides C-compatible FFI bindings that allow integration with:

- **iOS**: Swift/Objective-C via XCFramework
- **Android**: Kotlin/Java via JNI

## API Reference

### Error Codes

| Code | Constant | Description |
|------|----------|-------------|
| 0 | `AIP_SUCCESS` | Success |
| -1 | `AIP_ERROR_NULL_POINTER` | Null pointer passed |
| -2 | `AIP_ERROR_INVALID_DATA` | Invalid data format |
| -3 | `AIP_ERROR_MODEL_NOT_LOADED` | Model not loaded |
| -4 | `AIP_ERROR_INFERENCE_FAILED` | Inference failed |
| -5 | `AIP_ERROR_FILE_NOT_FOUND` | Model file not found |
| -6 | `AIP_ERROR_LOAD_FAILED` | Model load failed |

### EDM (Emotion Data Model)

```c
// Create/Destroy
void* aip_edm_create();
void aip_edm_destroy(void* model);

// Load model from file
int aip_edm_load(void* model, const char* path);

// Inference
typedef struct {
    const float* data;
    size_t len;  // Must be 15
} AipFeatureArray;

typedef struct {
    float valence;
    float arousal;
    float dominance;
    int error_code;
} AipEmotionResult;

AipEmotionResult aip_edm_infer(void* model, AipFeatureArray features);
```

### Director (Interaction Strategy)

```c
// Create/Destroy
void* aip_director_create();
void aip_director_destroy(void* model);

// Load model from file
int aip_director_load(void* model, const char* path);

// Decision making
typedef struct {
    const float* data;
    size_t len;  // Must be 8
} AipUserTraits;

typedef struct {
    const float* data;
    size_t len;  // Must be 6
} AipEnvState;

typedef struct {
    float valence;
    float arousal;
    float dominance;
} AipEmotionInput;

typedef struct {
    float intensity_factor;
    float feedback_intensity;
    float pace_speed;
    float reward_scarcity;
    float env_arousal;
    float rhythm_modulation;
    float challenge_curve;
    int error_code;
} AipDecisionResult;

AipDecisionResult aip_director_decide(
    void* model,
    AipUserTraits user_traits,
    AipEnvState env_state,
    AipEmotionInput emotion
);
```

### Utility Functions

```c
const char* aip_get_version();
const char* aip_error_message(int code);
void aip_free_string(char* s);
```

## iOS Integration

### Build

```bash
./scripts/build_ios.sh
```

This generates `target/ios/Aip.xcframework`.

### Xcode Setup

1. Add `Aip.xcframework` to your project
2. Add to "Frameworks, Libraries, and Embedded Content"
3. Import the header:

```objc
#import <Aip/Aip.h>
```

### Swift Usage

```swift
// Create models
guard let edm = AipEdmModel(),
      let director = AipDirectorModel() else {
    print("Failed to create models")
    return
}

// Load pre-trained models
try edm.load(from: modelPath)
try director.load(from: directorPath)

// EDM inference
let features: [Float] = [0.5, 0.6, 0.4, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let emotion = try edm.infer(features: features)

// Director decision
let userTraits: [Float] = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let envState: [Float] = [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
let decision = try director.decide(
    userTraits: userTraits,
    envState: envState,
    emotion: emotion
)

print("Intensity: \(decision.intensityFactor)")
print("Pace: \(decision.paceSpeed)")
```

## Android Integration

### Build

```bash
export ANDROID_NDK_HOME=/path/to/ndk
./scripts/build_android.sh
```

This generates `target/android/aip-ffi.aar`.

### Gradle Setup

1. Copy `aip-ffi.aar` to `app/libs/`
2. Add to `build.gradle`:

```gradle
android {
    // ...
}

dependencies {
    implementation files('libs/aip-ffi.aar')
}
```

### Kotlin Usage

```kotlin
import com.aip.ffi.*

class GameManager {
    private var edm: AipEdmModel? = null
    private var director: AipDirectorModel? = null
    
    fun initialize(edmPath: String, directorPath: String) {
        edm = AipEdmModel.create()
        director = AipDirectorModel.create()
        
        edm?.load(edmPath)
        director?.load(directorPath)
    }
    
    fun processGameState(features: FloatArray): AipDecision {
        val emotion = edm?.infer(features) 
            ?: throw IllegalStateException("EDM not initialized")
        
        val userTraits = floatArrayOf(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f)
        val envState = floatArrayOf(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f)
        
        return director?.decide(userTraits, envState, emotion)
            ?: throw IllegalStateException("Director not initialized")
    }
    
    fun cleanup() {
        edm?.close()
        director?.close()
    }
}
```

## Unity Integration

### Build Native Library

```bash
# iOS
./scripts/build_ios.sh

# Android
./scripts/build_android.sh
```

### C# Wrapper

```csharp
using System;
using System.Runtime.InteropServices;

public class AipNative {
    [DllImport("aip")]
    public static extern IntPtr aip_edm_create();
    
    [DllImport("aip")]
    public static extern void aip_edm_destroy(IntPtr model);
    
    [DllImport("aip")]
    public static extern int aip_edm_load(IntPtr model, string path);
    
    // ... other declarations
}

public class AipEdmModel {
    private IntPtr handle;
    
    public AipEdmModel() {
        handle = AipNative.aip_edm_create();
    }
    
    ~AipEdmModel() {
        if (handle != IntPtr.Zero) {
            AipNative.aip_edm_destroy(handle);
        }
    }
    
    public void Load(string path) {
        AipNative.aip_edm_load(handle, path);
    }
    
    // ... other methods
}
```

## Performance Considerations

- **Model Size**: EDM ~170KB, Director ~158KB
- **Inference Latency**: <1ms on modern mobile CPUs
- **Memory**: ~10MB runtime footprint
- **Thread Safety**: Models are NOT thread-safe. Use separate instances per thread.

## Model Training

Models must be trained and exported before use:

```bash
# Train EDM
cargo run --features edm_roguelite_training -- train-edm --output models/edm.safetensors

# Train Director
cargo run --features director_roguelite_training -- train-director --output models/director.safetensors
```

## Troubleshooting

### iOS: "Library not loaded"

Ensure the framework is properly embedded:
1. Target → Build Phases → Embed Frameworks
2. Add `Aip.xcframework`
3. Set "Embed & Sign"

### Android: "UnsatisfiedLinkError"

1. Verify `libaip.so` exists in the correct `jniLibs/<arch>/` directory
2. Check ABI compatibility (arm64-v8a, armeabi-v7a, x86, x86_64)
3. Ensure `System.loadLibrary("aip")` is called before use

### Model Load Fails

1. Verify model file exists at specified path
2. Check file permissions
3. Ensure model was trained with compatible version