Shubhi324 commited on
Commit
be02d40
·
verified ·
1 Parent(s): 10d2b80

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py.py +118 -0
  2. moderator.py +37 -0
  3. requirements.txt +8 -0
app.py.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Depends, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from sqlalchemy.orm import Session
4
+ from typing import List
5
+ import database, schemas, moderator
6
+
7
+ # Init DB
8
+ database.init_db()
9
+
10
+ app = FastAPI(title="SafeStream API")
11
+
12
+ # Allow all origins for dev
13
+ app.add_middleware(
14
+ CORSMiddleware,
15
+ allow_origins=["*"],
16
+ allow_credentials=True,
17
+ allow_methods=["*"],
18
+ allow_headers=["*"],
19
+ )
20
+
21
+ def get_db():
22
+ db = database.SessionLocal()
23
+ try:
24
+ yield db
25
+ finally:
26
+ db.close()
27
+
28
+ @app.on_event("startup")
29
+ def startup_event():
30
+ # Seed data if empty
31
+ db = database.SessionLocal()
32
+ if db.query(database.Video).count() == 0:
33
+ # Using real YouTube IDs for the iframe
34
+ seed_videos = [
35
+ database.Video(title="Daily Vlog #102", url="dQw4w9WgXcQ", description="Just another day in the life. Comment below!"),
36
+ database.Video(title="Gaming Highlights", url="jNQXAC9IVRw", description="Insane plays from last night."),
37
+ database.Video(title="Relaxing Rain Sounds", url="q76bMs-NwRk", description="Sleep aid.")
38
+ ]
39
+ db.add_all(seed_videos)
40
+ db.commit()
41
+ db.close()
42
+
43
+ @app.get("/videos", response_model=List[schemas.Video])
44
+ def get_videos(db: Session = Depends(get_db)):
45
+ return db.query(database.Video).all()
46
+
47
+ @app.get("/videos/{video_id}", response_model=schemas.Video)
48
+ def get_video(video_id: int, db: Session = Depends(get_db)):
49
+ video = db.query(database.Video).filter(database.Video.id == video_id).first()
50
+ if not video:
51
+ raise HTTPException(status_code=404, detail="Video not found")
52
+ return video
53
+
54
+
55
+ @app.get("/videos/{video_id}/comments", response_model=List[schemas.Comment])
56
+ def get_comments(video_id: int, db: Session = Depends(get_db)):
57
+ return db.query(database.Comment).filter(database.Comment.video_id == video_id).all()
58
+
59
+ @app.post("/comments", response_model=schemas.Comment)
60
+ def create_comment(comment: schemas.CommentCreate, db: Session = Depends(get_db)):
61
+ # 1. Analyze for toxicity
62
+ analysis = moderator.moderator.analyze(comment.text)
63
+
64
+ # 2. Save to DB
65
+ db_comment = database.Comment(
66
+ video_id=comment.video_id,
67
+ user=comment.user,
68
+ text=comment.text,
69
+ timestamp=comment.timestamp,
70
+ is_toxic=analysis["is_toxic"],
71
+ toxicity_score=analysis["score"],
72
+ flagged_reason=analysis["reason"]
73
+ )
74
+ db.add(db_comment)
75
+ db.commit()
76
+ db.refresh(db_comment)
77
+ return db_comment
78
+
79
+ @app.delete("/comments")
80
+ def clear_comments(db: Session = Depends(get_db)):
81
+ db.query(database.Comment).delete()
82
+ db.commit()
83
+ return {"message": "All comments cleared"}
84
+
85
+ @app.get("/stats")
86
+ def get_stats(db: Session = Depends(get_db)):
87
+ comments = db.query(database.Comment).all()
88
+ total = len(comments)
89
+ toxic_comments = [c for c in comments if c.is_toxic]
90
+ toxic_count = len(toxic_comments)
91
+
92
+ # Custom Classification Logic for Demo
93
+ types = {
94
+ "Insult": 0,
95
+ "Identity Hate": 0,
96
+ "Threat": 0,
97
+ "Online Harassment": 0
98
+ }
99
+
100
+ for c in toxic_comments:
101
+ text = c.text.lower()
102
+ if any(w in text for w in ["kill", "die", "hurt", "attack", "gun", "shoot", "murder"]):
103
+ types["Threat"] += 1
104
+ elif any(w in text for w in ["hate", "racist", "gay", "lesbian", "black", "white", "jew", "muslim", "women", "men", "trans"]):
105
+ types["Identity Hate"] += 1
106
+ elif any(w in text for w in ["stupid", "idiot", "dumb", "ugly", "fat", "loser", "moron", "coward"]):
107
+ types["Insult"] += 1
108
+ else:
109
+ # Catch-all for other toxic comments
110
+ types["Online Harassment"] += 1
111
+
112
+ return {
113
+ "total_comments": total,
114
+ "toxic_comments": toxic_count,
115
+ "toxic_ratio": (toxic_count/total) if total > 0 else 0,
116
+ "types_breakdown": [{"name": k, "value": v} for k, v in types.items()]
117
+ }
118
+
moderator.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+ import torch
3
+
4
+ class ToxicityModel:
5
+ def __init__(self):
6
+ print("Loading Toxicity Model...")
7
+ # Using a model that is good for toxic comment detection
8
+ # 'distilbert-base-uncased-finetuned-sst-2-english' is Sentiment (Pos/Neg)
9
+ # Neg is a decent proxy for toxic for a demo.
10
+ # Alternatively: 'unitary/toxic-bert' is better but heavier.
11
+ try:
12
+ self.classifier = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
13
+ except Exception as e:
14
+ print(f"Error loading model: {e}")
15
+ self.classifier = None
16
+
17
+ def analyze(self, text: str):
18
+ if not self.classifier:
19
+ return {"is_toxic": False, "score": 0.0, "reason": "Model inactive"}
20
+
21
+ results = self.classifier(text)
22
+ # Format: [{'label': 'NEGATIVE', 'score': 0.99}]
23
+ result = results[0]
24
+
25
+ label = result['label']
26
+ score = result['score']
27
+
28
+ # Heuristic: If Negative and high confidence, flag it.
29
+ is_toxic = (label == 'NEGATIVE' and score > 0.6)
30
+
31
+ return {
32
+ "is_toxic": is_toxic,
33
+ "score": score,
34
+ "reason": f"Classified as {label} with confidence {score:.2f}"
35
+ }
36
+
37
+ moderator = ToxicityModel()
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pydantic
4
+ transformers
5
+ torch
6
+ scikit-learn
7
+ python-multipart
8
+ sqlalchemy