@@ -15,13 +15,31 @@ class PineconeVectorClient extends VectorClientBase {
1515 * The configured HTTP client for Pinecone.
1616 */
1717 protected function getPineconeClient (): \GuzzleHttp \Client {
18+ // Retrieve Pinecone API key and hostname from configuration.
1819 $ api_key = $ this ->getEmbeddingConfig ('pinecone_api_key ' );
19- $ hostname = rtrim ( $ this ->getEmbeddingConfig ('pinecone_hostname ' ), ' / ' );
20+ $ hostname = $ this ->getEmbeddingConfig ('pinecone_hostname ' );
2021
21- if (empty ($ api_key ) || empty ($ hostname )) {
22- throw new \Exception ('Pinecone API key or hostname is not set. Please check your configuration. ' );
22+ // If the Key module is used, resolve the values.
23+ if (is_array ($ api_key )) {
24+ $ api_key = key_get_key_value ($ api_key );
25+ }
26+ if (is_array ($ hostname )) {
27+ $ hostname = key_get_key_value ($ hostname );
28+ }
29+
30+ // Validate and sanitize the values.
31+ if (empty ($ api_key ) || !is_string ($ api_key )) {
32+ throw new \Exception ('Invalid or missing Pinecone API key. Please check your configuration. ' );
33+ }
34+ if (empty ($ hostname ) || !is_string ($ hostname )) {
35+ throw new \Exception ('Invalid or missing Pinecone hostname. Please check your configuration. ' );
2336 }
2437
38+ // Trim and sanitize the hostname and API key.
39+ $ api_key = trim ($ api_key );
40+ $ hostname = rtrim (trim ($ hostname ), '/ ' );
41+
42+ // Return a configured HTTP client.
2543 return $ this ->getHttpClient ([
2644 'headers ' => [
2745 'API-Key ' => $ api_key ,
@@ -81,9 +99,9 @@ public function upsert(array $parameters) {
8199 }
82100
83101 // Log the payload being sent for upsert.
84- /* watchdog('openai_embeddings', 'Pinecone upsert payload: @payload', [
102+ watchdog ('openai_embeddings ' , 'Pinecone upsert payload: @payload ' , [
85103 '@payload ' => json_encode ($ payload ),
86- ], WATCHDOG_DEBUG); */
104+ ], WATCHDOG_DEBUG );
87105
88106 try {
89107 $ response = $ client ->post ('/vectors/upsert ' , ['json ' => $ payload ]);
@@ -140,6 +158,125 @@ public function stats(): array {
140158 return [];
141159 }
142160}
161+
162+ /**
163+ * Delete records in Pinecone.
164+ *
165+ * @param array $parameters
166+ * An array with at least key 'source_ids'. The key
167+ * 'collection' is required if not using the Pinecone free Starter plan.
168+ *
169+ * @return \Psr\Http\Message\ResponseInterface
170+ * The response object.
171+ *
172+ * @throws \Exception
173+ * If required parameters are missing or an error occurs.
174+ */
175+ public function delete (array $ parameters ): ResponseInterface {
176+ // Ensure necessary parameters are provided.
177+ if (empty ($ parameters ['source_ids ' ]) && empty ($ parameters ['filter ' ])) {
178+ throw new \Exception ('Either "source_ids" to delete or a "filter" is required for Pinecone deletion. ' );
179+ }
180+
181+ if (!empty ($ parameters ['deleteAll ' ])) {
182+ throw new \Exception ('"deleteAll" must be handled by the deleteAll() method. ' );
183+ }
184+
185+ // Prepare the payload for deletion.
186+ $ payload = [];
187+ if (!empty ($ parameters ['source_ids ' ])) {
188+ $ payload ['ids ' ] = $ parameters ['source_ids ' ];
189+ }
190+ if (!empty ($ parameters ['collection ' ])) {
191+ $ payload ['namespace ' ] = $ parameters ['collection ' ];
192+ }
193+ if (!empty ($ parameters ['filter ' ])) {
194+ $ payload ['filter ' ] = $ parameters ['filter ' ];
195+ }
196+
197+ try {
198+ // Execute the delete request.
199+ return $ this ->getClient ()->post ('/vectors/delete ' , ['json ' => $ payload ]);
200+ } catch (RequestException $ e ) {
201+ watchdog ('openai_embeddings ' , 'Error during Pinecone delete: @message ' , ['@message ' => $ e ->getMessage ()], WATCHDOG_ERROR );
202+ throw $ e ;
203+ }
204+ }
143205
206+ /**
207+ * Delete all records in Pinecone.
208+ *
209+ * @param array $parameters
210+ * An array with at least the key 'collection'. Full deletion
211+ * is not supported in the Pinecone free Starter plan.
212+ *
213+ * @throws \Exception
214+ * If required parameters are missing or an error occurs.
215+ */
216+ public function deleteAll (array $ parameters ): void {
217+ // Use the configuration method provided by the VectorClientBase class.
218+ $ disable_namespace = $ this ->getEmbeddingConfig ('disable_namespace ' );
219+
220+ // Validate the Pinecone plan and required parameters.
221+ if (!empty ($ disable_namespace )) {
222+ watchdog ('openai_embeddings ' , 'Pinecone free starter plan does not support Delete All. ' , [], WATCHDOG_WARNING );
223+ throw new \Exception ('Pinecone free starter plan does not support full namespace deletion. ' );
224+ }
225+ if (empty ($ parameters ['collection ' ])) {
226+ throw new \Exception ('Namespace (collection) is required for deleteAll in Pinecone. ' );
227+ }
228+
229+ // Retrieve Pinecone API key and hostname from configuration.
230+ $ api_key = $ this ->getEmbeddingConfig ('pinecone_api_key ' );
231+ $ hostname = $ this ->getEmbeddingConfig ('pinecone_hostname ' );
232+
233+ // If the Key module is used, resolve the values.
234+ if (is_array ($ api_key )) {
235+ $ api_key = key_get_key_value ($ api_key );
236+ }
237+ if (is_array ($ hostname )) {
238+ $ hostname = key_get_key_value ($ hostname );
239+ }
240+
241+ // Validate the resolved values.
242+ if (empty ($ api_key ) || !is_string ($ api_key )) {
243+ throw new \Exception ('Invalid or missing Pinecone API key. Please check your configuration. ' );
244+ }
245+ if (empty ($ hostname ) || !is_string ($ hostname )) {
246+ throw new \Exception ('Invalid or missing Pinecone hostname. Please check your configuration. ' );
247+ }
248+
249+ // Trim and sanitize the hostname and API key.
250+ $ api_key = trim ($ api_key );
251+ $ hostname = rtrim (trim ($ hostname ), '/ ' );
252+
253+ // Prepare the payload for full deletion.
254+ $ payload = [
255+ 'deleteAll ' => TRUE ,
256+ 'namespace ' => $ parameters ['collection ' ],
257+ ];
258+
259+ try {
260+ // Create a Guzzle client with the resolved configuration.
261+ $ client = $ this ->getHttpClient ([
262+ 'headers ' => [
263+ 'API-Key ' => $ api_key ,
264+ ],
265+ 'base_uri ' => $ hostname ,
266+ ]);
267+
268+ // Execute the deleteAll request.
269+ $ client ->post ('/vectors/delete ' , ['json ' => $ payload ]);
270+ } catch (RequestException $ e ) {
271+ watchdog ('openai_embeddings ' , 'Error during Pinecone deleteAll: @message ' , ['@message ' => $ e ->getMessage ()], WATCHDOG_ERROR );
272+ throw $ e ;
273+ } catch (\Exception $ e ) {
274+ watchdog ('openai_embeddings ' , 'Unexpected error during Pinecone deleteAll: @message ' , ['@message ' => $ e ->getMessage ()], WATCHDOG_ERROR );
275+ throw $ e ;
276+ }
277+ }
278+
279+
280+
144281}
145282
0 commit comments