GitHub Actions commited on
Commit
307bbbc
·
1 Parent(s): 89be117

Deploy backend from GitHub 453f0e24ea5bcdd0ce6030af03ea7622ccc75dcb

Browse files
backend/app/api/routes.py CHANGED
@@ -116,8 +116,8 @@ async def _analyze_text(text: str, user_id: str | None = None) -> dict:
116
  )
117
  saved = await save_document(COLLECTION, doc.id, doc.to_dict())
118
  result["id"] = doc.id if saved else text_hash
119
- except Exception as e:
120
- logger.warning("Firestore persist failed", error=str(e))
121
  result["id"] = text_hash
122
 
123
  return result
@@ -195,11 +195,11 @@ async def assist_text(request: AssistRequest):
195
  """Call Groq API to propose a rewrite of flagged text to reduce AI threat indicators.
196
 
197
  The AI Fixer should:
198
- 1. Make text sound more human and natural
199
- 2. Remove any harmful, offensive, or extreme language
200
- 3. Simplify overly complex or robotic phrasing
201
- 4. Maintain the original meaning and key information
202
- 5. Use casual, conversational language
203
  """
204
  if not settings.GROQ_API_KEY:
205
  raise HTTPException(
@@ -214,18 +214,24 @@ async def assist_text(request: AssistRequest):
214
  logs: list[str] = []
215
  logs.append(f"Preparing rewrite request for Groq model: {settings.GROQ_MODEL}")
216
 
217
- # Improved prompt that specifically targets reducing AI detection and harm scores
218
  prompt = (
219
- "You are a text editor helping to make writing sound more natural and human. "
220
- "Rewrite the following text following these rules:\n\n"
221
- "1. Use simple, casual, conversational language like a real person would write\n"
222
- "2. Remove any offensive, harmful, hateful, or extreme language completely\n"
223
- "3. Avoid robotic phrases, formal tone, or AI-typical patterns\n"
224
- "4. Add small imperfections like informal contractions (e.g., 'it's', 'don't')\n"
225
- "5. Keep the core meaning and key facts, but make it sound authentic\n"
226
- "6. If the text is a greeting or simple message, keep it short and friendly\n\n"
227
- "Return ONLY the rewritten text with no explanations, comments, or meta-text.\n\n"
228
- f"Text to rewrite:\n{request.text}"
 
 
 
 
 
 
229
  )
230
 
231
  try:
@@ -241,19 +247,33 @@ async def assist_text(request: AssistRequest):
241
  "model": settings.GROQ_MODEL,
242
  "messages": [{"role": "user", "content": prompt}],
243
  "max_tokens": 8192,
244
- "temperature": 0.8, # Increased from 0.7 for more natural variation
 
 
 
245
  },
246
  )
247
  response.raise_for_status()
248
  data = response.json()
249
  fixed_text = data["choices"][0]["message"]["content"].strip()
250
 
251
- # Remove any meta-commentary that the model might add
252
- if fixed_text.startswith('Here') or fixed_text.startswith('Sure'):
253
- # Try to extract just the rewritten text
 
 
 
 
 
 
 
 
254
  lines = fixed_text.split('\n')
255
  if len(lines) > 1:
256
  fixed_text = '\n'.join(lines[1:]).strip()
 
 
 
257
 
258
  logs.append("Groq model returned rewritten text successfully.")
259
  except httpx.TimeoutException:
 
116
  )
117
  saved = await save_document(COLLECTION, doc.id, doc.to_dict())
118
  result["id"] = doc.id if saved else text_hash
119
+ except Exception:
120
+ # Silently skip Firestore - it's optional
121
  result["id"] = text_hash
122
 
123
  return result
 
195
  """Call Groq API to propose a rewrite of flagged text to reduce AI threat indicators.
196
 
197
  The AI Fixer should:
198
+ 1. Make text sound EXTREMELY human and natural with imperfections
199
+ 2. Remove any harmful, offensive, or extreme language completely
200
+ 3. Use casual, everyday language with natural variations
201
+ 4. Add human quirks: contractions, filler words, casual tone
202
+ 5. Maintain the original meaning and key information
203
  """
204
  if not settings.GROQ_API_KEY:
205
  raise HTTPException(
 
214
  logs: list[str] = []
215
  logs.append(f"Preparing rewrite request for Groq model: {settings.GROQ_MODEL}")
216
 
217
+ # Enhanced prompt specifically designed to evade AI detection
218
  prompt = (
219
+ "You are helping someone rewrite text to sound completely natural and human-written. "
220
+ "Your goal is to make it indistinguishable from casual, authentic human writing.\n\n"
221
+ "CRITICAL RULES:\n"
222
+ "1. Write like a real person texting or chatting - use informal, conversational tone\n"
223
+ "2. Add natural imperfections: contractions (don't, it's, there's), filler words (just, really, kinda)\n"
224
+ "3. Remove ALL harmful, offensive, hateful, or toxic language - replace with friendly alternatives\n"
225
+ "4. Vary sentence length - mix short and long sentences naturally\n"
226
+ "5. Use simple everyday vocabulary - avoid fancy or technical words\n"
227
+ "6. Add casual expressions and natural flow (like, you know, I mean)\n"
228
+ "7. If it's a greeting, keep it super short and casual (max 10 words)\n"
229
+ "8. Don't be overly polite or formal - write like you're texting a friend\n"
230
+ "9. Include minor typos or informal grammar occasionally (but readable)\n"
231
+ "10. Keep the core message but make it sound spontaneous and unedited\n\n"
232
+ "IMPORTANT: Return ONLY the rewritten text. No explanations, no 'Here is', no meta-commentary. "
233
+ "Just the natural-sounding version.\n\n"
234
+ f"Text to make human-like:\n{request.text}"
235
  )
236
 
237
  try:
 
247
  "model": settings.GROQ_MODEL,
248
  "messages": [{"role": "user", "content": prompt}],
249
  "max_tokens": 8192,
250
+ "temperature": 0.9, # Increased to 0.9 for more natural variation
251
+ "top_p": 0.95, # Added to increase diversity
252
+ "frequency_penalty": 0.3, # Reduce repetition
253
+ "presence_penalty": 0.3, # Encourage natural variation
254
  },
255
  )
256
  response.raise_for_status()
257
  data = response.json()
258
  fixed_text = data["choices"][0]["message"]["content"].strip()
259
 
260
+ # Aggressively remove any meta-commentary
261
+ # Common AI patterns to strip out
262
+ meta_phrases = [
263
+ "here is", "here's", "sure", "certainly", "of course",
264
+ "i've rewritten", "i rewrote", "rewritten version",
265
+ "here you go", "this is", "below is"
266
+ ]
267
+
268
+ first_line = fixed_text.split('\n')[0].lower()
269
+ if any(phrase in first_line for phrase in meta_phrases):
270
+ # Skip the meta-commentary line
271
  lines = fixed_text.split('\n')
272
  if len(lines) > 1:
273
  fixed_text = '\n'.join(lines[1:]).strip()
274
+ # Remove quotes if the AI wrapped it
275
+ if fixed_text.startswith('"') and fixed_text.endswith('"'):
276
+ fixed_text = fixed_text[1:-1].strip()
277
 
278
  logs.append("Groq model returned rewritten text successfully.")
279
  except httpx.TimeoutException:
backend/app/db/firestore.py CHANGED
@@ -44,7 +44,8 @@ def init_firebase() -> None:
44
  global _db, _enabled
45
 
46
  if not settings.FIREBASE_CREDENTIALS_JSON:
47
- logger.warning("FIREBASE_CREDENTIALS_JSON not set – Firestore disabled")
 
48
  return
49
 
50
  try:
@@ -60,10 +61,10 @@ def init_firebase() -> None:
60
  _enabled = True
61
  project = settings.FIREBASE_PROJECT_ID or cred_dict.get("project_id", "")
62
  logger.info("Firebase + Firestore initialised", project=project)
63
- except Exception as e:
 
64
  _db = None
65
  _enabled = False
66
- logger.warning("Firebase init failed – Firestore disabled", error=str(e))
67
 
68
 
69
  # ---- Public helpers --------------------------------------------------------
@@ -75,11 +76,8 @@ async def save_document(collection: str, doc_id: str, data: dict) -> bool:
75
  try:
76
  _db.collection(collection).document(doc_id).set(data)
77
  return True
78
- except google.auth.exceptions.RefreshError as e:
79
- logger.debug("Firestore save_document skipped – credential refresh failed", collection=collection, doc_id=doc_id, error=str(e))
80
- return False
81
- except Exception as e:
82
- logger.warning("Firestore save_document failed", collection=collection, doc_id=doc_id, error=str(e))
83
  return False
84
 
85
 
@@ -90,11 +88,8 @@ async def get_document(collection: str, doc_id: str) -> dict | None:
90
  try:
91
  doc = _db.collection(collection).document(doc_id).get()
92
  return doc.to_dict() if doc.exists else None
93
- except google.auth.exceptions.RefreshError as e:
94
- logger.debug("Firestore get_document skipped – credential refresh failed", collection=collection, doc_id=doc_id, error=str(e))
95
- return None
96
- except Exception as e:
97
- logger.warning("Firestore get_document failed", collection=collection, doc_id=doc_id, error=str(e))
98
  return None
99
 
100
 
 
44
  global _db, _enabled
45
 
46
  if not settings.FIREBASE_CREDENTIALS_JSON:
47
+ # Silently disable if not configured - no need to spam logs
48
+ _enabled = False
49
  return
50
 
51
  try:
 
61
  _enabled = True
62
  project = settings.FIREBASE_PROJECT_ID or cred_dict.get("project_id", "")
63
  logger.info("Firebase + Firestore initialised", project=project)
64
+ except Exception:
65
+ # Silently fail - Firestore is optional, no need to spam logs
66
  _db = None
67
  _enabled = False
 
68
 
69
 
70
  # ---- Public helpers --------------------------------------------------------
 
76
  try:
77
  _db.collection(collection).document(doc_id).set(data)
78
  return True
79
+ except (google.auth.exceptions.RefreshError, Exception):
80
+ # Silently fail - no logs, just return False
 
 
 
81
  return False
82
 
83
 
 
88
  try:
89
  doc = _db.collection(collection).document(doc_id).get()
90
  return doc.to_dict() if doc.exists else None
91
+ except (google.auth.exceptions.RefreshError, Exception):
92
+ # Silently fail - no logs, just return None
 
 
 
93
  return None
94
 
95