Refactor chat title sanitization logic in backend and frontend
This commit is contained in:
@@ -29,10 +29,19 @@ ensure_sources_column(engine)
|
|||||||
app = FastAPI(title="LLM Desktop Backend", version="0.1.0" )
|
app = FastAPI(title="LLM Desktop Backend", version="0.1.0" )
|
||||||
|
|
||||||
|
|
||||||
def sanitize_generated_chat_title(title: str) -> str:
|
def sanitize_chat_title(title: str) -> str:
|
||||||
cleaned_title = html.unescape(title or "")
|
cleaned_title = html.unescape(title or "")
|
||||||
cleaned_title = re.sub(r'<think(?:ing)?>.*?</think(?:ing)?>', '', cleaned_title, flags=re.DOTALL | re.IGNORECASE)
|
cleaned_title = re.sub(r'<think(?:ing)?>.*?</think(?:ing)?>', '', cleaned_title, flags=re.DOTALL | re.IGNORECASE)
|
||||||
cleaned_title = re.sub(r'[*#]', '', cleaned_title)
|
cleaned_title = cleaned_title.strip()
|
||||||
|
|
||||||
|
previous_title = None
|
||||||
|
while cleaned_title and cleaned_title != previous_title:
|
||||||
|
previous_title = cleaned_title
|
||||||
|
cleaned_title = re.sub(r'^\s*#+\s*', '', cleaned_title)
|
||||||
|
cleaned_title = re.sub(r'^\s*\*{1,2}\s*', '', cleaned_title)
|
||||||
|
cleaned_title = re.sub(r'\s*\*{1,2}\s*$', '', cleaned_title)
|
||||||
|
cleaned_title = cleaned_title.strip()
|
||||||
|
|
||||||
cleaned_title = re.sub(r'\s+', ' ', cleaned_title)
|
cleaned_title = re.sub(r'\s+', ' ', cleaned_title)
|
||||||
return cleaned_title.strip()
|
return cleaned_title.strip()
|
||||||
|
|
||||||
@@ -248,7 +257,17 @@ async def startup_prepare_models_route():
|
|||||||
@app.get("/sessions", response_model=schemas.SessionsResponse)
|
@app.get("/sessions", response_model=schemas.SessionsResponse)
|
||||||
def get_sessions(db: Session = Depends(get_db)):
|
def get_sessions(db: Session = Depends(get_db)):
|
||||||
sessions = db.query(models.ChatSession).order_by(models.ChatSession.created_at.desc()).all()
|
sessions = db.query(models.ChatSession).order_by(models.ChatSession.created_at.desc()).all()
|
||||||
return {"sessions": sessions}
|
return {
|
||||||
|
"sessions": [
|
||||||
|
{
|
||||||
|
"id": session.id,
|
||||||
|
"session_id": session.session_id,
|
||||||
|
"name": sanitize_chat_title(session.name),
|
||||||
|
"created_at": session.created_at,
|
||||||
|
}
|
||||||
|
for session in sessions
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@app.post("/sessions", response_model=schemas.ChatSession)
|
@app.post("/sessions", response_model=schemas.ChatSession)
|
||||||
def create_session(req: schemas.CreateSessionRequest, db: Session = Depends(get_db)):
|
def create_session(req: schemas.CreateSessionRequest, db: Session = Depends(get_db)):
|
||||||
@@ -361,7 +380,7 @@ async def generate_title(req: schemas.GenerateTitleRequest, db: Session = Depend
|
|||||||
|
|
||||||
print(f"Original title from LLM: {title}") # Debugging line to see the raw title
|
print(f"Original title from LLM: {title}") # Debugging line to see the raw title
|
||||||
|
|
||||||
cleaned_title = sanitize_generated_chat_title(title)
|
cleaned_title = sanitize_chat_title(title)
|
||||||
|
|
||||||
print(f"Cleaned title before saving: {cleaned_title}") # Debugging line to see the cleaned title
|
print(f"Cleaned title before saving: {cleaned_title}") # Debugging line to see the cleaned title
|
||||||
|
|
||||||
@@ -389,7 +408,7 @@ def rename_session(session_id: str, req: schemas.GenerateTitleResponse, db: Sess
|
|||||||
if not session:
|
if not session:
|
||||||
raise HTTPException(status_code=404, detail="Session not found")
|
raise HTTPException(status_code=404, detail="Session not found")
|
||||||
|
|
||||||
session.name = req.title
|
session.name = sanitize_chat_title(req.title)
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
|
|||||||
33
src/App.jsx
33
src/App.jsx
@@ -19,12 +19,22 @@ import {
|
|||||||
supportsAudioInputCapture,
|
supportsAudioInputCapture,
|
||||||
} from './audioInput'
|
} from './audioInput'
|
||||||
|
|
||||||
function sanitizeGeneratedChatTitle(title) {
|
function sanitizeChatTitle(title) {
|
||||||
return (title || '')
|
let cleanedTitle = String(title || '')
|
||||||
.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, '')
|
.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, '')
|
||||||
.replace(/[*#]/g, '')
|
|
||||||
.replace(/\s+/g, ' ')
|
|
||||||
.trim()
|
.trim()
|
||||||
|
|
||||||
|
let previousTitle = null
|
||||||
|
while (cleanedTitle && cleanedTitle !== previousTitle) {
|
||||||
|
previousTitle = cleanedTitle
|
||||||
|
cleanedTitle = cleanedTitle
|
||||||
|
.replace(/^\s*#+\s*/, '')
|
||||||
|
.replace(/^\s*\*{1,2}\s*/, '')
|
||||||
|
.replace(/\s*\*{1,2}\s*$/, '')
|
||||||
|
.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleanedTitle.replace(/\s+/g, ' ').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendOllamaErrorHint(text, marker, block) {
|
function appendOllamaErrorHint(text, marker, block) {
|
||||||
@@ -1569,7 +1579,11 @@ async function regenerateFromIndex(index, overrideUserText = null) {
|
|||||||
fetch(`${backendApiUrl}/sessions`)
|
fetch(`${backendApiUrl}/sessions`)
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const sessionsWithMessages = data.sessions.map(s => ({ ...s, messages: [] }));
|
const sessionsWithMessages = data.sessions.map(s => ({
|
||||||
|
...s,
|
||||||
|
name: sanitizeChatTitle(s.name),
|
||||||
|
messages: [],
|
||||||
|
}));
|
||||||
setChatSessions(sessionsWithMessages);
|
setChatSessions(sessionsWithMessages);
|
||||||
if (sessionsWithMessages.length > 0) {
|
if (sessionsWithMessages.length > 0) {
|
||||||
setActiveSessionId(sessionsWithMessages[0].session_id);
|
setActiveSessionId(sessionsWithMessages[0].session_id);
|
||||||
@@ -2190,7 +2204,7 @@ async function sendMessage() {
|
|||||||
})
|
})
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const sanitizedTitle = sanitizeGeneratedChatTitle(data.title)
|
const sanitizedTitle = sanitizeChatTitle(data.title)
|
||||||
setChatSessions(prevSessions =>
|
setChatSessions(prevSessions =>
|
||||||
prevSessions.map(session =>
|
prevSessions.map(session =>
|
||||||
session.session_id === targetSessionId ? { ...session, name: sanitizedTitle } : session
|
session.session_id === targetSessionId ? { ...session, name: sanitizedTitle } : session
|
||||||
@@ -2232,7 +2246,7 @@ async function createNewChat() {
|
|||||||
body: JSON.stringify({ session_id: newSessionId })
|
body: JSON.stringify({ session_id: newSessionId })
|
||||||
});
|
});
|
||||||
const newSession = await res.json();
|
const newSession = await res.json();
|
||||||
const sessionWithMessages = { ...newSession, messages: [] };
|
const sessionWithMessages = { ...newSession, name: sanitizeChatTitle(newSession.name), messages: [] };
|
||||||
setChatSessions(prevSessions => [sessionWithMessages, ...prevSessions]);
|
setChatSessions(prevSessions => [sessionWithMessages, ...prevSessions]);
|
||||||
setActiveSessionId(newSession.session_id);
|
setActiveSessionId(newSession.session_id);
|
||||||
textareaRef.current?.focus();
|
textareaRef.current?.focus();
|
||||||
@@ -2281,15 +2295,16 @@ async function createNewChat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRename(sessionId, newName) {
|
function handleRename(sessionId, newName) {
|
||||||
|
const sanitizedName = sanitizeChatTitle(newName)
|
||||||
fetch(`${backendApiUrl}/sessions/${sessionId}/rename`, {
|
fetch(`${backendApiUrl}/sessions/${sessionId}/rename`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ title: newName })
|
body: JSON.stringify({ title: sanitizedName })
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setChatSessions(prevSessions =>
|
setChatSessions(prevSessions =>
|
||||||
prevSessions.map(session =>
|
prevSessions.map(session =>
|
||||||
session.session_id === sessionId ? { ...session, name: newName } : session
|
session.session_id === sessionId ? { ...session, name: sanitizedName } : session
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
setEditingSessionId(null);
|
setEditingSessionId(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user