77
88namespace OCA \OpenAi \Service ;
99
10+ use DateInterval ;
11+ use DateTime ;
1012use Exception ;
1113use OCA \OpenAi \AppInfo \Application ;
1214use OCP \IAppConfig ;
@@ -33,7 +35,7 @@ class OpenAiSettingsService {
3335 'max_tokens ' => 'integer ' ,
3436 'use_max_completion_tokens_param ' => 'boolean ' ,
3537 'llm_extra_params ' => 'string ' ,
36- 'quota_period ' => 'integer ' ,
38+ 'quota_period ' => 'array ' ,
3739 'quotas ' => 'array ' ,
3840 'translation_provider_enabled ' => 'boolean ' ,
3941 'llm_provider_enabled ' => 'boolean ' ,
@@ -62,6 +64,67 @@ public function __construct(
6264 ) {
6365 }
6466
67+ /**
68+ * Gets the timestamp of the beginning of the quota period
69+ *
70+ * @return int
71+ * @throws Exception
72+ */
73+ public function getQuotaStart (): int {
74+ $ quotaPeriod = $ this ->getQuotaPeriod ();
75+ $ now = new DateTime ();
76+
77+ if ($ quotaPeriod ['unit ' ] === 'day ' ) {
78+ // Get a timestamp of the beginning of the time period
79+ $ periodStart = $ now ->sub (new DateInterval ('P ' . $ quotaPeriod ['length ' ] . 'D ' ));
80+ } else {
81+ $ periodStart = new DateTime (date ('Y-m- ' . $ quotaPeriod ['day ' ]));
82+ // Ensure that this isn't in the future
83+ if ($ periodStart > $ now ) {
84+ $ periodStart = $ periodStart ->sub (new DateInterval ('P1M ' ));
85+ }
86+ if ($ quotaPeriod ['length ' ] > 1 ) {
87+ // Calculate number of months since 2000-01 to ensure the start month is consistent
88+ $ startDate = new DateTime ('2000-01- ' . $ quotaPeriod ['day ' ]);
89+ $ months = $ startDate ->diff ($ periodStart )->m + $ startDate ->diff ($ periodStart )->y * 12 ;
90+ $ remainder = $ months % $ quotaPeriod ['length ' ];
91+ $ periodStart = $ periodStart ->sub (new DateInterval ('P ' . $ remainder . 'M ' ));
92+ }
93+ }
94+ return $ periodStart ->getTimestamp ();
95+ }
96+
97+ /**
98+ * Gets the timestamp of the end of the quota period
99+ * if the period is floating, then this will be the current time
100+ *
101+ * @return int
102+ * @throws Exception
103+ */
104+ public function getQuotaEnd (): int {
105+ $ quotaPeriod = $ this ->getQuotaPeriod ();
106+ $ now = new DateTime ();
107+
108+ if ($ quotaPeriod ['unit ' ] === 'day ' ) {
109+ // Get a timestamp of the beginning of the time period
110+ $ periodEnd = $ now ;
111+ } else {
112+ $ periodEnd = new DateTime (date ('Y-m- ' . $ quotaPeriod ['day ' ]));
113+ // Ensure that this isn't in the past
114+ if ($ periodEnd < $ now ) {
115+ $ periodEnd = $ periodEnd ->add (new DateInterval ('P1M ' ));
116+ }
117+ if ($ quotaPeriod ['length ' ] > 1 ) {
118+ // Calculate number of months since 2000-01 to ensure the start month is consistent
119+ $ startDate = new DateTime ('2000-01- ' . $ quotaPeriod ['day ' ]);
120+ $ months = $ startDate ->diff ($ periodEnd )->m + $ startDate ->diff ($ periodEnd )->y * 12 ;
121+ $ remainder = $ months % $ quotaPeriod ['length ' ];
122+ $ periodEnd = $ periodEnd ->add (new DateInterval ('P ' . $ quotaPeriod ['length ' ] - $ remainder . 'M ' ));
123+ }
124+ }
125+ return $ periodEnd ->getTimestamp ();
126+ }
127+
65128 public function invalidateModelsCache (): void {
66129 $ cache = $ this ->cacheFactory ->createDistributed (Application::APP_ID );
67130 $ cache ->clear (Application::MODELS_CACHE_KEY );
@@ -197,10 +260,23 @@ public function getLlmExtraParams(): string {
197260 }
198261
199262 /**
200- * @return int
263+ * @return array
201264 */
202- public function getQuotaPeriod (): int {
203- return intval ($ this ->appConfig ->getValueString (Application::APP_ID , 'quota_period ' , strval (Application::DEFAULT_QUOTA_PERIOD ))) ?: Application::DEFAULT_QUOTA_PERIOD ;
265+ public function getQuotaPeriod (): array {
266+ $ value = json_decode (
267+ $ this ->appConfig ->getValueString (Application::APP_ID , 'quota_period ' , json_encode (Application::DEFAULT_QUOTA_CONFIG )),
268+ true
269+ ) ?: Application::DEFAULT_QUOTA_CONFIG ;
270+ // Migrate from old quota period to new one
271+ if (is_int ($ value )) {
272+ $ value = ['length ' => $ value ];
273+ }
274+ foreach (Application::DEFAULT_QUOTA_CONFIG as $ key => $ defaultValue ) {
275+ if (!isset ($ value [$ key ])) {
276+ $ value [$ key ] = $ defaultValue ;
277+ }
278+ }
279+ return $ value ;
204280 }
205281
206282 /**
@@ -593,14 +669,31 @@ public function setLlmExtraParams(string $llmExtraParams): void {
593669 }
594670
595671 /**
596- * Setter for quotaPeriod; minimum is 1 day
597- * @param int $quotaPeriod
672+ * Setter for quotaPeriod; minimum is 1 day.
673+ * Days are floating, and months are set dates
674+ * @param array $quotaPeriod
598675 * @return void
676+ * @throws Exception
599677 */
600- public function setQuotaPeriod (int $ quotaPeriod ): void {
601- // Validate input:
602- $ quotaPeriod = max (1 , $ quotaPeriod );
603- $ this ->appConfig ->setValueString (Application::APP_ID , 'quota_period ' , strval ($ quotaPeriod ));
678+ public function setQuotaPeriod (array $ quotaPeriod ): void {
679+ if (!isset ($ quotaPeriod ['length ' ]) || !is_int ($ quotaPeriod ['length ' ])) {
680+ throw new Exception ('Invalid quota period length ' );
681+ }
682+ $ quotaPeriod ['length ' ] = max (1 , $ quotaPeriod ['length ' ]);
683+ if (!isset ($ quotaPeriod ['unit ' ]) || !is_string ($ quotaPeriod ['unit ' ])) {
684+ throw new Exception ('Invalid quota period unit ' );
685+ }
686+ // Checks month period
687+ if ($ quotaPeriod ['unit ' ] === 'month ' ) {
688+ if (!isset ($ quotaPeriod ['day ' ]) || !is_int ($ quotaPeriod ['day ' ])) {
689+ throw new Exception ('Invalid quota period day ' );
690+ }
691+ $ quotaPeriod ['day ' ] = max (1 , $ quotaPeriod ['day ' ]);
692+ $ quotaPeriod ['day ' ] = min ($ quotaPeriod ['day ' ], 28 );
693+ } elseif ($ quotaPeriod ['unit ' ] !== 'day ' ) {
694+ throw new Exception ('Invalid quota period unit ' );
695+ }
696+ $ this ->appConfig ->setValueString (Application::APP_ID , 'quota_period ' , json_encode ($ quotaPeriod ));
604697 }
605698
606699 /**
0 commit comments