viskav commited on
Commit
7865292
Β·
verified Β·
1 Parent(s): f23e11d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -0
app.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from pydantic import BaseModel, Field
4
+ from llama_cpp import Llama
5
+ import re
6
+
7
+ # ==================== MODEL CONFIG ====================
8
+ MODEL_REPO = "bartowski/Phi-3.5-mini-instruct-GGUF"
9
+ MODEL_FILE = "Phi-3.5-mini-instruct-Q4_K_M.gguf"
10
+
11
+ print("πŸš€ Loading Phi-3.5 Mini (Fast Summarizer)...")
12
+ llm = Llama.from_pretrained(
13
+ repo_id=MODEL_REPO,
14
+ filename=MODEL_FILE,
15
+ n_threads=4,
16
+ n_ctx=2048, # Enough for summarization
17
+ n_batch=256,
18
+ n_gpu_layers=0,
19
+ verbose=False,
20
+ )
21
+ print("βœ… Model loaded")
22
+
23
+ # ==================== FASTAPI ====================
24
+ app = FastAPI(
25
+ title="AI Summarizer",
26
+ description="Fast & Accurate AI Text Summarizer",
27
+ version="1.0"
28
+ )
29
+
30
+ app.add_middleware(
31
+ CORSMiddleware,
32
+ allow_origins=["*"],
33
+ allow_methods=["*"],
34
+ allow_headers=["*"],
35
+ )
36
+
37
+ # ==================== REQUEST ====================
38
+ class SummarizeRequest(BaseModel):
39
+ text: str = Field(..., min_length=1, max_length=2000)
40
+ length: str = "short" # short | medium | long
41
+
42
+ # ==================== PROMPTS ====================
43
+ LENGTH_INSTRUCTIONS = {
44
+ "short": "Summarize in 2–3 concise sentences.",
45
+ "medium": "Summarize in 4–5 clear sentences.",
46
+ "long": "Summarize in a detailed paragraph.",
47
+ }
48
+
49
+ # ==================== CLEAN OUTPUT ====================
50
+ def clean_output(text: str) -> str:
51
+ text = re.sub(r"<\|.*?\|>", "", text)
52
+ text = re.sub(r"\s+", " ", text)
53
+ return text.strip()
54
+
55
+ # ==================== ENDPOINT ====================
56
+ @app.post("/api/summarize")
57
+ async def summarize(req: SummarizeRequest):
58
+ text = req.text.strip()
59
+ if not text:
60
+ raise HTTPException(status_code=400, detail="Text cannot be empty")
61
+
62
+ length_instruction = LENGTH_INSTRUCTIONS.get(req.length, LENGTH_INSTRUCTIONS["short"])
63
+
64
+ prompt = (
65
+ f"<|user|>\n"
66
+ f"You are an expert text summarizer.\n"
67
+ f"{length_instruction}\n\n"
68
+ f"Text:\n{text}\n"
69
+ f"<|end|>\n"
70
+ f"<|assistant|>\n"
71
+ )
72
+
73
+ try:
74
+ output = llm(
75
+ prompt,
76
+ max_tokens=140 if req.length == "short" else 220,
77
+ temperature=0.3, # Low = factual
78
+ top_p=0.9,
79
+ top_k=40,
80
+ repeat_penalty=1.05,
81
+ stop=["<|end|>", "<|user|>"],
82
+ echo=False,
83
+ )
84
+
85
+ summary = clean_output(output["choices"][0]["text"])
86
+
87
+ if not summary:
88
+ raise RuntimeError("Empty summary")
89
+
90
+ return {
91
+ "original_length": len(text),
92
+ "summary": summary,
93
+ "length": req.length,
94
+ "success": True
95
+ }
96
+
97
+ except Exception as e:
98
+ print("❌ Summarization error:", e)
99
+ raise HTTPException(status_code=500, detail="Summarization failed")
100
+
101
+ @app.get("/")
102
+ def health():
103
+ return {"status": "ok", "model": MODEL_FILE}