Spaces:
Running
Running
eheguy commited on
Commit ·
ee5c5ad
1
Parent(s): 8194c3e
Remove detector and evaluator, simplify API
Browse files- detector.py +0 -40
- evaluator.py +0 -22
- main.py +5 -25
- requirements.txt +0 -5
detector.py
DELETED
|
@@ -1,40 +0,0 @@
|
|
| 1 |
-
import torch
|
| 2 |
-
from transformers import pipeline
|
| 3 |
-
|
| 4 |
-
# Cache the pipeline at module level — load once, reuse forever
|
| 5 |
-
_pipeline = None
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
def _get_pipeline():
|
| 9 |
-
global _pipeline
|
| 10 |
-
if _pipeline is None:
|
| 11 |
-
_pipeline = pipeline(
|
| 12 |
-
"text-classification",
|
| 13 |
-
model="Hello-SimpleAI/chatgpt-detector-roberta",
|
| 14 |
-
device=0 if torch.cuda.is_available() else -1,
|
| 15 |
-
)
|
| 16 |
-
return _pipeline
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
def get_ai_score(text: str) -> float:
|
| 20 |
-
"""
|
| 21 |
-
Returns a float between 0.0 and 1.0 representing the probability
|
| 22 |
-
that the text was AI-generated.
|
| 23 |
-
1.0 = definitely AI
|
| 24 |
-
0.0 = definitely human
|
| 25 |
-
"""
|
| 26 |
-
# Model has 512 token limit — truncate to be safe
|
| 27 |
-
truncated = text[:512]
|
| 28 |
-
|
| 29 |
-
result = _get_pipeline()(truncated)[0]
|
| 30 |
-
|
| 31 |
-
label = result["label"].upper()
|
| 32 |
-
score = result["score"]
|
| 33 |
-
|
| 34 |
-
# This model returns:
|
| 35 |
-
# "ChatGPT" label = AI-generated
|
| 36 |
-
# "Human" label = human-written
|
| 37 |
-
if label == "CHATGPT":
|
| 38 |
-
return round(score, 4)
|
| 39 |
-
else:
|
| 40 |
-
return round(1 - score, 4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
evaluator.py
DELETED
|
@@ -1,22 +0,0 @@
|
|
| 1 |
-
from sentence_transformers import SentenceTransformer, util
|
| 2 |
-
|
| 3 |
-
# Cache the SentenceTransformer model globally after first load
|
| 4 |
-
_model = None
|
| 5 |
-
|
| 6 |
-
def get_similarity(text_a: str, text_b: str) -> float:
|
| 7 |
-
global _model
|
| 8 |
-
if _model is None:
|
| 9 |
-
_model = SentenceTransformer('all-MiniLM-L6-v2')
|
| 10 |
-
|
| 11 |
-
# Encode both inputs into embeddings
|
| 12 |
-
embedding_a = _model.encode(text_a, convert_to_tensor=True)
|
| 13 |
-
embedding_b = _model.encode(text_b, convert_to_tensor=True)
|
| 14 |
-
|
| 15 |
-
# Compute cosine similarity
|
| 16 |
-
similarity = util.cos_sim(embedding_a, embedding_b)
|
| 17 |
-
|
| 18 |
-
return float(similarity[0][0])
|
| 19 |
-
|
| 20 |
-
def meaning_preserved(text_a: str, text_b: str, threshold: float = 0.85) -> bool:
|
| 21 |
-
similarity = get_similarity(text_a, text_b)
|
| 22 |
-
return similarity >= threshold
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main.py
CHANGED
|
@@ -8,8 +8,6 @@ from dotenv import load_dotenv
|
|
| 8 |
load_dotenv()
|
| 9 |
|
| 10 |
from humanizer import humanize_text
|
| 11 |
-
from detector import get_ai_score
|
| 12 |
-
from evaluator import get_similarity, meaning_preserved
|
| 13 |
|
| 14 |
from fastapi.middleware.cors import CORSMiddleware
|
| 15 |
|
|
@@ -33,35 +31,17 @@ class HumanizeRequest(BaseModel):
|
|
| 33 |
class HumanizeResponse(BaseModel):
|
| 34 |
humanized: str
|
| 35 |
mode: str
|
| 36 |
-
score_before: float
|
| 37 |
-
score_after: float
|
| 38 |
-
similarity_score: float
|
| 39 |
-
meaning_preserved: bool
|
| 40 |
|
| 41 |
@app.post("/humanize", response_model=HumanizeResponse)
|
| 42 |
async def humanize(request: HumanizeRequest):
|
| 43 |
if request.mode not in ("simple", "standard", "enhanced"):
|
| 44 |
-
raise HTTPException(
|
| 45 |
-
|
|
|
|
|
|
|
| 46 |
try:
|
| 47 |
-
score_before = get_ai_score(request.text)
|
| 48 |
humanized_text = await humanize_text(request.text, mode=request.mode)
|
| 49 |
-
|
| 50 |
-
if not meaning_preserved(request.text, humanized_text):
|
| 51 |
-
humanized_text = await humanize_text(request.text, mode=request.mode)
|
| 52 |
-
|
| 53 |
-
score_after = get_ai_score(humanized_text)
|
| 54 |
-
similarity_score = get_similarity(request.text, humanized_text)
|
| 55 |
-
preserved = meaning_preserved(request.text, humanized_text)
|
| 56 |
-
|
| 57 |
-
return HumanizeResponse(
|
| 58 |
-
humanized=humanized_text,
|
| 59 |
-
mode=request.mode,
|
| 60 |
-
score_before=score_before,
|
| 61 |
-
score_after=score_after,
|
| 62 |
-
similarity_score=similarity_score,
|
| 63 |
-
meaning_preserved=preserved
|
| 64 |
-
)
|
| 65 |
except Exception as e:
|
| 66 |
import traceback
|
| 67 |
raise HTTPException(status_code=500, detail=traceback.format_exc())
|
|
|
|
| 8 |
load_dotenv()
|
| 9 |
|
| 10 |
from humanizer import humanize_text
|
|
|
|
|
|
|
| 11 |
|
| 12 |
from fastapi.middleware.cors import CORSMiddleware
|
| 13 |
|
|
|
|
| 31 |
class HumanizeResponse(BaseModel):
|
| 32 |
humanized: str
|
| 33 |
mode: str
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
@app.post("/humanize", response_model=HumanizeResponse)
|
| 36 |
async def humanize(request: HumanizeRequest):
|
| 37 |
if request.mode not in ("simple", "standard", "enhanced"):
|
| 38 |
+
raise HTTPException(
|
| 39 |
+
status_code=400,
|
| 40 |
+
detail="mode must be one of: simple, standard, enhanced"
|
| 41 |
+
)
|
| 42 |
try:
|
|
|
|
| 43 |
humanized_text = await humanize_text(request.text, mode=request.mode)
|
| 44 |
+
return HumanizeResponse(humanized=humanized_text, mode=request.mode)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
except Exception as e:
|
| 46 |
import traceback
|
| 47 |
raise HTTPException(status_code=500, detail=traceback.format_exc())
|
requirements.txt
CHANGED
|
@@ -2,8 +2,3 @@ fastapi
|
|
| 2 |
uvicorn
|
| 3 |
python-dotenv
|
| 4 |
groq
|
| 5 |
-
|
| 6 |
-
# Large installs: pip install may take a few minutes
|
| 7 |
-
transformers
|
| 8 |
-
torch
|
| 9 |
-
sentence-transformers
|
|
|
|
| 2 |
uvicorn
|
| 3 |
python-dotenv
|
| 4 |
groq
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|