openai_client_cli/program/loaders/
organization.rs

1use crate::{Entry, Error, Result, traits::*};
2use regex::Regex;
3use shellexpand::path::tilde;
4use std::{env, fs, path::{Path, PathBuf}, str::FromStr};
5use tracing::{debug, info};
6
7/// The organization ID.
8pub struct Organization(String);
9
10impl Organization {
11  fn post_fetch_ok(self, source: &str) -> Result<Self> {
12    info!(
13      "Successfully fetched the organization ID from {source}: {:?}",
14      format!("{}...{}", &self.value_ref()[..7], &self.value_ref()[26..]),
15    );
16    Ok(self)
17  }
18}
19
20impl FromFile for Organization {
21  fn from_file<P>(path: P) -> Result<Self>
22  where
23    P: AsRef<Path>,
24  {
25    let text = fs::read_to_string(path)?;
26    Self::from_str(&text)
27  }
28}
29
30impl FromStr for Organization {
31  type Err = Error;
32
33  fn from_str(text: &str) -> Result<Self> {
34    Ok(Self(
35      Regex::new(r"org-[[:alnum:]]{24}")?
36        .find(text)
37        .ok_or(Error::msg("Invalid format of OpenAI organization ID"))?
38        .as_str()
39        .to_string()
40    ))
41  }
42}
43
44impl Loader<String> for Organization {
45  fn fetch(entry: &Entry) -> Result<Self> {
46    for provided_file in [
47        entry.organization_file.as_ref(),
48        entry.key_file.as_ref(),
49      ]
50      .into_iter()
51      .flatten()
52    {
53      let source = &format!("the provided file {provided_file:?}");
54      match Organization::from_file(provided_file) {
55        Ok(organization) => return organization.post_fetch_ok(source),
56        Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
57      }
58    }
59
60    let source = "the environment variable `OPENAI_ORG_KEY`";
61    match env::var("OPENAI_ORG_KEY")
62      .map_err(Error::from)
63      .and_then(Organization::try_from)
64    {
65      Ok(organization) => return organization.post_fetch_ok(source),
66      Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
67    }
68
69    for default_file in [
70        &PathBuf::from("openai.env"),
71        &PathBuf::from(".openai_profile"),
72        &PathBuf::from(".env"),
73        &PathBuf::from(tilde("~/openai.env")),
74        &PathBuf::from(tilde("~/.openai_profile")),
75        &PathBuf::from(tilde("~/.env")),
76      ].into_iter()
77    {
78      let source = &format!("the default file {default_file:?}");
79      match Organization::from_file(default_file) {
80        Ok(organization) => return organization.post_fetch_ok(source),
81        Err(err) => debug!("Failed to obtain the organization ID from {source}: {err:?}"),
82      }
83    }
84    Err(Error::msg("Failed to fetch the organization ID"))
85  }
86  fn value(self) -> String {
87    self.0
88  }
89  fn value_ref(&self) -> &String {
90    &self.0
91  }
92}
93
94impl TryFrom<&str> for Organization {
95  type Error = Error;
96
97  fn try_from(text: &str) -> Result<Self> {
98    Self::from_str(text)
99  }
100}
101
102impl TryFrom<String> for Organization {
103  type Error = Error;
104
105  fn try_from(text: String) -> Result<Self> {
106    Self::from_str(&text)
107  }
108}
109
110impl TryFrom<&String> for Organization {
111  type Error = Error;
112
113  fn try_from(text: &String) -> Result<Self> {
114    Self::from_str(text)
115  }
116}