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,62 @@ public function __construct(
6264 ) {
6365 }
6466
67+ /**
68+ * @return int
69+ * @throws Exception
70+ */
71+ public function getQuotaStart (): int {
72+ $ quotaPeriod = $ this ->getQuotaPeriod ();
73+ $ now = new DateTime ();
74+
75+ if ($ quotaPeriod ['unit ' ] === 'day ' ) {
76+ // Get a timestamp of the beginning of the time period
77+ $ periodStart = $ now ->sub (new DateInterval ('P ' . $ quotaPeriod ['length ' ] . 'D ' ));
78+ } else {
79+ $ periodStart = new DateTime (date ('Y-m- ' . $ quotaPeriod ['day ' ]));
80+ // Ensure that this isn't in the future
81+ if ($ periodStart > $ now ) {
82+ $ periodStart = $ periodStart ->sub (new DateInterval ('P1M ' ));
83+ }
84+ if ($ quotaPeriod ['length ' ] > 1 ) {
85+ // Calculate number of months since 2000-01 to ensure the start month is consistent
86+ $ startDate = new DateTime ('2000-01- ' . $ quotaPeriod ['day ' ]);
87+ $ months = $ startDate ->diff ($ periodStart )->m + $ startDate ->diff ($ periodStart )->y * 12 ;
88+ $ remainder = $ months % $ quotaPeriod ['length ' ];
89+ $ periodStart = $ periodStart ->sub (new DateInterval ('P ' . $ remainder . 'M ' ));
90+ }
91+ }
92+ return $ periodStart ->getTimestamp ();
93+ }
94+
95+ /**
96+ * @return int
97+ * @throws Exception
98+ */
99+ public function getQuotaEnd (): int {
100+ $ quotaPeriod = $ this ->getQuotaPeriod ();
101+ $ now = new DateTime ();
102+
103+ if ($ quotaPeriod ['unit ' ] === 'day ' ) {
104+ // Get a timestamp of the beginning of the time period
105+ $ periodEnd = $ now ;
106+ } else {
107+ $ periodEnd = new DateTime (date ('Y-m- ' . $ quotaPeriod ['day ' ]));
108+ // Ensure that this isn't in the past
109+ if ($ periodEnd < $ now ) {
110+ $ periodEnd = $ periodEnd ->add (new DateInterval ('P1M ' ));
111+ }
112+ if ($ quotaPeriod ['length ' ] > 1 ) {
113+ // Calculate number of months since 2000-01 to ensure the start month is consistent
114+ $ startDate = new DateTime ('2000-01- ' . $ quotaPeriod ['day ' ]);
115+ $ months = $ startDate ->diff ($ periodEnd )->m + $ startDate ->diff ($ periodEnd )->y * 12 ;
116+ $ remainder = $ months % $ quotaPeriod ['length ' ];
117+ $ periodEnd = $ periodEnd ->add (new DateInterval ('P ' . $ quotaPeriod ['length ' ] - $ remainder . 'M ' ));
118+ }
119+ }
120+ return $ periodEnd ->getTimestamp ();
121+ }
122+
65123 public function invalidateModelsCache (): void {
66124 $ cache = $ this ->cacheFactory ->createDistributed (Application::APP_ID );
67125 $ cache ->clear (Application::MODELS_CACHE_KEY );
@@ -197,10 +255,20 @@ public function getLlmExtraParams(): string {
197255 }
198256
199257 /**
200- * @return int
258+ * @return array
201259 */
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 ;
260+ public function getQuotaPeriod (): array {
261+ $ value = json_decode (
262+ $ this ->appConfig ->getValueString (Application::APP_ID , 'quota_period ' , json_encode (Application::DEFAULT_QUOTA_CONFIG )),
263+ true
264+ ) ?: Application::DEFAULT_QUOTA_CONFIG ;
265+ if (is_int ($ value )) {
266+ return [
267+ 'length ' => $ value ,
268+ 'unit ' => 'day ' ,
269+ ];
270+ }
271+ return $ value ;
204272 }
205273
206274 /**
@@ -593,14 +661,31 @@ public function setLlmExtraParams(string $llmExtraParams): void {
593661 }
594662
595663 /**
596- * Setter for quotaPeriod; minimum is 1 day
597- * @param int $quotaPeriod
664+ * Setter for quotaPeriod; minimum is 1 day.
665+ * Days are floating, and months are set dates
666+ * @param array $quotaPeriod
598667 * @return void
668+ * @throws Exception
599669 */
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 ));
670+ public function setQuotaPeriod (array $ quotaPeriod ): void {
671+ if (!isset ($ quotaPeriod ['length ' ]) || !is_int ($ quotaPeriod ['length ' ])) {
672+ throw new Exception ('Invalid quota period length ' );
673+ }
674+ $ quotaPeriod ['length ' ] = max (1 , $ quotaPeriod ['length ' ]);
675+ if (!isset ($ quotaPeriod ['unit ' ]) || !is_string ($ quotaPeriod ['unit ' ])) {
676+ throw new Exception ('Invalid quota period unit ' );
677+ }
678+ // Checks month period
679+ if ($ quotaPeriod ['unit ' ] === 'month ' ) {
680+ if (!isset ($ quotaPeriod ['day ' ]) || !is_int ($ quotaPeriod ['day ' ])) {
681+ throw new Exception ('Invalid quota period day ' );
682+ }
683+ $ quotaPeriod ['day ' ] = max (1 , $ quotaPeriod ['day ' ]);
684+ $ quotaPeriod ['day ' ] = min ($ quotaPeriod ['day ' ], 28 );
685+ } elseif ($ quotaPeriod ['unit ' ] !== 'day ' ) {
686+ throw new Exception ('Invalid quota period unit ' );
687+ }
688+ $ this ->appConfig ->setValueString (Application::APP_ID , 'quota_period ' , json_encode ($ quotaPeriod ));
604689 }
605690
606691 /**
0 commit comments