Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
# app.py
|
| 2 |
import asyncio
|
| 3 |
import re
|
| 4 |
from typing import Literal
|
|
@@ -9,8 +8,8 @@ from llama_cpp import Llama
|
|
| 9 |
|
| 10 |
# ---------------- MODEL CONFIG ---------------- #
|
| 11 |
|
| 12 |
-
#
|
| 13 |
-
MODEL_PATH = "
|
| 14 |
|
| 15 |
# CPU settings for llama.cpp
|
| 16 |
N_THREADS = 4
|
|
@@ -21,7 +20,7 @@ N_GPU_LAYERS = 0
|
|
| 21 |
# Concurrency limit
|
| 22 |
MAX_CONCURRENT_REQUESTS = 6
|
| 23 |
|
| 24 |
-
#
|
| 25 |
END_TOKEN = "###END_OF_RESPONSE###"
|
| 26 |
|
| 27 |
print("Loading model:", MODEL_PATH)
|
|
@@ -41,7 +40,7 @@ app = FastAPI(title="FormatAI Humanizer Backend")
|
|
| 41 |
|
| 42 |
app.add_middleware(
|
| 43 |
CORSMiddleware,
|
| 44 |
-
allow_origins=["*"],
|
| 45 |
allow_methods=["*"],
|
| 46 |
allow_headers=["*"],
|
| 47 |
)
|
|
@@ -62,29 +61,29 @@ STYLE_PROMPTS = {
|
|
| 62 |
"professional": (
|
| 63 |
"STYLE: PROFESSIONAL\n"
|
| 64 |
"Rewrite the user's text in a STRICTLY professional, corporate, formal tone. "
|
| 65 |
-
"Use respectful and clear business language. Do NOT add explanations.
|
| 66 |
-
f"then write {END_TOKEN}."
|
| 67 |
),
|
| 68 |
|
| 69 |
"casual": (
|
| 70 |
"STYLE: CASUAL\n"
|
| 71 |
-
"Rewrite the user's text in a friendly,
|
| 72 |
-
"Do NOT add explanations.
|
| 73 |
-
f"{END_TOKEN}."
|
| 74 |
),
|
| 75 |
|
| 76 |
"academic": (
|
| 77 |
"STYLE: ACADEMIC\n"
|
| 78 |
-
"Rewrite the user's text in formal academic language suitable for scholarly
|
| 79 |
-
"Use
|
| 80 |
-
f"then write {END_TOKEN}."
|
| 81 |
),
|
| 82 |
|
| 83 |
"marketing": (
|
| 84 |
"STYLE: MARKETING\n"
|
| 85 |
-
"Rewrite the user's text
|
| 86 |
-
"Use
|
| 87 |
-
f"then write {END_TOKEN}."
|
| 88 |
),
|
| 89 |
}
|
| 90 |
|
|
@@ -92,14 +91,14 @@ STYLE_PROMPTS = {
|
|
| 92 |
# ---------------- HELPERS ---------------- #
|
| 93 |
|
| 94 |
def clean_output(raw: str) -> str:
|
| 95 |
-
"""
|
| 96 |
if not raw:
|
| 97 |
return ""
|
| 98 |
|
| 99 |
-
# Remove system markers
|
| 100 |
raw = re.sub(r"<\|/?(system|assistant|user|end)\|>", "", raw, flags=re.I)
|
| 101 |
|
| 102 |
-
#
|
| 103 |
if END_TOKEN in raw:
|
| 104 |
raw = raw.split(END_TOKEN)[0]
|
| 105 |
|
|
@@ -109,9 +108,8 @@ def clean_output(raw: str) -> str:
|
|
| 109 |
|
| 110 |
|
| 111 |
def build_prompt(text: str, style: str) -> str:
|
| 112 |
-
"""
|
| 113 |
system = STYLE_PROMPTS[style]
|
| 114 |
-
|
| 115 |
return (
|
| 116 |
f"<|system|>\n{system}\n\n"
|
| 117 |
f"<|user|>\n{text}\n\n"
|
|
@@ -157,11 +155,11 @@ async def transform(req: TransformRequest):
|
|
| 157 |
if req.style not in STYLE_PROMPTS:
|
| 158 |
raise HTTPException(400, "Invalid style")
|
| 159 |
|
| 160 |
-
#
|
| 161 |
temperature = 0.65 if req.style == "marketing" else 0.25
|
| 162 |
|
| 163 |
prompt = build_prompt(text, req.style)
|
| 164 |
-
transformed = await call_llm(prompt, temperature
|
| 165 |
|
| 166 |
return {
|
| 167 |
"original": text,
|
|
@@ -174,7 +172,7 @@ async def transform(req: TransformRequest):
|
|
| 174 |
|
| 175 |
@app.post("/api/humanize")
|
| 176 |
async def humanize(req: HumanizeRequest):
|
| 177 |
-
"""
|
| 178 |
prompt = build_prompt(req.text.strip(), "casual")
|
| 179 |
out = await call_llm(prompt, temperature=0.4)
|
| 180 |
return {"result": out}
|
|
|
|
|
|
|
| 1 |
import asyncio
|
| 2 |
import re
|
| 3 |
from typing import Literal
|
|
|
|
| 8 |
|
| 9 |
# ---------------- MODEL CONFIG ---------------- #
|
| 10 |
|
| 11 |
+
# Model is in ROOT of the repository, not inside a folder
|
| 12 |
+
MODEL_PATH = "/code/Phi-3.1-mini-4k-instruct-IQ2_M.gguf"
|
| 13 |
|
| 14 |
# CPU settings for llama.cpp
|
| 15 |
N_THREADS = 4
|
|
|
|
| 20 |
# Concurrency limit
|
| 21 |
MAX_CONCURRENT_REQUESTS = 6
|
| 22 |
|
| 23 |
+
# Token to force stopping the generation
|
| 24 |
END_TOKEN = "###END_OF_RESPONSE###"
|
| 25 |
|
| 26 |
print("Loading model:", MODEL_PATH)
|
|
|
|
| 40 |
|
| 41 |
app.add_middleware(
|
| 42 |
CORSMiddleware,
|
| 43 |
+
allow_origins=["*"], # Vercel frontend allowed
|
| 44 |
allow_methods=["*"],
|
| 45 |
allow_headers=["*"],
|
| 46 |
)
|
|
|
|
| 61 |
"professional": (
|
| 62 |
"STYLE: PROFESSIONAL\n"
|
| 63 |
"Rewrite the user's text in a STRICTLY professional, corporate, formal tone. "
|
| 64 |
+
"Use respectful and clear business language. Do NOT add explanations. "
|
| 65 |
+
f"Output ONLY the rewritten text, then write {END_TOKEN}."
|
| 66 |
),
|
| 67 |
|
| 68 |
"casual": (
|
| 69 |
"STYLE: CASUAL\n"
|
| 70 |
+
"Rewrite the user's text in a friendly, conversational, relaxed tone. "
|
| 71 |
+
"Use contractions and natural flow. Do NOT add explanations. "
|
| 72 |
+
f"Output ONLY the rewritten text, then write {END_TOKEN}."
|
| 73 |
),
|
| 74 |
|
| 75 |
"academic": (
|
| 76 |
"STYLE: ACADEMIC\n"
|
| 77 |
+
"Rewrite the user's text in precise, formal academic language suitable for scholarly writing. "
|
| 78 |
+
"Use objective vocabulary and clear structure. Do NOT add explanations. "
|
| 79 |
+
f"Output ONLY the rewritten text, then write {END_TOKEN}."
|
| 80 |
),
|
| 81 |
|
| 82 |
"marketing": (
|
| 83 |
"STYLE: MARKETING\n"
|
| 84 |
+
"Rewrite the user's text into persuasive, compelling marketing language. "
|
| 85 |
+
"Use emotional hooks, strong benefits, and engaging tone. Do NOT add explanations. "
|
| 86 |
+
f"Output ONLY the rewritten text, then write {END_TOKEN}."
|
| 87 |
),
|
| 88 |
}
|
| 89 |
|
|
|
|
| 91 |
# ---------------- HELPERS ---------------- #
|
| 92 |
|
| 93 |
def clean_output(raw: str) -> str:
|
| 94 |
+
"""Trim unwanted tokens and cleanup."""
|
| 95 |
if not raw:
|
| 96 |
return ""
|
| 97 |
|
| 98 |
+
# Remove system markers if any appear
|
| 99 |
raw = re.sub(r"<\|/?(system|assistant|user|end)\|>", "", raw, flags=re.I)
|
| 100 |
|
| 101 |
+
# Cut off at END_TOKEN
|
| 102 |
if END_TOKEN in raw:
|
| 103 |
raw = raw.split(END_TOKEN)[0]
|
| 104 |
|
|
|
|
| 108 |
|
| 109 |
|
| 110 |
def build_prompt(text: str, style: str) -> str:
|
| 111 |
+
"""Build prompt for the selected style."""
|
| 112 |
system = STYLE_PROMPTS[style]
|
|
|
|
| 113 |
return (
|
| 114 |
f"<|system|>\n{system}\n\n"
|
| 115 |
f"<|user|>\n{text}\n\n"
|
|
|
|
| 155 |
if req.style not in STYLE_PROMPTS:
|
| 156 |
raise HTTPException(400, "Invalid style")
|
| 157 |
|
| 158 |
+
# Marketing = more creativity
|
| 159 |
temperature = 0.65 if req.style == "marketing" else 0.25
|
| 160 |
|
| 161 |
prompt = build_prompt(text, req.style)
|
| 162 |
+
transformed = await call_llm(prompt, temperature)
|
| 163 |
|
| 164 |
return {
|
| 165 |
"original": text,
|
|
|
|
| 172 |
|
| 173 |
@app.post("/api/humanize")
|
| 174 |
async def humanize(req: HumanizeRequest):
|
| 175 |
+
"""Fallback endpoint — always uses casual."""
|
| 176 |
prompt = build_prompt(req.text.strip(), "casual")
|
| 177 |
out = await call_llm(prompt, temperature=0.4)
|
| 178 |
return {"result": out}
|