Files
herolib/lib/clients/vastai/client.v
mariobassem 34b1aad175 feat: Add VastAI client
- Add a new VastAI client to the project.
- This client allows users to search for and create GPU instances on VastAI.
- It uses the VastAI API to interact with the platform.
- Includes functionality for searching offers, getting top offers, and creating instances.

Co-authored-by: mahmmoud.hassanein <mahmmoud.hassanein@gmail.com>
2025-01-23 19:22:39 +02:00

174 lines
5.2 KiB
V

module vastai
import json
// Represents a GPU offer from Vast.ai
pub struct GPUOffer {
pub:
id int // Unique instance ID
cuda_max_good int // Maximum reliable CUDA version
gpu_name string // Name of the GPU
gpu_ram int // GPU RAM in MB
num_gpus int // Number of GPUs
dlperf f64 // Deep Learning Performance score
dlperf_per_dphtotal f64 // Performance per dollar per hour
reliability f64 // Instance reliability score
total_flops f64 // Total FLOPS
credit_discount f64 // Credit discount
rented bool // Whether instance is currently rented
rentable bool // Whether instance can be rented
verification string // Verification status
external bool // Whether instance is external
dph_total f64 // Total dollars per hour
storage_total int // Total storage in GB
inet_up f64 // Upload bandwidth in Mbps
inet_down f64 // Download bandwidth in Mbps
}
// Search parameters for filtering GPU offers
@[params]
pub struct SearchParams {
pub mut:
order ?string // Sort order (default: score descending)
query ?string // Search query string
min_gpu_ram ?int // Minimum GPU RAM in MB
min_num_gpus ?int // Minimum number of GPUs
min_dlperf ?f64 // Minimum deep learning performance score
max_dph ?f64 // Maximum dollars per hour
min_reliability ?f64 // Minimum reliability score
verified_only ?bool // Only show verified instances
external ?bool // Include external instances
rentable ?bool // Show only rentable instances
rented ?bool // Show only rented instances
}
// Response from the search API
struct SearchResponse {
success bool
offers []GPUOffer
}
// Searches for GPU offers based on the provided parameters
pub fn (mut va VastAI) search_offers(params SearchParams) ![]GPUOffer {
// Get HTTP client
mut http_client := va.httpclient()!
// Make request
resp := http_client.send(method: .put, prefix: '/search/asks/?', data: json.encode(params))!
if resp.code != 200 {
return error('request failed with code ${resp.code}: ${resp.data}')
}
// Parse response
search_resp := json.decode(SearchResponse, resp.data)!
return search_resp.offers
}
// Helper method to get top N offers sorted by performance/price
pub fn (mut v VastAI) get_top_offers(count int) ![]GPUOffer {
params := SearchParams{
order: 'dlperf_per_dphtotal-' // Sort by performance per dollar (descending)
rentable: true // Only show available instances
min_reliability: 0.98 // High reliability
}
offers := v.search_offers(params)!
if offers.len <= count {
return offers
}
return offers[..count]
}
// Helper method to find cheapest offers meeting minimum requirements
pub fn (mut va VastAI) find_cheapest_offers(min_gpu_ram int, min_gpus int, count int) ![]GPUOffer {
params := SearchParams{
order: 'dph_total' // Sort by price (ascending)
min_gpu_ram: min_gpu_ram
min_num_gpus: min_gpus
rentable: true // Only show available instances
min_reliability: 0.95 // Reasonable reliability threshold
}
offers := va.search_offers(params)!
if offers.len <= count {
return offers
}
return offers[..count]
}
// Helper method to find most powerful GPUs available
pub fn (mut va VastAI) find_most_powerful(count int) ![]GPUOffer {
params := SearchParams{
order: 'dlperf-' // Sort by deep learning performance (descending)
rentable: true // Only show available instances
min_reliability: 0.95 // Reasonable reliability threshold
}
offers := va.search_offers(params)!
if offers.len <= count {
return offers
}
return offers[..count]
}
// CreateInstanceConfig represents the configuration for creating a new instance from an offer
@[params]
pub struct CreateInstanceConfig {
pub:
template_id ?string
template_hash_id ?string
image ?string // Docker image name
disk ?int
extra_env ?map[string]string // Environment variables
runtype ?string // "args" or "ssh"
onstart ?string
label ?string
image_login ?string
price ?f32
target_state ?string // "running" or "stopped"
cancel_unavail ?bool
vm ?bool
client_id ?string
apikey_id ?string
}
@[params]
pub struct CreateInstanceArgs {
pub:
id int
config CreateInstanceConfig
}
// CreateInstanceResponse represents the response from creating a new instance
pub struct CreateInstanceResponse {
pub:
success bool
new_contract int
}
// Creates a new instance by accepting a provider offer
pub fn (mut va VastAI) create_instance(args CreateInstanceArgs) !CreateInstanceResponse {
// Get HTTP client
mut http_client := va.httpclient()!
// Make request
resp := http_client.send(
method: .put
prefix: '/asks/${args.id}/?'
data: json.encode(args.config)
)!
if resp.code != 200 {
return error('request failed with code ${resp.code}: ${resp.data}')
}
// Parse response
instance_resp := json.decode(CreateInstanceResponse, resp.data)!
return instance_resp
}