use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CoworkPlan {
pub id: String,
pub name: String,
#[serde(rename = "requestsPerMinute")]
pub requests_per_minute: u32,
#[serde(rename = "monthlyLimit")]
pub monthly_limit: u32,
}
impl Default for CoworkPlan {
fn default() -> Self {
Self {
id: "free".to_string(),
name: "Free".to_string(),
requests_per_minute: 5,
monthly_limit: 30,
}
}
}
impl CoworkPlan {
pub fn is_paid(&self) -> bool {
self.id != "free"
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CoworkFeatures {
#[serde(default, rename = "web_research")]
pub web_research: bool,
#[serde(default, rename = "document_export")]
pub document_export: bool,
#[serde(default, rename = "image_analysis")]
pub image_analysis: bool,
#[serde(default, rename = "priority_support")]
pub priority_support: bool,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CoworkUsage {
#[serde(default)]
pub used: u32,
#[serde(default)]
pub limit: u32,
#[serde(default, rename = "creditsUsed")]
pub credits_used: f32,
}
impl CoworkUsage {
pub fn is_limit_reached(&self) -> bool {
self.used >= self.limit
}
pub fn remaining(&self) -> u32 {
self.limit.saturating_sub(self.used)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoworkProfile {
pub name: String,
pub email: String,
pub plan: CoworkPlan,
pub usage: CoworkUsage,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoworkModelsResponse {
pub plan: String,
pub plan_name: String,
pub model_access_level: String,
pub models: Vec<String>,
pub total_models: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoworkCapabilities {
pub profile: CoworkProfile,
pub features: CoworkFeatures,
pub is_valid: bool,
pub models: Vec<String>,
pub upgrade_message: Option<String>,
}
impl Default for CoworkCapabilities {
fn default() -> Self {
Self {
profile: CoworkProfile {
name: String::new(),
email: String::new(),
plan: CoworkPlan::default(),
usage: CoworkUsage::default(),
},
features: CoworkFeatures::default(),
is_valid: true,
models: vec![],
upgrade_message: None,
}
}
}
impl CoworkCapabilities {
pub fn free() -> Self {
Self::default()
}
pub fn can_use_model(&self, model: &str) -> bool {
self.models.iter().any(|m| m == model)
}
pub fn can_use_feature(&self, feature: &str) -> bool {
match feature {
"web_research" => self.features.web_research,
"document_export" => self.features.document_export,
"image_analysis" => self.features.image_analysis,
"priority_support" => self.features.priority_support,
_ => false,
}
}
pub fn can_make_request(&self) -> bool {
self.is_valid && !self.profile.usage.is_limit_reached()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_deserialize_profile() {
let json = json!({
"name": "Test User",
"email": "test@example.com",
"plan": {
"id": "plus",
"name": "Plus",
"requestsPerMinute": 20,
"monthlyLimit": 100
},
"usage": {
"used": 15,
"limit": 100,
"creditsUsed": 2.5
}
});
let profile: CoworkProfile = serde_json::from_value(json).unwrap();
assert_eq!(profile.name, "Test User");
assert_eq!(profile.plan.id, "plus");
assert_eq!(profile.plan.requests_per_minute, 20);
assert_eq!(profile.usage.credits_used, 2.5);
}
}