fix pydantic obj for FT endpoints

This commit is contained in:
Ishaan Jaff 2024-07-31 12:41:39 -07:00
parent 415611b7f2
commit ef5aeb17a1
4 changed files with 36 additions and 184 deletions

View file

@ -18,6 +18,7 @@ import httpx
import litellm import litellm
from litellm import get_secret from litellm import get_secret
from litellm._logging import verbose_logger
from litellm.llms.fine_tuning_apis.azure import AzureOpenAIFineTuningAPI from litellm.llms.fine_tuning_apis.azure import AzureOpenAIFineTuningAPI
from litellm.llms.fine_tuning_apis.openai import ( from litellm.llms.fine_tuning_apis.openai import (
FineTuningJob, FineTuningJob,
@ -51,6 +52,9 @@ async def acreate_fine_tuning_job(
Async: Creates and executes a batch from an uploaded file of request Async: Creates and executes a batch from an uploaded file of request
""" """
verbose_logger.debug(
"inside acreate_fine_tuning_job model=%s and kwargs=%s", model, kwargs
)
try: try:
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
kwargs["acreate_fine_tuning_job"] = True kwargs["acreate_fine_tuning_job"] = True
@ -156,11 +160,15 @@ def create_fine_tuning_job(
seed=seed, seed=seed,
) )
create_fine_tuning_job_data_dict = create_fine_tuning_job_data.model_dump(
exclude_none=True
)
response = openai_fine_tuning_apis_instance.create_fine_tuning_job( response = openai_fine_tuning_apis_instance.create_fine_tuning_job(
api_base=api_base, api_base=api_base,
api_key=api_key, api_key=api_key,
organization=organization, organization=organization,
create_fine_tuning_job_data=create_fine_tuning_job_data, create_fine_tuning_job_data=create_fine_tuning_job_data_dict,
timeout=timeout, timeout=timeout,
max_retries=optional_params.max_retries, max_retries=optional_params.max_retries,
_is_async=_is_async, _is_async=_is_async,

View file

@ -50,18 +50,18 @@ class OpenAIFineTuningAPI(BaseLLM):
async def acreate_fine_tuning_job( async def acreate_fine_tuning_job(
self, self,
create_fine_tuning_job_data: FineTuningJobCreate, create_fine_tuning_job_data: dict,
openai_client: AsyncOpenAI, openai_client: AsyncOpenAI,
) -> FineTuningJob: ) -> FineTuningJob:
response = await openai_client.fine_tuning.jobs.create( response = await openai_client.fine_tuning.jobs.create(
**create_fine_tuning_job_data # type: ignore **create_fine_tuning_job_data
) )
return response return response
def create_fine_tuning_job( def create_fine_tuning_job(
self, self,
_is_async: bool, _is_async: bool,
create_fine_tuning_job_data: FineTuningJobCreate, create_fine_tuning_job_data: dict,
api_key: Optional[str], api_key: Optional[str],
api_base: Optional[str], api_base: Optional[str],
timeout: Union[float, httpx.Timeout], timeout: Union[float, httpx.Timeout],
@ -95,7 +95,7 @@ class OpenAIFineTuningAPI(BaseLLM):
verbose_logger.debug( verbose_logger.debug(
"creating fine tuning job, args= %s", create_fine_tuning_job_data "creating fine tuning job, args= %s", create_fine_tuning_job_data
) )
response = openai_client.fine_tuning.jobs.create(**create_fine_tuning_job_data) # type: ignore response = openai_client.fine_tuning.jobs.create(**create_fine_tuning_job_data)
return response return response
async def acancel_fine_tuning_job( async def acancel_fine_tuning_job(

View file

@ -1,157 +0,0 @@
#########################################################################
# /v1/fine_tuning Endpoints
# Equivalent of https://platform.openai.com/docs/api-reference/fine-tuning
##########################################################################
import asyncio
import traceback
from datetime import datetime, timedelta, timezone
from typing import List, Optional
import fastapi
import httpx
from fastapi import (
APIRouter,
Depends,
File,
Form,
Header,
HTTPException,
Request,
Response,
UploadFile,
status,
)
import litellm
from litellm import CreateFileRequest, FileContentRequest
from litellm._logging import verbose_proxy_logger
from litellm.batches.main import FileObject
from litellm.proxy._types import *
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
router = APIRouter()
from litellm.llms.fine_tuning_apis.openai import (
FineTuningJob,
FineTuningJobCreate,
OpenAIFineTuningAPI,
)
@router.post(
"/v1/fine_tuning/jobs",
dependencies=[Depends(user_api_key_auth)],
tags=["fine-tuning"],
)
@router.post(
"/fine_tuning/jobs",
dependencies=[Depends(user_api_key_auth)],
tags=["fine-tuning"],
)
async def create_fine_tuning_job(
request: Request,
fastapi_response: Response,
fine_tuning_job: FineTuningJobCreate,
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
):
"""
Creates a fine-tuning job which begins the process of creating a new model from a given dataset.
This is the equivalent of POST https://api.openai.com/v1/fine_tuning/jobs
Supports Identical Params as: https://platform.openai.com/docs/api-reference/fine-tuning/create
Example Curl:
```
curl http://localhost:4000/v1/fine_tuning/jobs \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-1234" \
-d '{
"model": "gpt-3.5-turbo",
"training_file": "file-abc123",
"hyperparameters": {
"n_epochs": 4
}
}'
```
"""
from litellm.proxy.proxy_server import (
add_litellm_data_to_request,
general_settings,
get_custom_headers,
proxy_config,
proxy_logging_obj,
version,
)
try:
# Convert Pydantic model to dict
data = fine_tuning_job.dict(exclude_unset=True)
# Include original request and headers in the data
data = await add_litellm_data_to_request(
data=data,
request=request,
general_settings=general_settings,
user_api_key_dict=user_api_key_dict,
version=version,
proxy_config=proxy_config,
)
# For now, use custom_llm_provider=="openai" -> this will change as LiteLLM adds more providers for fine-tuning
response = await litellm.acreate_fine_tuning_job(
custom_llm_provider="openai", **data
)
### ALERTING ###
asyncio.create_task(
proxy_logging_obj.update_request_status(
litellm_call_id=data.get("litellm_call_id", ""), status="success"
)
)
### RESPONSE HEADERS ###
hidden_params = getattr(response, "_hidden_params", {}) or {}
model_id = hidden_params.get("model_id", None) or ""
cache_key = hidden_params.get("cache_key", None) or ""
api_base = hidden_params.get("api_base", None) or ""
fastapi_response.headers.update(
get_custom_headers(
user_api_key_dict=user_api_key_dict,
model_id=model_id,
cache_key=cache_key,
api_base=api_base,
version=version,
model_region=getattr(user_api_key_dict, "allowed_model_region", ""),
)
)
return response
except Exception as e:
await proxy_logging_obj.post_call_failure_hook(
user_api_key_dict=user_api_key_dict, original_exception=e, request_data=data
)
verbose_proxy_logger.error(
"litellm.proxy.proxy_server.create_fine_tuning_job(): Exception occurred - {}".format(
str(e)
)
)
verbose_proxy_logger.debug(traceback.format_exc())
if isinstance(e, HTTPException):
raise ProxyException(
message=getattr(e, "message", str(e.detail)),
type=getattr(e, "type", "None"),
param=getattr(e, "param", "None"),
code=getattr(e, "status_code", status.HTTP_400_BAD_REQUEST),
)
else:
error_msg = f"{str(e)}"
raise ProxyException(
message=getattr(e, "message", error_msg),
type=getattr(e, "type", "None"),
param=getattr(e, "param", "None"),
code=getattr(e, "status_code", 500),
)

View file

@ -9,7 +9,6 @@ from typing import (
Mapping, Mapping,
Optional, Optional,
Tuple, Tuple,
TypedDict,
Union, Union,
) )
@ -31,7 +30,7 @@ from openai.types.beta.threads.message import Message as OpenAIMessage
from openai.types.beta.threads.message_content import MessageContent from openai.types.beta.threads.message_content import MessageContent
from openai.types.beta.threads.run import Run from openai.types.beta.threads.run import Run
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing_extensions import Dict, Required, override from typing_extensions import Dict, Required, TypedDict, override
FileContent = Union[IO[bytes], bytes, PathLike] FileContent = Union[IO[bytes], bytes, PathLike]
@ -457,15 +456,17 @@ class ChatCompletionUsageBlock(TypedDict):
total_tokens: int total_tokens: int
class Hyperparameters(TypedDict): class Hyperparameters(BaseModel):
batch_size: Optional[Union[str, int]] # "Number of examples in each batch." batch_size: Optional[Union[str, int]] = None # "Number of examples in each batch."
learning_rate_multiplier: Optional[ learning_rate_multiplier: Optional[Union[str, float]] = (
Union[str, float] None # Scaling factor for the learning rate
] # Scaling factor for the learning rate )
n_epochs: Optional[Union[str, int]] # "The number of epochs to train the model for" n_epochs: Optional[Union[str, int]] = (
None # "The number of epochs to train the model for"
)
class FineTuningJobCreate(TypedDict): class FineTuningJobCreate(BaseModel):
""" """
FineTuningJobCreate - Create a fine-tuning job FineTuningJobCreate - Create a fine-tuning job
@ -489,16 +490,16 @@ class FineTuningJobCreate(TypedDict):
model: str # "The name of the model to fine-tune." model: str # "The name of the model to fine-tune."
training_file: str # "The ID of an uploaded file that contains training data." training_file: str # "The ID of an uploaded file that contains training data."
hyperparameters: Optional[ hyperparameters: Optional[Hyperparameters] = (
Hyperparameters None # "The hyperparameters used for the fine-tuning job."
] # "The hyperparameters used for the fine-tuning job." )
suffix: Optional[ suffix: Optional[str] = (
str None # "A string of up to 18 characters that will be added to your fine-tuned model name."
] # "A string of up to 18 characters that will be added to your fine-tuned model name." )
validation_file: Optional[ validation_file: Optional[str] = (
str None # "The ID of an uploaded file that contains validation data."
] # "The ID of an uploaded file that contains validation data." )
integrations: Optional[ integrations: Optional[List[str]] = (
List[str] None # "A list of integrations to enable for your fine-tuning job."
] # "A list of integrations to enable for your fine-tuning job." )
seed: Optional[int] # "The seed controls the reproducibility of the job." seed: Optional[int] = None # "The seed controls the reproducibility of the job."