first commit
This commit is contained in:
145
core/providers/gemini/files.go
Normal file
145
core/providers/gemini/files.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package gemini
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/maximhq/bifrost/core/schemas"
|
||||
)
|
||||
|
||||
// Gemini Files API types
|
||||
// The Gemini Files API allows uploading files for use with multimodal models.
|
||||
|
||||
// GeminiFileResponse represents a file object from Gemini's API.
|
||||
type GeminiFileResponse struct {
|
||||
Name string `json:"name"` // Resource name (e.g., "files/abc123")
|
||||
DisplayName string `json:"displayName"` // User-provided display name
|
||||
MimeType string `json:"mimeType"` // MIME type of the file
|
||||
SizeBytes string `json:"sizeBytes"` // Size in bytes (as string)
|
||||
CreateTime string `json:"createTime"` // RFC3339 timestamp
|
||||
UpdateTime string `json:"updateTime"` // RFC3339 timestamp
|
||||
ExpirationTime string `json:"expirationTime,omitempty"` // RFC3339 timestamp when file will be deleted
|
||||
SHA256Hash string `json:"sha256Hash"` // Base64 encoded SHA256 hash
|
||||
URI string `json:"uri"` // URI for accessing the file
|
||||
State string `json:"state"` // "PROCESSING", "ACTIVE", "FAILED"
|
||||
VideoMetadata *GeminiFileVideoMetadata `json:"videoMetadata,omitempty"`
|
||||
}
|
||||
|
||||
// GeminiFileVideoMetadata contains video-specific metadata.
|
||||
type GeminiFileVideoMetadata struct {
|
||||
VideoDuration string `json:"videoDuration"` // Duration in seconds
|
||||
}
|
||||
|
||||
// GeminiFileListResponse represents the response from listing files.
|
||||
type GeminiFileListResponse struct {
|
||||
Files []GeminiFileResponse `json:"files"`
|
||||
NextPageToken string `json:"nextPageToken,omitempty"`
|
||||
}
|
||||
|
||||
// ToBifrostFileStatus converts Gemini file state to Bifrost status.
|
||||
func ToBifrostFileStatus(state string) schemas.FileStatus {
|
||||
switch state {
|
||||
case "PROCESSING":
|
||||
return schemas.FileStatusProcessing
|
||||
case "ACTIVE":
|
||||
return schemas.FileStatusProcessed
|
||||
case "FAILED":
|
||||
return schemas.FileStatusError
|
||||
default:
|
||||
return schemas.FileStatus(strings.ToLower(state))
|
||||
}
|
||||
}
|
||||
|
||||
// ToGeminiFileListResponse converts a Bifrost file list response to Gemini format.
|
||||
func ToGeminiFileListResponse(resp *schemas.BifrostFileListResponse) *GeminiFileListResponse {
|
||||
files := make([]GeminiFileResponse, len(resp.Data))
|
||||
for i, f := range resp.Data {
|
||||
updateAt := f.UpdatedAt
|
||||
if updateAt == 0 {
|
||||
updateAt = f.CreatedAt
|
||||
}
|
||||
files[i] = GeminiFileResponse{
|
||||
Name: f.ID,
|
||||
DisplayName: f.Filename,
|
||||
SizeBytes: fmt.Sprintf("%d", f.Bytes),
|
||||
CreateTime: formatGeminiTimestamp(f.CreatedAt),
|
||||
UpdateTime: formatGeminiTimestamp(updateAt),
|
||||
State: toGeminiFileState(f.Status),
|
||||
ExpirationTime: formatGeminiTimestamp(safeDerefInt64(f.ExpiresAt)),
|
||||
}
|
||||
}
|
||||
result := &GeminiFileListResponse{Files: files}
|
||||
if resp.After != nil && *resp.After != "" {
|
||||
result.NextPageToken = *resp.After
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ToGeminiFileRetrieveResponse converts a Bifrost file retrieve response to Gemini format.
|
||||
func ToGeminiFileRetrieveResponse(resp *schemas.BifrostFileRetrieveResponse) *GeminiFileResponse {
|
||||
updateAt := resp.UpdatedAt
|
||||
if updateAt == 0 {
|
||||
updateAt = resp.CreatedAt
|
||||
}
|
||||
return &GeminiFileResponse{
|
||||
Name: resp.ID,
|
||||
DisplayName: resp.Filename,
|
||||
SizeBytes: fmt.Sprintf("%d", resp.Bytes),
|
||||
CreateTime: formatGeminiTimestamp(resp.CreatedAt),
|
||||
UpdateTime: formatGeminiTimestamp(updateAt),
|
||||
State: toGeminiFileState(resp.Status),
|
||||
URI: resp.StorageURI,
|
||||
ExpirationTime: formatGeminiTimestamp(safeDerefInt64(resp.ExpiresAt)),
|
||||
}
|
||||
}
|
||||
|
||||
// toGeminiFileState converts Bifrost file status to Gemini state.
|
||||
func toGeminiFileState(status schemas.FileStatus) string {
|
||||
switch status {
|
||||
case schemas.FileStatusProcessing:
|
||||
return "PROCESSING"
|
||||
case schemas.FileStatusProcessed:
|
||||
return "ACTIVE"
|
||||
case schemas.FileStatusError:
|
||||
return "FAILED"
|
||||
default:
|
||||
return strings.ToUpper(string(status))
|
||||
}
|
||||
}
|
||||
|
||||
// formatGeminiTimestamp converts Unix timestamp to Gemini RFC3339 format.
|
||||
func formatGeminiTimestamp(unixTime int64) string {
|
||||
if unixTime == 0 {
|
||||
return ""
|
||||
}
|
||||
return time.Unix(unixTime, 0).UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// safeDerefInt64 safely dereferences an int64 pointer.
|
||||
func safeDerefInt64(ptr *int64) int64 {
|
||||
if ptr == nil {
|
||||
return 0
|
||||
}
|
||||
return *ptr
|
||||
}
|
||||
|
||||
// ToGeminiFileUploadResponse converts a Bifrost file upload response to Gemini format.
|
||||
func ToGeminiFileUploadResponse(resp *schemas.BifrostFileUploadResponse) map[string]interface{} {
|
||||
file := map[string]interface{}{
|
||||
"name": resp.ID,
|
||||
"displayName": resp.Filename,
|
||||
"mimeType": "application/octet-stream",
|
||||
"sizeBytes": fmt.Sprintf("%d", resp.Bytes),
|
||||
"createTime": formatGeminiTimestamp(resp.CreatedAt),
|
||||
"updateTime": formatGeminiTimestamp(resp.CreatedAt),
|
||||
"state": toGeminiFileState(resp.Status),
|
||||
"uri": resp.StorageURI,
|
||||
}
|
||||
if exp := formatGeminiTimestamp(safeDerefInt64(resp.ExpiresAt)); exp != "" {
|
||||
file["expirationTime"] = exp
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"file": file,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user