Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d1e6991
(fix:attachements) sep id for redux ops
ManishMadan2882 Oct 15, 2025
ed118c5
(fix:ui) popups, toast, share modal
ManishMadan2882 Oct 16, 2025
d2c7a3c
Merge branch 'main' of https://github.com/manishmadan2882/docsgpt
ManishMadan2882 Oct 16, 2025
03cf554
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 17, 2025
d9dc84b
(feat:agentsPreview) stable preview, ui fixes
ManishMadan2882 Oct 17, 2025
97767fe
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 18, 2025
11ce740
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 19, 2025
dc742b1
(fix:ui) light theme icon, sleek scroll
ManishMadan2882 Oct 20, 2025
6eb77c4
Merge branch 'main' of https://github.com/manishmadan2882/docsgpt
ManishMadan2882 Oct 20, 2025
2575e05
(chore:i18n) missin keys
ManishMadan2882 Oct 22, 2025
7b9cd26
(chore:i18n) missing keys
ManishMadan2882 Oct 22, 2025
2838b7a
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 23, 2025
bcd8dc8
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 24, 2025
ae0bcfe
(feat:preferrenceSlice) autoclear invalid source from storage
ManishMadan2882 Oct 24, 2025
bf87c3c
Merge branch 'main' of https://github.com/manishmadan2882/docsgpt
ManishMadan2882 Oct 24, 2025
0ee85bc
(fix:general) delete all conv close btn
ManishMadan2882 Oct 24, 2025
4ae042c
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 25, 2025
64ea9b0
(fix:tts) play one at a time
ManishMadan2882 Oct 26, 2025
2357e3f
Merge branch 'main' of https://github.com/arc53/DocsGPT
actions-user Oct 28, 2025
89b13c5
Merge branch 'main' of https://github.com/manishmadan2882/docsgpt
ManishMadan2882 Oct 28, 2025
3b7e88e
(fix:tts) gracefully unmount
ManishMadan2882 Oct 28, 2025
bd0b7c4
(feat:tts) audio LRU cache
ManishMadan2882 Oct 28, 2025
79cd6d9
(feat:tts) pointer on hovered area
ManishMadan2882 Oct 28, 2025
7b0d4fe
(feat:tts) clean text for speach
ManishMadan2882 Oct 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion application/api/user/attachments/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,15 @@ class TextToSpeech(Resource):
@api.expect(tts_model)
@api.doc(description="Synthesize audio speech from text")
def post(self):
from application.utils import clean_text_for_tts

data = request.get_json()
text = data["text"]
cleaned_text = clean_text_for_tts(text)

try:
tts_instance = TTSCreator.create_tts(settings.TTS_PROVIDER)
audio_base64, detected_language = tts_instance.text_to_speech(text)
audio_base64, detected_language = tts_instance.text_to_speech(cleaned_text)
return make_response(
jsonify(
{
Expand Down
41 changes: 41 additions & 0 deletions application/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,44 @@ def generate_image_url(image_path):
else:
base_url = getattr(settings, "API_URL", "http://localhost:7091")
return f"{base_url}/api/images/{image_path}"


def clean_text_for_tts(text: str) -> str:
"""
clean text for Text-to-Speech processing.
"""
# Handle code blocks and links
text = re.sub(r'```mermaid[\s\S]*?```', ' flowchart, ', text) ## ```mermaid...```
text = re.sub(r'```[\s\S]*?```', ' code block, ', text) ## ```code```
text = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', text) ## [text](url)
text = re.sub(r'!\[([^\]]*)\]\([^\)]+\)', '', text) ## ![alt](url)

# Remove markdown formatting
text = re.sub(r'`([^`]+)`', r'\1', text) ## `code`
text = re.sub(r'\{([^}]*)\}', r' \1 ', text) ## {text}
text = re.sub(r'[{}]', ' ', text) ## unmatched {}
text = re.sub(r'\[([^\]]+)\]', r' \1 ', text) ## [text]
text = re.sub(r'[\[\]]', ' ', text) ## unmatched []
text = re.sub(r'(\*\*|__)(.*?)\1', r'\2', text) ## **bold** __bold__
text = re.sub(r'(\*|_)(.*?)\1', r'\2', text) ## *italic* _italic_
text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE) ## # headers
text = re.sub(r'^>\s+', '', text, flags=re.MULTILINE) ## > blockquotes
text = re.sub(r'^[\s]*[-\*\+]\s+', '', text, flags=re.MULTILINE) ## - * + lists
text = re.sub(r'^[\s]*\d+\.\s+', '', text, flags=re.MULTILINE) ## 1. numbered lists
text = re.sub(r'^[\*\-_]{3,}\s*$', '', text, flags=re.MULTILINE) ## --- *** ___ rules
text = re.sub(r'<[^>]*>', '', text) ## <html> tags

#Remove non-ASCII (emojis, special Unicode)
text = re.sub(r'[^\x20-\x7E\n\r\t]', '', text)

#Replace special sequences
text = re.sub(r'-->', ', ', text) ## -->
text = re.sub(r'<--', ', ', text) ## <--
text = re.sub(r'=>', ', ', text) ## =>
text = re.sub(r'::', ' ', text) ## ::

#Normalize whitespace
text = re.sub(r'\s+', ' ', text)
text = text.strip()

return text
4 changes: 3 additions & 1 deletion frontend/src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
{recentAgents?.length > 0 ? (
<div>
<div className="mx-4 my-auto mt-2 flex h-6 items-center">
<p className="mt-1 ml-4 text-sm font-semibold">Agents</p>
<p className="mt-1 ml-4 text-sm font-semibold">
{t('navigation.agents')}
</p>
</div>
<div className="agents-container">
<div>
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/PageNotFound.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

export default function PageNotFound() {
const { t } = useTranslation();

return (
<div className="dark:bg-raisin-black grid min-h-screen">
<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">
<h1>404</h1>
<p>The page you are looking for does not exist.</p>
<h1>{t('pageNotFound.title')}</h1>
<p>{t('pageNotFound.message')}</p>
<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">
<Link to="/">Go Back Home</Link>
<Link to="/">{t('pageNotFound.goHome')}</Link>
</button>
</p>
</div>
Expand Down
15 changes: 10 additions & 5 deletions frontend/src/agents/AgentLogs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';

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

export default function AgentLogs() {
const { t } = useTranslation();
const navigate = useNavigate();
const { agentId } = useParams();
const token = useSelector(selectToken);
Expand Down Expand Up @@ -45,12 +47,12 @@ export default function AgentLogs() {
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<p className="text-eerie-black dark:text-bright-gray mt-px text-sm font-semibold">
Back to all agents
{t('agents.backToAll')}
</p>
</div>
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
<h1 className="text-eerie-black m-0 text-[32px] font-bold md:text-[40px] dark:text-white">
Agent Logs
{t('agents.logs.title')}
</h1>
</div>
<div className="mt-6 flex flex-col gap-3 px-4">
Expand All @@ -59,9 +61,10 @@ export default function AgentLogs() {
<p className="text-[#28292E] dark:text-[#E0E0E0]">{agent.name}</p>
<p className="text-xs text-[#28292E] dark:text-[#E0E0E0]/40">
{agent.last_used_at
? 'Last used at ' +
? t('agents.logs.lastUsedAt') +
' ' +
new Date(agent.last_used_at).toLocaleString()
: 'No usage history'}
: t('agents.logs.noUsageHistory')}
</p>
</div>
)}
Expand All @@ -79,7 +82,9 @@ export default function AgentLogs() {
<Spinner />
</div>
) : (
agent && <Logs agentId={agent.id} tableHeader="Agent endpoint logs" />
agent && (
<Logs agentId={agent.id} tableHeader={t('agents.logs.tableHeader')} />
)
)}
</div>
);
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/agents/AgentPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';

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

export default function AgentPreview() {
const { t } = useTranslation();
const dispatch = useDispatch<AppDispatch>();

const queries = useSelector(selectPreviewQueries);
Expand Down Expand Up @@ -130,8 +132,7 @@ export default function AgentPreview() {
/>
</div>
<p className="text-gray-4000 dark:text-sonic-silver w-full bg-transparent text-center text-xs md:inline">
This is a preview of the agent. You can publish it to start using it
in conversations.
{t('agents.preview.testMessage')}
</p>
</div>
</div>
Expand Down
20 changes: 12 additions & 8 deletions frontend/src/agents/AgentsList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';

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

export default function AgentsList() {
const { t } = useTranslation();
const dispatch = useDispatch();
const token = useSelector(selectToken);
const selectedAgent = useSelector(selectSelectedAgent);
Expand All @@ -33,11 +35,10 @@ export default function AgentsList() {
return (
<div className="p-4 md:p-12">
<h1 className="text-eerie-black mb-0 text-[32px] font-bold lg:text-[40px] dark:text-[#E0E0E0]">
Agents
{t('agents.title')}
</h1>
<p className="dark:text-gray-4000 mt-5 text-[15px] text-[#71717A]">
Discover and create custom versions of DocsGPT that combine
instructions, extra knowledge, and any combination of skills
{t('agents.description')}
</p>
{agentSectionsConfig.map((sectionConfig) => (
<AgentSection key={sectionConfig.id} config={sectionConfig} />
Expand All @@ -51,6 +52,7 @@ function AgentSection({
}: {
config: (typeof agentSectionsConfig)[number];
}) {
const { t } = useTranslation();
const navigate = useNavigate();
const dispatch = useDispatch();
const token = useSelector(selectToken);
Expand Down Expand Up @@ -85,16 +87,18 @@ function AgentSection({
<div className="flex w-full items-center justify-between">
<div className="flex flex-col gap-2">
<h2 className="text-[18px] font-semibold text-[#18181B] dark:text-[#E0E0E0]">
{config.title}
{t(`agents.sections.${config.id}.title`)}
</h2>
<p className="text-[13px] text-[#71717A]">{config.description}</p>
<p className="text-[13px] text-[#71717A]">
{t(`agents.sections.${config.id}.description`)}
</p>
</div>
{config.showNewAgentButton && (
<button
className="bg-purple-30 hover:bg-violets-are-blue rounded-full px-4 py-2 text-sm text-white"
onClick={() => navigate('/agents/new')}
>
New Agent
{t('agents.newAgent')}
</button>
)}
</div>
Expand All @@ -117,13 +121,13 @@ function AgentSection({
</div>
) : (
<div className="flex h-72 w-full flex-col items-center justify-center gap-3 text-base text-[#18181B] dark:text-[#E0E0E0]">
<p>{config.emptyStateDescription}</p>
<p>{t(`agents.sections.${config.id}.emptyState`)}</p>
{config.showNewAgentButton && (
<button
className="bg-purple-30 hover:bg-violets-are-blue ml-2 rounded-full px-4 py-2 text-sm text-white"
onClick={() => navigate('/agents/new')}
>
New Agent
{t('agents.newAgent')}
</button>
)}
</div>
Expand Down
Loading