| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- package models
- import (
- "context"
- "fmt"
- "io"
- "net/http"
- "os"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/httputils"
- computeapi "yunion.io/x/onecloud/pkg/apis/compute"
- hostapi "yunion.io/x/onecloud/pkg/apis/host"
- api "yunion.io/x/onecloud/pkg/apis/llm"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- )
- func (llm *SLLM) GetDetailsProbedModels(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- mdlInfos, err := llm.getProbedInstantModelsExt(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "getProbedPackagesExt")
- }
- return jsonutils.Marshal(mdlInfos), nil
- }
- func (llm *SLLM) PerformSaveInstantModel(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.LLMSaveInstantModelInput,
- ) (jsonutils.JSONObject, error) {
- if llm.Status != api.LLM_STATUS_RUNNING {
- return nil, httperrors.NewInvalidStatusError("LLM is not running")
- }
- mdlInfos, err := llm.getProbedInstantModelsExt(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "getProbedPackagesExt")
- }
- var mdlInfo *api.LLMInternalInstantMdlInfo
- for _, info := range mdlInfos {
- if info.ModelId == input.ModelId {
- mdlInfo = &info
- break
- }
- }
- if mdlInfo == nil {
- return nil, httperrors.NewBadRequestError("ModelId %s not found", input.ModelId)
- }
- mountDirs, err := llm.detectModelPaths(ctx, userCred, *mdlInfo)
- if err != nil {
- return nil, errors.Wrap(err, "detectModelPaths")
- }
- if len(input.ModelFullName) == 0 {
- input.ModelFullName = fmt.Sprintf("%s-%s", mdlInfo.Name+":"+mdlInfo.Tag, time.Now().Format("060102"))
- }
- var ownerId mcclient.IIdentityProvider
- if len(input.TenantId) > 0 {
- domainId := input.ProjectDomainId
- if len(domainId) == 0 {
- domainId = userCred.GetProjectDomainId()
- } else {
- domain, err := db.TenantCacheManager.FetchDomainByIdOrName(ctx, domainId)
- if err != nil {
- return nil, errors.Wrap(err, "TenantCache.FetchDomainByIdOrName")
- }
- domainId = domain.GetId()
- }
- tenant, err := db.TenantCacheManager.FetchTenantByIdOrNameInDomain(ctx, input.TenantId, domainId)
- if err != nil {
- return nil, errors.Wrap(err, "TenantCache.FetchById")
- }
- ownerId = &db.SOwnerId{
- DomainId: domainId,
- Domain: tenant.Domain,
- ProjectId: tenant.Id,
- Project: tenant.Name,
- }
- } else {
- ownerId = userCred
- }
- input.ProjectId = ownerId.GetProjectId()
- input.ProjectDomainId = ownerId.GetProjectDomainId()
- modelName, modelTag, _ := llm.GetLargeLanguageModelName(input.ModelFullName)
- if len(modelName) == 0 {
- modelName = mdlInfo.Name
- }
- if len(modelTag) == 0 {
- modelTag = mdlInfo.Tag
- }
- drv := llm.GetLLMContainerDriver()
- instantModelCreateInput := api.InstantModelCreateInput{
- LlmType: drv.GetType(),
- ModelId: mdlInfo.ModelId,
- ModelName: modelName,
- ModelTag: modelTag,
- Mounts: mountDirs,
- }
- instantModelCreateInput.Name = input.ModelFullName
- boolTrue := true
- instantModelCreateInput.DoNotImport = &boolTrue
- log.Debugf("instantModelCreateInput: %s", jsonutils.Marshal(instantModelCreateInput))
- instantMdlObj, err := db.DoCreate(GetInstantModelManager(), ctx, userCred, nil, jsonutils.Marshal(instantModelCreateInput), ownerId)
- if err != nil {
- return nil, errors.Wrap(err, "GetInstantModelManager.DoCreate")
- }
- instantMdl := instantMdlObj.(*SInstantModel)
- input.InstantModelId = instantMdl.Id
- _, err = llm.StartSaveModelImageTask(ctx, userCred, input)
- if err != nil {
- return nil, errors.Wrap(err, "StartSaveAppImageTask")
- }
- return jsonutils.Marshal(instantMdl), nil
- }
- func (llm *SLLM) DoSaveModelImage(ctx context.Context, userCred mcclient.TokenCredential, session *mcclient.ClientSession, input api.LLMSaveInstantModelInput) error {
- llm.SetStatus(ctx, userCred, api.LLM_STATUS_SAVING_MODEL, "DoSaveModelImage")
- instantModelObj, err := GetInstantModelManager().FetchById(input.InstantModelId)
- if err != nil {
- return errors.Wrap(err, "GetInstantModelManager.FetchById")
- }
- instantModel := instantModelObj.(*SInstantModel)
- drv, err := GetLLMContainerInstantModelDriver(llm.GetLLMContainerDriver().GetType())
- if err != nil {
- return errors.Wrap(err, "GetLLMContainerInstantModelDriver")
- }
- prefix, saveDirs, err := drv.GetSaveDirectories(instantModel)
- if err != nil {
- return errors.Wrap(err, "GetSaveDirectories")
- }
- saveImageInput := computeapi.ContainerSaveVolumeMountToImageInput{
- GenerateName: input.ModelFullName,
- Notes: fmt.Sprintf("instance model image for %s(%s)", instantModel.ModelId, instantModel.ModelName+":"+instantModel.ModelTag),
- Index: 0,
- Dirs: saveDirs,
- UsedByPostOverlay: true,
- DirPrefix: prefix,
- }
- lc, err := llm.GetLLMContainer()
- if err != nil {
- return errors.Wrap(err, "GetLLMContainer")
- }
- result, err := compute.Containers.PerformAction(session, lc.CmpId, "save-volume-mount-image", jsonutils.Marshal(saveImageInput))
- if err != nil {
- return errors.Wrap(err, "compute.Containers.PerformAction")
- }
- log.Debugf("container save-volume-mount-image result: %s", result)
- saveImageOutput := hostapi.ContainerSaveVolumeMountToImageInput{}
- err = result.Unmarshal(&saveImageOutput)
- if err != nil {
- return errors.Wrap(err, "save-volume-mount-image.result.Unmarshal")
- }
- err = instantModel.saveImageId(ctx, userCred, saveImageOutput.ImageId)
- if err != nil {
- return errors.Wrap(err, "saveImageId")
- }
- return nil
- }
- func (llm *SLLM) StartSaveModelImageTask(ctx context.Context, userCred mcclient.TokenCredential, input api.LLMSaveInstantModelInput) (*taskman.STask, error) {
- llm.SetStatus(ctx, userCred, api.LLM_STATUS_START_SAVE_MODEL, "StartSaveModelImageTask")
- params := jsonutils.Marshal(input)
- task, err := taskman.TaskManager.NewTask(ctx, "LLMStartSaveModelImageTask", llm, userCred, params.(*jsonutils.JSONDict), "", "")
- if err != nil {
- return nil, errors.Wrap(err, "taskman.TaskManager.NewTask")
- }
- err = task.ScheduleRun(nil)
- if err != nil {
- return nil, errors.Wrap(err, "task.ScheduleRun")
- }
- return task, nil
- }
- func (llm *SLLM) detectModelPaths(ctx context.Context, userCred mcclient.TokenCredential, pkgInfo api.LLMInternalInstantMdlInfo) ([]string, error) {
- drv, err := GetLLMContainerInstantModelDriver(llm.GetLLMContainerDriver().GetType())
- if err != nil {
- return nil, errors.Wrap(err, "GetLLMContainerInstantModelDriver")
- }
- return drv.DetectModelPaths(ctx, userCred, llm, pkgInfo)
- }
- // HttpGet performs a GET request and returns the response body
- func (llm *SLLM) HttpGet(ctx context.Context, url string) ([]byte, error) {
- client := httputils.GetTimeoutClient(0)
- transport := httputils.GetTransport(true)
- client.Transport = transport
- resp, err := httputils.Request(client, ctx, httputils.GET, url, http.Header{}, nil, false)
- if err != nil {
- return nil, errors.Wrap(err, "http request failed")
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- if resp.StatusCode == http.StatusNotFound {
- return nil, httperrors.NewResourceNotFoundError("url %s not found", url)
- }
- return nil, errors.Errorf("unexpected status code: %d", resp.StatusCode)
- }
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- return nil, errors.Wrap(err, "failed to read response body")
- }
- return body, nil
- }
- // HttpDownloadFile downloads a file from URL and saves it to the specified path
- func (llm *SLLM) HttpDownloadFile(ctx context.Context, url string, filePath string) error {
- client := httputils.GetTimeoutClient(0)
- transport := httputils.GetTransport(true)
- client.Transport = transport
- resp, err := httputils.Request(client, ctx, httputils.GET, url, http.Header{}, nil, false)
- if err != nil {
- return errors.Wrap(err, "http request failed")
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- if resp.StatusCode == http.StatusNotFound {
- return errors.Wrapf(httperrors.ErrResourceNotFound, "url %s not found", url)
- }
- return errors.Errorf("unexpected status code: %d", resp.StatusCode)
- }
- // create temporary file first, then rename to avoid partial downloads
- tmpPath := filePath + ".tmp"
- out, err := os.Create(tmpPath)
- if err != nil {
- return errors.Wrapf(err, "failed to create file %s", tmpPath)
- }
- written, err := io.Copy(out, resp.Body)
- out.Close()
- if err != nil {
- os.Remove(tmpPath)
- return errors.Wrap(err, "failed to write file")
- }
- log.Infof("Downloaded %d bytes to %s", written, filePath)
- // rename tmp file to final path
- if err := os.Rename(tmpPath, filePath); err != nil {
- os.Remove(tmpPath)
- return errors.Wrapf(err, "failed to rename %s to %s", tmpPath, filePath)
- }
- return nil
- }
|