Pujan Neupane commited on
Commit
b5008e5
·
1 Parent(s): b42863e

written the handshake part

Browse files
Files changed (3) hide show
  1. README.md +33 -7
  2. app.py +38 -6
  3. requirements.txt +189 -28
README.md CHANGED
@@ -113,12 +113,21 @@ uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4
113
 
114
  ---
115
 
116
- ### **Testing the API**
117
 
118
- - Use `curl` for testing:
119
- ```bash
120
- curl -X 'POST' 'http://127.0.0.1:8000/analyze' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"text": "sample text"}'
121
- ```
 
 
 
 
 
 
 
 
 
122
 
123
  ---
124
 
@@ -127,6 +136,23 @@ uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4
127
  - **Swagger UI:** `http://127.0.0.1:8000/docs` -> `/docs`
128
  - **ReDoc:** `http://127.0.0.1:8000/redoc` -> `/redoc`
129
 
130
- ### **Implement it with NEST.js**
 
 
131
 
132
- will be updated
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  ---
115
 
116
+ ### **🧪 Testing the API**
117
 
118
+ You can test the FastAPI endpoint using `curl` like this:
119
+
120
+ ```bash
121
+ curl -X POST http://127.0.0.1:8000/analyze \
122
+ -H "Authorization: Bearer HelloThere" \
123
+ -H "Content-Type: application/json" \
124
+ -d '{"text": "This is a sample sentence for analysis."}'
125
+ ```
126
+
127
+ - The `-H "Authorization: Bearer HelloThere"` part is used to simulate the **handshake**.
128
+ - FastAPI checks this token against the one loaded from the `.env` file.
129
+ - If the token matches, the request is accepted and processed.
130
+ - Otherwise, it responds with a `403 Unauthorized` error.
131
 
132
  ---
133
 
 
136
  - **Swagger UI:** `http://127.0.0.1:8000/docs` -> `/docs`
137
  - **ReDoc:** `http://127.0.0.1:8000/redoc` -> `/redoc`
138
 
139
+ ### **🔐 Handshake Mechanism**
140
+
141
+ In this part, we're implementing a simple handshake to verify that the request is coming from a trusted source (e.g., our NestJS server). Here's how it works:
142
 
143
+ - We load a secret token from the `.env` file.
144
+ - When a request is made to the FastAPI server, we extract the `Authorization` header and compare it with our expected secret token.
145
+ - If the token does **not** match, we immediately return a **403 Forbidden** response with the message `"Unauthorized"`.
146
+ - If the token **does** match, we allow the request to proceed to the next step.
147
+
148
+ The verification function looks like this:
149
+
150
+ ```python
151
+ def verify_token(auth: str):
152
+ if auth != f"Bearer {EXPECTED_TOKEN}":
153
+ raise HTTPException(status_code=403, detail="Unauthorized")
154
+ ```
155
+
156
+ This provides a basic but effective layer of security to prevent unauthorized access to the API.
157
+
158
+ ### **Implement it with NEST.js**
app.py CHANGED
@@ -1,16 +1,31 @@
1
  import torch
2
  from transformers import GPT2LMHeadModel, GPT2TokenizerFast
3
- from fastapi import FastAPI, HTTPException
4
  from pydantic import BaseModel
5
  import asyncio
6
  from concurrent.futures import ThreadPoolExecutor
7
  from contextlib import asynccontextmanager
 
8
 
9
  # FastAPI instance
10
  app = FastAPI()
11
- model, tokenizer = None, None
12
  executor = ThreadPoolExecutor(max_workers=20)
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  # Function to load model and tokenizer
15
 
16
 
@@ -31,14 +46,17 @@ async def lifespan(app: FastAPI):
31
  yield
32
 
33
 
 
34
  app = FastAPI(lifespan=lifespan)
35
 
 
 
36
 
37
  class TextInput(BaseModel):
38
  text: str
39
 
40
 
41
- # Function to classify the text
42
 
43
 
44
  def classify_text_sync(sentence: str):
@@ -61,13 +79,20 @@ def classify_text_sync(sentence: str):
61
  return result, perplexity
62
 
63
 
 
 
 
64
  async def classify_text(sentence: str):
65
  loop = asyncio.get_event_loop()
66
  return await loop.run_in_executor(executor, classify_text_sync, sentence)
67
 
68
 
 
 
 
69
  @app.post("/analyze")
70
- async def analyze_text(data: TextInput):
 
71
  user_input = data.text.strip()
72
 
73
  if not user_input:
@@ -81,17 +106,24 @@ async def analyze_text(data: TextInput):
81
  }
82
 
83
 
 
 
 
84
  @app.get("/health")
85
  async def health_check():
86
  return {"status": "ok"}
87
 
88
 
 
 
 
89
  @app.get("/")
90
  def index():
91
- return {"Its an API"}
92
 
93
 
 
94
  if __name__ == "__main__":
95
  import uvicorn
96
 
97
- uvicorn.run("app:app", host="0.0.0.0", port=8000, workers=4) # Specify 4 workers
 
1
  import torch
2
  from transformers import GPT2LMHeadModel, GPT2TokenizerFast
3
+ from fastapi import FastAPI, HTTPException, Header
4
  from pydantic import BaseModel
5
  import asyncio
6
  from concurrent.futures import ThreadPoolExecutor
7
  from contextlib import asynccontextmanager
8
+ from dotenv import dotenv_values
9
 
10
  # FastAPI instance
11
  app = FastAPI()
 
12
  executor = ThreadPoolExecutor(max_workers=20)
13
 
14
+ # Load .env file
15
+ env = dotenv_values(".env")
16
+ EXPECTED_TOKEN = env.get("SECRET_TOKEN")
17
+
18
+ # Global variables for model and tokenizer
19
+ model, tokenizer = None, None
20
+
21
+ # Function to verify token
22
+
23
+
24
+ def verify_token(auth: str):
25
+ if auth != f"Bearer {EXPECTED_TOKEN}":
26
+ raise HTTPException(status_code=403, detail="Unauthorized")
27
+
28
+
29
  # Function to load model and tokenizer
30
 
31
 
 
46
  yield
47
 
48
 
49
+ # Attach the lifespan context manager
50
  app = FastAPI(lifespan=lifespan)
51
 
52
+ # Request body for input data
53
+
54
 
55
  class TextInput(BaseModel):
56
  text: str
57
 
58
 
59
+ # Sync function to classify text
60
 
61
 
62
  def classify_text_sync(sentence: str):
 
79
  return result, perplexity
80
 
81
 
82
+ # Async wrapper for text classification
83
+
84
+
85
  async def classify_text(sentence: str):
86
  loop = asyncio.get_event_loop()
87
  return await loop.run_in_executor(executor, classify_text_sync, sentence)
88
 
89
 
90
+ # POST route to analyze text
91
+
92
+
93
  @app.post("/analyze")
94
+ async def analyze_text(data: TextInput, authorization: str = Header(default="")):
95
+ verify_token(authorization) # Token verification
96
  user_input = data.text.strip()
97
 
98
  if not user_input:
 
106
  }
107
 
108
 
109
+ # Health check route
110
+
111
+
112
  @app.get("/health")
113
  async def health_check():
114
  return {"status": "ok"}
115
 
116
 
117
+ # Simple index route
118
+
119
+
120
  @app.get("/")
121
  def index():
122
+ return {"message": "It's an API"}
123
 
124
 
125
+ # Start the app (run with uvicorn)
126
  if __name__ == "__main__":
127
  import uvicorn
128
 
129
+ uvicorn.run("main:app", host="0.0.0.0", port=8000, workers=4)
requirements.txt CHANGED
@@ -1,49 +1,210 @@
 
 
 
 
 
 
1
  annotated-types==0.7.0
2
  anyio==4.9.0
 
 
 
 
 
 
 
 
 
 
 
 
3
  certifi==2025.1.31
4
- charset-normalizer==3.4.1
 
5
  click==8.1.8
 
 
 
 
 
 
 
 
 
 
 
 
6
  fastapi==0.115.12
7
- filelock==3.18.0
8
- fsspec==2025.3.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  h11==0.14.0
 
 
 
 
 
10
  huggingface-hub==0.30.2
11
  idna==3.10
12
- Jinja2==3.1.6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  MarkupSafe==3.0.2
 
 
 
 
 
 
14
  mpmath==1.3.0
15
- networkx==3.4.2
16
- numpy==2.2.5
17
- nvidia-cublas-cu12==12.4.5.8
18
- nvidia-cuda-cupti-cu12==12.4.127
19
- nvidia-cuda-nvrtc-cu12==12.4.127
20
- nvidia-cuda-runtime-cu12==12.4.127
21
- nvidia-cudnn-cu12==9.1.0.70
22
- nvidia-cufft-cu12==11.2.1.3
23
- nvidia-curand-cu12==10.3.5.147
24
- nvidia-cusolver-cu12==11.6.1.9
25
- nvidia-cusparse-cu12==12.3.1.170
26
- nvidia-cusparselt-cu12==0.6.2
27
- nvidia-nccl-cu12==2.21.5
28
- nvidia-nvjitlink-cu12==12.4.127
29
- nvidia-nvtx-cu12==12.4.127
30
- packaging==25.0
31
- pydantic==2.11.3
32
- pydantic_core==2.33.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  PyYAML==6.0.2
 
 
34
  regex==2024.11.6
35
  requests==2.32.3
 
 
 
 
 
36
  safetensors==0.5.3
37
- setuptools==79.0.0
 
 
 
 
 
 
38
  sniffio==1.3.1
 
 
 
39
  starlette==0.46.2
 
40
  sympy==1.13.1
 
 
 
 
41
  tokenizers==0.21.1
42
- torch==2.6.0
 
 
 
 
43
  tqdm==4.67.1
 
44
  transformers==4.51.3
45
  triton==3.2.0
46
- typing-inspection==0.4.0
47
- typing_extensions==4.13.2
48
- urllib3==2.4.0
49
- uvicorn==0.34.2
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ absl-py==2.2.2
2
+ accelerate==1.6.0
3
+ aiohappyeyeballs==2.6.1
4
+ aiohttp==3.11.16
5
+ aiosignal==1.3.2
6
+ altair==5.5.0
7
  annotated-types==0.7.0
8
  anyio==4.9.0
9
+ argon2-cffi==23.1.0
10
+ argon2-cffi-bindings==21.2.0
11
+ arrow==1.3.0
12
+ asgiref==3.8.1
13
+ asttokens==3.0.0
14
+ async-lru==2.0.5
15
+ attrs==25.3.0
16
+ babel==2.17.0
17
+ beautifulsoup4==4.13.4
18
+ bleach==6.2.0
19
+ blinker==1.9.0
20
+ cachetools==5.5.2
21
  certifi==2025.1.31
22
+ cffi==1.17.1
23
+ charset-normalizer==2.1.1
24
  click==8.1.8
25
+ comm==0.2.2
26
+ contourpy==1.3.1
27
+ cycler==0.12.1
28
+ datasets==3.5.0
29
+ DateTime==4.7
30
+ debugpy==1.8.13
31
+ decorator==5.2.1
32
+ defusedxml==0.7.1
33
+ dill==0.3.8
34
+ Django==5.2
35
+ dotenv==0.9.9
36
+ executing==2.2.0
37
  fastapi==0.115.12
38
+ fastjsonschema==2.21.1
39
+ filelock==3.13.1
40
+ Flask==3.1.0
41
+ flask-cors==5.0.1
42
+ fonttools==4.56.0
43
+ fqdn==1.5.1
44
+ frozenlist==1.6.0
45
+ fsspec==2024.6.1
46
+ generativeai==0.0.1
47
+ gitdb==4.0.12
48
+ GitPython==3.1.44
49
+ google-ai-generativelanguage==0.6.15
50
+ google-api-core==2.24.2
51
+ google-api-python-client==2.165.0
52
+ google-auth==2.38.0
53
+ google-auth-httplib2==0.2.0
54
+ google-genai==1.7.0
55
+ google-generativeai==0.8.4
56
+ googleapis-common-protos==1.69.2
57
+ grpcio==1.71.0
58
+ grpcio-status==1.71.0
59
  h11==0.14.0
60
+ h5py==3.13.0
61
+ html5lib==1.1
62
+ httpcore==1.0.7
63
+ httplib2==0.22.0
64
+ httpx==0.28.1
65
  huggingface-hub==0.30.2
66
  idna==3.10
67
+ inquirerpy==0.3.4
68
+ ipykernel==6.29.5
69
+ ipython==9.0.2
70
+ ipython_pygments_lexers==1.1.1
71
+ isoduration==20.11.0
72
+ itsdangerous==2.2.0
73
+ jedi==0.19.2
74
+ Jinja2==3.1.4
75
+ joblib==1.4.2
76
+ json5==0.12.0
77
+ jsonpointer==3.0.0
78
+ jsonschema==4.23.0
79
+ jsonschema-specifications==2024.10.1
80
+ jupyter-events==0.12.0
81
+ jupyter-lsp==2.2.5
82
+ jupyter_client==8.6.3
83
+ jupyter_core==5.7.2
84
+ jupyter_server==2.15.0
85
+ jupyter_server_terminals==0.5.3
86
+ jupyterlab==4.4.0
87
+ jupyterlab_pygments==0.3.0
88
+ jupyterlab_server==2.27.3
89
+ keras==3.9.2
90
+ kiwisolver==1.4.8
91
+ markdown-it-py==3.0.0
92
  MarkupSafe==3.0.2
93
+ matplotlib==3.10.1
94
+ matplotlib-inline==0.1.7
95
+ mdurl==0.1.2
96
+ mechanize==0.4.10
97
+ mistune==3.1.3
98
+ ml_dtypes==0.5.1
99
  mpmath==1.3.0
100
+ multidict==6.4.3
101
+ multiprocess==0.70.16
102
+ namex==0.0.8
103
+ narwhals==1.35.0
104
+ nbclient==0.10.2
105
+ nbconvert==7.16.6
106
+ nbformat==5.10.4
107
+ nest-asyncio==1.6.0
108
+ networkx==3.3
109
+ notebook==7.4.0
110
+ notebook_shim==0.2.4
111
+ numpy==2.2.4
112
+ nvidia-cublas-cu11==11.11.3.6
113
+ nvidia-cuda-cupti-cu11==11.8.87
114
+ nvidia-cuda-nvrtc-cu11==11.8.89
115
+ nvidia-cuda-runtime-cu11==11.8.89
116
+ nvidia-cudnn-cu11==9.1.0.70
117
+ nvidia-cufft-cu11==10.9.0.58
118
+ nvidia-curand-cu11==10.3.0.86
119
+ nvidia-cusolver-cu11==11.4.1.48
120
+ nvidia-cusparse-cu11==11.7.5.86
121
+ nvidia-nccl-cu11==2.21.5
122
+ nvidia-nvtx-cu11==11.8.86
123
+ optree==0.15.0
124
+ overrides==7.7.0
125
+ packaging==24.2
126
+ pandas==2.2.3
127
+ pandocfilters==1.5.1
128
+ parso==0.8.4
129
+ pexpect==4.9.0
130
+ pfzy==0.3.4
131
+ pillow==11.1.0
132
+ platformdirs==4.3.7
133
+ prometheus_client==0.21.1
134
+ prompt_toolkit==3.0.50
135
+ propcache==0.3.1
136
+ proto-plus==1.26.1
137
+ protobuf==5.29.4
138
+ psutil==7.0.0
139
+ ptyprocess==0.7.0
140
+ pure_eval==0.2.3
141
+ pyarrow==19.0.1
142
+ pyasn1==0.6.1
143
+ pyasn1_modules==0.4.1
144
+ pycparser==2.22
145
+ pydantic==2.10.6
146
+ pydantic_core==2.27.2
147
+ pydeck==0.9.1
148
+ pygame==2.6.1
149
+ Pygments==2.19.1
150
+ pyparsing==3.2.2
151
+ pystyle==2.0
152
+ python-dateutil==2.9.0.post0
153
+ python-dotenv==1.1.0
154
+ python-json-logger==3.3.0
155
+ pytz==2025.1
156
  PyYAML==6.0.2
157
+ pyzmq==26.3.0
158
+ referencing==0.36.2
159
  regex==2024.11.6
160
  requests==2.32.3
161
+ rfc3339-validator==0.1.4
162
+ rfc3986-validator==0.1.1
163
+ rich==14.0.0
164
+ rpds-py==0.24.0
165
+ rsa==4.9
166
  safetensors==0.5.3
167
+ scikit-learn==1.6.1
168
+ scipy==1.15.2
169
+ seaborn==0.13.2
170
+ Send2Trash==1.8.3
171
+ setuptools==70.2.0
172
+ six==1.17.0
173
+ smmap==5.0.2
174
  sniffio==1.3.1
175
+ soupsieve==2.6
176
+ sqlparse==0.5.3
177
+ stack-data==0.6.3
178
  starlette==0.46.2
179
+ streamlit==1.44.1
180
  sympy==1.13.1
181
+ tenacity==9.1.2
182
+ terminado==0.18.1
183
+ threadpoolctl==3.6.0
184
+ tinycss2==1.4.0
185
  tokenizers==0.21.1
186
+ toml==0.10.2
187
+ torch==2.6.0+cu118
188
+ torchaudio==2.6.0+cu118
189
+ torchvision==0.21.0+cu118
190
+ tornado==6.4.2
191
  tqdm==4.67.1
192
+ traitlets==5.14.3
193
  transformers==4.51.3
194
  triton==3.2.0
195
+ types-python-dateutil==2.9.0.20241206
196
+ typing_extensions==4.12.2
197
+ tzdata==2025.2
198
+ uri-template==1.3.0
199
+ uritemplate==4.1.1
200
+ urllib3==1.26.20
201
+ watchdog==6.0.0
202
+ wcwidth==0.2.13
203
+ webcolors==24.11.1
204
+ webencodings==0.5.1
205
+ websocket-client==1.8.0
206
+ websockets==15.0.1
207
+ Werkzeug==3.1.3
208
+ xxhash==3.5.0
209
+ yarl==1.20.0
210
+ zope.interface==7.2