GoshawkVortexAI commited on
Commit
ff296bd
·
verified ·
1 Parent(s): 3a5e4d6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -0
app.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """LexiAI – Space sunucusu (tek dosya).
2
+ Ana dizindeki LoRA adapter'ını Qwen2.5-7B-Instruct üzerine yükler,
3
+ index.html'i "/" adresinde yayınlar, yorumu "/comment" adresinden akıtır.
4
+ Token gerekmez. GPU'lu Space gerekir (en az ~24 GB VRAM, ya da 4-bit için QUANT=4)."""
5
+ import os, json, threading
6
+ import torch, uvicorn
7
+ from fastapi import FastAPI, Request
8
+ from fastapi.responses import FileResponse, StreamingResponse, JSONResponse
9
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, BitsAndBytesConfig
10
+ from peft import PeftModel
11
+
12
+ HERE = os.path.dirname(os.path.abspath(__file__))
13
+ BASE = "Qwen/Qwen2.5-7B-Instruct"
14
+ SYSTEM = ("Sen Türk hukuku konusunda yardımcı bir asistansın. Bir sınıflandırıcının sonucunu ve belge metnini alırsın. "
15
+ "Türkçe, en fazla 120 kelimeyle yorumla: 1) Belge ne ve sınıflandırma makul mü, "
16
+ "2) Dikkat edilmesi gereken noktalar/riskler, 3) Önerilen sonraki adım. Kısa maddeler kullan. "
17
+ "Kesin hukuki tavsiye verme.")
18
+
19
+ tok = AutoTokenizer.from_pretrained(HERE if os.path.exists(os.path.join(HERE, "tokenizer.json")) else BASE)
20
+ kw = dict(device_map="auto")
21
+ if os.environ.get("QUANT") == "4":
22
+ kw["quantization_config"] = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_compute_dtype=torch.bfloat16)
23
+ else:
24
+ kw["torch_dtype"] = torch.bfloat16
25
+ model = AutoModelForCausalLM.from_pretrained(BASE, **kw)
26
+ if os.path.exists(os.path.join(HERE, "adapter_config.json")):
27
+ model = PeftModel.from_pretrained(model, HERE)
28
+ model.eval()
29
+ lock = threading.Lock()
30
+
31
+ app = FastAPI()
32
+
33
+ @app.get("/")
34
+ def home():
35
+ return FileResponse(os.path.join(HERE, "index.html"))
36
+
37
+ @app.get("/health")
38
+ def health():
39
+ return {"ok": True}
40
+
41
+ @app.post("/comment")
42
+ async def comment(req: Request):
43
+ try:
44
+ d = await req.json()
45
+ except Exception:
46
+ return JSONResponse({"error": "Geçersiz istek"}, status_code=400)
47
+ info = str(d.get("info", ""))[:1000]
48
+ text = str(d.get("text", ""))[:3000]
49
+ msgs = [{"role": "system", "content": SYSTEM},
50
+ {"role": "user", "content": info + "\n\nBelge metni:\n" + text}]
51
+ ids = tok.apply_chat_template(msgs, add_generation_prompt=True, return_tensors="pt").to(model.device)
52
+ streamer = TextIteratorStreamer(tok, skip_prompt=True, skip_special_tokens=True)
53
+
54
+ def work():
55
+ with lock, torch.inference_mode():
56
+ model.generate(input_ids=ids, attention_mask=torch.ones_like(ids), streamer=streamer,
57
+ max_new_tokens=350, do_sample=True, temperature=0.3, top_p=0.9)
58
+
59
+ threading.Thread(target=work, daemon=True).start()
60
+ return StreamingResponse((t for t in streamer), media_type="text/plain; charset=utf-8")
61
+
62
+ if __name__ == "__main__":
63
+ uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))