chore: import upstream snapshot with attribution
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import json
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from jinja2 import Template
|
||||
import re
|
||||
from datamodel_code_generator import InputFileType, generate
|
||||
from pydantic import BaseModel
|
||||
|
||||
APP_TEMPLATE_STR = '''# generated by instructor-codegen:
|
||||
# timestamp: {{timestamp}}
|
||||
# task_name: {{task_name}}
|
||||
# api_path: {{api_path}}
|
||||
# json_schema_path: {{json_schema_path}}
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from jinja2 import Template
|
||||
from models import {{title}}
|
||||
|
||||
import openai
|
||||
import instructor
|
||||
|
||||
instructor.from_openai()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
class TemplateVariables(BaseModel):
|
||||
{% for var in jinja_vars %}
|
||||
{{var.strip()}}: str
|
||||
{% endfor %}
|
||||
|
||||
class RequestSchema(BaseModel):
|
||||
template_variables: TemplateVariables
|
||||
model: str
|
||||
temperature: int
|
||||
|
||||
PROMPT_TEMPLATE = Template("""{{prompt_template}}""".strip())
|
||||
|
||||
@app.post("{{api_path}}", response_model={{title}})
|
||||
async def {{task_name}}(input: RequestSchema) -> {{title}}:
|
||||
rendered_prompt = PROMPT_TEMPLATE.render(**input.template_variables.model_dump())
|
||||
return await openai.ChatCompletion.acreate(
|
||||
model=input.model,
|
||||
temperature=input.temperature,
|
||||
response_model={{title}},
|
||||
messages=[
|
||||
{"role": "user", "content": rendered_prompt}
|
||||
]
|
||||
) # type: ignore
|
||||
'''
|
||||
|
||||
|
||||
class TemplateVariables(BaseModel):
|
||||
biography: str
|
||||
|
||||
|
||||
def load_json_schema(json_schema_path: str) -> dict:
|
||||
try:
|
||||
with open(json_schema_path) as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to load JSON schema: {e}") from e
|
||||
|
||||
|
||||
def generate_pydantic_model(json_schema_path: str):
|
||||
input_path = Path(json_schema_path)
|
||||
output_path = Path("./models.py")
|
||||
generate(
|
||||
input_=input_path, input_file_type=InputFileType.JsonSchema, output=output_path
|
||||
)
|
||||
|
||||
|
||||
def extract_jinja_vars(prompt_template: str) -> list:
|
||||
return re.findall(r"\{\{(.*?)\}\}", prompt_template)
|
||||
|
||||
|
||||
def render_app_template(template_str: str, **kwargs) -> str:
|
||||
app_template = Template(template_str)
|
||||
return app_template.render(**kwargs)
|
||||
|
||||
|
||||
def create_app(
|
||||
api_path: str, task_name: str, json_schema_path: str, prompt_template: str
|
||||
) -> str:
|
||||
if not api_path.startswith("/"):
|
||||
api_path = "/" + api_path
|
||||
|
||||
schema = load_json_schema(json_schema_path)
|
||||
title = schema["title"]
|
||||
generate_pydantic_model(json_schema_path)
|
||||
|
||||
jinja_vars = extract_jinja_vars(prompt_template)
|
||||
|
||||
return render_app_template(
|
||||
APP_TEMPLATE_STR,
|
||||
timestamp=datetime.datetime.now().isoformat(),
|
||||
task_name=task_name,
|
||||
api_path=api_path,
|
||||
json_schema_path=json_schema_path,
|
||||
title=title,
|
||||
jinja_vars=jinja_vars,
|
||||
prompt_template=prompt_template,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
fastapi_code = create_app(
|
||||
api_path="/api/v1/extract_person",
|
||||
task_name="extract_person",
|
||||
json_schema_path="./input.json",
|
||||
prompt_template="Extract the person from the following: {{biography}}",
|
||||
)
|
||||
|
||||
with open("./run.py", "w") as f:
|
||||
f.write(fastapi_code)
|
||||
|
||||
print("FastAPI application generated and saved to './run.py'")
|
||||
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"title": "ExtractPerson",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"type": "integer"
|
||||
},
|
||||
"phoneNumbers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["home", "work", "mobile"]
|
||||
},
|
||||
"number": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "number"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["name", "age", "phoneNumbers"]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# generated by datamodel-codegen:
|
||||
# filename: input.json
|
||||
# timestamp: 2023-09-10T00:33:42+00:00
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Type(Enum):
|
||||
home = "home"
|
||||
work = "work"
|
||||
mobile = "mobile"
|
||||
|
||||
|
||||
class PhoneNumber(BaseModel):
|
||||
type: Type
|
||||
number: str
|
||||
|
||||
|
||||
class ExtractPerson(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
phoneNumbers: list[PhoneNumber]
|
||||
@@ -0,0 +1,35 @@
|
||||
# FastAPI Code Generator
|
||||
|
||||
## Overview
|
||||
|
||||
Generates FastAPI application code from API path, task name, JSON schema path, and Jinja2 prompt template. Also creates a `models.py` file for Pydantic models.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- FastAPI
|
||||
- Pydantic
|
||||
- Jinja2
|
||||
- datamodel-code-generator
|
||||
|
||||
## Functions
|
||||
|
||||
### `create_app(api_path: str, task_name: str, json_schema_path: str, prompt_template: str) -> str`
|
||||
|
||||
Main function to generate FastAPI application code.
|
||||
|
||||
## Usage
|
||||
|
||||
Run the script with required parameters.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
fastapi_code = create_app(
|
||||
api_path="/api/v1/extract_person",
|
||||
task_name="extract_person",
|
||||
json_schema_path="./input.json",
|
||||
prompt_template="Extract the person from the following: {{biography}}",
|
||||
)
|
||||
```
|
||||
|
||||
Outputs FastAPI application code to `./run.py` and a Pydantic model to `./models.py`.
|
||||
@@ -0,0 +1,43 @@
|
||||
# This file was generated by instructor
|
||||
# timestamp: 2023-09-09T20:33:42.572627
|
||||
# task_name: extract_person
|
||||
# api_path: /api/v1/extract_person
|
||||
# json_schema_path: ./input.json
|
||||
|
||||
import instructor
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from jinja2 import Template
|
||||
from models import ExtractPerson
|
||||
from openai import AsyncOpenAI
|
||||
|
||||
aclient = instructor.apatch(AsyncOpenAI())
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class TemplateVariables(BaseModel):
|
||||
biography: str
|
||||
|
||||
|
||||
class RequestSchema(BaseModel):
|
||||
template_variables: TemplateVariables
|
||||
model: str
|
||||
temperature: int
|
||||
|
||||
|
||||
PROMPT_TEMPLATE = Template(
|
||||
"""Extract the person from the following: {{biography}}""".strip()
|
||||
)
|
||||
|
||||
|
||||
@app.post("/api/v1/extract_person", response_model=ExtractPerson)
|
||||
async def extract_person(input: RequestSchema) -> ExtractPerson:
|
||||
rendered_prompt = PROMPT_TEMPLATE.render(**input.template_variables.model_dump())
|
||||
return await aclient.chat.completions.create(
|
||||
model=input.model,
|
||||
temperature=input.temperature,
|
||||
response_model=ExtractPerson,
|
||||
messages=[{"role": "user", "content": rendered_prompt}],
|
||||
) # type: ignore
|
||||
Reference in New Issue
Block a user