Skip to content

Commit

Permalink
Merge pull request #2 from backmesh/test
Browse files Browse the repository at this point in the history
Optional callbacks + add basic tests in CI
  • Loading branch information
depombo authored Aug 27, 2024
2 parents 6fe0b21 + 1a1e7d2 commit 365b1e6
Show file tree
Hide file tree
Showing 9 changed files with 8,140 additions and 144 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2

- name: Install dependencies
run: yarn

- name: Run tests
run: yarn test
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
dist
dist
openai-node
scripts/test-runner
6 changes: 6 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
28 changes: 25 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "openai-react-native",
"version": "0.2.3",
"version": "0.2.4",
"description": "OpenAI React Native API Client without polyfills",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"prepare": "npm run build"
"prepare": "npm run build",
"test": "./scripts/test"
},
"keywords": [
"openai",
Expand All @@ -30,12 +31,33 @@
"trailingComma": "es5",
"useTabs": false
},
"jest": {
"preset": "jest-expo",
"testPathIgnorePatterns": [
"openai-node"
],
"moduleNameMapper": {
"^react-native-sse$": "<rootDir>/node_modules/react-native-sse"
}
},
"dependencies": {
"expo-file-system": "^17.0.1",
"openai": "^4.56.0",
"react-native-sse": "^1.2.1"
},
"devDependencies": {
"typescript": "^5.5.4"
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.12",
"@types/react": "~18.2.45",
"@types/react-test-renderer": "^18.0.7",
"expo": "~51.0.28",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.5",
"react-test-renderer": "18.2.0",
"typescript": "~5.3.3",
"xmlhttprequest": "^1.8.0"
}
}
9 changes: 9 additions & 0 deletions scripts/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

rm -rf openai-node
git clone https://github.com/openai/openai-node.git
cd openai-node
bash scripts/mock --daemon
cd ..
cp openai-node/scripts/test scripts/test-runner
bash scripts/test-runner
50 changes: 22 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ export type RunCallback = (data: OpenAINode.Beta.Threads.Run) => void;
export type ErrorCallback = (error: any) => void;
export type OpenCallback = () => void;
export type DoneCallback = () => void;

export type OptionalCallbacks = {
onError?: ErrorCallback;
onOpen?: OpenCallback;
onDone?: DoneCallback;
};
export interface ClientOptions extends ClientOptionsNode {
apiKey: string;
baseURL: string;
}

export class OpenAI {
private apiKey: string;
private baseURL: string;
public apiKey: string;
public baseURL: string;
private client: OpenAINode;

constructor(opts: ClientOptions) {
Expand All @@ -39,6 +43,9 @@ export class OpenAI {
};

public beta = {
assistants: {
list: async () => this.client.beta.assistants.list(),
},
threads: {
create: async (body?: OpenAINode.Beta.ThreadCreateParams) =>
this.client.beta.threads.create(body),
Expand All @@ -57,22 +64,14 @@ export class OpenAI {
threadId: string,
body: OpenAINode.Beta.Threads.Runs.RunCreateParamsNonStreaming,
onData: ChatCompletionCallback,
onError: ErrorCallback,
onOpen?: OpenCallback,
onDone?: DoneCallback
): void => {
this.client.beta.threads.runs.stream;
callbacks: OptionalCallbacks
): void =>
this._stream(
`${this.baseURL}/threads/${threadId}/runs`,
body,
onData,
{
onError,
onOpen,
onDone,
}
);
},
callbacks
),
},
},
};
Expand Down Expand Up @@ -104,15 +103,14 @@ export class OpenAI {
stream: (
params: OpenAINode.ChatCompletionCreateParamsNonStreaming,
onData: ChatCompletionCallback,
onError?: ErrorCallback,
onOpen?: OpenCallback,
onDone?: DoneCallback
callbacks: OptionalCallbacks
): void =>
this._stream(`${this.baseURL}/chat/completions`, params, onData, {
onError,
onOpen,
onDone,
}),
this._stream(
`${this.baseURL}/chat/completions`,
params,
onData,
callbacks
),
},
};

Expand Down Expand Up @@ -170,11 +168,7 @@ export class OpenAI {
| OpenAINode.ChatCompletionCreateParamsNonStreaming
| OpenAINode.Beta.Threads.Runs.RunCreateParamsNonStreaming,
onData: ChatCompletionCallback | RunCallback,
callbacks: {
onError?: ErrorCallback;
onOpen?: OpenCallback;
onDone?: DoneCallback;
}
callbacks: OptionalCallbacks
) {
const { onError, onOpen, onDone } = callbacks;
const requestBody = { ...params, stream: true };
Expand Down
106 changes: 106 additions & 0 deletions tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
OpenAI,
} from '../src/index';

// jest runs in node, but this is needed by react-native-sse
global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;

// using mocks from https://github.com/openai/openai-node/blob/master/.stats.yml#L2
describe('OpenAI Integration Tests', () => {
let openAI: OpenAI;

beforeEach(() => {
openAI = new OpenAI({
apiKey: 'test-api-key', // Replace with a valid API key
baseURL: 'http://127.0.0.1:4010', // Replace with your local server URL
});
});

describe('beta.assistants', () => {
it('should get assistants', async () => {
const assistant = await openAI.beta.assistants.list();
expect(assistant).toBeDefined();
});
});

describe('moderations', () => {
it('should create moderation', async () => {
const moderation = await openAI.moderations.create({ input: 'test' });
expect(moderation).toBeDefined();
expect(moderation.id).toBeDefined();
});
});

describe('chat.completions', () => {
it('should create completion', async () => {
const completion = await openAI.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{"role": "user", "content": "Hello!"}],
});
expect(completion).toBeDefined();
expect(completion.id).toBeDefined();
const content = completion.choices[0].message;
expect(content).toBeDefined();
});
it('should stream completion', async () => {
openAI.chat.completions.stream(
{
model: 'gpt-4o-mini',
messages: [{"role": "user", "content": "Hello!"}],
},
(completion) => {
expect(completion).toBeDefined();
expect(completion.id).toBeDefined();
const content = completion.choices[0].message;
expect(content).toBeDefined();
},
{
onError: (error) => expect(error).not.toBeDefined(),
}
);
});
});

// https://stackoverflow.com/questions/58262638/why-doesnt-expo-file-system-work-in-jest
// describe('files', () => {
// it('should upload file', async () => {
// const FileUploadTestComponent = () => {
// const [file, setFile] = useState<any | null>(null);
// const [error, setError] = useState<any | null>(null);

// const handleFileUpload = async () => {
// try {
// const uploadedFile = await openAI.files.create('../README.md', 'fine-tune');
// setFile(uploadedFile);
// } catch (err) {
// setError(err);
// }
// };

// return (
// <View>
// <Button title="Upload File" onPress={handleFileUpload} />
// {file && (
// <Text>File uploaded successfully: {file.id}</Text>
// )}
// {error && (
// <Text>Error uploading file: {error}</Text>
// )}
// </View>
// );
// };
// const { getByText, findByText } = renderer.create(<FileUploadTestComponent />);
// fireEvent.press(getByText('Upload File'));

// const successMessage = await findByText(/File uploaded successfully:/);
// expect(successMessage).toBeDefined();

// const tree = renderer.create(<View>Snapshot test!</View>).toJSON();
// expect(tree).toMatchSnapshot();

// const file = await openAI.files.create('../README.md', 'fine-tune');
// expect(file).toBeDefined();
// expect(file.id).toBeDefined();
// });
// });
});
22 changes: 15 additions & 7 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"outDir": "./dist",
"module": "commonjs",
"target": "es6",
"declaration": true,
"strict": true,
"esModuleInterop": true
"paths": {
"@/*": [
"./*"
]
}
},
"include": ["src"],
"exclude": ["node_modules"]
"include": [
"**/*.ts",
"**/*.tsx",
".expo/types/**/*.ts",
"expo-env.d.ts"
],
"exclude": [
"openai-node"
]
}
Loading

0 comments on commit 365b1e6

Please sign in to comment.