Skip to content

Commit 1502e57

Browse files
Frontend audit: Bug fixes and refinements (#2112)
* (fix:attachements) sep id for redux ops * (fix:ui) popups, toast, share modal * (feat:agentsPreview) stable preview, ui fixes * (fix:ui) light theme icon, sleek scroll * (chore:i18n) missin keys * (chore:i18n) missing keys * (feat:preferrenceSlice) autoclear invalid source from storage * (fix:general) delete all conv close btn * (fix:tts) play one at a time * (fix:tts) gracefully unmount * (feat:tts) audio LRU cache * (feat:tts) pointer on hovered area * (feat:tts) clean text for speach --------- Co-authored-by: GH Action - Upstream Sync <action@github.com>
1 parent 814f71f commit 1502e57

40 files changed

Lines changed: 1800 additions & 485 deletions

application/api/user/attachments/routes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,15 @@ class TextToSpeech(Resource):
130130
@api.expect(tts_model)
131131
@api.doc(description="Synthesize audio speech from text")
132132
def post(self):
133+
from application.utils import clean_text_for_tts
134+
133135
data = request.get_json()
134136
text = data["text"]
137+
cleaned_text = clean_text_for_tts(text)
138+
135139
try:
136140
tts_instance = TTSCreator.create_tts(settings.TTS_PROVIDER)
137-
audio_base64, detected_language = tts_instance.text_to_speech(text)
141+
audio_base64, detected_language = tts_instance.text_to_speech(cleaned_text)
138142
return make_response(
139143
jsonify(
140144
{

application/utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,44 @@ def generate_image_url(image_path):
187187
else:
188188
base_url = getattr(settings, "API_URL", "http://localhost:7091")
189189
return f"{base_url}/api/images/{image_path}"
190+
191+
192+
def clean_text_for_tts(text: str) -> str:
193+
"""
194+
clean text for Text-to-Speech processing.
195+
"""
196+
# Handle code blocks and links
197+
text = re.sub(r'```mermaid[\s\S]*?```', ' flowchart, ', text) ## ```mermaid...```
198+
text = re.sub(r'```[\s\S]*?```', ' code block, ', text) ## ```code```
199+
text = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', text) ## [text](url)
200+
text = re.sub(r'!\[([^\]]*)\]\([^\)]+\)', '', text) ## ![alt](url)
201+
202+
# Remove markdown formatting
203+
text = re.sub(r'`([^`]+)`', r'\1', text) ## `code`
204+
text = re.sub(r'\{([^}]*)\}', r' \1 ', text) ## {text}
205+
text = re.sub(r'[{}]', ' ', text) ## unmatched {}
206+
text = re.sub(r'\[([^\]]+)\]', r' \1 ', text) ## [text]
207+
text = re.sub(r'[\[\]]', ' ', text) ## unmatched []
208+
text = re.sub(r'(\*\*|__)(.*?)\1', r'\2', text) ## **bold** __bold__
209+
text = re.sub(r'(\*|_)(.*?)\1', r'\2', text) ## *italic* _italic_
210+
text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE) ## # headers
211+
text = re.sub(r'^>\s+', '', text, flags=re.MULTILINE) ## > blockquotes
212+
text = re.sub(r'^[\s]*[-\*\+]\s+', '', text, flags=re.MULTILINE) ## - * + lists
213+
text = re.sub(r'^[\s]*\d+\.\s+', '', text, flags=re.MULTILINE) ## 1. numbered lists
214+
text = re.sub(r'^[\*\-_]{3,}\s*$', '', text, flags=re.MULTILINE) ## --- *** ___ rules
215+
text = re.sub(r'<[^>]*>', '', text) ## <html> tags
216+
217+
#Remove non-ASCII (emojis, special Unicode)
218+
text = re.sub(r'[^\x20-\x7E\n\r\t]', '', text)
219+
220+
#Replace special sequences
221+
text = re.sub(r'-->', ', ', text) ## -->
222+
text = re.sub(r'<--', ', ', text) ## <--
223+
text = re.sub(r'=>', ', ', text) ## =>
224+
text = re.sub(r'::', ' ', text) ## ::
225+
226+
#Normalize whitespace
227+
text = re.sub(r'\s+', ' ', text)
228+
text = text.strip()
229+
230+
return text

frontend/src/Navigation.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
411411
{recentAgents?.length > 0 ? (
412412
<div>
413413
<div className="mx-4 my-auto mt-2 flex h-6 items-center">
414-
<p className="mt-1 ml-4 text-sm font-semibold">Agents</p>
414+
<p className="mt-1 ml-4 text-sm font-semibold">
415+
{t('navigation.agents')}
416+
</p>
415417
</div>
416418
<div className="agents-container">
417419
<div>

frontend/src/PageNotFound.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import { Link } from 'react-router-dom';
2+
import { useTranslation } from 'react-i18next';
23

34
export default function PageNotFound() {
5+
const { t } = useTranslation();
6+
47
return (
58
<div className="dark:bg-raisin-black grid min-h-screen">
69
<p className="text-jet dark:bg-outer-space mx-auto my-auto mt-20 flex w-full max-w-6xl flex-col place-items-center gap-6 rounded-3xl bg-gray-100 p-6 lg:p-10 xl:p-16 dark:text-gray-100">
7-
<h1>404</h1>
8-
<p>The page you are looking for does not exist.</p>
10+
<h1>{t('pageNotFound.title')}</h1>
11+
<p>{t('pageNotFound.message')}</p>
912
<button className="pointer-cursor bg-blue-1000 hover:bg-blue-3000 mr-4 flex cursor-pointer items-center justify-center rounded-full px-4 py-2 text-white transition-colors duration-100">
10-
<Link to="/">Go Back Home</Link>
13+
<Link to="/">{t('pageNotFound.goHome')}</Link>
1114
</button>
1215
</p>
1316
</div>

frontend/src/agents/AgentLogs.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
23
import { useSelector } from 'react-redux';
34
import { useNavigate, useParams } from 'react-router-dom';
45

@@ -11,6 +12,7 @@ import Logs from '../settings/Logs';
1112
import { Agent } from './types';
1213

1314
export default function AgentLogs() {
15+
const { t } = useTranslation();
1416
const navigate = useNavigate();
1517
const { agentId } = useParams();
1618
const token = useSelector(selectToken);
@@ -45,12 +47,12 @@ export default function AgentLogs() {
4547
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
4648
</button>
4749
<p className="text-eerie-black dark:text-bright-gray mt-px text-sm font-semibold">
48-
Back to all agents
50+
{t('agents.backToAll')}
4951
</p>
5052
</div>
5153
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
5254
<h1 className="text-eerie-black m-0 text-[32px] font-bold md:text-[40px] dark:text-white">
53-
Agent Logs
55+
{t('agents.logs.title')}
5456
</h1>
5557
</div>
5658
<div className="mt-6 flex flex-col gap-3 px-4">
@@ -59,9 +61,10 @@ export default function AgentLogs() {
5961
<p className="text-[#28292E] dark:text-[#E0E0E0]">{agent.name}</p>
6062
<p className="text-xs text-[#28292E] dark:text-[#E0E0E0]/40">
6163
{agent.last_used_at
62-
? 'Last used at ' +
64+
? t('agents.logs.lastUsedAt') +
65+
' ' +
6366
new Date(agent.last_used_at).toLocaleString()
64-
: 'No usage history'}
67+
: t('agents.logs.noUsageHistory')}
6568
</p>
6669
</div>
6770
)}
@@ -79,7 +82,9 @@ export default function AgentLogs() {
7982
<Spinner />
8083
</div>
8184
) : (
82-
agent && <Logs agentId={agent.id} tableHeader="Agent endpoint logs" />
85+
agent && (
86+
<Logs agentId={agent.id} tableHeader={t('agents.logs.tableHeader')} />
87+
)
8388
)}
8489
</div>
8590
);

frontend/src/agents/AgentPreview.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useCallback, useEffect, useRef, useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
23
import { useDispatch, useSelector } from 'react-redux';
34

45
import MessageInput from '../components/MessageInput';
@@ -17,6 +18,7 @@ import { selectSelectedAgent } from '../preferences/preferenceSlice';
1718
import { AppDispatch } from '../store';
1819

1920
export default function AgentPreview() {
21+
const { t } = useTranslation();
2022
const dispatch = useDispatch<AppDispatch>();
2123

2224
const queries = useSelector(selectPreviewQueries);
@@ -130,8 +132,7 @@ export default function AgentPreview() {
130132
/>
131133
</div>
132134
<p className="text-gray-4000 dark:text-sonic-silver w-full bg-transparent text-center text-xs md:inline">
133-
This is a preview of the agent. You can publish it to start using it
134-
in conversations.
135+
{t('agents.preview.testMessage')}
135136
</p>
136137
</div>
137138
</div>

frontend/src/agents/AgentsList.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
23
import { useDispatch, useSelector } from 'react-redux';
34
import { useNavigate } from 'react-router-dom';
45

@@ -17,6 +18,7 @@ import { agentSectionsConfig } from './agents.config';
1718
import { Agent } from './types';
1819

1920
export default function AgentsList() {
21+
const { t } = useTranslation();
2022
const dispatch = useDispatch();
2123
const token = useSelector(selectToken);
2224
const selectedAgent = useSelector(selectSelectedAgent);
@@ -33,11 +35,10 @@ export default function AgentsList() {
3335
return (
3436
<div className="p-4 md:p-12">
3537
<h1 className="text-eerie-black mb-0 text-[32px] font-bold lg:text-[40px] dark:text-[#E0E0E0]">
36-
Agents
38+
{t('agents.title')}
3739
</h1>
3840
<p className="dark:text-gray-4000 mt-5 text-[15px] text-[#71717A]">
39-
Discover and create custom versions of DocsGPT that combine
40-
instructions, extra knowledge, and any combination of skills
41+
{t('agents.description')}
4142
</p>
4243
{agentSectionsConfig.map((sectionConfig) => (
4344
<AgentSection key={sectionConfig.id} config={sectionConfig} />
@@ -51,6 +52,7 @@ function AgentSection({
5152
}: {
5253
config: (typeof agentSectionsConfig)[number];
5354
}) {
55+
const { t } = useTranslation();
5456
const navigate = useNavigate();
5557
const dispatch = useDispatch();
5658
const token = useSelector(selectToken);
@@ -85,16 +87,18 @@ function AgentSection({
8587
<div className="flex w-full items-center justify-between">
8688
<div className="flex flex-col gap-2">
8789
<h2 className="text-[18px] font-semibold text-[#18181B] dark:text-[#E0E0E0]">
88-
{config.title}
90+
{t(`agents.sections.${config.id}.title`)}
8991
</h2>
90-
<p className="text-[13px] text-[#71717A]">{config.description}</p>
92+
<p className="text-[13px] text-[#71717A]">
93+
{t(`agents.sections.${config.id}.description`)}
94+
</p>
9195
</div>
9296
{config.showNewAgentButton && (
9397
<button
9498
className="bg-purple-30 hover:bg-violets-are-blue rounded-full px-4 py-2 text-sm text-white"
9599
onClick={() => navigate('/agents/new')}
96100
>
97-
New Agent
101+
{t('agents.newAgent')}
98102
</button>
99103
)}
100104
</div>
@@ -117,13 +121,13 @@ function AgentSection({
117121
</div>
118122
) : (
119123
<div className="flex h-72 w-full flex-col items-center justify-center gap-3 text-base text-[#18181B] dark:text-[#E0E0E0]">
120-
<p>{config.emptyStateDescription}</p>
124+
<p>{t(`agents.sections.${config.id}.emptyState`)}</p>
121125
{config.showNewAgentButton && (
122126
<button
123127
className="bg-purple-30 hover:bg-violets-are-blue ml-2 rounded-full px-4 py-2 text-sm text-white"
124128
onClick={() => navigate('/agents/new')}
125129
>
126-
New Agent
130+
{t('agents.newAgent')}
127131
</button>
128132
)}
129133
</div>

0 commit comments

Comments
 (0)