Repository navigation
Expand file tree
/
Copy pathapp.py
More file actions
105 lines (85 loc) · 3.11 KB
/
Copy pathapp.py
File metadata and controls
105 lines (85 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""Week 06 — Plagiarism Checker (Flask backend, LCS via DP)"""
from flask import Flask, jsonify, request, send_from_directory
app = Flask(__name__, static_folder="static")
# ---------------------------------------------------------------------------
# LCS — Dynamic Programming
# ---------------------------------------------------------------------------
def lcs(text_a, text_b):
"""
Longest Common Subsequence length using bottom-up DP.
Returns: (lcs_length, dp_table)
"""
m, n = len(text_a), len(text_b)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text_a[i - 1] == text_b[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n], dp
def backtrack_lcs(dp, text_a, text_b):
"""Backtrack through the DP table to recover the actual LCS string."""
i, j = len(text_a), len(text_b)
result = []
while i > 0 and j > 0:
if text_a[i - 1] == text_b[j - 1]:
result.append(text_a[i - 1])
i -= 1
j -= 1
elif dp[i - 1][j] >= dp[i][j - 1]:
i -= 1
else:
j -= 1
return "".join(reversed(result))
def similarity_score(text_a, text_b, lcs_length):
"""Similarity = LCS length / max(len(A), len(B)) * 100."""
if not text_a and not text_b:
return 100.0
if not text_a or not text_b:
return 0.0
return lcs_length / max(len(text_a), len(text_b)) * 100
def generate_diff(dp, text_a, text_b):
"""
Walk the DP table from (m, n) to (0, 0) and classify each character as
'match' (in LCS), 'removed' (only in A), or 'added' (only in B).
"""
i, j = len(text_a), len(text_b)
diff = []
while i > 0 or j > 0:
if i > 0 and j > 0 and text_a[i - 1] == text_b[j - 1]:
diff.append({"char": text_a[i - 1], "status": "match"})
i -= 1
j -= 1
elif j > 0 and (i == 0 or dp[i][j - 1] >= dp[i - 1][j]):
diff.append({"char": text_b[j - 1], "status": "added"})
j -= 1
else:
diff.append({"char": text_a[i - 1], "status": "removed"})
i -= 1
return list(reversed(diff))
# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------
@app.route("/")
def index():
return send_from_directory("static", "index.html")
@app.route("/check", methods=["POST"])
def check():
data = request.get_json() or {}
text_a = data.get("text_a", "")
text_b = data.get("text_b", "")
length, dp = lcs(text_a, text_b)
lcs_str = backtrack_lcs(dp, text_a, text_b)
score = similarity_score(text_a, text_b, length)
diff = generate_diff(dp, text_a, text_b)
return jsonify({
"similarity": round(score, 2),
"lcs_length": length,
"lcs_string": lcs_str,
"len_a": len(text_a),
"len_b": len(text_b),
"diff": diff,
})
if __name__ == "__main__":
app.run(debug=True, port=5000)