feat(ai-proxy): add support for OpenAI Fine-Tuning API (#2424)

This commit is contained in:
woody
2025-06-17 13:44:00 +08:00
committed by GitHub
parent c471bb2003
commit 926913f0e7
4 changed files with 121 additions and 53 deletions

View File

@@ -379,6 +379,33 @@ func getApiName(path string) provider.ApiName {
if strings.HasSuffix(path, "/v1/models") {
return provider.ApiNameModels
}
if strings.HasSuffix(path, "/v1/fine_tuning/jobs") {
return provider.ApiNameFineTuningJobs
}
if util.RegRetrieveFineTuningJobPath.MatchString(path) {
return provider.ApiNameFineTuningRetrieveJob
}
if util.RegRetrieveFineTuningJobEventsPath.MatchString(path) {
return provider.PathOpenAIFineTuningJobEvents
}
if util.RegRetrieveFineTuningJobCheckpointsPath.MatchString(path) {
return provider.PathOpenAIFineTuningJobCheckpoints
}
if util.RegCancelFineTuningJobPath.MatchString(path) {
return provider.ApiNameFineTuningCancelJob
}
if util.RegResumeFineTuningJobPath.MatchString(path) {
return provider.ApiNameFineTuningResumeJob
}
if util.RegPauseFineTuningJobPath.MatchString(path) {
return provider.ApiNameFineTuningPauseJob
}
if util.RegFineTuningCheckpointPermissionPath.MatchString(path) {
return provider.ApiNameFineTuningCheckpointPermissions
}
if util.RegDeleteFineTuningCheckpointPermissionPath.MatchString(path) {
return provider.PathOpenAIFineDeleteTuningCheckpointPermission
}
// cohere style
if strings.HasSuffix(path, "/v1/rerank") {
return provider.ApiNameCohereV1Rerank

View File

@@ -41,9 +41,19 @@ func (m *openaiProviderInitializer) DefaultCapabilities() map[string]string {
string(ApiNameRetrieveBatch): PathOpenAIRetrieveBatch,
string(ApiNameCancelBatch): PathOpenAICancelBatch,
string(ApiNameResponses): PathOpenAIResponses,
string(ApiNameFineTuningJobs): PathOpenAIFineTuningJobs,
string(ApiNameFineTuningRetrieveJob): PathOpenAIFineTuningRetrieveJob,
string(ApiNameFineTuningJobEvents): PathOpenAIFineTuningJobEvents,
string(ApiNameFineTuningJobCheckpoints): PathOpenAIFineTuningJobCheckpoints,
string(ApiNameFineTuningCancelJob): PathOpenAIFineTuningCancelJob,
string(ApiNameFineTuningResumeJob): PathOpenAIFineTuningResumeJob,
string(ApiNameFineTuningPauseJob): PathOpenAIFineTuningPauseJob,
string(ApiNameFineTuningCheckpointPermissions): PathOpenAIFineTuningCheckpointPermissions,
string(ApiNameDeleteFineTuningCheckpointPermission): PathOpenAIFineDeleteTuningCheckpointPermission,
}
}
// isDirectPath checks if the path is a known standard OpenAI interface path.
func isDirectPath(path string) bool {
return strings.HasSuffix(path, "/completions") ||
strings.HasSuffix(path, "/embeddings") ||
@@ -52,7 +62,9 @@ func isDirectPath(path string) bool {
strings.HasSuffix(path, "/images/variations") ||
strings.HasSuffix(path, "/images/edits") ||
strings.HasSuffix(path, "/models") ||
strings.HasSuffix(path, "/responses")
strings.HasSuffix(path, "/responses") ||
strings.HasSuffix(path, "/fine_tuning/jobs") ||
strings.HasSuffix(path, "/fine_tuning/checkpoints")
}
func (m *openaiProviderInitializer) CreateProvider(config ProviderConfig) (Provider, error) {

View File

@@ -42,6 +42,15 @@ const (
ApiNameCancelBatch ApiName = "openai/v1/cancelbatch"
ApiNameModels ApiName = "openai/v1/models"
ApiNameResponses ApiName = "openai/v1/responses"
ApiNameFineTuningJobs ApiName = "openai/v1/fine-tuningjobs"
ApiNameFineTuningRetrieveJob ApiName = "openai/v1/retrievefine-tuningjob"
ApiNameFineTuningJobEvents ApiName = "openai/v1/fine-tuningjobsevents"
ApiNameFineTuningJobCheckpoints ApiName = "openai/v1/fine-tuningjobcheckpoints"
ApiNameFineTuningCancelJob ApiName = "openai/v1/cancelfine-tuningjob"
ApiNameFineTuningResumeJob ApiName = "openai/v1/resumefine-tuningjob"
ApiNameFineTuningPauseJob ApiName = "openai/v1/pausefine-tuningjob"
ApiNameFineTuningCheckpointPermissions ApiName = "openai/v1/fine-tuningjobcheckpointpermissions"
ApiNameDeleteFineTuningCheckpointPermission ApiName = "openai/v1/deletefine-tuningjobcheckpointpermission"
PathOpenAICompletions = "/v1/completions"
PathOpenAIChatCompletions = "/v1/chat/completions"
@@ -58,6 +67,15 @@ const (
PathOpenAIImageVariation = "/v1/images/variations"
PathOpenAIAudioSpeech = "/v1/audio/speech"
PathOpenAIResponses = "/v1/responses"
PathOpenAIFineTuningJobs = "/v1/fine_tuning/jobs"
PathOpenAIFineTuningRetrieveJob = "/v1/fine_tuning/jobs/{fine_tuning_job_id}"
PathOpenAIFineTuningJobEvents = "/v1/fine_tuning/jobs/{fine_tuning_job_id}/events"
PathOpenAIFineTuningJobCheckpoints = "/v1/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints"
PathOpenAIFineTuningCancelJob = "/v1/fine_tuning/jobs/{fine_tuning_job_id}/cancel"
PathOpenAIFineTuningResumeJob = "/v1/fine_tuning/jobs/{fine_tuning_job_id}/resume"
PathOpenAIFineTuningPauseJob = "/v1/fine_tuning/jobs/{fine_tuning_job_id}/pause"
PathOpenAIFineTuningCheckpointPermissions = "/v1/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions"
PathOpenAIFineDeleteTuningCheckpointPermission = "/v1/fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}"
// TODO: 以下是一些非标准的API名称需要进一步确认是否支持
ApiNameCohereV1Rerank ApiName = "cohere/v1/rerank"
@@ -842,11 +860,14 @@ func (c *ProviderConfig) DefaultTransformResponseHeaders(ctx wrapper.HttpContext
func (c *ProviderConfig) needToProcessRequestBody(apiName ApiName) bool {
switch apiName {
case ApiNameChatCompletion,
ApiNameCompletion,
ApiNameEmbeddings,
ApiNameImageGeneration,
ApiNameImageEdit,
ApiNameImageVariation,
ApiNameAudioSpeech:
ApiNameAudioSpeech,
ApiNameFineTuningJobs,
ApiNameResponses:
return true
}
return false

View File

@@ -21,6 +21,14 @@ var (
RegCancelBatchPath = regexp.MustCompile(`^.*/v1/batches/(?P<batch_id>[^/]+)/cancel$`)
RegRetrieveFilePath = regexp.MustCompile(`^.*/v1/files/(?P<file_id>[^/]+)$`)
RegRetrieveFileContentPath = regexp.MustCompile(`^.*/v1/files/(?P<file_id>[^/]+)/content$`)
RegRetrieveFineTuningJobPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)$`)
RegRetrieveFineTuningJobEventsPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)/events$`)
RegRetrieveFineTuningJobCheckpointsPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)/checkpoints$`)
RegCancelFineTuningJobPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)/cancel$`)
RegResumeFineTuningJobPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)/resume$`)
RegPauseFineTuningJobPath = regexp.MustCompile(`^.*/v1/fine_tuning/jobs/(?P<fine_tuning_job_id>[^/]+)/pause$`)
RegFineTuningCheckpointPermissionPath = regexp.MustCompile(`^.*/v1/fine_tuning/checkpoints/(?P<fine_tuned_model_checkpoint>[^/]+)/permissions$`)
RegDeleteFineTuningCheckpointPermissionPath = regexp.MustCompile(`^.*/v1/fine_tuning/checkpoints/(?P<fine_tuned_model_checkpoint>[^/]+)/permissions/(?P<permission_id>[^/]+)$`)
)
type ErrorHandlerFunc func(statusCodeDetails string, err error) error