rizzdeep commited on
Commit
bae565d
·
verified ·
1 Parent(s): a25fc54

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +32 -19
main.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import FastAPI, File, UploadFile, HTTPException, Request
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from pydantic import BaseModel
4
  import pandas as pd
@@ -9,23 +9,21 @@ from transformers import AutoTokenizer, AutoModelForCausalLM
9
  import uvicorn
10
  import nest_asyncio
11
  import os
 
12
 
13
- # Allow uvicorn to run inside Colab (safe for Spaces / Render too)
14
  nest_asyncio.apply()
 
15
  # ========== Environment Setup ==========
16
  device = "cpu"
17
-
18
- # Set offload folder path
19
  offload_dir = "/data/model_offload"
20
  os.makedirs(offload_dir, exist_ok=True)
21
 
22
  adapter_path = "./phi3-ds-expert-lora"
23
  base_model_id = "microsoft/Phi-3-mini-4k-instruct"
24
 
25
- # Load LoRA config
26
  peft_config = PeftConfig.from_pretrained(adapter_path)
27
 
28
- # Load base model
29
  base_model = AutoModelForCausalLM.from_pretrained(
30
  base_model_id,
31
  torch_dtype="auto",
@@ -36,7 +34,6 @@ base_model = AutoModelForCausalLM.from_pretrained(
36
  tokenizer = AutoTokenizer.from_pretrained(base_model_id)
37
  tokenizer.pad_token = tokenizer.eos_token
38
 
39
- # Load LoRA adapter with explicit offload_dir
40
  model = PeftModel.from_pretrained(
41
  base_model,
42
  adapter_path,
@@ -46,7 +43,6 @@ model = PeftModel.from_pretrained(
46
  model.to(device)
47
  model.eval()
48
 
49
-
50
  # ========== FastAPI App ==========
51
  app = FastAPI()
52
 
@@ -62,6 +58,9 @@ app.add_middleware(
62
  # Global dataset storage
63
  uploaded_df = None
64
 
 
 
 
65
  # ========== Pydantic Request Schema ==========
66
  class PromptRequest(BaseModel):
67
  prompt: str
@@ -85,18 +84,22 @@ def generate_prompt(prompt_text, df=None):
85
  with torch.no_grad():
86
  outputs = model.generate(
87
  **inputs,
88
- max_new_tokens=128, # fast generation
89
- do_sample=False, # deterministic
90
  eos_token_id=tokenizer.eos_token_id,
91
  pad_token_id=tokenizer.eos_token_id
92
  )
93
 
94
- # Decode only the new generated tokens (ignoring prompt)
95
  generated_tokens = outputs[0][input_length:]
96
  response = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
97
 
98
  return response
99
 
 
 
 
 
 
100
  # ========== API Endpoints ==========
101
 
102
  @app.get("/")
@@ -104,24 +107,37 @@ def read_root():
104
  return {"message": "🚀 API is live and running!"}
105
 
106
  @app.post("/generate")
107
- async def generate(request: PromptRequest):
108
  if not request.prompt.strip():
109
  raise HTTPException(status_code=400, detail="Prompt cannot be empty.")
110
- result = generate_prompt(request.prompt, df=uploaded_df)
111
- return {"response": result}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  MAX_FILE_SIZE = 15 * 1024 * 1024 # 15 MB
114
 
115
  @app.post("/upload")
116
  async def upload_file(request: Request, file: UploadFile = File(...)):
117
- # Check content-length header if available
118
  content_length = request.headers.get("content-length")
119
  if content_length and int(content_length) > MAX_FILE_SIZE:
120
  raise HTTPException(status_code=413, detail="File too large. Max size is 15 MB.")
121
 
122
  content = await file.read()
123
 
124
- # Double-check actual content size after reading
125
  if len(content) > MAX_FILE_SIZE:
126
  raise HTTPException(status_code=413, detail="File too large. Max size is 15 MB.")
127
 
@@ -132,9 +148,6 @@ async def upload_file(request: Request, file: UploadFile = File(...)):
132
  uploaded_df = pd.read_excel(io.BytesIO(content))
133
  else:
134
  raise HTTPException(status_code=400, detail="Only CSV and Excel files are supported.")
135
-
136
-
137
-
138
  except Exception as e:
139
  raise HTTPException(status_code=500, detail=f"Error while uploading file: {str(e)}")
140
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Request, BackgroundTasks
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from pydantic import BaseModel
4
  import pandas as pd
 
9
  import uvicorn
10
  import nest_asyncio
11
  import os
12
+ import uuid
13
 
14
+ # Allow uvicorn to run inside Colab / Spaces
15
  nest_asyncio.apply()
16
+
17
  # ========== Environment Setup ==========
18
  device = "cpu"
 
 
19
  offload_dir = "/data/model_offload"
20
  os.makedirs(offload_dir, exist_ok=True)
21
 
22
  adapter_path = "./phi3-ds-expert-lora"
23
  base_model_id = "microsoft/Phi-3-mini-4k-instruct"
24
 
 
25
  peft_config = PeftConfig.from_pretrained(adapter_path)
26
 
 
27
  base_model = AutoModelForCausalLM.from_pretrained(
28
  base_model_id,
29
  torch_dtype="auto",
 
34
  tokenizer = AutoTokenizer.from_pretrained(base_model_id)
35
  tokenizer.pad_token = tokenizer.eos_token
36
 
 
37
  model = PeftModel.from_pretrained(
38
  base_model,
39
  adapter_path,
 
43
  model.to(device)
44
  model.eval()
45
 
 
46
  # ========== FastAPI App ==========
47
  app = FastAPI()
48
 
 
58
  # Global dataset storage
59
  uploaded_df = None
60
 
61
+ # In-memory job results store
62
+ job_results = {}
63
+
64
  # ========== Pydantic Request Schema ==========
65
  class PromptRequest(BaseModel):
66
  prompt: str
 
84
  with torch.no_grad():
85
  outputs = model.generate(
86
  **inputs,
87
+ max_new_tokens=128,
88
+ do_sample=False,
89
  eos_token_id=tokenizer.eos_token_id,
90
  pad_token_id=tokenizer.eos_token_id
91
  )
92
 
 
93
  generated_tokens = outputs[0][input_length:]
94
  response = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
95
 
96
  return response
97
 
98
+ # ========== Background Inference Task ==========
99
+ def run_inference(prompt_text, job_id, df=None):
100
+ result = generate_prompt(prompt_text, df)
101
+ job_results[job_id] = result
102
+
103
  # ========== API Endpoints ==========
104
 
105
  @app.get("/")
 
107
  return {"message": "🚀 API is live and running!"}
108
 
109
  @app.post("/generate")
110
+ async def generate(request: PromptRequest, background_tasks: BackgroundTasks):
111
  if not request.prompt.strip():
112
  raise HTTPException(status_code=400, detail="Prompt cannot be empty.")
113
+
114
+ job_id = str(uuid.uuid4())
115
+ job_results[job_id] = "processing"
116
+ background_tasks.add_task(run_inference, request.prompt, job_id, uploaded_df)
117
+ return {"job_id": job_id}
118
+
119
+ @app.get("/status/{job_id}")
120
+ async def job_status(job_id: str):
121
+ if job_id not in job_results:
122
+ raise HTTPException(status_code=404, detail="Job ID not found")
123
+
124
+ result = job_results[job_id]
125
+ if result == "processing":
126
+ return {"status": "processing"}
127
+ else:
128
+ return {"status": "complete", "result": result}
129
 
130
  MAX_FILE_SIZE = 15 * 1024 * 1024 # 15 MB
131
 
132
  @app.post("/upload")
133
  async def upload_file(request: Request, file: UploadFile = File(...)):
134
+ global uploaded_df
135
  content_length = request.headers.get("content-length")
136
  if content_length and int(content_length) > MAX_FILE_SIZE:
137
  raise HTTPException(status_code=413, detail="File too large. Max size is 15 MB.")
138
 
139
  content = await file.read()
140
 
 
141
  if len(content) > MAX_FILE_SIZE:
142
  raise HTTPException(status_code=413, detail="File too large. Max size is 15 MB.")
143
 
 
148
  uploaded_df = pd.read_excel(io.BytesIO(content))
149
  else:
150
  raise HTTPException(status_code=400, detail="Only CSV and Excel files are supported.")
 
 
 
151
  except Exception as e:
152
  raise HTTPException(status_code=500, detail=f"Error while uploading file: {str(e)}")
153