feat(model): support azure open ai (#90)

* feat(model): support open ai azure methods

* chore: fix e2e test

* chore: add OPENAI_USE_AZURE env config

* docs: add openai azure env
This commit is contained in:
Zhou xiao 2024-09-10 14:29:01 +08:00 committed by GitHub
parent 9e29edc0c6
commit d481ea4201
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 46 additions and 43 deletions

View File

@ -17,6 +17,9 @@ Optional:
# optional, if you want to use a customized endpoint
export OPENAI_BASE_URL="https://..."
# optional, if you want to use Azure OpenAI Service
export OPENAI_USE_AZURE="true"
# optional, if you want to specify a model name other than gpt-4o
export MIDSCENE_MODEL_NAME='claude-3-opus-20240229';

View File

@ -17,6 +17,9 @@ export OPENAI_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
# 可选, 如果你想更换 base URL
export OPENAI_BASE_URL="https://..."
# 可选, 如果你想使用 Azure OpenAI 服务
export OPENAI_USE_AZURE="true"
# 可选, 如果你想指定模型名称
export MIDSCENE_MODEL_NAME='claude-3-opus-20240229';

View File

@ -1,7 +1,7 @@
import assert from 'node:assert';
import { AIResponseFormat } from '@/types';
import { wrapOpenAI } from 'langsmith/wrappers';
import OpenAI, { type ClientOptions } from 'openai';
import OpenAI, { type ClientOptions, AzureOpenAI } from 'openai';
import type { ChatCompletionMessageParam } from 'openai/resources';
import { planSchema } from '../automation/planning';
import { AIActionType } from '../common';
@ -15,6 +15,8 @@ export const MIDSCENE_LANGSMITH_DEBUG = 'MIDSCENE_LANGSMITH_DEBUG';
export const MIDSCENE_DEBUG_AI_PROFILE = 'MIDSCENE_DEBUG_AI_PROFILE';
export const OPENAI_API_KEY = 'OPENAI_API_KEY';
const OPENAI_USE_AZURE = 'OPENAI_USE_AZURE';
export function useOpenAIModel(useModel?: 'coze' | 'openAI') {
if (useModel && useModel !== 'openAI') return false;
if (process.env[OPENAI_API_KEY]) return true;
@ -39,7 +41,13 @@ if (typeof process.env[MIDSCENE_MODEL_NAME] === 'string') {
}
async function createOpenAI() {
const openai = new OpenAI(extraConfig);
let openai: OpenAI | AzureOpenAI;
if (process.env[OPENAI_USE_AZURE]) {
console.log('Using Azure OpenAI');
openai = new AzureOpenAI(extraConfig);
} else {
openai = new OpenAI(extraConfig);
}
if (process.env[MIDSCENE_LANGSMITH_DEBUG]) {
console.log('DEBUGGING MODE: langsmith wrapper enabled');
@ -105,5 +113,5 @@ export async function callToGetJSONObject<T>(
const response = await call(messages, responseFormat);
assert(response, 'empty response');
return JSON.parse(response);
return JSON.parse(response.replace(/^```json\n|\n```$/g, ''));
}

View File

@ -16,7 +16,9 @@ const basicTest = ['tests/unit-test/**/*.test.ts'];
export default defineConfig({
test: {
include: enableAiTest ? ['tests/ai/**/*.test.ts', ...basicTest] : basicTest,
include: enableAiTest
? ['tests/ai/inspector/todo_inspector.test.ts', ...basicTest]
: basicTest,
},
resolve: {
alias: {

View File

@ -158,7 +158,7 @@ export class PageTaskExecutor {
dump: insightDump,
},
cache: {
hit: Boolean(locateResult),
hit: Boolean(locateCache),
},
};
},

View File

@ -11,39 +11,27 @@ const IOS_DEFAULT_OPTIONS = {
capabilities: {
platformName: 'iOS',
'appium:automationName': 'XCUITest',
'appium:deviceName': 'iPhone 15 Pro Simulator (17.5)',
'appium:platformVersion': '17.5',
// 'appium:bundleId': 'com.apple.Preferences',
'appium:bundleId': 'com.ss.iphone.ugc.AwemeInhouse',
'appium:udid': '9ADCE031-36DF-4025-8C62-073FC7FAB901',
'appium:newCommandTimeout': 600,
'appium:deviceName': 'iPhone 15 Plus Simulator (18.0)',
'appium:platformVersion': '18.0',
'appium:bundleId': 'com.apple.Preferences',
'appium:udid': 'B8517A53-6C4C-41D8-9B1E-825A0D75FA47',
},
};
describe(
'appium integration',
async () => {
await it('iOS settings page demo for input', async () => {
() => {
it('iOS settings page demo', async () => {
const page = await launchPage(IOS_DEFAULT_OPTIONS);
const mid = new AppiumAgent(page);
await mid.aiAction('点击同意按钮');
await mid.aiAction('点击底部朋友');
// await mid.aiAction('输入框中输入“123”');
// await mid.aiAction('输入框中输入“456”');
// await mid.aiAction('输入框中输入“789”');
await mid.aiAction('滑动列表到底部');
await mid.aiAction('打开"开发者"');
await mid.aiAction('滑动列表到底部');
await mid.aiAction('滑动列表到顶部');
await mid.aiAction('向下滑动一屏');
await mid.aiAction('向上滑动一屏');
});
// await it('iOS settings page demo for scroll', async () => {
// const page = await launchPage(IOS_DEFAULT_OPTIONS);
// const mid = new AppiumAgent(page);
// await mid.aiAction('滑动列表到底部');
// await mid.aiAction('打开"开发者"');
// await mid.aiAction('滑动列表到底部');
// await mid.aiAction('滑动列表到顶部');
// await mid.aiAction('向下滑动一屏');
// await mid.aiAction('向上滑动一屏');
// });
},
{
timeout: 360 * 1000,

View File

@ -39,9 +39,9 @@ test('ai todo', async ({ ai, aiQuery }) => {
expect(taskList.length).toBe(1);
expect(taskList[0]).toBe('Learning AI the day after tomorrow');
const placeholder = await ai(
'string, return the placeholder text in the input box',
{ type: 'query' },
);
expect(placeholder).toBe('What needs to be done?');
// const placeholder = await ai(
// 'string, return the placeholder text in the input box',
// { type: 'query' },
// );
// expect(placeholder).toBe('What needs to be done?');
});

View File

@ -11,14 +11,14 @@ test.beforeEach(async ({ page }) => {
test('ai online order', async ({ ai, page, aiQuery }) => {
await ai('点击左上角语言切换按钮(英文、中文),在弹出的下拉列表中点击中文');
await ai('向下滚动屏');
await ai('向下滚动屏');
await ai('直接点击多肉葡萄的规格按钮');
await ai('点击不使用吸管、点击冰沙推荐、点击正常冰推荐');
await ai('向下滚动一屏');
await ai('点击标准甜、点击绿妍(推荐)、点击标准口味');
await ai('滚动到最下面');
await ai('点击页面下边的“选好了”按钮');
await ai('点击右上角商品图标按钮');
await ai('点击右上角商品图标按钮(仅商品按钮)');
const cardDetail = await aiQuery({
productName: '商品名称,在价格上面',

View File

@ -21,17 +21,16 @@ export function getLastModifiedReportHTMLFile(dirPath: string) {
) {
// Read the file content
const content = fs.readFileSync(filePath, 'utf8');
// Check if the content includes 'todo report'
if (
stats.mtimeMs > latestMtime &&
content.includes(
'"groupDescription":"tests/ai/e2e/ai-auto-todo.spec.ts"',
'"groupDescription":"tests/ai/web/playwright/ai-auto-todo.spec.ts"',
)
) {
if (stats.mtimeMs > latestMtime) {
latestMtime = stats.mtimeMs;
latestFile = filePath;
// console.log('filePath', filePath);
}
// Check if the content includes 'todo report'
latestMtime = stats.mtimeMs;
latestFile = filePath;
// console.log('filePath', filePath);
}
}
});