Spaces:
Sleeping
Sleeping
feat(models): expand SubActionModel with all transactional and promotional subactions per Apple ILMessageFilterSubAction
Browse files- README.md +10 -0
- app.py +3 -43
- models/enums.py +38 -0
- models/models.py +25 -0
README.md
CHANGED
|
@@ -9,3 +9,13 @@ license: apache-2.0
|
|
| 9 |
---
|
| 10 |
|
| 11 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
---
|
| 10 |
|
| 11 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 12 |
+
|
| 13 |
+
## Organisation des modèles
|
| 14 |
+
|
| 15 |
+
Les modèles Pydantic (`BaseModel`) sont désormais définis dans `models/models.py` et les énumérations (`Enum`) dans `models/enums.py`. Le fichier `app.py` importe ces classes pour la logique de l'API.
|
| 16 |
+
|
| 17 |
+
- `models/models.py` : Contient les modèles de données (MessageModel, QueryModel, AppModel, InputModel, OutputModel, ReportModel).
|
| 18 |
+
- `models/enums.py` : Contient les énumérations (ActionModel, SubActionModel).
|
| 19 |
+
|
| 20 |
+
Cela facilite la réutilisation et la maintenance du code.
|
| 21 |
+
|
app.py
CHANGED
|
@@ -6,8 +6,6 @@ import re
|
|
| 6 |
import httpx
|
| 7 |
from fastapi import FastAPI
|
| 8 |
from fastapi.responses import JSONResponse, FileResponse
|
| 9 |
-
from pydantic import BaseModel
|
| 10 |
-
from enum import Enum
|
| 11 |
from transformers import pipeline
|
| 12 |
from phishing_datasets import submit_entry
|
| 13 |
from url_tools import extract_urls, resolve_short_url, extract_domain_from_url
|
|
@@ -15,7 +13,8 @@ from urlscan_client import UrlscanClient
|
|
| 15 |
import requests
|
| 16 |
from mnemonic_attack import find_confusable_brand
|
| 17 |
|
| 18 |
-
|
|
|
|
| 19 |
|
| 20 |
app = FastAPI()
|
| 21 |
urlscan = UrlscanClient()
|
|
@@ -25,45 +24,11 @@ for handler in logging.root.handlers[:]:
|
|
| 25 |
logging.root.removeHandler(handler)
|
| 26 |
|
| 27 |
logging.basicConfig(
|
| 28 |
-
level=logging.
|
| 29 |
format='%(levelname)s: %(asctime)s %(message)s',
|
| 30 |
handlers=[logging.StreamHandler(sys.stdout)]
|
| 31 |
)
|
| 32 |
|
| 33 |
-
class MessageModel(BaseModel):
|
| 34 |
-
text: str
|
| 35 |
-
|
| 36 |
-
class QueryModel(BaseModel):
|
| 37 |
-
sender: str
|
| 38 |
-
message: MessageModel
|
| 39 |
-
|
| 40 |
-
class AppModel(BaseModel):
|
| 41 |
-
version: str
|
| 42 |
-
|
| 43 |
-
class InputModel(BaseModel):
|
| 44 |
-
_version: int
|
| 45 |
-
query: QueryModel
|
| 46 |
-
app: AppModel
|
| 47 |
-
|
| 48 |
-
class ActionModel(Enum):
|
| 49 |
-
# Insufficient information to determine an action to take. In a query response, has the effect of allowing the message to be shown normally.
|
| 50 |
-
NONE = 0
|
| 51 |
-
# Allow the message to be shown normally.
|
| 52 |
-
ALLOW = 1
|
| 53 |
-
# Prevent the message from being shown normally, filtered as Junk message.
|
| 54 |
-
JUNK = 2
|
| 55 |
-
# Prevent the message from being shown normally, filtered as Promotional message.
|
| 56 |
-
PROMOTION = 3
|
| 57 |
-
# Prevent the message from being shown normally, filtered as Transactional message.
|
| 58 |
-
TRANSACTION = 4
|
| 59 |
-
|
| 60 |
-
class SubActionModel(Enum):
|
| 61 |
-
NONE = 0
|
| 62 |
-
|
| 63 |
-
class OutputModel(BaseModel):
|
| 64 |
-
action: ActionModel
|
| 65 |
-
sub_action: SubActionModel
|
| 66 |
-
|
| 67 |
pipe = pipeline(task="text-classification", model="mrm8488/bert-tiny-finetuned-sms-spam-detection")
|
| 68 |
|
| 69 |
@app.get("/.well-known/apple-app-site-association", include_in_schema=False)
|
|
@@ -117,7 +82,6 @@ def predict(model: InputModel) -> OutputModel:
|
|
| 117 |
case 'promotion':
|
| 118 |
return OutputModel(action=ActionModel.PROMOTION, sub_action=SubActionModel.NONE)
|
| 119 |
|
| 120 |
-
|
| 121 |
# Brand usurpation detection using confusables
|
| 122 |
confusable_brand = find_confusable_brand(text)
|
| 123 |
if confusable_brand:
|
|
@@ -197,10 +161,6 @@ def predict(model: InputModel) -> OutputModel:
|
|
| 197 |
logging.info(f"[FINAL ACTION] {action}")
|
| 198 |
return OutputModel(action=action, sub_action=SubActionModel.NONE)
|
| 199 |
|
| 200 |
-
class ReportModel(BaseModel):
|
| 201 |
-
sender: str
|
| 202 |
-
message: str
|
| 203 |
-
|
| 204 |
@app.post("/report")
|
| 205 |
def report(model: ReportModel):
|
| 206 |
submit_entry(model.sender, model.message)
|
|
|
|
| 6 |
import httpx
|
| 7 |
from fastapi import FastAPI
|
| 8 |
from fastapi.responses import JSONResponse, FileResponse
|
|
|
|
|
|
|
| 9 |
from transformers import pipeline
|
| 10 |
from phishing_datasets import submit_entry
|
| 11 |
from url_tools import extract_urls, resolve_short_url, extract_domain_from_url
|
|
|
|
| 13 |
import requests
|
| 14 |
from mnemonic_attack import find_confusable_brand
|
| 15 |
|
| 16 |
+
from models.models import MessageModel, QueryModel, AppModel, InputModel, OutputModel, ReportModel
|
| 17 |
+
from models.enums import ActionModel, SubActionModel
|
| 18 |
|
| 19 |
app = FastAPI()
|
| 20 |
urlscan = UrlscanClient()
|
|
|
|
| 24 |
logging.root.removeHandler(handler)
|
| 25 |
|
| 26 |
logging.basicConfig(
|
| 27 |
+
level=logging.INFO,
|
| 28 |
format='%(levelname)s: %(asctime)s %(message)s',
|
| 29 |
handlers=[logging.StreamHandler(sys.stdout)]
|
| 30 |
)
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
pipe = pipeline(task="text-classification", model="mrm8488/bert-tiny-finetuned-sms-spam-detection")
|
| 33 |
|
| 34 |
@app.get("/.well-known/apple-app-site-association", include_in_schema=False)
|
|
|
|
| 82 |
case 'promotion':
|
| 83 |
return OutputModel(action=ActionModel.PROMOTION, sub_action=SubActionModel.NONE)
|
| 84 |
|
|
|
|
| 85 |
# Brand usurpation detection using confusables
|
| 86 |
confusable_brand = find_confusable_brand(text)
|
| 87 |
if confusable_brand:
|
|
|
|
| 161 |
logging.info(f"[FINAL ACTION] {action}")
|
| 162 |
return OutputModel(action=action, sub_action=SubActionModel.NONE)
|
| 163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
@app.post("/report")
|
| 165 |
def report(model: ReportModel):
|
| 166 |
submit_entry(model.sender, model.message)
|
models/enums.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
|
| 3 |
+
class ActionModel(Enum):
|
| 4 |
+
"""
|
| 5 |
+
Enum representing the main actions for message filtering, according to Apple's ILMessageFilterAction:
|
| 6 |
+
https://developer.apple.com/documentation/identitylookup/ilmessagefilteraction
|
| 7 |
+
"""
|
| 8 |
+
NONE = 0 # No action determined, message is handled normally
|
| 9 |
+
ALLOW = 1 # Allow the message to be shown
|
| 10 |
+
JUNK = 2 # Filter as junk
|
| 11 |
+
PROMOTION = 3 # Filter as promotion (extension, not in Apple doc)
|
| 12 |
+
TRANSACTION = 4 # Filter as transaction (extension, not in Apple doc)
|
| 13 |
+
# Apple only defines NONE, ALLOW, JUNK; PROMOTION and TRANSACTION are for extension
|
| 14 |
+
|
| 15 |
+
class SubActionModel(Enum):
|
| 16 |
+
"""
|
| 17 |
+
Enum representing sub-actions for message filtering, including all transactional and promotional subactions as described in Apple's documentation:
|
| 18 |
+
https://developer.apple.com/documentation/identitylookup/ilmessagefiltersubaction
|
| 19 |
+
"""
|
| 20 |
+
# General
|
| 21 |
+
NONE = 0 # Allows the system to show the message unfiltered due to insufficient information to determine an action.
|
| 22 |
+
REPORT_JUNK = 1 # Report as junk
|
| 23 |
+
|
| 24 |
+
# Transactional Subactions
|
| 25 |
+
TRANSACTIONAL_OTHERS = 100 # Filtered as an Others message.
|
| 26 |
+
TRANSACTIONAL_FINANCE = 101 # Filtered as a Finance message.
|
| 27 |
+
TRANSACTIONAL_ORDERS = 102 # Filtered as an Orders (eCommerce) message.
|
| 28 |
+
TRANSACTIONAL_REMINDERS = 103 # Filtered as a Reminder message.
|
| 29 |
+
TRANSACTIONAL_HEALTH = 104 # Filtered as a Health message.
|
| 30 |
+
TRANSACTIONAL_WEATHER = 105 # Filtered as a Weather message.
|
| 31 |
+
TRANSACTIONAL_CARRIER = 106 # Filtered as a Carrier message.
|
| 32 |
+
TRANSACTIONAL_REWARDS = 107 # Filtered as a Rewards message.
|
| 33 |
+
TRANSACTIONAL_PUBLIC_SERVICES = 108 # Filtered as a Government/Public Services message.
|
| 34 |
+
|
| 35 |
+
# Promotional Subactions
|
| 36 |
+
PROMOTIONAL_OTHERS = 200 # Filtered as an Others message.
|
| 37 |
+
PROMOTIONAL_OFFERS = 201 # Filtered as an Offers message.
|
| 38 |
+
PROMOTIONAL_COUPONS = 202 # Filtered as a Coupons message.
|
models/models.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pydantic import BaseModel
|
| 2 |
+
from enum import Enum
|
| 3 |
+
|
| 4 |
+
class MessageModel(BaseModel):
|
| 5 |
+
text: str
|
| 6 |
+
|
| 7 |
+
class QueryModel(BaseModel):
|
| 8 |
+
sender: str
|
| 9 |
+
message: MessageModel
|
| 10 |
+
|
| 11 |
+
class AppModel(BaseModel):
|
| 12 |
+
version: str
|
| 13 |
+
|
| 14 |
+
class InputModel(BaseModel):
|
| 15 |
+
_version: int
|
| 16 |
+
query: QueryModel
|
| 17 |
+
app: AppModel
|
| 18 |
+
|
| 19 |
+
class OutputModel(BaseModel):
|
| 20 |
+
action: 'ActionModel'
|
| 21 |
+
sub_action: 'SubActionModel'
|
| 22 |
+
|
| 23 |
+
class ReportModel(BaseModel):
|
| 24 |
+
sender: str
|
| 25 |
+
message: str
|