Skip to content

Commit 0308c5b

Browse files
committed
🐛 fix: fix schema required
1 parent c726d58 commit 0308c5b

File tree

4 files changed

+174
-2
lines changed

4 files changed

+174
-2
lines changed

src/openapi/index.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export class OpenAPIConvertor {
3131
const parameters = this.mergeSchemas(...Object.values(parametersSchema));
3232

3333
if (requestBodySchema && Object.keys(requestBodySchema.properties).length > 0) {
34-
console.log(requestBodySchema);
3534
parameters.properties[OPENAPI_REQUEST_BODY_KEY] = requestBodySchema;
3635
parameters.required?.push('_requestBody');
3736
}
@@ -168,7 +167,7 @@ export class OpenAPIConvertor {
168167
for (const [contentType, mediaType] of Object.entries(requestBody.content)) {
169168
if (mediaType.schema) {
170169
// 直接使用已解析的 Schema
171-
const resolvedSchema = mediaType.schema;
170+
const resolvedSchema = this.removeRequiredFields(mediaType.schema);
172171

173172
// 根据不同的 content-type,可以在这里添加特定的处理逻辑
174173
switch (contentType) {
@@ -196,6 +195,30 @@ export class OpenAPIConvertor {
196195
return requestBodySchema as PluginSchema;
197196
}
198197

198+
private removeRequiredFields(schema: any): any {
199+
if (schema && typeof schema === 'object') {
200+
// 如果是对象类型,遍历它的每个属性
201+
for (const key in schema) {
202+
// eslint-disable-next-line no-prototype-builtins
203+
if (schema.hasOwnProperty(key)) {
204+
const value = schema[key];
205+
206+
// 如果属性是 required 并且值为 true,则删除该属性
207+
if (key === 'required' && value === true) {
208+
delete schema[key];
209+
} else {
210+
// 否则,如果属性是对象或数组,则递归处理
211+
schema[key] = this.removeRequiredFields(value);
212+
}
213+
}
214+
}
215+
} else if (Array.isArray(schema)) {
216+
// 如果是数组类型,遍历每个元素
217+
return schema.map(this.removeRequiredFields.bind(this));
218+
}
219+
return schema;
220+
}
221+
199222
private mergeSchemas(...schemas: any[]) {
200223
// 初始化合并后的 Schema
201224
const mergedSchema: PluginSchema = {

tests/__snapshots__/openapi.test.ts.snap

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,59 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3+
exports[`OpenAPIConvertor > convertOpenAPIToPluginSchema > ChatWithPDF 1`] = `
4+
[
5+
{
6+
"description": "Load a PDF document",
7+
"name": "loadPdf",
8+
"parameters": {
9+
"properties": {
10+
"_requestBody": {
11+
"properties": {
12+
"pdf_url": {
13+
"description": "The temporary URL of the PDF document to load.",
14+
"format": "uri",
15+
"type": "string",
16+
},
17+
},
18+
"required": [
19+
"pdf_url",
20+
],
21+
"type": "object",
22+
},
23+
},
24+
"type": "object",
25+
},
26+
},
27+
{
28+
"description": "Query a loaded PDF document",
29+
"name": "queryPdf",
30+
"parameters": {
31+
"properties": {
32+
"_requestBody": {
33+
"properties": {
34+
"pdf_url": {
35+
"description": "The temporary URL of the PDF document that is already loaded.",
36+
"format": "uri",
37+
"type": "string",
38+
},
39+
"query": {
40+
"description": "The query or question to ask based on the PDF document.",
41+
"type": "string",
42+
},
43+
},
44+
"required": [
45+
"query",
46+
"pdf_url",
47+
],
48+
"type": "object",
49+
},
50+
},
51+
"type": "object",
52+
},
53+
},
54+
]
55+
`;
56+
357
exports[`OpenAPIConvertor > convertOpenAPIToPluginSchema > can convert OpenAPI v2 MJ openAPI 1`] = `
458
[
559
{

tests/fixtures/ChatWithPDF.json

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{
2+
"components": {
3+
"schemas": {
4+
"loadPdfRequest": {
5+
"type": "object",
6+
"required": ["pdf_url"],
7+
"properties": {
8+
"pdf_url": {
9+
"type": "string",
10+
"format": "uri",
11+
"description": "The temporary URL of the PDF document to load.",
12+
"required": true
13+
}
14+
}
15+
},
16+
"queryPdfRequest": {
17+
"type": "object",
18+
"required": ["query", "pdf_url"],
19+
"properties": {
20+
"query": {
21+
"type": "string",
22+
"description": "The query or question to ask based on the PDF document.",
23+
"required": true
24+
},
25+
"pdf_url": {
26+
"type": "string",
27+
"format": "uri",
28+
"description": "The temporary URL of the PDF document that is already loaded.",
29+
"required": true
30+
}
31+
}
32+
},
33+
"queryPdfResponse": {
34+
"type": "object",
35+
"properties": {
36+
"results": {
37+
"type": "array",
38+
"items": { "type": "string" },
39+
"description": "The list of text chunks from the PDF document that are relevant to the user's query."
40+
}
41+
}
42+
}
43+
}
44+
},
45+
"info": {
46+
"title": "ChatWithPDF",
47+
"description": "A plugin that allows users to load and query PDF documents or Google Drive documents using ChatGPT. Users must first provide a PDF URL for processing. Once the PDF is loaded, users can query, analyze, or ask questions from that PDF name without needing to specify everytime. User must provide a PDF or Google Drive link that can be publically accessible, only documents can be loaded. The query will be able to extract relevant parts of the document to the users request. The load may take a while to process and if it does not work on the first try, try again, unless you get an error message back. User can only load documents that can be publically accessible on the internet. If they wish to use Google Docs they must first export it as a PDF, upload it to Google Drive then share a link that anybody can access via the link so we can download and process it. And if they wish to upload their document they can instead use service like [Upload Document](https://tmpfiles.org/).",
48+
"version": "v3"
49+
},
50+
"openapi": "3.0.1",
51+
"paths": {
52+
"/pdf/load": {
53+
"post": {
54+
"operationId": "loadPdf",
55+
"summary": "Load a PDF document",
56+
"requestBody": {
57+
"required": true,
58+
"content": {
59+
"application/json": { "schema": { "$ref": "#/components/schemas/loadPdfRequest" } }
60+
}
61+
},
62+
"responses": { "200": { "description": "OK" } }
63+
}
64+
},
65+
"/pdf/query": {
66+
"post": {
67+
"operationId": "queryPdf",
68+
"summary": "Query a loaded PDF document",
69+
"requestBody": {
70+
"required": true,
71+
"content": {
72+
"application/json": { "schema": { "$ref": "#/components/schemas/queryPdfRequest" } }
73+
}
74+
},
75+
"responses": {
76+
"200": {
77+
"description": "OK",
78+
"content": {
79+
"application/json": { "schema": { "$ref": "#/components/schemas/queryPdfResponse" } }
80+
}
81+
}
82+
}
83+
}
84+
}
85+
},
86+
"servers": [{ "url": "https://chatwithpdf.sdan.io" }]
87+
}

tests/openapi.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { OpenAPIConvertor } from '@lobehub/chat-plugin-sdk/openapi';
22
import { describe, expect, it } from 'vitest';
33

4+
import ChatWithPDF from './fixtures/ChatWithPDF.json';
45
import OpenAPI_Auth_API_Key from './fixtures/OpenAPI_Auth_API_Key.json';
56
import OpenAPIV2 from './fixtures/OpenAPI_V2.json';
67
import openAPIV3 from './fixtures/OpenAPI_V3.json';
@@ -28,6 +29,13 @@ describe('OpenAPIConvertor', () => {
2829

2930
expect(plugins).toMatchSnapshot();
3031
});
32+
33+
it('ChatWithPDF', async () => {
34+
const convertor = new OpenAPIConvertor(ChatWithPDF);
35+
const plugins = await convertor.convertOpenAPIToPluginSchema();
36+
37+
expect(plugins).toMatchSnapshot();
38+
});
3139
});
3240

3341
describe('convertAuthToSettingsSchema', () => {

0 commit comments

Comments
 (0)