记录一下快速模板,整体很简单,如果不接auth,只需要以下:
提供一个/.well-known/ai-plugin.json
接口,返回openAI所需要的格式
提供openAPI规范的文档
CORS设置
其他的和普通的web开发类似.
本地开发就直接使用localhost即可,前几天官方localhost无法联通 ,最近应该修复了.
要让GPT更好理解接口内容,接口需要写详细的文档,在文档内写清楚各个参数作用和可选值以及示例.
Spring Boot 增加对文档的依赖 1 2 3 4 5 <dependency > <groupId > org.springdoc</groupId > <artifactId > springdoc-openapi-starter-webmvc-ui</artifactId > <version > 2.1.0</version > </dependency >
增加一个bean配置:
1 2 3 4 5 6 7 @Bean public OpenAPI openAPI () { return new OpenAPI () .info(new Info ().title("html fetcher" ) .description("get content from url" ) .version("1.0" )); }
文档的地址为/v3/api-docs
增加ai-plugin.json接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @GetMapping(value = "/.well-known/ai-plugin.json", produces = "application/json") public String aiPlugin () { return """ { "schema_version": "v1", "name_for_human": "html fetcher Plugin", "name_for_model": "html_fetcher", "description_for_human": "Plugin for getting content from url", "description_for_model": "Plugin for getting content from url", "auth": { "type": "none" }, "api": { "type": "openapi", "url": "http://localhost:8080/v3/api-docs", "is_user_authenticated": false }, "logo_url": "http://localhost:8080/logo.png", "contact_email": "support@example.com", "legal_info_url": "http://www.example.com/legal" } """ ;}
logo直接放到\resources\static
中 内容根据自己插件修改,本地开发直接写localhost,部署写对应的网站地址.
CORS设置 测试的时候允许可以写*, 后续上线更改为openai.com:
1 2 3 4 5 6 7 8 9 10 @Bean public CorsFilter corsFilter () { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource (); CorsConfiguration config = new CorsConfiguration (); config.addAllowedOrigin("*" ); config.addAllowedHeader("*" ); config.addAllowedMethod("*" ); source.registerCorsConfiguration("/**" , config); return new CorsFilter (source); }
要写自定义文档可以用spring-doc的相关注解. 比如写在接口上用@Operation
, 字段上使用@Schema
注解.@Schema
内可以用allowableValues
和example
等来约束openai的查询.
fastapi fastapi自带openAPI集成,只需要把json dump成yaml即可, setup比较简单, 这里直接全部放一起了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*" ], allow_credentials=True , allow_methods=["*" ], allow_headers=["*" ], ) app.mount("/static" , StaticFiles(directory="static" ), name="static" ) @app.get("/openapi.yaml" ) async def get_openapi (): return Response(content=yaml.dump(app.openapi()), media_type="application/yaml" ) @app.get("/.well-known/ai-plugin.json" ) async def openai_api_plugin (): return { "schema_version" : "v1" , "name_for_human" : "" , "name_for_model" : "" , "description_for_human" : "" , "description_for_model" : "" , "auth" : { "type" : "none" }, "api" : { "type" : "openapi" , "url" : "http://localhost:8000/openapi.yaml" , "is_user_authenticated" : False }, "logo_url" : "http://localhost:8000/static/logo.png" , "contact_email" : "support@example.com" , "legal_info_url" : "http://www.example.com/legal" }
自定义文档内容对于接口的可以用summary
,response_description
参数, query参数可以用Annotationd, 一个例子:
1 2 3 4 5 6 @app.get("/api/query_profit_data" , summary='query profit data by company code, year and quarter' , response_description=""" return profit data in format {"key":{"0":"value"}}, panda's dataframe""" )async def query_profit_data (code: Annotated[str , Query(description="the company code" , example="sh.600000" )], year: Annotated[int , Query(description="year to get profit" , example=2023 )], quarter: Annotated[ int , Query(description="quarter to get profit. allow values:1,2,3,4" , example=1 )] ):
参考资料 chatgpt plugin: https://openai.com/blog/chatgpt-plugins
spring doc: https://springdoc.org/v2/
fastapi: https://fastapi.tiangolo.com/