hardkpentium101 Qwen-Coder commited on
Commit
e6027ef
·
1 Parent(s): 9a520d5

Simplify prompt and validation - robust creative output

Browse files

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Files changed (1) hide show
  1. backend/src/rag_system.py +35 -133
backend/src/rag_system.py CHANGED
@@ -23,59 +23,14 @@ logging.basicConfig(level=logging.INFO)
23
  logger = logging.getLogger(__name__)
24
 
25
 
26
- # Prompt for Sarvam-1 - Creative writing inspired by Hindi literature
27
- CREATIVE_PROMPT = """You are a multilingual creative writer deeply inspired by the traditions of Hindi literature and Indian nature poetry.
28
 
29
- You will receive:
30
- 1. Retrieved context passages from a Hindi literature knowledge base
31
- 2. A user prompt requesting a poem or story
32
 
33
- Your task is to create an ORIGINAL creative piece inspired by the themes present in the context.
34
-
35
- IMPORTANT RULES:
36
-
37
- 1. The retrieved context is ONLY for thematic inspiration.
38
- 2. DO NOT summarize, explain, or quote the context.
39
- 3. DO NOT mention authors, poets, books, or literary works from the context.
40
- 4. DO NOT repeat sentences or phrases from the context.
41
- 5. The output must be completely original.
42
-
43
- Creative Guidelines:
44
-
45
- • Extract inspiration from imagery, emotions, philosophy, and themes found in the context.
46
- • Use vivid descriptions of nature, emotions, and atmosphere.
47
- • Maintain a style reminiscent of classical Hindi literary prose or poetry.
48
- • Use metaphors, sensory details, and cultural depth.
49
- • Write naturally in the same language as the user's query.
50
-
51
- Behavior Rules:
52
-
53
- If the context contains biographies, explanations, or references to poets:
54
- → IGNORE those parts and focus only on nature-related themes.
55
-
56
- If the context is weak or irrelevant:
57
- → Still generate a creative piece using general themes of nature and Hindi literary style.
58
-
59
- Output Requirements:
60
-
61
- • Return ONLY the poem or story.
62
- • Do not explain your reasoning.
63
- • Do not mention the context.
64
- • Do not include headings like "Based on the context".
65
-
66
- ------------------------------------
67
-
68
- Context:
69
- {context_str}
70
-
71
- ------------------------------------
72
-
73
- User Prompt:
74
- {query}
75
-
76
- ------------------------------------
77
-
78
- Generate an original creative response in {language}."""
79
 
80
  UNSUPPORTED_LANG_PROMPT = """I apologize, but I only support the following languages:
81
 
@@ -197,113 +152,60 @@ class SimpleRAGSystem:
197
  return self._synthesize_answer(query, context_docs)
198
 
199
  def _is_valid_creative_output(self, text: str) -> bool:
200
- """Check if output is valid creative writing vs meta-commentary/prompt leakage"""
201
- if not text or len(text) < 20:
202
  return False
203
 
204
  text_lower = text.lower()
205
 
206
- # Reject if it contains prompt/instruction keywords
207
- invalid_patterns = [
208
- # Apologies/inability
209
- "i cannot", "i can't", "unable to", "sorry", "apologize",
210
- "i'm not", "i am not",
211
- # Prompt structure leakage
212
- "you are a multilingual", "retrieved context", "user prompt",
213
- "your task is to", "important rules", "creative guidelines",
214
- "behavior rules", "output requirements", "do not mention",
215
- "do not explain", "do not include", "based on the context",
216
- # Prompt content leakage
217
- "extract inspiration", "vivid descriptions", "sensory details",
218
- "classical hindi", "literary prose", "cultural depth",
219
- "write naturally", "same language as", "user's query",
220
- # Context references
221
- "context contains", "biographies", "explanations", "references to poets",
222
- "context is weak", "irrelevant", "general themes",
223
- # Separator leakage
224
  "------------------------------------",
225
- # Meta commentary
226
- "generate an original", "creative response", "creative piece",
227
- "thematic inspiration", "summarize", "explain", "or quote",
228
  ]
229
 
230
- if any(pattern in text_lower for pattern in invalid_patterns):
231
  return False
232
-
233
- # Accept if it looks like creative writing (has multiple lines)
234
- lines = [l.strip() for l in text.split('\n') if l.strip()]
235
- if len(lines) >= 3:
236
- return True
237
-
238
- # Single line but long enough and no invalid patterns
239
- if len(text) > 50:
240
- return True
241
-
242
- return False
243
 
244
  def _clean_output(self, text: str) -> str:
245
- """Clean up LLM output - remove informal/garbled text and artifacts"""
246
  if not text:
247
  return text
248
 
249
- # Remove common artifacts
250
  text = re.sub(r'</?s>', '', text)
251
  text = re.sub(r'\[/?INST\]', '', text)
252
  text = re.sub(r'\[/?SYS\]', '', text)
253
  text = re.sub(r'\[\d+\]', '', text)
 
254
 
255
- # Remove prompt structure leakage
256
- text = re.sub(r'You are a multilingual.*', '', text, flags=re.IGNORECASE)
257
- text = re.sub(r'You will receive:.*', '', text, flags=re.IGNORECASE)
258
- text = re.sub(r'Your task is to.*', '', text, flags=re.IGNORECASE)
259
- text = re.sub(r'IMPORTANT RULES:.*', '', text, flags=re.IGNORECASE)
260
- text = re.sub(r'Creative Guidelines:.*', '', text, flags=re.IGNORECASE)
261
- text = re.sub(r'Behavior Rules:.*', '', text, flags=re.IGNORECASE)
262
- text = re.sub(r'Output Requirements:.*', '', text, flags=re.IGNORECASE)
263
- text = re.sub(r'Context:.*', '', text, flags=re.IGNORECASE)
264
- text = re.sub(r'User Prompt:.*', '', text, flags=re.IGNORECASE)
265
- text = re.sub(r'Generate an original.*', '', text, flags=re.IGNORECASE)
266
- text = re.sub(r'-{10,}', '', text) # Remove separator lines
267
-
268
- # Remove meta-commentary lines
269
  lines = text.split('\n')
270
- cleaned_lines = []
271
-
272
  for line in lines:
273
  line = line.strip()
274
- line_lower = line.lower()
275
-
276
- # Skip meta-commentary patterns
277
- skip_patterns = [
278
- # Apologies/inability
279
- "i'm not good", "i cannot", "i can't", "i am unable",
280
- "sorry", "apologize",
281
- # Prompt leakage
282
- "you are a", "you will receive", "your task is",
283
- "important rules", "creative guidelines", "behavior rules",
284
- "output requirements", "do not mention", "do not explain",
285
- "based on the context", "thematic inspiration",
286
- # Instructions
287
- "extract inspiration", "use vivid", "maintain a style",
288
- "write naturally", "generate a creative",
289
- # Meta
290
- "fetched documents", "retrieved context",
291
- ]
292
- if any(marker in line_lower for marker in skip_patterns):
293
  continue
294
- if line.count('!') > 2 or line.count('?') > 2 or line.count('~') > 1:
295
  continue
296
- if len(line) < 15 and any(c in line for c in ['<3', '><', 'xp', 'xd']):
297
  continue
298
- if line:
299
- cleaned_lines.append(line)
300
 
301
- result = '\n'.join(cleaned_lines)
302
-
303
- if len(result) < len(text) * 0.3:
304
- return text
305
-
306
- return result.strip()
307
 
308
  def _synthesize_answer(self, query: str, context_docs: List[Dict]) -> str:
309
  """Synthesize an answer from retrieved documents when LLM is unavailable"""
 
23
  logger = logging.getLogger(__name__)
24
 
25
 
26
+ # Prompt for Sarvam-1 - Simple, direct creative writing
27
+ CREATIVE_PROMPT = """{context_str}
28
 
29
+ ---
30
+ Write a poem or short story about: {query}
31
+ Language: {language}
32
 
33
+ Write only the creative piece, nothing else:"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  UNSUPPORTED_LANG_PROMPT = """I apologize, but I only support the following languages:
36
 
 
152
  return self._synthesize_answer(query, context_docs)
153
 
154
  def _is_valid_creative_output(self, text: str) -> bool:
155
+ """Check if output is valid creative writing vs prompt/instruction leakage"""
156
+ if not text or len(text) < 30:
157
  return False
158
 
159
  text_lower = text.lower()
160
 
161
+ # Hard reject - these indicate broken output
162
+ hard_reject = [
163
+ "you are a", "you will receive", "your task is",
164
+ "important rules", "creative guidelines", "output requirements",
165
+ "please provide", "at least one", "feel free", "add more",
166
+ "based on these", "you can use", "when generating",
167
+ "topic description", "use as input", "generating content",
168
+ "write only", "write a poem", "write a story", "language:",
169
+ "context:", "user prompt:", "generate an original",
170
+ "i cannot", "i can't", "unable to", "sorry",
 
 
 
 
 
 
 
 
171
  "------------------------------------",
 
 
 
172
  ]
173
 
174
+ if any(pattern in text_lower for pattern in hard_reject):
175
  return False
176
+
177
+ # Must have multiple lines to be creative writing
178
+ lines = [l.strip() for l in text.split('\n') if l.strip() and len(l.strip()) > 10]
179
+ return len(lines) >= 2
 
 
 
 
 
 
 
180
 
181
  def _clean_output(self, text: str) -> str:
182
+ """Clean up LLM output - remove artifacts and garbage"""
183
  if not text:
184
  return text
185
 
186
+ # Remove artifacts
187
  text = re.sub(r'</?s>', '', text)
188
  text = re.sub(r'\[/?INST\]', '', text)
189
  text = re.sub(r'\[/?SYS\]', '', text)
190
  text = re.sub(r'\[\d+\]', '', text)
191
+ text = re.sub(r'-{10,}', '', text)
192
 
193
+ # Remove lines that are clearly not creative content
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  lines = text.split('\n')
195
+ cleaned = []
 
196
  for line in lines:
197
  line = line.strip()
198
+ # Skip very short lines, emoji lines, instruction-like lines
199
+ if len(line) < 5:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  continue
201
+ if ': )' in line or ':)' in line or line.count('!') > 2:
202
  continue
203
+ if line.lower().startswith(('please', 'thank', 'sorry', 'note:', 'context:', 'topic:')):
204
  continue
205
+ cleaned.append(line)
 
206
 
207
+ result = '\n'.join(cleaned).strip()
208
+ return result if result else text
 
 
 
 
209
 
210
  def _synthesize_answer(self, query: str, context_docs: List[Dict]) -> str:
211
  """Synthesize an answer from retrieved documents when LLM is unavailable"""