ProCreations commited on
Commit
14ffd10
Β·
verified Β·
1 Parent(s): 62f171e

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +516 -0
  2. test_thinking.py +51 -0
app.py ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Just search - A Smart Search Agent using Menlo/Lucy-128k
4
+ Part of the Just, AKA Simple series
5
+ Built with Gradio, DuckDuckGo Search, and Hugging Face Transformers
6
+ """
7
+
8
+ import gradio as gr
9
+ import torch
10
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
11
+ from duckduckgo_search import DDGS
12
+ import json
13
+ import re
14
+ import time
15
+ from typing import List, Dict, Tuple
16
+ import spaces
17
+
18
+ # Initialize the model and tokenizer globally for efficiency
19
+ MODEL_NAME = "Menlo/Lucy-128k"
20
+ tokenizer = None
21
+ model = None
22
+ search_pipeline = None
23
+
24
+ def initialize_model():
25
+ """Initialize the Menlo/Lucy-128k model and tokenizer"""
26
+ global tokenizer, model, search_pipeline
27
+ try:
28
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
29
+ model = AutoModelForCausalLM.from_pretrained(
30
+ MODEL_NAME,
31
+ torch_dtype=torch.float16,
32
+ device_map="auto",
33
+ trust_remote_code=True
34
+ )
35
+ search_pipeline = pipeline(
36
+ "text-generation",
37
+ model=model,
38
+ tokenizer=tokenizer,
39
+ torch_dtype=torch.float16,
40
+ device_map="auto",
41
+ max_new_tokens=2048,
42
+ temperature=0.7,
43
+ do_sample=True,
44
+ pad_token_id=tokenizer.eos_token_id
45
+ )
46
+ return True
47
+ except Exception as e:
48
+ print(f"Error initializing model: {e}")
49
+ return False
50
+
51
+ def extract_thinking_and_response(text: str) -> Tuple[str, str]:
52
+ """Extract thinking process and clean response from AI output"""
53
+ thinking = ""
54
+ response = text
55
+
56
+ # Extract thinking content
57
+ thinking_match = re.search(r'<think>(.*?)</think>', text, re.DOTALL)
58
+ if thinking_match:
59
+ thinking = thinking_match.group(1).strip()
60
+ response = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
61
+
62
+ # Clean up the response
63
+ response = re.sub(r'^(Assistant:|AI:|Response:|Answer:)\s*', '', response.strip())
64
+ response = re.sub(r'\[INST\].*?\[\/INST\]', '', response)
65
+ response = re.sub(r'<\|.*?\|>', '', response)
66
+
67
+ return thinking.strip(), response.strip()
68
+
69
+ def clean_response(text: str) -> str:
70
+ """Clean up the AI response to extract just the relevant content"""
71
+ _, response = extract_thinking_and_response(text)
72
+ return response
73
+
74
+ @spaces.GPU
75
+ def generate_search_queries(user_query: str) -> Tuple[List[str], str]:
76
+ """Generate multiple search queries based on user input using AI"""
77
+ prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
78
+ You are a search query generator. Given a user's question, generate 3-5 different search queries that would help find comprehensive information to answer their question. Return only the search queries, one per line, without numbering or bullet points.
79
+
80
+ Example:
81
+ User: "What are the latest developments in AI?"
82
+ latest AI developments 2024
83
+ artificial intelligence breakthroughs recent
84
+ AI technology advances news
85
+ machine learning innovations 2024
86
+
87
+ <|eot_id|><|start_header_id|>user<|end_header_id|>
88
+ {user_query}
89
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
90
+
91
+ try:
92
+ response = search_pipeline(prompt, max_new_tokens=200, temperature=0.3)
93
+ generated_text = response[0]['generated_text']
94
+
95
+ # Extract just the assistant's response
96
+ assistant_response = generated_text.split('<|start_header_id|>assistant<|end_header_id|>')[-1]
97
+ thinking, cleaned_response = extract_thinking_and_response(assistant_response)
98
+
99
+ # Split into individual queries and clean them
100
+ queries = [q.strip() for q in cleaned_response.split('\n') if q.strip()]
101
+ # Filter out any non-query text
102
+ queries = [q for q in queries if len(q) > 5 and not q.startswith('Note:') and not q.startswith('Example:')]
103
+
104
+ return queries[:5], thinking # Return max 5 queries and thinking
105
+ except Exception as e:
106
+ print(f"Error generating queries: {e}")
107
+ # Fallback to simple query variations
108
+ return [user_query, f"{user_query} 2024", f"{user_query} latest"], ""
109
+
110
+ def search_web(queries: List[str]) -> List[Dict]:
111
+ """Search the web using DuckDuckGo with multiple queries"""
112
+ all_results = []
113
+ ddgs = DDGS()
114
+
115
+ for query in queries:
116
+ try:
117
+ results = ddgs.text(query, max_results=5, region='wt-wt', safesearch='moderate')
118
+ for result in results:
119
+ result['search_query'] = query
120
+ all_results.append(result)
121
+ time.sleep(0.5) # Rate limiting
122
+ except Exception as e:
123
+ print(f"Error searching for '{query}': {e}")
124
+ continue
125
+
126
+ # Remove duplicates based on URL
127
+ seen_urls = set()
128
+ unique_results = []
129
+ for result in all_results:
130
+ if result['href'] not in seen_urls:
131
+ seen_urls.add(result['href'])
132
+ unique_results.append(result)
133
+
134
+ return unique_results[:15] # Return max 15 results
135
+
136
+ @spaces.GPU
137
+ def filter_relevant_results(user_query: str, search_results: List[Dict]) -> Tuple[List[Dict], str]:
138
+ """Use AI to filter and rank search results by relevance"""
139
+ if not search_results:
140
+ return [], ""
141
+
142
+ # Prepare results summary for AI
143
+ results_text = ""
144
+ for i, result in enumerate(search_results[:12]): # Limit to avoid token overflow
145
+ results_text += f"{i+1}. Title: {result.get('title', 'No title')}\n"
146
+ results_text += f" URL: {result.get('href', 'No URL')}\n"
147
+ results_text += f" Snippet: {result.get('body', 'No description')[:200]}...\n\n"
148
+
149
+ prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
150
+ You are a search result evaluator. Given a user's question and search results, identify which results are most relevant and helpful for answering the question.
151
+
152
+ Return only the numbers of the most relevant results (1-5 results maximum), separated by commas. Consider:
153
+ - Direct relevance to the question
154
+ - Credibility of the source
155
+ - Recency of information
156
+ - Comprehensiveness of content
157
+
158
+ Example response: 1, 3, 7
159
+
160
+ <|eot_id|><|start_header_id|>user<|end_header_id|>
161
+ Question: {user_query}
162
+
163
+ Search Results:
164
+ {results_text}
165
+
166
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
167
+
168
+ try:
169
+ response = search_pipeline(prompt, max_new_tokens=100, temperature=0.1)
170
+ generated_text = response[0]['generated_text']
171
+
172
+ # Extract assistant's response
173
+ assistant_response = generated_text.split('<|start_header_id|>assistant<|end_header_id|>')[-1]
174
+ thinking, cleaned_response = extract_thinking_and_response(assistant_response)
175
+
176
+ # Extract numbers
177
+ numbers = re.findall(r'\d+', cleaned_response)
178
+ selected_indices = [int(n) - 1 for n in numbers if int(n) <= len(search_results)]
179
+
180
+ return [search_results[i] for i in selected_indices if 0 <= i < len(search_results)][:5], thinking
181
+ except Exception as e:
182
+ print(f"Error filtering results: {e}")
183
+ return search_results[:5], "" # Fallback to first 5 results
184
+
185
+ @spaces.GPU
186
+ def generate_final_answer(user_query: str, selected_results: List[Dict]) -> Tuple[str, str]:
187
+ """Generate final answer based on selected search results"""
188
+ if not selected_results:
189
+ return "I couldn't find relevant information to answer your question. Please try rephrasing your query.", ""
190
+
191
+ # Prepare context from selected results
192
+ context = ""
193
+ for i, result in enumerate(selected_results):
194
+ context += f"Source {i+1}: {result.get('title', 'Unknown')}\n"
195
+ context += f"Content: {result.get('body', 'No content available')}\n"
196
+ context += f"URL: {result.get('href', 'No URL')}\n\n"
197
+
198
+ prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
199
+ You are a helpful research assistant. Based on the provided search results, give a comprehensive answer to the user's question.
200
+
201
+ Guidelines:
202
+ - Synthesize information from multiple sources
203
+ - Be accurate and factual
204
+ - Cite sources when possible
205
+ - If information is conflicting, mention it
206
+ - Keep the answer well-structured and easy to read
207
+ - Include relevant URLs for further reading
208
+
209
+ <|eot_id|><|start_header_id|>user<|end_header_id|>
210
+ Question: {user_query}
211
+
212
+ Search Results:
213
+ {context}
214
+
215
+ Please provide a comprehensive answer based on these sources.
216
+
217
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
218
+
219
+ try:
220
+ response = search_pipeline(prompt, max_new_tokens=1024, temperature=0.2)
221
+ generated_text = response[0]['generated_text']
222
+
223
+ # Extract assistant's response
224
+ assistant_response = generated_text.split('<|start_header_id|>assistant<|end_header_id|>')[-1]
225
+ thinking, answer = extract_thinking_and_response(assistant_response)
226
+
227
+ return answer, thinking
228
+ except Exception as e:
229
+ print(f"Error generating final answer: {e}")
230
+ return "I encountered an error while processing the search results. Please try again.", ""
231
+
232
+ def search_agent_workflow(user_query: str, progress=gr.Progress()) -> Tuple[str, str, str]:
233
+ """Main workflow that orchestrates the search agent"""
234
+ if not user_query.strip():
235
+ return "Please enter a search query.", "", ""
236
+
237
+ progress(0.1, desc="Initializing...")
238
+ all_thinking = []
239
+
240
+ # Step 1: Generate search queries
241
+ progress(0.2, desc="Generating search queries...")
242
+ queries, thinking1 = generate_search_queries(user_query)
243
+ if thinking1:
244
+ all_thinking.append(f"**Query Generation:**\n{thinking1}")
245
+ queries_text = "Generated queries:\n" + "\n".join(f"β€’ {q}" for q in queries)
246
+
247
+ # Step 2: Search the web
248
+ progress(0.4, desc="Searching the web...")
249
+ search_results = search_web(queries)
250
+
251
+ if not search_results:
252
+ return "No search results found. Please try a different query.", queries_text, "\n\n".join(all_thinking)
253
+
254
+ # Step 3: Filter relevant results
255
+ progress(0.6, desc="Filtering relevant results...")
256
+ relevant_results, thinking2 = filter_relevant_results(user_query, search_results)
257
+ if thinking2:
258
+ all_thinking.append(f"**Result Filtering:**\n{thinking2}")
259
+
260
+ # Step 4: Generate final answer
261
+ progress(0.8, desc="Generating comprehensive answer...")
262
+ final_answer, thinking3 = generate_final_answer(user_query, relevant_results)
263
+ if thinking3:
264
+ all_thinking.append(f"**Answer Generation:**\n{thinking3}")
265
+
266
+ progress(1.0, desc="Complete!")
267
+
268
+ # Prepare debug info
269
+ debug_info = f"{queries_text}\n\nSelected {len(relevant_results)} relevant sources:\n"
270
+ for i, result in enumerate(relevant_results):
271
+ debug_info += f"{i+1}. {result.get('title', 'No title')} - {result.get('href', 'No URL')}\n"
272
+
273
+ thinking_display = "\n\n".join(all_thinking) if all_thinking else "No thinking process recorded."
274
+
275
+ return final_answer, debug_info, thinking_display
276
+
277
+ # Custom CSS for dark blue theme and mobile responsiveness
278
+ custom_css = """
279
+ /* Dark blue theme */
280
+ :root {
281
+ --primary-bg: #0a1628;
282
+ --secondary-bg: #1e3a5f;
283
+ --accent-bg: #2563eb;
284
+ --text-primary: #f8fafc;
285
+ --text-secondary: #cbd5e1;
286
+ --border-color: #334155;
287
+ --input-bg: #1e293b;
288
+ --button-bg: #3b82f6;
289
+ --button-hover: #2563eb;
290
+ }
291
+
292
+ /* Global styles */
293
+ .gradio-container {
294
+ background: linear-gradient(135deg, var(--primary-bg) 0%, var(--secondary-bg) 100%) !important;
295
+ color: var(--text-primary) !important;
296
+ font-family: 'Inter', 'Segoe UI', system-ui, sans-serif !important;
297
+ }
298
+
299
+ /* Mobile responsiveness */
300
+ @media (max-width: 768px) {
301
+ .gradio-container {
302
+ padding: 10px !important;
303
+ }
304
+
305
+ .gr-form {
306
+ gap: 15px !important;
307
+ }
308
+
309
+ .gr-button {
310
+ font-size: 16px !important;
311
+ padding: 12px 20px !important;
312
+ }
313
+ }
314
+
315
+ /* Input styling */
316
+ .gr-textbox textarea, .gr-textbox input {
317
+ background: var(--input-bg) !important;
318
+ border: 1px solid var(--border-color) !important;
319
+ color: var(--text-primary) !important;
320
+ border-radius: 8px !important;
321
+ }
322
+
323
+ /* Button styling */
324
+ .gr-button {
325
+ background: linear-gradient(135deg, var(--button-bg) 0%, var(--accent-bg) 100%) !important;
326
+ color: white !important;
327
+ border: none !important;
328
+ border-radius: 8px !important;
329
+ font-weight: 600 !important;
330
+ transition: all 0.3s ease !important;
331
+ }
332
+
333
+ .gr-button:hover {
334
+ background: linear-gradient(135deg, var(--button-hover) 0%, var(--button-bg) 100%) !important;
335
+ transform: translateY(-1px) !important;
336
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important;
337
+ }
338
+
339
+ /* Output styling */
340
+ .gr-markdown, .gr-textbox {
341
+ background: var(--input-bg) !important;
342
+ border: 1px solid var(--border-color) !important;
343
+ border-radius: 8px !important;
344
+ color: var(--text-primary) !important;
345
+ }
346
+
347
+ /* Header styling */
348
+ .gr-markdown h1 {
349
+ color: var(--accent-bg) !important;
350
+ text-align: center !important;
351
+ margin-bottom: 20px !important;
352
+ font-size: 2.5rem !important;
353
+ font-weight: 700 !important;
354
+ }
355
+
356
+ /* Thinking section styling */
357
+ #thinking-output {
358
+ background: var(--secondary-bg) !important;
359
+ border: 1px solid var(--border-color) !important;
360
+ border-radius: 8px !important;
361
+ padding: 15px !important;
362
+ font-family: 'Fira Code', 'Monaco', monospace !important;
363
+ font-size: 0.9rem !important;
364
+ line-height: 1.4 !important;
365
+ }
366
+
367
+ /* Loading animation */
368
+ .gr-loading {
369
+ background: var(--secondary-bg) !important;
370
+ border-radius: 8px !important;
371
+ }
372
+
373
+ /* Scrollbar styling */
374
+ ::-webkit-scrollbar {
375
+ width: 8px;
376
+ }
377
+
378
+ ::-webkit-scrollbar-track {
379
+ background: var(--primary-bg);
380
+ }
381
+
382
+ ::-webkit-scrollbar-thumb {
383
+ background: var(--accent-bg);
384
+ border-radius: 4px;
385
+ }
386
+
387
+ ::-webkit-scrollbar-thumb:hover {
388
+ background: var(--button-hover);
389
+ }
390
+ """
391
+
392
+ def create_interface():
393
+ """Create the Gradio interface"""
394
+ with gr.Blocks(
395
+ theme=gr.themes.Base(
396
+ primary_hue="blue",
397
+ secondary_hue="slate",
398
+ neutral_hue="slate",
399
+ text_size="lg",
400
+ spacing_size="lg",
401
+ radius_size="md"
402
+ ),
403
+ css=custom_css,
404
+ title="Just search - AI Search Agent",
405
+ head="<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
406
+ ) as interface:
407
+
408
+ gr.Markdown("# πŸ” Just search", elem_id="header")
409
+ gr.Markdown(
410
+ "*Part of the Just, AKA Simple series*\n\n"
411
+ "**Intelligent search agent powered by Menlo/Lucy-128k**\n\n"
412
+ "Ask any question and get comprehensive answers from the web.",
413
+ elem_id="description"
414
+ )
415
+
416
+ with gr.Row():
417
+ with gr.Column(scale=4):
418
+ query_input = gr.Textbox(
419
+ label="Your Question",
420
+ placeholder="Ask me anything... (e.g., 'What are the latest developments in AI?')",
421
+ lines=2,
422
+ elem_id="query-input"
423
+ )
424
+ with gr.Column(scale=1):
425
+ search_btn = gr.Button(
426
+ "πŸ”Ž Search",
427
+ variant="primary",
428
+ size="lg",
429
+ elem_id="search-button"
430
+ )
431
+
432
+ with gr.Row():
433
+ answer_output = gr.Markdown(
434
+ label="Answer",
435
+ elem_id="answer-output",
436
+ height=400
437
+ )
438
+
439
+ with gr.Accordion("πŸ€” AI Thinking Process", open=False):
440
+ thinking_output = gr.Markdown(
441
+ label="Model's Chain of Thought",
442
+ elem_id="thinking-output",
443
+ height=300
444
+ )
445
+
446
+ with gr.Accordion("πŸ”§ Debug Info", open=False):
447
+ debug_output = gr.Textbox(
448
+ label="Search Process Details",
449
+ lines=8,
450
+ elem_id="debug-output"
451
+ )
452
+
453
+ # Event handlers
454
+ search_btn.click(
455
+ fn=search_agent_workflow,
456
+ inputs=[query_input],
457
+ outputs=[answer_output, debug_output, thinking_output],
458
+ show_progress=True
459
+ )
460
+
461
+ query_input.submit(
462
+ fn=search_agent_workflow,
463
+ inputs=[query_input],
464
+ outputs=[answer_output, debug_output, thinking_output],
465
+ show_progress=True
466
+ )
467
+
468
+ # Example queries
469
+ gr.Examples(
470
+ examples=[
471
+ ["What are the latest breakthroughs in quantum computing?"],
472
+ ["How does climate change affect ocean currents?"],
473
+ ["What are the best practices for sustainable agriculture?"],
474
+ ["Explain the recent developments in renewable energy technology"],
475
+ ["What are the health benefits of the Mediterranean diet?"]
476
+ ],
477
+ inputs=query_input,
478
+ outputs=[answer_output, debug_output, thinking_output],
479
+ fn=search_agent_workflow,
480
+ cache_examples=False
481
+ )
482
+
483
+ gr.Markdown(
484
+ "---\n**Note:** This search agent generates multiple queries, searches the web, "
485
+ "filters results for relevance, and provides comprehensive answers. "
486
+ "Results are sourced from DuckDuckGo search."
487
+ )
488
+
489
+ return interface
490
+
491
+ def main():
492
+ """Main function to initialize and launch the app"""
493
+ print("πŸš€ Initializing Just search...")
494
+
495
+ # Initialize the model
496
+ if not initialize_model():
497
+ print("❌ Failed to initialize model. Please check your setup.")
498
+ return
499
+
500
+ print("βœ… Model initialized successfully!")
501
+ print("🌐 Creating interface...")
502
+
503
+ # Create and launch the interface
504
+ interface = create_interface()
505
+
506
+ print("πŸŽ‰ Just search is ready!")
507
+ interface.launch(
508
+ server_name="0.0.0.0",
509
+ server_port=7860,
510
+ share=True,
511
+ show_error=True,
512
+ debug=True
513
+ )
514
+
515
+ if __name__ == "__main__":
516
+ main()
test_thinking.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script to verify thinking extraction works correctly
4
+ """
5
+
6
+ import re
7
+ from typing import Tuple
8
+
9
+ def extract_thinking_and_response(text: str) -> Tuple[str, str]:
10
+ """Extract thinking process and clean response from AI output"""
11
+ thinking = ""
12
+ response = text
13
+
14
+ # Extract thinking content
15
+ thinking_match = re.search(r'<think>(.*?)</think>', text, re.DOTALL)
16
+ if thinking_match:
17
+ thinking = thinking_match.group(1).strip()
18
+ response = re.sub(r'<think>.*?</think>', '', text, flags=re.DOTALL)
19
+
20
+ # Clean up the response
21
+ response = re.sub(r'^(Assistant:|AI:|Response:|Answer:)\s*', '', response.strip())
22
+ response = re.sub(r'\[INST\].*?\[\/INST\]', '', response)
23
+ response = re.sub(r'<\|.*?\|>', '', response)
24
+
25
+ return thinking.strip(), response.strip()
26
+
27
+ # Test cases
28
+ test_cases = [
29
+ # Basic thinking extraction
30
+ "<think>I need to analyze this query and generate search terms.</think>Here are the search queries:\n1. AI developments 2024\n2. artificial intelligence news",
31
+
32
+ # No thinking
33
+ "Here are the search queries:\n1. AI developments 2024\n2. artificial intelligence news",
34
+
35
+ # Complex thinking
36
+ "<think>The user is asking about quantum computing breakthroughs. I should focus on recent developments, key research areas, and practical applications. Let me think about the best search terms...</think>Based on your question, here are optimized search queries for quantum computing breakthroughs.",
37
+
38
+ # Thinking with newlines
39
+ "<think>\nThis is a complex question about climate change.\nI need to consider multiple aspects:\n1. Ocean currents\n2. Temperature changes\n3. Recent research\n</think>Climate change affects ocean currents in several ways..."
40
+ ]
41
+
42
+ print("Testing thinking extraction...")
43
+ for i, test in enumerate(test_cases, 1):
44
+ thinking, response = extract_thinking_and_response(test)
45
+ print(f"\nTest {i}:")
46
+ print(f"Original: {test[:100]}...")
47
+ print(f"Thinking: {thinking[:100]}..." if thinking else "Thinking: None")
48
+ print(f"Response: {response[:100]}...")
49
+ print("-" * 50)
50
+
51
+ print("βœ… Thinking extraction test completed!")