Skip to content

Commit fd086c9

Browse files
authored
Add NeedleFiles sub-client (#3)
1 parent 79ac0ca commit fd086c9

File tree

5 files changed

+128
-17
lines changed

5 files changed

+128
-17
lines changed

needle/v1/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
NeedleBaseClient,
1212
)
1313
from needle.v1.collections import NeedleCollections
14+
from needle.v1.files import NeedleFiles
1415

1516

1617
NEEDLE_DEFAULT_URL = "https://needle-ai.com"
@@ -46,3 +47,4 @@ def __init__(
4647

4748
# sub clients
4849
self.collections = NeedleCollections(config, headers)
50+
self.files = NeedleFiles(config, headers)

needle/v1/files/__init__.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""
2+
This module provides NeedleFiles class for interacting with Needle API's files endpoint.
3+
"""
4+
5+
import requests
6+
7+
from needle.v1.models import (
8+
NeedleConfig,
9+
NeedleBaseClient,
10+
Error,
11+
)
12+
13+
14+
class NeedleFiles(NeedleBaseClient):
15+
"""
16+
A client for interacting with the Needle API's files endpoint.
17+
18+
This class provides methods to create upload and download URLs for files within the Needle API.
19+
It uses a requests session to handle HTTP requests with a default timeout of 120 seconds.
20+
"""
21+
22+
def __init__(self, config: NeedleConfig, headers: dict):
23+
super().__init__(config, headers)
24+
25+
self.endpoint = f"{config.url}/api/v1/files"
26+
27+
# requests config
28+
self.session = requests.Session()
29+
self.session.headers.update(headers)
30+
self.session.timeout = 120
31+
32+
def get_download_url(self, file_id: str) -> str:
33+
"""
34+
Retrieves the download URL for the given file.
35+
If the file was manually uploaded, then the download URL will be valid for a short time therefore you should read the file before it expires.
36+
37+
Args:
38+
file_id (str): ID of the file to get the download URL for.
39+
40+
Returns:
41+
str: The download URL for the file.
42+
43+
Raises:
44+
Error: If the API request fails.
45+
"""
46+
if not file_id:
47+
raise Error(
48+
message="file_id is required",
49+
code=422,
50+
)
51+
52+
url = f"{self.endpoint}/{file_id}/download_url"
53+
resp = self.session.get(url)
54+
body = resp.json()
55+
56+
if resp.status_code >= 400:
57+
error = body.get("error")
58+
raise Error(**error)
59+
60+
return body.get("result")

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "needle-python"
7-
version = "0.3.0"
7+
version = "0.4.0"
88
description = "Needle client library for Python"
99
authors = [
1010
"Onur Eken <m.onureken@gmail.com>",
Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,11 @@
3535
"outputs": [],
3636
"source": [
3737
"from needle.v1 import NeedleClient\n",
38-
"from needle.v1.models import FileToAdd\n",
39-
"\n",
4038
"\n",
4139
"ndl = NeedleClient()\n",
42-
"collection_id = \"clt_01J4NW2THDSQC7GDD19CMCTAAK\"\n",
40+
"collection_id = \"clt_01J6SPFD61D5QYGSHK6W15M3VB\"\n",
4341
"\n",
44-
"prompt = \"What techniques moved into adopt in this volume of technology radar?\"\n",
42+
"prompt = \"How do joins work in PQL?\"\n",
4543
"results = ndl.collections.search(collection_id, text=prompt)\n",
4644
"\n",
4745
"for r in results:\n",
@@ -50,26 +48,18 @@
5048
},
5149
{
5250
"cell_type": "code",
53-
"execution_count": 8,
51+
"execution_count": null,
5452
"metadata": {},
55-
"outputs": [
56-
{
57-
"name": "stdout",
58-
"output_type": "stream",
59-
"text": [
60-
"Retrieval-Augmented Generation (RAG) technique moved into the \"Adopt\" category in this volume of the Technology Radar.\n"
61-
]
62-
}
63-
],
53+
"outputs": [],
6454
"source": [
6555
"system_messages = [{\"role\": \"system\", \"content\": r.content} for r in results] # results from Needle\n",
6656
"user_message = {\n",
6757
" \"role\": \"user\",\n",
6858
" \"content\": f\"\"\"\n",
6959
" Only answer the question based on the provided results data. \n",
70-
" If there is no data in the provided data for the question, do not try to generate an answer. \n",
60+
" If there is no data in the provided data for the question, do not generate an answer. \n",
7161
" This is the question: {prompt}\n",
72-
"\"\"\",\n",
62+
" \"\"\",\n",
7363
"}\n",
7464
"\n",
7565
"openai_client = OpenAI()\n",

tutorials/files.ipynb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": 1,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"import os"
10+
]
11+
},
12+
{
13+
"cell_type": "code",
14+
"execution_count": 2,
15+
"metadata": {},
16+
"outputs": [],
17+
"source": [
18+
"os.environ[\"NEEDLE_API_KEY\"] = \"\""
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {},
25+
"outputs": [],
26+
"source": [
27+
"from needle.v1 import NeedleClient\n",
28+
"\n",
29+
"ndl = NeedleClient(\n",
30+
" url=\"http://localhost:3000\",\n",
31+
")\n",
32+
"collection_id = \"clt_01JBS48E0M6YF2AN9ZAXVK8S2P\"\n",
33+
"\n",
34+
"ndl.files.get_download_url(\"fle_01JBS5EXXRGSQMCY7B6XMRXETE\")"
35+
]
36+
}
37+
],
38+
"metadata": {
39+
"kernelspec": {
40+
"display_name": "needle-tutorial-Pi3Ihry5",
41+
"language": "python",
42+
"name": "python3"
43+
},
44+
"language_info": {
45+
"codemirror_mode": {
46+
"name": "ipython",
47+
"version": 3
48+
},
49+
"file_extension": ".py",
50+
"mimetype": "text/x-python",
51+
"name": "python",
52+
"nbconvert_exporter": "python",
53+
"pygments_lexer": "ipython3",
54+
"version": "3.10.4"
55+
}
56+
},
57+
"nbformat": 4,
58+
"nbformat_minor": 2
59+
}

0 commit comments

Comments
 (0)