obaes commited on
Commit
71680bc
·
verified ·
1 Parent(s): 61d1342

Upload 10 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ static/image.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: fraudio
3
  emoji: 🐢
4
  colorFrom: green
5
  colorTo: purple
@@ -8,18 +8,18 @@ sdk_version: 6.3.0
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
11
- short_description: fraudio
12
  ---
13
 
14
  # 🛡️ Documentary Fraud Management MCP Service
15
 
16
- A robust documentary fraud detection service using Google Gemini 3 Flash and Nano Banana Pro, integrated with a Gradio UI and serving as an MCP (Model Context Protocol) server.
17
 
18
  ## ✨ Features
19
 
20
  - **Dual-Model Analysis**:
21
- - **Gemini 3 Flash**: Handles complex reasoning, entity extraction (Names, Dates, IDs), and overall fraud scoring.
22
- - **Gemini Nano Banana Pro**: Performs critical visual analysis to detect clones, font mismatches, and retouching.
23
  - **Support for Images & PDFs**: Automatically converts PDF pages to images for visual manipulation detection.
24
  - **Dynamic Context**: Prompts include real-time date/time (currently 2026-01-21) for accurate expiration and inconsistency checks.
25
  - **Historical Explorer**:
@@ -33,7 +33,7 @@ A robust documentary fraud detection service using Google Gemini 3 Flash and Nan
33
 
34
  ### Prerequisites
35
  - Python 3.10+
36
- - Google API Key (Gemini)
37
 
38
  ### Installation
39
  1. Clone the repository and navigate to the directory.
@@ -65,7 +65,7 @@ A robust documentary fraud detection service using Google Gemini 3 Flash and Nan
65
  ## 🛠️ Architecture
66
 
67
  - `app.py`: Gradio interface, session management, and persistent file handling.
68
- - `fraud_analyzer.py`: Core logic for Gemini integration, PDF conversion, and metadata extraction.
69
  - `vector_service.py`: Fingerprinting and history storage using ChromaDB.
70
  - `uploads/`: Persistent storage for analyzed documents.
71
  - `chroma_db/`: Vector database storage.
 
1
  ---
2
+ title: fraudoo
3
  emoji: 🐢
4
  colorFrom: green
5
  colorTo: purple
 
8
  app_file: app.py
9
  pinned: false
10
  license: apache-2.0
11
+ short_description: fraudoo
12
  ---
13
 
14
  # 🛡️ Documentary Fraud Management MCP Service
15
 
16
+ A robust documentary fraud detection service using LLM Services 3 Flash and Nano Banana Pro, integrated with a Gradio UI and serving as an MCP (Model Context Protocol) server.
17
 
18
  ## ✨ Features
19
 
20
  - **Dual-Model Analysis**:
21
+ - **LLM Services 3 Flash**: Handles complex reasoning, entity extraction (Names, Dates, IDs), and overall fraud scoring.
22
+ - **LLM Services Nano Banana Pro**: Performs critical visual analysis to detect clones, font mismatches, and retouching.
23
  - **Support for Images & PDFs**: Automatically converts PDF pages to images for visual manipulation detection.
24
  - **Dynamic Context**: Prompts include real-time date/time (currently 2026-01-21) for accurate expiration and inconsistency checks.
25
  - **Historical Explorer**:
 
33
 
34
  ### Prerequisites
35
  - Python 3.10+
36
+ - Google API Key (LLM Services)
37
 
38
  ### Installation
39
  1. Clone the repository and navigate to the directory.
 
65
  ## 🛠️ Architecture
66
 
67
  - `app.py`: Gradio interface, session management, and persistent file handling.
68
+ - `fraud_analyzer.py`: Core logic for LLM Services integration, PDF conversion, and metadata extraction.
69
  - `vector_service.py`: Fingerprinting and history storage using ChromaDB.
70
  - `uploads/`: Persistent storage for analyzed documents.
71
  - `chroma_db/`: Vector database storage.
app.py CHANGED
@@ -12,14 +12,33 @@ import shutil
12
  API_KEY = os.environ.get("GOOGLE_API_KEY")
13
  analyzer = FraudAnalyzer(API_KEY) if API_KEY else None
14
  vector_db = VectorService()
15
- UPLOAD_DIR = "./uploads"
 
16
  os.makedirs(UPLOAD_DIR, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def parse_flash_metrics(analysis_text):
19
  """Attempt to parse structured fields from Flash's response."""
20
  metrics = {"label": "Unknown", "amount": "0", "fraud_score": "0"}
21
  try:
22
- # Sometimes Gemini wraps in ```json ... ```
23
  clean_text = analysis_text
24
  json_match = re.search(r"```json\s*(\{.*?\})\s*```", analysis_text, re.DOTALL)
25
  if json_match:
@@ -44,7 +63,7 @@ def parse_flash_metrics(analysis_text):
44
 
45
  def process_document(file_path):
46
  """
47
- Analyzes a document for fraud using Gemini 3 Flash and Nano Banana.
48
  Extracts structured data, detects duplicates, and generates a fraud score.
49
 
50
  Args:
@@ -65,7 +84,7 @@ def process_document(file_path):
65
  dup_msg = f"⚠️ DUPLICATE DETECTED: {dup_result['type']}"
66
 
67
  result = analyzer.analyze_document(persistent_path)
68
- metrics = parse_flash_metrics(result['gemini_analysis'])
69
 
70
  doc_id = str(uuid.uuid4())[:8]
71
 
@@ -73,7 +92,7 @@ def process_document(file_path):
73
  formatted_score = f"{score_val}/100"
74
 
75
  meta = result['metadata']
76
- meta['gemini_analysis'] = result['gemini_analysis']
77
  meta['filename'] = filename
78
  meta['label'] = metrics['label']
79
  meta['amount'] = metrics['amount']
@@ -82,7 +101,7 @@ def process_document(file_path):
82
 
83
  vector_db.add_document(persistent_path, doc_id, metadata={k: str(v) for k, v in meta.items() if v is not None})
84
 
85
- return f"ID: {doc_id} | {dup_msg}", result['gemini_analysis'], json.dumps(result['metadata'], indent=2), doc_id, persistent_path, get_history_df()
86
 
87
  def get_history_df():
88
  """
@@ -143,13 +162,14 @@ def retrieve_document(doc_id):
143
  return f"Not found: {doc_id}", None, None, None
144
 
145
  meta = doc['metadata']
146
- analysis = meta.get('gemini_analysis', "No analysis.")
 
147
  file_path = meta.get('file_path')
148
 
149
  if not os.path.exists(file_path):
150
  return f"Error: File missing at {file_path}", analysis, "{}", None
151
 
152
- display_meta = {k: v for k, v in meta.items() if k not in ['gemini_analysis', 'file_path']}
153
  return f"Retrieved: {meta.get('filename')}", analysis, json.dumps(display_meta, indent=2), file_path
154
 
155
  css = """
@@ -157,6 +177,9 @@ body { background-color: #f0f2f5; font-family: 'Inter', sans-serif; }
157
  .container { max-width: 1000px; margin: auto; padding: 20px; }
158
  .header { text-align: center; margin-bottom: 40px; }
159
  .result-box { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
 
 
 
160
  """
161
 
162
  with gr.Blocks() as demo:
@@ -204,6 +227,24 @@ with gr.Blocks() as demo:
204
  detail_analysis = gr.Markdown()
205
  detail_meta = gr.Code(language="json")
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  # Events
208
  submit_btn.click(
209
  fn=process_document,
@@ -233,4 +274,9 @@ with gr.Blocks() as demo:
233
 
234
  if __name__ == "__main__":
235
  # Ensure UPLOAD_DIR exists and is used
236
- demo.launch(mcp_server=True, theme=gr.themes.Soft(), css=css)
 
 
 
 
 
 
12
  API_KEY = os.environ.get("GOOGLE_API_KEY")
13
  analyzer = FraudAnalyzer(API_KEY) if API_KEY else None
14
  vector_db = VectorService()
15
+ UPLOAD_DIR = os.path.abspath("./uploads")
16
+ STATIC_DIR = os.path.abspath("./static")
17
  os.makedirs(UPLOAD_DIR, exist_ok=True)
18
+ os.makedirs(STATIC_DIR, exist_ok=True)
19
+
20
+ def load_static_html(filename):
21
+ """Read a static HTML file and return its content for embedding."""
22
+ path = os.path.join(STATIC_DIR, filename)
23
+ if os.path.exists(path):
24
+ with open(path, "r", encoding="utf-8") as f:
25
+ content = f.read()
26
+ # Extract style blocks
27
+ styles = re.findall(r"(<style>.*?</style>)", content, re.DOTALL | re.IGNORECASE)
28
+ # Extract body content
29
+ body_match = re.search(r"<body[^>]*>(.*?)</body>", content, re.DOTALL | re.IGNORECASE)
30
+
31
+ style_str = "\n".join(styles)
32
+ body_str = body_match.group(1) if body_match else content
33
+
34
+ return f'<div class="static-page-container">{style_str}{body_str}</div>'
35
+ return f"Error: {filename} not found."
36
 
37
  def parse_flash_metrics(analysis_text):
38
  """Attempt to parse structured fields from Flash's response."""
39
  metrics = {"label": "Unknown", "amount": "0", "fraud_score": "0"}
40
  try:
41
+ # Sometimes LLM Services wraps in ```json ... ```
42
  clean_text = analysis_text
43
  json_match = re.search(r"```json\s*(\{.*?\})\s*```", analysis_text, re.DOTALL)
44
  if json_match:
 
63
 
64
  def process_document(file_path):
65
  """
66
+ Analyzes a document for fraud using LLM Services 3 Flash and Nano Banana.
67
  Extracts structured data, detects duplicates, and generates a fraud score.
68
 
69
  Args:
 
84
  dup_msg = f"⚠️ DUPLICATE DETECTED: {dup_result['type']}"
85
 
86
  result = analyzer.analyze_document(persistent_path)
87
+ metrics = parse_flash_metrics(result['llm_analysis'])
88
 
89
  doc_id = str(uuid.uuid4())[:8]
90
 
 
92
  formatted_score = f"{score_val}/100"
93
 
94
  meta = result['metadata']
95
+ meta['llm_analysis'] = result['llm_analysis']
96
  meta['filename'] = filename
97
  meta['label'] = metrics['label']
98
  meta['amount'] = metrics['amount']
 
101
 
102
  vector_db.add_document(persistent_path, doc_id, metadata={k: str(v) for k, v in meta.items() if v is not None})
103
 
104
+ return f"ID: {doc_id} | {dup_msg}", result['llm_analysis'], json.dumps(result['metadata'], indent=2), doc_id, persistent_path, get_history_df()
105
 
106
  def get_history_df():
107
  """
 
162
  return f"Not found: {doc_id}", None, None, None
163
 
164
  meta = doc['metadata']
165
+ # Fallback for historical 'gemini_analysis' key
166
+ analysis = meta.get('llm_analysis', meta.get('gemini_analysis', "No analysis."))
167
  file_path = meta.get('file_path')
168
 
169
  if not os.path.exists(file_path):
170
  return f"Error: File missing at {file_path}", analysis, "{}", None
171
 
172
+ display_meta = {k: v for k, v in meta.items() if k not in ['llm_analysis', 'gemini_analysis', 'file_path']}
173
  return f"Retrieved: {meta.get('filename')}", analysis, json.dumps(display_meta, indent=2), file_path
174
 
175
  css = """
 
177
  .container { max-width: 1000px; margin: auto; padding: 20px; }
178
  .header { text-align: center; margin-bottom: 40px; }
179
  .result-box { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
180
+ .footer-links { text-align: center; padding: 20px; border-top: 1px solid #e2e8f0; margin-top: 40px; }
181
+ .footer-links a { margin: 0 15px; text-decoration: none; color: #4f46e5; font-weight: 600; }
182
+ .help-card { background: white; padding: 2rem; border-radius: 15px; border-left: 5px solid #4f46e5; margin-bottom: 1rem; }
183
  """
184
 
185
  with gr.Blocks() as demo:
 
227
  detail_analysis = gr.Markdown()
228
  detail_meta = gr.Code(language="json")
229
 
230
+ with gr.TabItem("Help & Legal", id=3):
231
+ with gr.Column(elem_classes="container"):
232
+ gr.Markdown("## 🐢 Fraudoo Support & Legal")
233
+
234
+ with gr.Tabs():
235
+ with gr.TabItem("📧 Support"):
236
+ gr.HTML(load_static_html("support.html"))
237
+ with gr.TabItem("⚖️ Privacy Policy"):
238
+ gr.HTML(load_static_html("privacy.html"))
239
+ with gr.TabItem("📜 Terms of Service"):
240
+ gr.HTML(load_static_html("terms.html"))
241
+
242
+ gr.HTML(f"""
243
+ <div class="footer-links">
244
+ <span style="color: #64748b; margin-left: 20px;">© 2026 Fraudoo 🐢</span>
245
+ </div>
246
+ """)
247
+
248
  # Events
249
  submit_btn.click(
250
  fn=process_document,
 
274
 
275
  if __name__ == "__main__":
276
  # Ensure UPLOAD_DIR exists and is used
277
+ demo.launch(
278
+ mcp_server=True,
279
+ theme=gr.themes.Soft(),
280
+ css=css,
281
+ allowed_paths=[STATIC_DIR, UPLOAD_DIR]
282
+ )
fraud_analyzer.py CHANGED
@@ -1,5 +1,5 @@
1
  import os
2
- import google.generativeai as genai
3
  from PIL import Image
4
  import io
5
  import puremagic
@@ -9,11 +9,11 @@ from datetime import datetime
9
 
10
  class FraudAnalyzer:
11
  def __init__(self, api_key):
12
- genai.configure(api_key=api_key)
13
- # Gemini 3 Flash for reasoning and extraction
14
- self.model_flash = genai.GenerativeModel('gemini-3-flash-preview')
15
  # Nano Banana for specific image-centric analysis
16
- self.model_nano = genai.GenerativeModel('nano-banana-pro-preview')
17
 
18
  def analyze_document(self, file_path):
19
  """Perform visual and structural analysis + data extraction."""
@@ -56,7 +56,10 @@ class FraudAnalyzer:
56
 
57
  if image_input:
58
  # Dual analysis for images (or PDF converted to image)
59
- visual_resp = self.model_nano.generate_content([visual_prompt, image_input])
 
 
 
60
 
61
  # Flash for Extraction & Combined Reasoning
62
  content_to_flash = [
@@ -68,17 +71,23 @@ class FraudAnalyzer:
68
  content_to_flash.append(f"Extracted Text: {text_content}")
69
  content_to_flash.append(image_input)
70
 
71
- combined_resp = self.model_flash.generate_content(content_to_flash)
 
 
 
72
 
73
  return {
74
- "gemini_analysis": f"Visual Report (Nano Banana):\n{visual_resp.text}\n\nFinal Reasoning (Flash):\n{combined_resp.text}",
75
  "metadata": metadata
76
  }
77
  else:
78
  # Fallback for text-only or unsupported image conversion
79
- combined_resp = self.model_flash.generate_content([extraction_prompt, f"Metadata: {metadata}", f"Text: {text_content}"])
 
 
 
80
  return {
81
- "gemini_analysis": f"Reasoning (Flash):\n{combined_resp.text}",
82
  "metadata": metadata
83
  }
84
 
 
1
  import os
2
+ from google import genai
3
  from PIL import Image
4
  import io
5
  import puremagic
 
9
 
10
  class FraudAnalyzer:
11
  def __init__(self, api_key):
12
+ self.client = genai.Client(api_key=api_key)
13
+ # LLM Services 3 Flash for reasoning and extraction
14
+ self.model_flash = 'gemini-3-flash-preview'
15
  # Nano Banana for specific image-centric analysis
16
+ self.model_nano = 'nano-banana-pro-preview'
17
 
18
  def analyze_document(self, file_path):
19
  """Perform visual and structural analysis + data extraction."""
 
56
 
57
  if image_input:
58
  # Dual analysis for images (or PDF converted to image)
59
+ visual_resp = self.client.models.generate_content(
60
+ model=self.model_nano,
61
+ contents=[visual_prompt, image_input]
62
+ )
63
 
64
  # Flash for Extraction & Combined Reasoning
65
  content_to_flash = [
 
71
  content_to_flash.append(f"Extracted Text: {text_content}")
72
  content_to_flash.append(image_input)
73
 
74
+ combined_resp = self.client.models.generate_content(
75
+ model=self.model_flash,
76
+ contents=content_to_flash
77
+ )
78
 
79
  return {
80
+ "llm_analysis": f"Visual Report (Nano Banana):\n{visual_resp.text}\n\nFinal Reasoning (Flash):\n{combined_resp.text}",
81
  "metadata": metadata
82
  }
83
  else:
84
  # Fallback for text-only or unsupported image conversion
85
+ combined_resp = self.client.models.generate_content(
86
+ model=self.model_flash,
87
+ contents=[extraction_prompt, f"Metadata: {metadata}", f"Text: {text_content}"]
88
+ )
89
  return {
90
+ "llm_analysis": f"Reasoning (Flash):\n{combined_resp.text}",
91
  "metadata": metadata
92
  }
93
 
mcp_server.py CHANGED
@@ -28,14 +28,14 @@ def validate_document(file_path: str) -> str:
28
  if dup_result:
29
  dup_info = f"\n[!] DUPLICATE DETECTED: This document matches a previously seen file ({dup_result['type']} match).\n"
30
 
31
- # 2. Perform Gemini & Metadata analysis
32
  analysis = analyzer.analyze_document(file_path)
33
 
34
  # 3. Store in vector DB for future checks
35
  doc_id = os.path.basename(file_path)
36
  vector_db.add_document(file_path, doc_id)
37
 
38
- return f"{dup_info}\n--- Analysis ---\n{analysis['gemini_analysis']}\n\n--- Metadata ---\n{analysis['metadata']}"
39
 
40
  @mcp.tool()
41
  def list_history() -> str:
 
28
  if dup_result:
29
  dup_info = f"\n[!] DUPLICATE DETECTED: This document matches a previously seen file ({dup_result['type']} match).\n"
30
 
31
+ # 2. Perform LLM Services & Metadata analysis
32
  analysis = analyzer.analyze_document(file_path)
33
 
34
  # 3. Store in vector DB for future checks
35
  doc_id = os.path.basename(file_path)
36
  vector_db.add_document(file_path, doc_id)
37
 
38
+ return f"{dup_info}\n--- Analysis ---\n{analysis['llm_analysis']}\n\n--- Metadata ---\n{analysis['metadata']}"
39
 
40
  @mcp.tool()
41
  def list_history() -> str:
requirements.txt CHANGED
@@ -28,9 +28,9 @@ google-api-core==2.29.0
28
  google-api-python-client==2.188.0
29
  google-auth==2.48.0rc0
30
  google-auth-httplib2==0.3.0
31
- google-generativeai==0.8.6
32
  googleapis-common-protos==1.72.0
33
- gradio==6.3.0
34
  gradio_client==2.0.3
35
  groovy==0.1.2
36
  grpcio==1.76.0
@@ -106,6 +106,7 @@ safehttpx==0.1.7
106
  semantic-version==2.10.0
107
  shellingham==1.5.4
108
  six==1.17.0
 
109
  sse-starlette==3.2.0
110
  starlette==0.50.0
111
  sympy==1.14.0
@@ -124,6 +125,6 @@ uvicorn==0.40.0
124
  uvloop==0.22.1
125
  watchfiles==1.1.1
126
  websocket-client==1.9.0
127
- websockets==16.0
128
  zipp==3.23.0
129
  zope.interface==8.2
 
28
  google-api-python-client==2.188.0
29
  google-auth==2.48.0rc0
30
  google-auth-httplib2==0.3.0
31
+ google-genai==1.62.0
32
  googleapis-common-protos==1.72.0
33
+ gradio==6.5.1
34
  gradio_client==2.0.3
35
  groovy==0.1.2
36
  grpcio==1.76.0
 
106
  semantic-version==2.10.0
107
  shellingham==1.5.4
108
  six==1.17.0
109
+ sniffio==1.3.1
110
  sse-starlette==3.2.0
111
  starlette==0.50.0
112
  sympy==1.14.0
 
125
  uvloop==0.22.1
126
  watchfiles==1.1.1
127
  websocket-client==1.9.0
128
+ websockets==15.0.1
129
  zipp==3.23.0
130
  zope.interface==8.2
static/image.png ADDED

Git LFS Details

  • SHA256: 3b1363d5a2c5770ad3dbd4b89e90bd76aa073abb46f0ad6f08e5c2dd50d18b17
  • Pointer size: 131 Bytes
  • Size of remote file: 173 kB
static/privacy.html ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Privacy Policy - Fraudoo</title>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --primary: #10b981;
12
+ --secondary: #3b82f6;
13
+ --bg: #f8fafc;
14
+ --text: #1e293b;
15
+ }
16
+
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ background: linear-gradient(135deg, #f0fdf4 0%, #e0f2fe 100%);
20
+ color: var(--text);
21
+ margin: 0;
22
+ padding: 2rem;
23
+ display: flex;
24
+ justify-content: center;
25
+ }
26
+
27
+ .container {
28
+ background: rgba(255, 255, 255, 0.9);
29
+ backdrop-filter: blur(10px);
30
+ padding: 3rem;
31
+ border-radius: 20px;
32
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
33
+ max-width: 800px;
34
+ width: 100%;
35
+ line-height: 1.6;
36
+ }
37
+
38
+ h1 {
39
+ color: var(--primary);
40
+ text-align: center;
41
+ margin-bottom: 2rem;
42
+ }
43
+
44
+ h2 {
45
+ color: var(--secondary);
46
+ margin-top: 2rem;
47
+ }
48
+
49
+ .back-btn {
50
+ display: inline-block;
51
+ margin-top: 2rem;
52
+ padding: 0.75rem 1.5rem;
53
+ background: var(--text);
54
+ color: white;
55
+ text-decoration: none;
56
+ border-radius: 10px;
57
+ font-weight: 600;
58
+ }
59
+ </style>
60
+ </head>
61
+
62
+ <body>
63
+ <div class="container">
64
+ <h1>🐢 Privacy Policy</h1>
65
+ <p>Last Updated: February 11, 2026</p>
66
+
67
+ <h2>1. Data Collection</h2>
68
+ <p>At Fraudoo, we prioritize the privacy of your sensitive documents. When you upload a document for analysis,
69
+ the file is processed locally and sent to LLM Services APIs for visual and textual analysis.</p>
70
+
71
+ <h2>2. Use of Documents</h2>
72
+ <p>Documents are stored in a local <code>uploads/</code> directory on your host machine to enable historical
73
+ retrieval. We do not transmit this data to any third party other than the necessary API calls to Google for
74
+ analysis.</p>
75
+
76
+ <h2>3. Data Deletion</h2>
77
+ <p>Users have the right to delete their analysis history at any time using the dashboard's delete feature, which
78
+ removes both the database record and the stored file.</p>
79
+
80
+ <h2>4. Third-Party Services</h2>
81
+ <p>The analysis is powered by LLM Services. Please refer to <a href="https://policies.google.com/privacy"
82
+ target="_blank">Google's Privacy Policy</a> for details on how they handle data processed through their
83
+ AI models.</p>
84
+
85
+ <a href="/" class="back-btn">← Back to App</a>
86
+ </div>
87
+ </body>
88
+
89
+ </html>
static/support.html ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Customer Support - Fraudoo</title>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --primary: #4f46e5;
12
+ --secondary: #ec4899;
13
+ --bg: #f8fafc;
14
+ --text: #1e293b;
15
+ }
16
+
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
20
+ color: var(--text);
21
+ margin: 0;
22
+ display: flex;
23
+ justify-content: center;
24
+ align-items: center;
25
+ min-height: 100vh;
26
+ }
27
+
28
+ .container {
29
+ background: rgba(255, 255, 255, 0.8);
30
+ backdrop-filter: blur(10px);
31
+ padding: 3rem;
32
+ border-radius: 20px;
33
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
34
+ max-width: 600px;
35
+ width: 90%;
36
+ border: 1px solid rgba(255, 255, 255, 0.3);
37
+ }
38
+
39
+ h1 {
40
+ background: linear-gradient(to right, var(--primary), var(--secondary));
41
+ -webkit-background-clip: text;
42
+ background-clip: text;
43
+ -webkit-text-fill-color: transparent;
44
+ margin-bottom: 2rem;
45
+ text-align: center;
46
+ }
47
+
48
+ .support-item {
49
+ margin-bottom: 1.5rem;
50
+ border-bottom: 1px solid #e2e8f0;
51
+ padding-bottom: 1rem;
52
+ }
53
+
54
+ .support-item:last-child {
55
+ border-bottom: none;
56
+ }
57
+
58
+ .support-item strong {
59
+ display: block;
60
+ margin-bottom: 0.5rem;
61
+ color: var(--primary);
62
+ }
63
+
64
+ .back-btn {
65
+ display: inline-block;
66
+ margin-top: 2rem;
67
+ padding: 0.75rem 1.5rem;
68
+ background: var(--primary);
69
+ color: white;
70
+ text-decoration: none;
71
+ border-radius: 10px;
72
+ font-weight: 600;
73
+ transition: transform 0.2s;
74
+ }
75
+
76
+ .back-btn:hover {
77
+ transform: translateY(-2px);
78
+ }
79
+ </style>
80
+ </head>
81
+
82
+ <body>
83
+ <div class="container">
84
+ <h1>🐢 Customer Support</h1>
85
+ <p>Need help with Fraudoo? Our team is here to ensure your document validation experience is seamless.</p>
86
+
87
+ <div class="support-item">
88
+ <strong>📧 Email Support</strong>
89
+ <p>Reach out to us at <a href="mailto:support@fraudoo.tech">support@fraudoo.tech</a>. We typically respond
90
+ within 24 hours.</p>
91
+ </div>
92
+
93
+ <div class="support-item">
94
+ <strong>📚 Documentation</strong>
95
+ <p>Check out our README for local setup instructions and API integration tips.</p>
96
+ </div>
97
+
98
+ <div class="support-item">
99
+ <strong>🕒 Availability</strong>
100
+ <p>Monday - Friday: 9 AM - 6 PM UTC</p>
101
+ </div>
102
+
103
+ <a href="/" class="back-btn">← Back to App</a>
104
+ </div>
105
+ </body>
106
+
107
+ </html>
static/terms.html ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Terms of Service - Fraudoo</title>
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&display=swap" rel="stylesheet">
9
+ <style>
10
+ :root {
11
+ --primary: #8b5cf6;
12
+ --secondary: #d946ef;
13
+ --bg: #f8fafc;
14
+ --text: #1e293b;
15
+ }
16
+
17
+ body {
18
+ font-family: 'Inter', sans-serif;
19
+ background: linear-gradient(135deg, #f5f3ff 0%, #fdf2f8 100%);
20
+ color: var(--text);
21
+ margin: 0;
22
+ padding: 2rem;
23
+ display: flex;
24
+ justify-content: center;
25
+ }
26
+
27
+ .container {
28
+ background: rgba(255, 255, 255, 0.9);
29
+ backdrop-filter: blur(10px);
30
+ padding: 3rem;
31
+ border-radius: 20px;
32
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
33
+ max-width: 800px;
34
+ width: 100%;
35
+ line-height: 1.6;
36
+ }
37
+
38
+ h1 {
39
+ color: var(--primary);
40
+ text-align: center;
41
+ margin-bottom: 2rem;
42
+ }
43
+
44
+ h2 {
45
+ color: var(--secondary);
46
+ margin-top: 1.5rem;
47
+ }
48
+
49
+ .back-btn {
50
+ display: inline-block;
51
+ margin-top: 2rem;
52
+ padding: 0.75rem 1.5rem;
53
+ background: var(--primary);
54
+ color: white;
55
+ text-decoration: none;
56
+ border-radius: 10px;
57
+ font-weight: 600;
58
+ }
59
+ </style>
60
+ </head>
61
+
62
+ <body>
63
+ <div class="container">
64
+ <h1>🐢 Terms of Service</h1>
65
+ <p>By using Fraudoo, you agree to the following terms.</p>
66
+
67
+ <h2>1. Acceptable Use</h2>
68
+ <p>You may use this tool for legitimate document verification purposes. Any attempt to reverse-engineer the
69
+ fraud detection logic or bypass security measures is prohibited.</p>
70
+
71
+ <h2>2. AI-Generated Content</h2>
72
+ <p>Fraudoo uses LLM Services models. While highly advanced, AI analysis can result in false positives or
73
+ negatives. Users must perform their own due diligence before making decisions based on the analysis.</p>
74
+
75
+ <h2>3. Liability</h2>
76
+ <p>Fraudoo is provided "as is" without warranty. We are not liable for any financial or legal consequences
77
+ resulting from the interpretation of document scores or reasoning produced by the service.</p>
78
+
79
+ <h2>4. Data Sovereignty</h2>
80
+ <p>You are responsible for ensuring you have the legal right to process the documents you upload to this
81
+ service.</p>
82
+
83
+ <a href="/" class="back-btn">← Back to App</a>
84
+ </div>
85
+ </body>
86
+
87
+ </html>
vector_service.py CHANGED
@@ -6,7 +6,7 @@ import hashlib
6
  class VectorService:
7
  def __init__(self, db_path="./chroma_db"):
8
  self.client = chromadb.PersistentClient(path=db_path)
9
- # Use a simple default embedding function or Gemini if needed
10
  self.ef = embedding_functions.DefaultEmbeddingFunction()
11
  self.collection = self.client.get_or_create_collection(
12
  name="document_fingerprints",
 
6
  class VectorService:
7
  def __init__(self, db_path="./chroma_db"):
8
  self.client = chromadb.PersistentClient(path=db_path)
9
+ # Use a simple default embedding function or LLM Services if needed
10
  self.ef = embedding_functions.DefaultEmbeddingFunction()
11
  self.collection = self.client.get_or_create_collection(
12
  name="document_fingerprints",