videopix commited on
Commit
eb023cc
·
verified ·
1 Parent(s): 256d97e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -26
app.py CHANGED
@@ -1,13 +1,11 @@
1
  import io
2
  import asyncio
3
- import threading
4
- import time
5
- from fastapi import FastAPI, File, UploadFile
6
  from fastapi.responses import JSONResponse, HTMLResponse
7
  from PIL import Image
8
  import torch
9
  from transformers import AutoProcessor, AutoModelForCausalLM
10
- import requests
11
 
12
  # ---------------------------------------------------
13
  # FastAPI App
@@ -16,14 +14,31 @@ app = FastAPI(title="Florence Image Caption API")
16
 
17
  device = "cuda" if torch.cuda.is_available() else "cpu"
18
 
19
- # Lazy load model on first request (prevents HF timeout)
20
  processor = None
21
  model = None
22
  model_lock = asyncio.Lock()
23
 
 
 
 
 
 
 
 
 
 
 
 
24
 
 
 
 
 
 
 
 
25
  async def load_model():
26
- """Load Florence model only when first needed."""
27
  global processor, model
28
 
29
  if model is None:
@@ -38,7 +53,6 @@ async def load_model():
38
 
39
 
40
  def run_caption(image: Image.Image) -> str:
41
- """Perform caption generation."""
42
  inputs = processor(
43
  text="<MORE_DETAILED_CAPTION>",
44
  images=image,
@@ -67,17 +81,17 @@ def run_caption(image: Image.Image) -> str:
67
  # API Endpoint
68
  # ---------------------------------------------------
69
  @app.post("/img2caption")
70
- async def img2caption(file: UploadFile = File(...)):
 
 
 
71
  try:
72
- # Ensure model is loaded
73
  async with model_lock:
74
  await load_model()
75
 
76
- # Read and convert image
77
  data = await file.read()
78
  image = Image.open(io.BytesIO(data)).convert("RGB")
79
 
80
- # Caption
81
  caption = run_caption(image)
82
 
83
  return {"caption": caption}
@@ -87,10 +101,10 @@ async def img2caption(file: UploadFile = File(...)):
87
 
88
 
89
  # ---------------------------------------------------
90
- # Simple HTML UI
91
  # ---------------------------------------------------
92
  @app.get("/", response_class=HTMLResponse)
93
- def ui():
94
  return """
95
  <!DOCTYPE html>
96
  <html>
@@ -99,19 +113,11 @@ def ui():
99
  <style>
100
  body { font-family: Arial; max-width: 650px; margin: 40px auto; }
101
  h2 { text-align: center; }
102
- #preview {
103
- width: 100%; margin-top: 15px; display: none;
104
- border-radius: 8px;
105
- }
106
- #captionBox {
107
- margin-top: 20px; padding: 15px;
108
- background: #eee; border-radius: 6px; display: none;
109
- }
110
- button {
111
- padding: 12px; width: 100%; margin-top: 10px;
112
- background: #4A90E2; color: white; border: none;
113
- border-radius: 6px; cursor: pointer; font-size: 16px;
114
- }
115
  button:hover { background: #357ABD; }
116
  </style>
117
  </head>
@@ -127,6 +133,13 @@ def ui():
127
  <div id="captionBox"></div>
128
 
129
  <script>
 
 
 
 
 
 
 
130
  const imageInput = document.getElementById("imageInput");
131
  const preview = document.getElementById("preview");
132
  const captionBox = document.getElementById("captionBox");
@@ -154,6 +167,7 @@ def ui():
154
 
155
  const res = await fetch("/img2caption", {
156
  method: "POST",
 
157
  body: form
158
  });
159
 
@@ -167,6 +181,9 @@ def ui():
167
  """
168
 
169
 
 
 
 
170
  def keep_alive():
171
  pass
172
 
 
1
  import io
2
  import asyncio
3
+ import os
4
+ from fastapi import FastAPI, File, UploadFile, Depends, Header, HTTPException
 
5
  from fastapi.responses import JSONResponse, HTMLResponse
6
  from PIL import Image
7
  import torch
8
  from transformers import AutoProcessor, AutoModelForCausalLM
 
9
 
10
  # ---------------------------------------------------
11
  # FastAPI App
 
14
 
15
  device = "cuda" if torch.cuda.is_available() else "cpu"
16
 
17
+ # Lazy-loaded model and processor
18
  processor = None
19
  model = None
20
  model_lock = asyncio.Lock()
21
 
22
+ # ---------------------------------------------------
23
+ # Token Authentication
24
+ # ---------------------------------------------------
25
+
26
+ API_TOKEN = os.getenv("img2caption") # your secret token from variables
27
+
28
+ async def verify_token(authorization: str = Header(None)):
29
+ if authorization is None or not authorization.startswith("Bearer "):
30
+ raise HTTPException(status_code=401, detail="Missing Authorization header")
31
+
32
+ token = authorization.split("Bearer ")[-1].strip()
33
 
34
+ if token != API_TOKEN:
35
+ raise HTTPException(status_code=403, detail="Invalid token")
36
+
37
+
38
+ # ---------------------------------------------------
39
+ # Lazy Florence Model Load
40
+ # ---------------------------------------------------
41
  async def load_model():
 
42
  global processor, model
43
 
44
  if model is None:
 
53
 
54
 
55
  def run_caption(image: Image.Image) -> str:
 
56
  inputs = processor(
57
  text="<MORE_DETAILED_CAPTION>",
58
  images=image,
 
81
  # API Endpoint
82
  # ---------------------------------------------------
83
  @app.post("/img2caption")
84
+ async def img2caption(
85
+ file: UploadFile = File(...),
86
+ _: None = Depends(verify_token)
87
+ ):
88
  try:
 
89
  async with model_lock:
90
  await load_model()
91
 
 
92
  data = await file.read()
93
  image = Image.open(io.BytesIO(data)).convert("RGB")
94
 
 
95
  caption = run_caption(image)
96
 
97
  return {"caption": caption}
 
101
 
102
 
103
  # ---------------------------------------------------
104
+ # Protected HTML UI
105
  # ---------------------------------------------------
106
  @app.get("/", response_class=HTMLResponse)
107
+ async def ui(_: None = Depends(verify_token)):
108
  return """
109
  <!DOCTYPE html>
110
  <html>
 
113
  <style>
114
  body { font-family: Arial; max-width: 650px; margin: 40px auto; }
115
  h2 { text-align: center; }
116
+ #preview { width: 100%; margin-top: 15px; display: none; border-radius: 8px; }
117
+ #captionBox { margin-top: 20px; padding: 15px; background: #eee; border-radius: 6px; display: none; }
118
+ button { padding: 12px; width: 100%; margin-top: 10px;
119
+ background: #4A90E2; color: white; border: none;
120
+ border-radius: 6px; cursor: pointer; font-size: 16px; }
 
 
 
 
 
 
 
 
121
  button:hover { background: #357ABD; }
122
  </style>
123
  </head>
 
133
  <div id="captionBox"></div>
134
 
135
  <script>
136
+ let token = sessionStorage.getItem("authToken");
137
+
138
+ if (!token) {
139
+ token = prompt("Enter access token:");
140
+ sessionStorage.setItem("authToken", token);
141
+ }
142
+
143
  const imageInput = document.getElementById("imageInput");
144
  const preview = document.getElementById("preview");
145
  const captionBox = document.getElementById("captionBox");
 
167
 
168
  const res = await fetch("/img2caption", {
169
  method: "POST",
170
+ headers: { "Authorization": "Bearer " + token },
171
  body: form
172
  });
173
 
 
181
  """
182
 
183
 
184
+ # ---------------------------------------------------
185
+ # Run locally
186
+ # ---------------------------------------------------
187
  def keep_alive():
188
  pass
189