feat: Go backend, enhanced search, new widgets, Docker deploy
Major changes: - Add Go backend (backend/) with microservices architecture - Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler, proxy-manager, media-search, fastClassifier, language detection - New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard, UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions - Improved discover-svc with discover-db integration - Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md) - Library-svc: project_id schema migration - Remove deprecated finance-svc and travel-svc - Localization improvements across services Made-with: Cursor
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"@fastify/cors": "^9.0.1",
|
||||
"@toolsycc/json-repair": "^0.1.22",
|
||||
"fastify": "^4.28.1",
|
||||
"franc": "^6.2.0",
|
||||
"ollama": "^0.6.3",
|
||||
"openai": "^6.9.0",
|
||||
"zod": "^4.1.12"
|
||||
|
||||
@@ -6,6 +6,13 @@ import type { ChatTurnMessage } from '../types.js';
|
||||
|
||||
type Input = { chatHistory: ChatTurnMessage[]; locale?: string };
|
||||
|
||||
function getLastUserContent(history: ChatTurnMessage[]): string {
|
||||
for (let i = history.length - 1; i >= 0; i--) {
|
||||
if (history[i].role === 'user') return history[i].content ?? '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export async function generateSuggestions(input: Input, llm: BaseLLM): Promise<string[]> {
|
||||
const schema = z.object({
|
||||
suggestions: z.array(z.string()).describe('List of suggested questions or prompts'),
|
||||
@@ -14,7 +21,7 @@ export async function generateSuggestions(input: Input, llm: BaseLLM): Promise<s
|
||||
const res = await llm.generateObject<{ suggestions: string[] }>({
|
||||
schema,
|
||||
messages: [
|
||||
{ role: 'system', content: getSuggestionGeneratorPrompt(input.locale) },
|
||||
{ role: 'system', content: getSuggestionGeneratorPrompt(undefined, undefined) },
|
||||
{
|
||||
role: 'user',
|
||||
content: `<chat_history>\n${formatChatHistoryAsString(input.chatHistory)}\n</chat_history>`,
|
||||
|
||||
29
services/suggestions-svc/src/lib/prompts/detectLanguage.ts
Normal file
29
services/suggestions-svc/src/lib/prompts/detectLanguage.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { franc } from 'franc';
|
||||
|
||||
/** ISO 639-3 (franc) → human-readable language name */
|
||||
const ISO6393_TO_LANGUAGE: Record<string, string> = {
|
||||
rus: 'Russian', eng: 'English', deu: 'German', fra: 'French', spa: 'Spanish',
|
||||
ita: 'Italian', por: 'Portuguese', ukr: 'Ukrainian', pol: 'Polish', cmn: 'Chinese',
|
||||
jpn: 'Japanese', kor: 'Korean', arb: 'Arabic', tur: 'Turkish', bel: 'Belarusian',
|
||||
kaz: 'Kazakh', swe: 'Swedish', nob: 'Norwegian', dan: 'Danish', fin: 'Finnish',
|
||||
ces: 'Czech', slk: 'Slovak', hun: 'Hungarian', ron: 'Romanian', bul: 'Bulgarian',
|
||||
hrv: 'Croatian', srp: 'Serbian', ell: 'Greek', hin: 'Hindi', tha: 'Thai',
|
||||
vie: 'Vietnamese', ind: 'Indonesian', zlm: 'Malay', heb: 'Hebrew', pes: 'Persian',
|
||||
nld: 'Dutch',
|
||||
};
|
||||
|
||||
/** Fallback instruction when language cannot be determined */
|
||||
export const FALLBACK_RESPONSE_LANGUAGE = `
|
||||
<response_language>
|
||||
Always respond in the same language as the user's query. Detect the language from the conversation and reply accordingly. If the user wrote in Russian, respond in Russian; if in English, respond in English; and so on.
|
||||
</response_language>`;
|
||||
|
||||
/**
|
||||
* Detect language of text using franc. Returns human-readable language name or undefined if undetermined.
|
||||
*/
|
||||
export function detectLanguage(text: string): string | undefined {
|
||||
if (!text || text.trim().length < 2) return undefined;
|
||||
const code = franc(text.trim(), { minLength: 2 });
|
||||
if (code === 'und') return undefined;
|
||||
return ISO6393_TO_LANGUAGE[code] ?? code;
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
const LOCALE_TO_LANGUAGE: Record<string, string> = {
|
||||
ru: 'Russian',
|
||||
en: 'English',
|
||||
de: 'German',
|
||||
fr: 'French',
|
||||
es: 'Spanish',
|
||||
it: 'Italian',
|
||||
pt: 'Portuguese',
|
||||
uk: 'Ukrainian',
|
||||
pl: 'Polish',
|
||||
zh: 'Chinese',
|
||||
ja: 'Japanese',
|
||||
ko: 'Korean',
|
||||
};
|
||||
/** Принудительно русский язык везде */
|
||||
const RUSSIAN_RESPONSE_LANGUAGE = `
|
||||
<response_language>
|
||||
Always respond ONLY in Russian. Regardless of the user's query language, format your entire response in Russian.
|
||||
</response_language>`;
|
||||
|
||||
export function getLocaleInstruction(locale?: string): string {
|
||||
if (!locale) return '';
|
||||
const lang = locale.split('-')[0];
|
||||
const name = LOCALE_TO_LANGUAGE[lang] ?? lang;
|
||||
return `\n<response_language>\nUser's locale is ${locale}. Always format your response in ${name}.\n</response_language>`;
|
||||
export const FALLBACK_RESPONSE_LANGUAGE = RUSSIAN_RESPONSE_LANGUAGE;
|
||||
|
||||
/**
|
||||
* Build response language instruction. Always Russian.
|
||||
*/
|
||||
export function getLocaleInstruction(
|
||||
_locale?: string,
|
||||
_detectedLanguage?: string,
|
||||
): string {
|
||||
return RUSSIAN_RESPONSE_LANGUAGE;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ Rules:
|
||||
Today's date is ${new Date().toISOString()}
|
||||
`;
|
||||
|
||||
export function getSuggestionGeneratorPrompt(locale?: string): string {
|
||||
return base + getLocaleInstruction(locale);
|
||||
export function getSuggestionGeneratorPrompt(locale?: string, detectedLanguage?: string): string {
|
||||
return base + getLocaleInstruction(locale, detectedLanguage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user