solana-agent 27.3.6__py3-none-any.whl → 27.3.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solana_agent/__init__.py +1 -3
- solana_agent/adapters/mongodb_adapter.py +5 -2
- solana_agent/adapters/openai_adapter.py +32 -27
- solana_agent/adapters/pinecone_adapter.py +91 -63
- solana_agent/client/solana_agent.py +38 -23
- solana_agent/domains/agent.py +7 -13
- solana_agent/domains/routing.py +5 -5
- solana_agent/factories/agent_factory.py +49 -34
- solana_agent/interfaces/client/client.py +22 -13
- solana_agent/interfaces/plugins/plugins.py +2 -1
- solana_agent/interfaces/providers/data_storage.py +9 -2
- solana_agent/interfaces/providers/llm.py +26 -12
- solana_agent/interfaces/providers/memory.py +1 -1
- solana_agent/interfaces/providers/vector_storage.py +3 -9
- solana_agent/interfaces/services/agent.py +21 -6
- solana_agent/interfaces/services/knowledge_base.py +6 -8
- solana_agent/interfaces/services/query.py +16 -5
- solana_agent/interfaces/services/routing.py +0 -1
- solana_agent/plugins/manager.py +14 -9
- solana_agent/plugins/registry.py +13 -11
- solana_agent/plugins/tools/__init__.py +0 -5
- solana_agent/plugins/tools/auto_tool.py +1 -0
- solana_agent/repositories/memory.py +20 -22
- solana_agent/services/__init__.py +1 -1
- solana_agent/services/agent.py +119 -89
- solana_agent/services/knowledge_base.py +182 -131
- solana_agent/services/query.py +48 -24
- solana_agent/services/routing.py +30 -18
- {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/METADATA +6 -5
- solana_agent-27.3.8.dist-info/RECORD +39 -0
- solana_agent-27.3.6.dist-info/RECORD +0 -39
- {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/LICENSE +0 -0
- {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/WHEEL +0 -0
solana_agent/services/agent.py
CHANGED
@@ -4,8 +4,8 @@ Agent service implementation.
|
|
4
4
|
This service manages AI and human agents, their registration, tool assignments,
|
5
5
|
and response generation.
|
6
6
|
"""
|
7
|
+
|
7
8
|
import asyncio
|
8
|
-
from copy import deepcopy
|
9
9
|
import datetime as main_datetime
|
10
10
|
from datetime import datetime
|
11
11
|
import json
|
@@ -53,7 +53,10 @@ class AgentService(AgentServiceInterface):
|
|
53
53
|
)
|
54
54
|
|
55
55
|
def register_ai_agent(
|
56
|
-
self,
|
56
|
+
self,
|
57
|
+
name: str,
|
58
|
+
instructions: str,
|
59
|
+
specialization: str,
|
57
60
|
) -> None:
|
58
61
|
"""Register an AI agent with its specialization.
|
59
62
|
|
@@ -95,16 +98,19 @@ class AgentService(AgentServiceInterface):
|
|
95
98
|
system_prompt += f"\n\nVOICE OF THE BRAND:\n{self.business_mission.voice}"
|
96
99
|
|
97
100
|
if self.business_mission.values:
|
98
|
-
values_text = "\n".join(
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
values_text = "\n".join(
|
102
|
+
[
|
103
|
+
f"- {value.get('name', '')}: {value.get('description', '')}"
|
104
|
+
for value in self.business_mission.values
|
105
|
+
]
|
106
|
+
)
|
102
107
|
system_prompt += f"\n\nBUSINESS VALUES:\n{values_text}"
|
103
108
|
|
104
109
|
# Add goals if available
|
105
110
|
if self.business_mission.goals:
|
106
111
|
goals_text = "\n".join(
|
107
|
-
[f"- {goal}" for goal in self.business_mission.goals]
|
112
|
+
[f"- {goal}" for goal in self.business_mission.goals]
|
113
|
+
)
|
108
114
|
system_prompt += f"\n\nBUSINESS GOALS:\n{goals_text}"
|
109
115
|
|
110
116
|
return system_prompt
|
@@ -140,7 +146,9 @@ class AgentService(AgentServiceInterface):
|
|
140
146
|
"""
|
141
147
|
return self.tool_registry.get_agent_tools(agent_name)
|
142
148
|
|
143
|
-
async def execute_tool(
|
149
|
+
async def execute_tool(
|
150
|
+
self, agent_name: str, tool_name: str, parameters: Dict[str, Any]
|
151
|
+
) -> Dict[str, Any]:
|
144
152
|
"""Execute a tool on behalf of an agent."""
|
145
153
|
|
146
154
|
if not self.tool_registry:
|
@@ -156,7 +164,7 @@ class AgentService(AgentServiceInterface):
|
|
156
164
|
if not any(t.get("name") == tool_name for t in agent_tools):
|
157
165
|
return {
|
158
166
|
"status": "error",
|
159
|
-
"message": f"Agent '{agent_name}' doesn't have access to tool '{tool_name}'"
|
167
|
+
"message": f"Agent '{agent_name}' doesn't have access to tool '{tool_name}'",
|
160
168
|
}
|
161
169
|
|
162
170
|
try:
|
@@ -164,6 +172,7 @@ class AgentService(AgentServiceInterface):
|
|
164
172
|
return result
|
165
173
|
except Exception as e:
|
166
174
|
import traceback
|
175
|
+
|
167
176
|
print(traceback.format_exc())
|
168
177
|
return {"status": "error", "message": f"Error executing tool: {str(e)}"}
|
169
178
|
|
@@ -174,11 +183,22 @@ class AgentService(AgentServiceInterface):
|
|
174
183
|
query: Union[str, bytes],
|
175
184
|
memory_context: str = "",
|
176
185
|
output_format: Literal["text", "audio"] = "text",
|
177
|
-
audio_voice: Literal[
|
178
|
-
|
186
|
+
audio_voice: Literal[
|
187
|
+
"alloy",
|
188
|
+
"ash",
|
189
|
+
"ballad",
|
190
|
+
"coral",
|
191
|
+
"echo",
|
192
|
+
"fable",
|
193
|
+
"onyx",
|
194
|
+
"nova",
|
195
|
+
"sage",
|
196
|
+
"shimmer",
|
197
|
+
] = "nova",
|
179
198
|
audio_instructions: str = "You speak in a friendly and helpful manner.",
|
180
|
-
audio_output_format: Literal[
|
181
|
-
|
199
|
+
audio_output_format: Literal[
|
200
|
+
"mp3", "opus", "aac", "flac", "wav", "pcm"
|
201
|
+
] = "aac",
|
182
202
|
prompt: Optional[str] = None,
|
183
203
|
) -> AsyncGenerator[Union[str, bytes], None]: # pragma: no cover
|
184
204
|
"""Generate a response with support for text/audio input/output."""
|
@@ -186,8 +206,12 @@ class AgentService(AgentServiceInterface):
|
|
186
206
|
if not agent:
|
187
207
|
error_msg = f"Agent '{agent_name}' not found."
|
188
208
|
if output_format == "audio":
|
189
|
-
async for chunk in self.llm_provider.tts(
|
190
|
-
|
209
|
+
async for chunk in self.llm_provider.tts(
|
210
|
+
error_msg,
|
211
|
+
instructions=audio_instructions,
|
212
|
+
response_format=audio_output_format,
|
213
|
+
voice=audio_voice,
|
214
|
+
):
|
191
215
|
yield chunk
|
192
216
|
else:
|
193
217
|
yield error_msg
|
@@ -200,30 +224,33 @@ class AgentService(AgentServiceInterface):
|
|
200
224
|
# --- 2. Add Tool Usage Instructions EARLY ---
|
201
225
|
tool_usage_prompt_text = ""
|
202
226
|
if self.tool_registry:
|
203
|
-
tool_usage_prompt_text = self._get_tool_usage_prompt(
|
204
|
-
agent_name)
|
227
|
+
tool_usage_prompt_text = self._get_tool_usage_prompt(agent_name)
|
205
228
|
if tool_usage_prompt_text:
|
206
229
|
system_prompt_parts.append(
|
207
|
-
f"\n\n--- TOOL USAGE INSTRUCTIONS ---{tool_usage_prompt_text}"
|
230
|
+
f"\n\n--- TOOL USAGE INSTRUCTIONS ---{tool_usage_prompt_text}"
|
231
|
+
)
|
208
232
|
print(
|
209
|
-
f"Tools available to agent {agent_name}: {[t.get('name') for t in self.get_agent_tools(agent_name)]}"
|
233
|
+
f"Tools available to agent {agent_name}: {[t.get('name') for t in self.get_agent_tools(agent_name)]}"
|
234
|
+
)
|
210
235
|
|
211
236
|
# --- 3. Add User ID ---
|
212
|
-
system_prompt_parts.append(
|
237
|
+
system_prompt_parts.append("\n\n--- USER & SESSION INFO ---")
|
213
238
|
system_prompt_parts.append(f"User ID: {user_id}")
|
214
239
|
|
215
240
|
# --- 4. Add Memory Context ---
|
216
241
|
if memory_context:
|
217
242
|
# Make the header clearly separate it
|
218
243
|
system_prompt_parts.append(
|
219
|
-
|
244
|
+
"\n\n--- CONVERSATION HISTORY (Memory Context) ---"
|
245
|
+
)
|
220
246
|
system_prompt_parts.append(memory_context)
|
221
247
|
|
222
248
|
# --- 5. Add Additional Prompt (if provided) ---
|
223
249
|
if prompt:
|
224
250
|
# Make the header clearly separate it
|
225
251
|
system_prompt_parts.append(
|
226
|
-
|
252
|
+
"\n\n--- ADDITIONAL INSTRUCTIONS FOR THIS TURN ---"
|
253
|
+
)
|
227
254
|
system_prompt_parts.append(prompt)
|
228
255
|
|
229
256
|
# --- Assemble the final system prompt ---
|
@@ -237,15 +264,13 @@ class AgentService(AgentServiceInterface):
|
|
237
264
|
tool_buffer = ""
|
238
265
|
pending_chunk = "" # To hold text that might contain partial markers
|
239
266
|
is_tool_call = False
|
240
|
-
window_size = 30 # Increased window size for better detection
|
241
267
|
|
242
268
|
# Define start and end markers
|
243
269
|
start_marker = "[TOOL]"
|
244
270
|
end_marker = "[/TOOL]"
|
245
271
|
|
246
272
|
# Generate and stream response (ALWAYS use non-realtime for text generation)
|
247
|
-
print(
|
248
|
-
f"Generating response with {len(query)} characters of query text")
|
273
|
+
print(f"Generating response with {len(query)} characters of query text")
|
249
274
|
async for chunk in self.llm_provider.generate_text(
|
250
275
|
prompt=query,
|
251
276
|
system_prompt=final_system_prompt,
|
@@ -263,7 +288,8 @@ class AgentService(AgentServiceInterface):
|
|
263
288
|
# STEP 1: Check for tool call start marker
|
264
289
|
if start_marker in combined_chunk and not is_tool_call:
|
265
290
|
print(
|
266
|
-
f"Found tool start marker in chunk of length {len(combined_chunk)}"
|
291
|
+
f"Found tool start marker in chunk of length {len(combined_chunk)}"
|
292
|
+
)
|
267
293
|
is_tool_call = True
|
268
294
|
|
269
295
|
# Extract text before the marker and the marker itself with everything after
|
@@ -285,20 +311,18 @@ class AgentService(AgentServiceInterface):
|
|
285
311
|
|
286
312
|
# Check if the tool call is complete
|
287
313
|
if end_marker in tool_buffer:
|
288
|
-
print(
|
289
|
-
f"Tool call complete, buffer size: {len(tool_buffer)}")
|
314
|
+
print(f"Tool call complete, buffer size: {len(tool_buffer)}")
|
290
315
|
|
291
316
|
# Process the tool call
|
292
317
|
response_text = await self._handle_tool_call(
|
293
|
-
agent_name=agent_name,
|
294
|
-
tool_text=tool_buffer
|
318
|
+
agent_name=agent_name, tool_text=tool_buffer
|
295
319
|
)
|
296
320
|
|
297
321
|
# Clean the response to remove any markers or formatting
|
298
|
-
response_text = self._clean_tool_response(
|
299
|
-
response_text)
|
322
|
+
response_text = self._clean_tool_response(response_text)
|
300
323
|
print(
|
301
|
-
f"Tool execution complete, result size: {len(response_text)}"
|
324
|
+
f"Tool execution complete, result size: {len(response_text)}"
|
325
|
+
)
|
302
326
|
|
303
327
|
# Create new prompt with search/tool results
|
304
328
|
# Ensure query is string
|
@@ -307,36 +331,42 @@ class AgentService(AgentServiceInterface):
|
|
307
331
|
# --- REBUILD the system prompt for the follow-up call ---
|
308
332
|
# Start with base prompt again
|
309
333
|
follow_up_system_prompt_parts = [
|
310
|
-
self.get_agent_system_prompt(agent_name)
|
334
|
+
self.get_agent_system_prompt(agent_name)
|
335
|
+
]
|
311
336
|
# Add the instruction NOT to use tools again
|
312
337
|
follow_up_system_prompt_parts.append(
|
313
|
-
"\n\nCRITICAL: You have received the results from a tool. Base your response on the 'Search Result' provided in the user prompt. DO NOT use the tool calling format again for this turn."
|
314
|
-
|
315
|
-
f"\n\n--- USER & SESSION INFO ---")
|
338
|
+
"\n\nCRITICAL: You have received the results from a tool. Base your response on the 'Search Result' provided in the user prompt. DO NOT use the tool calling format again for this turn."
|
339
|
+
)
|
316
340
|
follow_up_system_prompt_parts.append(
|
317
|
-
|
341
|
+
"\n\n--- USER & SESSION INFO ---"
|
342
|
+
)
|
343
|
+
follow_up_system_prompt_parts.append(f"User ID: {user_id}")
|
318
344
|
if memory_context:
|
319
345
|
# Make the header clearly separate it
|
320
346
|
follow_up_system_prompt_parts.append(
|
321
|
-
|
322
|
-
|
323
|
-
|
347
|
+
"\n\n--- CONVERSATION HISTORY (Memory Context) ---"
|
348
|
+
)
|
349
|
+
follow_up_system_prompt_parts.append(memory_context)
|
324
350
|
if prompt:
|
325
351
|
# Make the header clearly separate it
|
326
352
|
follow_up_system_prompt_parts.append(
|
327
|
-
|
353
|
+
"\n\n--- ADDITIONAL INSTRUCTIONS FOR THIS TURN ---"
|
354
|
+
)
|
328
355
|
follow_up_system_prompt_parts.append(prompt)
|
329
356
|
|
330
357
|
# --- Assemble the final follow_up prompt ---
|
331
358
|
final_follow_up_system_prompt = "\n".join(
|
332
|
-
follow_up_system_prompt_parts
|
359
|
+
follow_up_system_prompt_parts
|
360
|
+
)
|
333
361
|
# --- End Rebuild ---"
|
334
362
|
|
335
363
|
# Generate a new response with the tool results
|
336
364
|
print("Generating new response with tool results")
|
337
365
|
if output_format == "text":
|
338
366
|
# Stream the follow-up response for text output
|
339
|
-
async for
|
367
|
+
async for (
|
368
|
+
processed_chunk
|
369
|
+
) in self.llm_provider.generate_text(
|
340
370
|
prompt=user_prompt,
|
341
371
|
system_prompt=final_follow_up_system_prompt,
|
342
372
|
api_key=self.api_key,
|
@@ -348,15 +378,16 @@ class AgentService(AgentServiceInterface):
|
|
348
378
|
else:
|
349
379
|
# For audio output, collect the full response first
|
350
380
|
tool_response = ""
|
351
|
-
async for
|
381
|
+
async for (
|
382
|
+
processed_chunk
|
383
|
+
) in self.llm_provider.generate_text(
|
352
384
|
prompt=user_prompt,
|
353
385
|
system_prompt=final_follow_up_system_prompt,
|
354
386
|
):
|
355
387
|
tool_response += processed_chunk
|
356
388
|
|
357
389
|
# Clean and add to our complete text record and audio buffer
|
358
|
-
tool_response = self._clean_for_audio(
|
359
|
-
tool_response)
|
390
|
+
tool_response = self._clean_for_audio(tool_response)
|
360
391
|
complete_text_response += tool_response
|
361
392
|
full_response_buffer += tool_response
|
362
393
|
|
@@ -380,8 +411,7 @@ class AgentService(AgentServiceInterface):
|
|
380
411
|
# Everything except the partial marker
|
381
412
|
chunk_to_yield = combined_chunk[:-i]
|
382
413
|
potential_marker = True
|
383
|
-
print(
|
384
|
-
f"Potential partial marker detected: '{pending_chunk}'")
|
414
|
+
print(f"Potential partial marker detected: '{pending_chunk}'")
|
385
415
|
break
|
386
416
|
|
387
417
|
if potential_marker:
|
@@ -405,7 +435,8 @@ class AgentService(AgentServiceInterface):
|
|
405
435
|
# Process any incomplete tool call as regular text
|
406
436
|
if is_tool_call and tool_buffer:
|
407
437
|
print(
|
408
|
-
f"Incomplete tool call detected, returning as regular text: {len(tool_buffer)} chars"
|
438
|
+
f"Incomplete tool call detected, returning as regular text: {len(tool_buffer)} chars"
|
439
|
+
)
|
409
440
|
if output_format == "text":
|
410
441
|
yield tool_buffer
|
411
442
|
|
@@ -417,28 +448,28 @@ class AgentService(AgentServiceInterface):
|
|
417
448
|
if output_format == "audio" and full_response_buffer:
|
418
449
|
# Clean text before TTS
|
419
450
|
print(
|
420
|
-
f"Processing {len(full_response_buffer)} characters for audio output"
|
421
|
-
|
422
|
-
|
451
|
+
f"Processing {len(full_response_buffer)} characters for audio output"
|
452
|
+
)
|
453
|
+
full_response_buffer = self._clean_for_audio(full_response_buffer)
|
423
454
|
|
424
455
|
# Process the entire response with TTS
|
425
456
|
async for audio_chunk in self.llm_provider.tts(
|
426
457
|
text=full_response_buffer,
|
427
458
|
voice=audio_voice,
|
428
459
|
response_format=audio_output_format,
|
429
|
-
instructions=audio_instructions
|
460
|
+
instructions=audio_instructions,
|
430
461
|
):
|
431
462
|
yield audio_chunk
|
432
463
|
|
433
464
|
# Store the complete text response
|
434
465
|
self.last_text_response = complete_text_response
|
435
|
-
print(
|
436
|
-
f"Response generation complete: {len(complete_text_response)} chars")
|
466
|
+
print(f"Response generation complete: {len(complete_text_response)} chars")
|
437
467
|
|
438
468
|
except Exception as e:
|
439
469
|
error_msg = f"I apologize, but I encountered an error: {str(e)}"
|
440
470
|
print(f"Error in generate_response: {str(e)}")
|
441
471
|
import traceback
|
472
|
+
|
442
473
|
print(traceback.format_exc())
|
443
474
|
|
444
475
|
if output_format == "audio":
|
@@ -446,7 +477,7 @@ class AgentService(AgentServiceInterface):
|
|
446
477
|
error_msg,
|
447
478
|
voice=audio_voice,
|
448
479
|
response_format=audio_output_format,
|
449
|
-
instructions=audio_instructions
|
480
|
+
instructions=audio_instructions,
|
450
481
|
):
|
451
482
|
yield chunk
|
452
483
|
else:
|
@@ -465,7 +496,7 @@ class AgentService(AgentServiceInterface):
|
|
465
496
|
chunk_size = 4096
|
466
497
|
|
467
498
|
for i in range(0, len(data), chunk_size):
|
468
|
-
yield data[i:i + chunk_size]
|
499
|
+
yield data[i : i + chunk_size]
|
469
500
|
# Small delay to simulate streaming
|
470
501
|
await asyncio.sleep(0.01)
|
471
502
|
|
@@ -514,6 +545,7 @@ class AgentService(AgentServiceInterface):
|
|
514
545
|
|
515
546
|
except Exception as e:
|
516
547
|
import traceback
|
548
|
+
|
517
549
|
print(traceback.format_exc())
|
518
550
|
return f"Error processing tool call: {str(e)}"
|
519
551
|
|
@@ -524,8 +556,6 @@ class AgentService(AgentServiceInterface):
|
|
524
556
|
if not tools:
|
525
557
|
return ""
|
526
558
|
|
527
|
-
# Get actual tool names
|
528
|
-
available_tool_names = [tool.get("name", "") for tool in tools]
|
529
559
|
tools_json = json.dumps(tools, indent=2)
|
530
560
|
|
531
561
|
return f"""
|
@@ -578,62 +608,62 @@ class AgentService(AgentServiceInterface):
|
|
578
608
|
return ""
|
579
609
|
|
580
610
|
# Remove Markdown links - [text](url) -> text
|
581
|
-
text = re.sub(r
|
611
|
+
text = re.sub(r"\[([^\]]+)\]\([^\)]+\)", r"\1", text)
|
582
612
|
|
583
613
|
# Remove inline code with backticks
|
584
|
-
text = re.sub(r
|
614
|
+
text = re.sub(r"`([^`]+)`", r"\1", text)
|
585
615
|
|
586
616
|
# Remove bold formatting - **text** or __text__ -> text
|
587
|
-
text = re.sub(r
|
617
|
+
text = re.sub(r"(\*\*|__)(.*?)\1", r"\2", text)
|
588
618
|
|
589
619
|
# Remove italic formatting - *text* or _text_ -> text
|
590
|
-
text = re.sub(r
|
620
|
+
text = re.sub(r"(\*|_)(.*?)\1", r"\2", text)
|
591
621
|
|
592
622
|
# Remove headers - ## Header -> Header
|
593
|
-
text = re.sub(r
|
623
|
+
text = re.sub(r"^\s*#+\s*(.*?)$", r"\1", text, flags=re.MULTILINE)
|
594
624
|
|
595
625
|
# Remove blockquotes - > Text -> Text
|
596
|
-
text = re.sub(r
|
626
|
+
text = re.sub(r"^\s*>\s*(.*?)$", r"\1", text, flags=re.MULTILINE)
|
597
627
|
|
598
628
|
# Remove horizontal rules (---, ***, ___)
|
599
|
-
text = re.sub(r
|
629
|
+
text = re.sub(r"^\s*[-*_]{3,}\s*$", "", text, flags=re.MULTILINE)
|
600
630
|
|
601
631
|
# Remove list markers - * Item or - Item or 1. Item -> Item
|
602
|
-
text = re.sub(r
|
603
|
-
text = re.sub(r
|
632
|
+
text = re.sub(r"^\s*[-*+]\s+(.*?)$", r"\1", text, flags=re.MULTILINE)
|
633
|
+
text = re.sub(r"^\s*\d+\.\s+(.*?)$", r"\1", text, flags=re.MULTILINE)
|
604
634
|
|
605
635
|
# Remove multiple consecutive newlines (keep just one)
|
606
|
-
text = re.sub(r
|
636
|
+
text = re.sub(r"\n{3,}", "\n\n", text)
|
607
637
|
|
608
638
|
# Remove emojis and other non-pronounceable characters
|
609
639
|
# Common emoji Unicode ranges
|
610
640
|
emoji_pattern = re.compile(
|
611
641
|
"["
|
612
|
-
"\
|
613
|
-
"\
|
614
|
-
"\
|
615
|
-
"\
|
616
|
-
"\
|
617
|
-
"\
|
618
|
-
"\
|
619
|
-
"\
|
620
|
-
"\
|
621
|
-
"\U00002702-\
|
622
|
-
"\
|
623
|
-
"\U00002600-\
|
624
|
-
"\U00002700-\
|
625
|
-
"\
|
626
|
-
"\
|
642
|
+
"\U0001f600-\U0001f64f" # emoticons
|
643
|
+
"\U0001f300-\U0001f5ff" # symbols & pictographs
|
644
|
+
"\U0001f680-\U0001f6ff" # transport & map symbols
|
645
|
+
"\U0001f700-\U0001f77f" # alchemical symbols
|
646
|
+
"\U0001f780-\U0001f7ff" # Geometric Shapes
|
647
|
+
"\U0001f800-\U0001f8ff" # Supplemental Arrows-C
|
648
|
+
"\U0001f900-\U0001f9ff" # Supplemental Symbols and Pictographs
|
649
|
+
"\U0001fa00-\U0001fa6f" # Chess Symbols
|
650
|
+
"\U0001fa70-\U0001faff" # Symbols and Pictographs Extended-A
|
651
|
+
"\U00002702-\U000027b0" # Dingbats
|
652
|
+
"\U000024c2-\U0000257f" # Enclosed characters
|
653
|
+
"\U00002600-\U000026ff" # Miscellaneous Symbols
|
654
|
+
"\U00002700-\U000027bf" # Dingbats
|
655
|
+
"\U0000fe00-\U0000fe0f" # Variation Selectors
|
656
|
+
"\U0001f1e0-\U0001f1ff" # Flags (iOS)
|
627
657
|
"]+",
|
628
|
-
flags=re.UNICODE
|
658
|
+
flags=re.UNICODE,
|
629
659
|
)
|
630
|
-
text = emoji_pattern.sub(r
|
660
|
+
text = emoji_pattern.sub(r" ", text)
|
631
661
|
|
632
662
|
# Replace special characters that can cause issues with TTS
|
633
|
-
text = re.sub(r
|
663
|
+
text = re.sub(r"[^\w\s\.\,\;\:\?\!\'\"\-\(\)]", " ", text)
|
634
664
|
|
635
665
|
# Replace multiple spaces with a single space
|
636
|
-
text = re.sub(r
|
666
|
+
text = re.sub(r"\s+", " ", text)
|
637
667
|
|
638
668
|
return text.strip()
|
639
669
|
|