@astro-minimax/ai 0.7.0 → 0.7.1
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.
- package/dist/intelligence/citation-appender.d.ts +19 -0
- package/dist/intelligence/citation-appender.d.ts.map +1 -0
- package/dist/intelligence/citation-appender.js +65 -0
- package/dist/intelligence/citation-guard.d.ts.map +1 -1
- package/dist/intelligence/citation-guard.js +12 -13
- package/dist/intelligence/index.d.ts +2 -0
- package/dist/intelligence/index.d.ts.map +1 -1
- package/dist/intelligence/index.js +1 -0
- package/dist/intelligence/response-templates.d.ts +16 -0
- package/dist/intelligence/response-templates.d.ts.map +1 -0
- package/dist/intelligence/response-templates.js +116 -0
- package/dist/prompt/prompt-builder.d.ts +0 -8
- package/dist/prompt/prompt-builder.d.ts.map +1 -1
- package/dist/prompt/prompt-builder.js +2 -9
- package/dist/prompt/semi-static-layer.d.ts +0 -4
- package/dist/prompt/semi-static-layer.d.ts.map +1 -1
- package/dist/prompt/semi-static-layer.js +7 -10
- package/dist/prompt/static-layer.d.ts.map +1 -1
- package/dist/prompt/static-layer.js +4 -2
- package/dist/prompt/types.d.ts +1 -0
- package/dist/prompt/types.d.ts.map +1 -1
- package/dist/search/search-api.d.ts.map +1 -1
- package/dist/search/search-api.js +2 -0
- package/dist/search/types.d.ts +2 -0
- package/dist/search/types.d.ts.map +1 -1
- package/dist/server/chat-handler.d.ts.map +1 -1
- package/dist/server/chat-handler.js +12 -1
- package/dist/utils/i18n.d.ts +1 -1
- package/dist/utils/i18n.d.ts.map +1 -1
- package/dist/utils/i18n.js +8 -0
- package/package.json +2 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ArticleContext, ProjectContext } from '../search/types.js';
|
|
2
|
+
export interface CitationAppenderConfig {
|
|
3
|
+
articles: ArticleContext[];
|
|
4
|
+
projects: ProjectContext[];
|
|
5
|
+
lang: string;
|
|
6
|
+
maxCitations: number;
|
|
7
|
+
minScore: number;
|
|
8
|
+
}
|
|
9
|
+
interface CitationCandidate {
|
|
10
|
+
title: string;
|
|
11
|
+
url: string;
|
|
12
|
+
score: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function selectCitations(articles: ArticleContext[], projects: ProjectContext[], maxCitations: number, minScore: number): CitationCandidate[];
|
|
15
|
+
export declare function formatCitationBlock(citations: CitationCandidate[], lang: string): string;
|
|
16
|
+
export declare function createCitationAppenderTransform(config: CitationAppenderConfig): (stream: ReadableStream<string>) => ReadableStream<string>;
|
|
17
|
+
export declare function shouldAppendCitations(response: string, articles: ArticleContext[], projects: ProjectContext[]): boolean;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=citation-appender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation-appender.d.ts","sourceRoot":"","sources":["../../src/intelligence/citation-appender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,cAAc,EAAE,EAC1B,QAAQ,EAAE,cAAc,EAAE,EAC1B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,iBAAiB,EAAE,CAarB;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,iBAAiB,EAAE,EAC9B,IAAI,EAAE,MAAM,GACX,MAAM,CAYR;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,sBAAsB,GAC7B,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,CAkC5D;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EAAE,EAC1B,QAAQ,EAAE,cAAc,EAAE,GACzB,OAAO,CAQT"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
function hasExistingCitations(text, validUrls) {
|
|
2
|
+
const linkPattern = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
3
|
+
const matches = [...text.matchAll(linkPattern)];
|
|
4
|
+
return matches.some(m => validUrls.has(m[2]));
|
|
5
|
+
}
|
|
6
|
+
export function selectCitations(articles, projects, maxCitations, minScore) {
|
|
7
|
+
const candidates = [
|
|
8
|
+
...articles
|
|
9
|
+
.filter(a => (a.score ?? 0) >= minScore)
|
|
10
|
+
.map(a => ({ title: a.title, url: a.url, score: a.score ?? 0 })),
|
|
11
|
+
...projects
|
|
12
|
+
.filter(p => (p.score ?? 0) >= minScore)
|
|
13
|
+
.map(p => ({ title: p.name, url: p.url, score: p.score ?? 0 })),
|
|
14
|
+
];
|
|
15
|
+
return candidates
|
|
16
|
+
.sort((a, b) => b.score - a.score)
|
|
17
|
+
.slice(0, maxCitations);
|
|
18
|
+
}
|
|
19
|
+
export function formatCitationBlock(citations, lang) {
|
|
20
|
+
if (citations.length === 0)
|
|
21
|
+
return '';
|
|
22
|
+
const heading = lang === 'zh' ? '延伸阅读' : 'Further Reading';
|
|
23
|
+
const lines = [
|
|
24
|
+
'',
|
|
25
|
+
`**${heading}:**`,
|
|
26
|
+
...citations.map(c => `- [${c.title}](${c.url})`),
|
|
27
|
+
];
|
|
28
|
+
return lines.join('\n');
|
|
29
|
+
}
|
|
30
|
+
export function createCitationAppenderTransform(config) {
|
|
31
|
+
const { articles, projects, lang, maxCitations = 3, minScore = 5 } = config;
|
|
32
|
+
const validUrls = new Set([
|
|
33
|
+
...articles.map(a => a.url),
|
|
34
|
+
...projects.map(p => p.url),
|
|
35
|
+
]);
|
|
36
|
+
return (stream) => {
|
|
37
|
+
let fullText = '';
|
|
38
|
+
const transform = new TransformStream({
|
|
39
|
+
transform(chunk, controller) {
|
|
40
|
+
fullText += chunk;
|
|
41
|
+
controller.enqueue(chunk);
|
|
42
|
+
},
|
|
43
|
+
flush(controller) {
|
|
44
|
+
if (hasExistingCitations(fullText, validUrls)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const citations = selectCitations(articles, projects, maxCitations, minScore);
|
|
48
|
+
if (citations.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const citationBlock = formatCitationBlock(citations, lang);
|
|
52
|
+
controller.enqueue(citationBlock);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
return stream.pipeThrough(transform);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function shouldAppendCitations(response, articles, projects) {
|
|
59
|
+
const validUrls = new Set([
|
|
60
|
+
...articles.map(a => a.url),
|
|
61
|
+
...projects.map(p => p.url),
|
|
62
|
+
]);
|
|
63
|
+
return !hasExistingCitations(response, validUrls) &&
|
|
64
|
+
[...articles, ...projects].some(item => (item.score ?? 0) >= 5);
|
|
65
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"citation-guard.d.ts","sourceRoot":"","sources":["../../src/intelligence/citation-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"citation-guard.d.ts","sourceRoot":"","sources":["../../src/intelligence/citation-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAS9E,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;AAgB1G;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAS3D;AAoBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,sBAAsB,GAAG,IAAI,CAuBhC;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CAClE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,CAuD7D"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { PRIVACY_REFUSAL_TEMPLATES, NO_ARTICLE_TEMPLATES, ARTICLE_COUNT_TEMPLATES, pickTemplate, pickTemplateWithVars, } from './response-templates.js';
|
|
1
2
|
const PRIVACY_PATTERNS = [
|
|
2
|
-
{ regex: /(住址|地址|住在哪|address|where.*live)/iu,
|
|
3
|
-
{ regex: /(收入|工资|薪资|salary|income|earn)/iu,
|
|
4
|
-
{ regex: /(家人|妻子|丈夫|孩子|父母|family|wife|husband|children|parent)/iu,
|
|
5
|
-
{ regex: /(电话|手机号|phone|mobile)/iu,
|
|
6
|
-
{ regex: /(身份证|id\s*card|passport)/iu,
|
|
7
|
-
{ regex: /(年龄|多大了|几岁|how old|age)/iu,
|
|
3
|
+
{ regex: /(住址|地址|住在哪|address|where.*live)/iu, key: 'address' },
|
|
4
|
+
{ regex: /(收入|工资|薪资|salary|income|earn)/iu, key: 'income' },
|
|
5
|
+
{ regex: /(家人|妻子|丈夫|孩子|父母|family|wife|husband|children|parent)/iu, key: 'family' },
|
|
6
|
+
{ regex: /(电话|手机号|phone|mobile)/iu, key: 'phone' },
|
|
7
|
+
{ regex: /(身份证|id\s*card|passport)/iu, key: 'id' },
|
|
8
|
+
{ regex: /(年龄|多大了|几岁|how old|age)/iu, key: 'age' },
|
|
8
9
|
];
|
|
9
10
|
/**
|
|
10
11
|
* Resolves the expected answer mode from the user query.
|
|
@@ -33,8 +34,10 @@ export function resolveAnswerMode(query) {
|
|
|
33
34
|
function checkPrivacyRefusal(query, lang) {
|
|
34
35
|
for (const pattern of PRIVACY_PATTERNS) {
|
|
35
36
|
if (pattern.regex.test(query)) {
|
|
37
|
+
const templates = PRIVACY_REFUSAL_TEMPLATES[pattern.key];
|
|
38
|
+
const text = templates ? pickTemplate(templates, lang) : '';
|
|
36
39
|
return {
|
|
37
|
-
text
|
|
40
|
+
text,
|
|
38
41
|
actions: ['preflight_reject'],
|
|
39
42
|
};
|
|
40
43
|
}
|
|
@@ -55,17 +58,13 @@ export function getCitationGuardPreflight(params) {
|
|
|
55
58
|
if (/有几篇|有多少篇|文章数量|总共.*文章|how many.*article/u.test(q)) {
|
|
56
59
|
const total = articles.length;
|
|
57
60
|
if (total > 0) {
|
|
58
|
-
const text = lang
|
|
59
|
-
? `Based on my search, I found ${total} related articles.`
|
|
60
|
-
: `根据我检索到的信息,当前共找到 ${total} 篇相关文章。`;
|
|
61
|
+
const text = pickTemplateWithVars(ARTICLE_COUNT_TEMPLATES, lang, { count: total });
|
|
61
62
|
return { text, actions: ['preflight_reject'] };
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
if (/有没有|是否有|有.*文章|写过.*吗|is there|any.*article/u.test(q)) {
|
|
65
66
|
if (articles.length === 0 && projects.length === 0) {
|
|
66
|
-
const text = lang
|
|
67
|
-
? 'No articles directly related to this topic were found. Try different keywords or ask another question.'
|
|
68
|
-
: '根据博客内容搜索,目前没有找到与这个主题直接相关的文章。你可以尝试用其他关键词搜索,或者问我其他问题。';
|
|
67
|
+
const text = pickTemplate(NO_ARTICLE_TEMPLATES, lang);
|
|
69
68
|
return { text, actions: ['preflight_reject'] };
|
|
70
69
|
}
|
|
71
70
|
}
|
|
@@ -4,5 +4,7 @@ export { shouldRunKeywordExtraction, extractSearchKeywords, KEYWORD_EXTRACTION_T
|
|
|
4
4
|
export { shouldSkipAnalysis, analyzeRetrievedEvidence, buildEvidenceSection, EVIDENCE_ANALYSIS_TIMEOUT_MS, EVIDENCE_ANALYSIS_MAX_TOKENS, } from './evidence-analysis.js';
|
|
5
5
|
export { getCitationGuardPreflight, createCitationGuardTransform, resolveAnswerMode, } from './citation-guard.js';
|
|
6
6
|
export type { AnswerMode } from './citation-guard.js';
|
|
7
|
+
export { createCitationAppenderTransform, shouldAppendCitations, selectCitations, formatCitationBlock, } from './citation-appender.js';
|
|
8
|
+
export type { CitationAppenderConfig } from './citation-appender.js';
|
|
7
9
|
export type { QueryComplexity, KeywordExtractionResult, TokenUsageStats, EvidenceAnalysisResult, CitationGuardPreflight, CitationGuardAction, } from './types.js';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intelligence/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/intelligence/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAE7B,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EACL,+BAA+B,EAC/B,qBAAqB,EACrB,eAAe,EACf,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
|
|
@@ -2,3 +2,4 @@ export { isLikelyFollowUp, hasNewSignificantTokens, hasQueryOverlap, shouldReuse
|
|
|
2
2
|
export { shouldRunKeywordExtraction, extractSearchKeywords, KEYWORD_EXTRACTION_TIMEOUT_MS, } from './keyword-extract.js';
|
|
3
3
|
export { shouldSkipAnalysis, analyzeRetrievedEvidence, buildEvidenceSection, EVIDENCE_ANALYSIS_TIMEOUT_MS, EVIDENCE_ANALYSIS_MAX_TOKENS, } from './evidence-analysis.js';
|
|
4
4
|
export { getCitationGuardPreflight, createCitationGuardTransform, resolveAnswerMode, } from './citation-guard.js';
|
|
5
|
+
export { createCitationAppenderTransform, shouldAppendCitations, selectCitations, formatCitationBlock, } from './citation-appender.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ResponseTemplate {
|
|
2
|
+
zh: string[];
|
|
3
|
+
en: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare const PRIVACY_REFUSAL_TEMPLATES: Record<string, ResponseTemplate>;
|
|
6
|
+
export declare const NO_ARTICLE_TEMPLATES: ResponseTemplate;
|
|
7
|
+
export declare const ARTICLE_COUNT_TEMPLATES: ResponseTemplate;
|
|
8
|
+
/**
|
|
9
|
+
* Randomly selects a template from the available options.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pickTemplate(templates: ResponseTemplate, lang: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Picks a template and interpolates variables.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pickTemplateWithVars(templates: ResponseTemplate, lang: string, vars: Record<string, string | number>): string;
|
|
16
|
+
//# sourceMappingURL=response-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-templates.d.ts","sourceRoot":"","sources":["../../src/intelligence/response-templates.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;CACd;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAyEtE,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,gBAWlC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,gBAWrC,CAAC;AAEF;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI9E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,gBAAgB,EAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACpC,MAAM,CAMR"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const PRIVACY_REFUSAL_TEMPLATES = {
|
|
2
|
+
address: {
|
|
3
|
+
zh: [
|
|
4
|
+
'具体住址是私人信息,未在博客中公开。',
|
|
5
|
+
'关于住址信息,博客中没有相关内容。',
|
|
6
|
+
'这个信息涉及隐私,博主没有在博客中分享。',
|
|
7
|
+
],
|
|
8
|
+
en: [
|
|
9
|
+
'Address is private and not disclosed on the blog.',
|
|
10
|
+
'The blogger has not shared address information publicly.',
|
|
11
|
+
'This is private information that is not available on the blog.',
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
income: {
|
|
15
|
+
zh: [
|
|
16
|
+
'收入信息未在博客中公开。',
|
|
17
|
+
'关于收入,博客中没有相关内容。',
|
|
18
|
+
'这个信息属于隐私范畴,博主没有公开。',
|
|
19
|
+
],
|
|
20
|
+
en: [
|
|
21
|
+
'Income information is not disclosed on the blog.',
|
|
22
|
+
'The blogger has not shared income details publicly.',
|
|
23
|
+
'This is private financial information not available on the blog.',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
family: {
|
|
27
|
+
zh: [
|
|
28
|
+
'家人信息未在博客中公开。',
|
|
29
|
+
'关于家人,博客中没有详细介绍。',
|
|
30
|
+
'这属于私人生活范畴,博主选择不公开。',
|
|
31
|
+
],
|
|
32
|
+
en: [
|
|
33
|
+
'Family information is not disclosed on the blog.',
|
|
34
|
+
'The blogger keeps family matters private.',
|
|
35
|
+
'Details about family members are not shared publicly.',
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
phone: {
|
|
39
|
+
zh: [
|
|
40
|
+
'联系电话未在博客中公开。',
|
|
41
|
+
'博主的联系方式没有在博客中分享。',
|
|
42
|
+
'电话号码属于隐私信息,无法提供。',
|
|
43
|
+
],
|
|
44
|
+
en: [
|
|
45
|
+
'Phone number is not disclosed on the blog.',
|
|
46
|
+
'Contact details are not shared publicly on the blog.',
|
|
47
|
+
'Phone numbers are private information not available here.',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
id: {
|
|
51
|
+
zh: [
|
|
52
|
+
'身份证件信息未在博客中公开。',
|
|
53
|
+
'这属于敏感个人信息,博主没有公开。',
|
|
54
|
+
'身份证件信息受保护,不在博客内容中。',
|
|
55
|
+
],
|
|
56
|
+
en: [
|
|
57
|
+
'ID information is not disclosed on the blog.',
|
|
58
|
+
'Identity document details are private and not shared.',
|
|
59
|
+
'This is sensitive personal information not available publicly.',
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
age: {
|
|
63
|
+
zh: [
|
|
64
|
+
'年龄信息未在博客中公开。',
|
|
65
|
+
'关于年龄,博客中没有明确提及。',
|
|
66
|
+
'这个信息博主没有在博客中分享。',
|
|
67
|
+
],
|
|
68
|
+
en: [
|
|
69
|
+
'Age information is not disclosed on the blog.',
|
|
70
|
+
'The blogger has not shared age details publicly.',
|
|
71
|
+
'Age is not mentioned in the blog content.',
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
export const NO_ARTICLE_TEMPLATES = {
|
|
76
|
+
zh: [
|
|
77
|
+
'根据博客内容搜索,目前没有找到与这个主题直接相关的文章。你可以尝试用其他关键词搜索,或者问我其他问题。',
|
|
78
|
+
'我在博客中没有找到相关的内容。试试换个方式提问,或者浏览其他话题。',
|
|
79
|
+
'抱歉,博客里暂时没有涉及这个话题的文章。你可以问我其他问题,我尽力帮你找答案。',
|
|
80
|
+
],
|
|
81
|
+
en: [
|
|
82
|
+
'No articles directly related to this topic were found. Try different keywords or ask another question.',
|
|
83
|
+
'I could not find relevant content in the blog. Try rephrasing your question or exploring other topics.',
|
|
84
|
+
'Sorry, there are no articles on this topic in the blog. Feel free to ask about something else.',
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
export const ARTICLE_COUNT_TEMPLATES = {
|
|
88
|
+
zh: [
|
|
89
|
+
'根据我检索到的信息,当前共找到 {count} 篇相关文章。',
|
|
90
|
+
'搜索结果显示,有 {count} 篇文章与你的问题相关。',
|
|
91
|
+
'我找到了 {count} 篇可能对你有帮助的文章。',
|
|
92
|
+
],
|
|
93
|
+
en: [
|
|
94
|
+
'Based on my search, I found {count} related articles.',
|
|
95
|
+
'The search returned {count} articles that may be relevant.',
|
|
96
|
+
'I discovered {count} articles related to your query.',
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Randomly selects a template from the available options.
|
|
101
|
+
*/
|
|
102
|
+
export function pickTemplate(templates, lang) {
|
|
103
|
+
const options = lang === 'en' ? templates.en : templates.zh;
|
|
104
|
+
const index = Math.floor(Math.random() * options.length);
|
|
105
|
+
return options[index];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Picks a template and interpolates variables.
|
|
109
|
+
*/
|
|
110
|
+
export function pickTemplateWithVars(templates, lang, vars) {
|
|
111
|
+
let text = pickTemplate(templates, lang);
|
|
112
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
113
|
+
text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
|
|
114
|
+
}
|
|
115
|
+
return text;
|
|
116
|
+
}
|
|
@@ -1,11 +1,3 @@
|
|
|
1
1
|
import type { PromptBuildConfig } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Assembles the three-layer system prompt.
|
|
4
|
-
*
|
|
5
|
-
* Structure:
|
|
6
|
-
* 1. Static layer — Author identity, role, behavior constraints (rarely changes)
|
|
7
|
-
* 2. Semi-static layer — Blog metadata loaded at startup (changes on rebuild)
|
|
8
|
-
* 3. Dynamic layer — Per-request search results + evidence analysis
|
|
9
|
-
*/
|
|
10
2
|
export declare function buildSystemPrompt(config: PromptBuildConfig): string;
|
|
11
3
|
//# sourceMappingURL=prompt-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/prompt/prompt-builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/prompt/prompt-builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAUnE"}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { buildStaticLayer } from './static-layer.js';
|
|
2
2
|
import { buildSemiStaticLayer } from './semi-static-layer.js';
|
|
3
3
|
import { buildDynamicLayer } from './dynamic-layer.js';
|
|
4
|
-
/**
|
|
5
|
-
* Assembles the three-layer system prompt.
|
|
6
|
-
*
|
|
7
|
-
* Structure:
|
|
8
|
-
* 1. Static layer — Author identity, role, behavior constraints (rarely changes)
|
|
9
|
-
* 2. Semi-static layer — Blog metadata loaded at startup (changes on rebuild)
|
|
10
|
-
* 3. Dynamic layer — Per-request search results + evidence analysis
|
|
11
|
-
*/
|
|
12
4
|
export function buildSystemPrompt(config) {
|
|
5
|
+
const lang = config.static.lang || config.dynamic.lang;
|
|
13
6
|
const layers = [
|
|
14
7
|
buildStaticLayer(config.static),
|
|
15
|
-
buildSemiStaticLayer(config.semiStatic),
|
|
8
|
+
buildSemiStaticLayer({ ...config.semiStatic, lang }),
|
|
16
9
|
buildDynamicLayer(config.dynamic),
|
|
17
10
|
].filter(Boolean);
|
|
18
11
|
return layers.join('\n\n');
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import type { SemiStaticLayerConfig } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Semi-static layer: blog metadata loaded at build/startup time.
|
|
4
|
-
* This changes when the blog is rebuilt, not per-request.
|
|
5
|
-
*/
|
|
6
2
|
export declare function buildSemiStaticLayer(config: SemiStaticLayerConfig): string;
|
|
7
3
|
//# sourceMappingURL=semi-static-layer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semi-static-layer.d.ts","sourceRoot":"","sources":["../../src/prompt/semi-static-layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"semi-static-layer.d.ts","sourceRoot":"","sources":["../../src/prompt/semi-static-layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGxD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CA+B1E"}
|
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
* Semi-static layer: blog metadata loaded at build/startup time.
|
|
3
|
-
* This changes when the blog is rebuilt, not per-request.
|
|
4
|
-
*/
|
|
1
|
+
import { t, getLang } from '../utils/i18n.js';
|
|
5
2
|
export function buildSemiStaticLayer(config) {
|
|
6
|
-
const { authorContext } = config;
|
|
3
|
+
const { authorContext, lang: configLang } = config;
|
|
7
4
|
if (!authorContext)
|
|
8
5
|
return '';
|
|
6
|
+
const lang = getLang(configLang);
|
|
9
7
|
const lines = [];
|
|
10
8
|
const { posts } = authorContext;
|
|
11
9
|
if (!posts.length)
|
|
12
10
|
return '';
|
|
13
|
-
// Blog overview
|
|
14
11
|
const totalPosts = posts.length;
|
|
15
12
|
const categories = [...new Set(posts.map(p => p.category).filter(Boolean))];
|
|
16
13
|
const recentPosts = posts
|
|
17
14
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
18
15
|
.slice(0, 10);
|
|
19
|
-
lines.push('##
|
|
20
|
-
lines.push(
|
|
16
|
+
lines.push('## ' + t('ai.semiStatic.blogOverview', lang));
|
|
17
|
+
lines.push('- ' + t('ai.semiStatic.totalPosts', lang, { count: totalPosts }));
|
|
21
18
|
if (categories.length) {
|
|
22
|
-
lines.push(
|
|
19
|
+
lines.push('- ' + t('ai.semiStatic.mainCategories', lang, { categories: categories.slice(0, 8).join(lang === 'zh' ? '、' : ', ') }));
|
|
23
20
|
}
|
|
24
21
|
lines.push('');
|
|
25
|
-
lines.push('##
|
|
22
|
+
lines.push('## ' + t('ai.semiStatic.latestArticles', lang));
|
|
26
23
|
for (const post of recentPosts) {
|
|
27
24
|
const date = post.date ? new Date(post.date).toISOString().slice(0, 10) : '';
|
|
28
25
|
const summary = post.summary ? ` — ${post.summary.slice(0, 60)}` : '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-layer.d.ts","sourceRoot":"","sources":["../../src/prompt/static-layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"static-layer.d.ts","sourceRoot":"","sources":["../../src/prompt/static-layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAkIpD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAqClE"}
|
|
@@ -32,8 +32,9 @@ const PROMPTS = {
|
|
|
32
32
|
'L1 原始博客内容:「相关文章」中的标题、摘要、要点、正文节选(最高优先级)',
|
|
33
33
|
'L2 策划数据:作者简介、项目列表、博客概况',
|
|
34
34
|
'L3 结构化事实:标签统计、分类聚合等推导数据',
|
|
35
|
+
'L4 外部验证来源:官方文档、GitHub 仓库、权威外部来源(需标注引用)',
|
|
35
36
|
'L5 语言风格:仅影响表达方式,不作为事实依据',
|
|
36
|
-
'当不同来源冲突时,L1 > L2 > L3 > L5',
|
|
37
|
+
'当不同来源冲突时,L1 > L2 > L3 > L4 > L5',
|
|
37
38
|
'L1 内容必须来自「相关文章」部分,禁止凭空编造',
|
|
38
39
|
],
|
|
39
40
|
privacyProtection: [
|
|
@@ -87,8 +88,9 @@ const PROMPTS = {
|
|
|
87
88
|
'L1 Blog content: titles, summaries, key points, excerpts from "Related Articles" (highest priority)',
|
|
88
89
|
'L2 Curated data: author bio, project list, blog overview',
|
|
89
90
|
'L3 Structured facts: tag statistics, category aggregations, derived data',
|
|
91
|
+
'L4 External verification: official docs, GitHub repos, authoritative sources (cite when used)',
|
|
90
92
|
'L5 Voice style: affects expression only, not to be used as factual evidence',
|
|
91
|
-
'When sources conflict: L1 > L2 > L3 > L5',
|
|
93
|
+
'When sources conflict: L1 > L2 > L3 > L4 > L5',
|
|
92
94
|
'L1 content must come from the "Related Articles" section; never fabricate',
|
|
93
95
|
],
|
|
94
96
|
privacyProtection: [
|
package/dist/prompt/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/prompt/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACxC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/prompt/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACxC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,EAAE,qBAAqB,CAAC;IAClC,OAAO,EAAE,kBAAkB,CAAC;CAC7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-api.d.ts","sourceRoot":"","sources":["../../src/search/search-api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAiC,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYhH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI,CAElE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"search-api.d.ts","sourceRoot":"","sources":["../../src/search/search-api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAiC,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYhH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI,CAElE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D,cAAc,EAAE,CAsClB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACjC,cAAc,EAAE,CAgBlB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAUzF"}
|
|
@@ -52,6 +52,7 @@ export function searchArticles(query, options = {}) {
|
|
|
52
52
|
categories: result.categories,
|
|
53
53
|
dateTime: result.dateTime,
|
|
54
54
|
fullContent,
|
|
55
|
+
score: result.score,
|
|
55
56
|
};
|
|
56
57
|
});
|
|
57
58
|
}
|
|
@@ -72,6 +73,7 @@ export function searchProjects(query, options = {}) {
|
|
|
72
73
|
name: r.title,
|
|
73
74
|
url: r.url.startsWith('http') ? r.url : `${baseUrl}${r.url}`,
|
|
74
75
|
description: r.excerpt || r.content.slice(0, 200),
|
|
76
|
+
score: r.score,
|
|
75
77
|
}));
|
|
76
78
|
}
|
|
77
79
|
/**
|
package/dist/search/types.d.ts
CHANGED
|
@@ -26,11 +26,13 @@ export interface ArticleContext {
|
|
|
26
26
|
categories: string[];
|
|
27
27
|
dateTime: number;
|
|
28
28
|
fullContent?: string;
|
|
29
|
+
score?: number;
|
|
29
30
|
}
|
|
30
31
|
export interface ProjectContext {
|
|
31
32
|
name: string;
|
|
32
33
|
url: string;
|
|
33
34
|
description: string;
|
|
35
|
+
score?: number;
|
|
34
36
|
}
|
|
35
37
|
export interface CachedSearchContext {
|
|
36
38
|
query: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,4CAA4C;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,4CAA4C;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../src/server/chat-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat-handler.d.ts","sourceRoot":"","sources":["../../src/server/chat-handler.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,kBAAkB,EAAgC,MAAM,YAAY,CAAC;AA4HnF,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0CtF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createUIMessageStream, createUIMessageStreamResponse, streamText, convertToModelMessages, } from 'ai';
|
|
2
2
|
import { t, getLang } from '../utils/i18n.js';
|
|
3
|
-
import { getClientIP, checkRateLimit, rateLimitResponse, searchArticles, searchProjects, getSessionCacheKey, getCachedContext, setCachedContext, shouldReuseSearchContext, buildLocalSearchQuery, shouldRunKeywordExtraction, extractSearchKeywords, KEYWORD_EXTRACTION_TIMEOUT_MS, shouldSkipAnalysis, analyzeRetrievedEvidence, buildEvidenceSection, EVIDENCE_ANALYSIS_TIMEOUT_MS, getCitationGuardPreflight, buildSystemPrompt, getAuthorContext, getVoiceProfile, mergeResults, getProviderManager, createCacheAdapter, detectPublicQuestion, getGlobalSearchCache, setGlobalSearchCache, getGlobalCacheTTL, getResponseCache, setResponseCache, getResponseCacheConfig, rankArticlesByIntent, } from '../index.js';
|
|
3
|
+
import { getClientIP, checkRateLimit, rateLimitResponse, searchArticles, searchProjects, getSessionCacheKey, getCachedContext, setCachedContext, shouldReuseSearchContext, buildLocalSearchQuery, shouldRunKeywordExtraction, extractSearchKeywords, KEYWORD_EXTRACTION_TIMEOUT_MS, shouldSkipAnalysis, analyzeRetrievedEvidence, buildEvidenceSection, EVIDENCE_ANALYSIS_TIMEOUT_MS, getCitationGuardPreflight, buildSystemPrompt, getAuthorContext, getVoiceProfile, mergeResults, getProviderManager, createCacheAdapter, detectPublicQuestion, getGlobalSearchCache, shouldAppendCitations, formatCitationBlock, selectCitations, setGlobalSearchCache, getGlobalCacheTTL, getResponseCache, setResponseCache, getResponseCacheConfig, rankArticlesByIntent, } from '../index.js';
|
|
4
4
|
import { createChatStatusData } from './types.js';
|
|
5
5
|
import { errors, corsPreflightResponse } from './errors.js';
|
|
6
6
|
import { notifyAiChat } from './notify.js';
|
|
@@ -464,6 +464,17 @@ async function runPipeline(args) {
|
|
|
464
464
|
hasTextOutput = text.length > 0;
|
|
465
465
|
if (hasTextOutput && errors.length === 0) {
|
|
466
466
|
adapter.recordSuccess();
|
|
467
|
+
if (shouldAppendCitations(responseText, relatedArticles, relatedProjects)) {
|
|
468
|
+
const citations = selectCitations(relatedArticles, relatedProjects, 3, 5);
|
|
469
|
+
if (citations.length > 0) {
|
|
470
|
+
const citationBlock = formatCitationBlock(citations, lang);
|
|
471
|
+
const citationId = `citation-${Date.now()}`;
|
|
472
|
+
writer.write({ type: 'text-start', id: citationId });
|
|
473
|
+
writer.write({ type: 'text-delta', id: citationId, delta: citationBlock });
|
|
474
|
+
writer.write({ type: 'text-end', id: citationId });
|
|
475
|
+
responseText += citationBlock;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
467
478
|
writer.write({ type: 'finish', finishReason: 'stop' });
|
|
468
479
|
streamSuccess = true;
|
|
469
480
|
// Save to response cache if enabled and public question
|
package/dist/utils/i18n.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI Package Internationalization
|
|
3
3
|
* Follows the same pattern as packages/core/src/utils/i18n.ts
|
|
4
4
|
*/
|
|
5
|
-
export type AITranslationKey = "ai.reasoning.thinking" | "ai.reasoning.viewReasoning" | "ai.reasoning.waiting" | "ai.error.network" | "ai.error.aborted" | "ai.error.rateLimit" | "ai.error.unavailable" | "ai.error.generic" | "ai.error.format" | "ai.error.noOutput" | "ai.placeholder" | "ai.clear" | "ai.clearConversation" | "ai.close" | "ai.closeChat" | "ai.retry" | "ai.status.searching" | "ai.status.generating" | "ai.status.found" | "ai.status.citation" | "ai.status.fallback" | "ai.prompt.techStack" | "ai.prompt.recommend" | "ai.prompt.build" | "ai.prompt.summarize" | "ai.prompt.explain" | "ai.prompt.related" | "ai.welcome.reading" | "ai.welcome.canHelp" | "ai.welcome.greeting" | "ai.welcome.demo" | "ai.welcome.demoHint" | "ai.welcome.demoPrompt" | "ai.header.reading" | "ai.header.mode" | "ai.assistantName" | "ai.status.live" | "ai.error.emptyMessage" | "ai.error.emptyContent" | "ai.error.inputTooLong" | "ai.error.timeout" | "ai.error.rateLimit.burst" | "ai.error.rateLimit.sustained" | "ai.error.rateLimit.daily" | "ai.prompt.section.responsibilities" | "ai.prompt.section.format" | "ai.prompt.section.principles" | "ai.prompt.section.constraints" | "ai.prompt.section.sourceLayers" | "ai.prompt.section.privacy" | "ai.prompt.section.answerModes" | "ai.prompt.section.preOutputChecks";
|
|
5
|
+
export type AITranslationKey = "ai.reasoning.thinking" | "ai.reasoning.viewReasoning" | "ai.reasoning.waiting" | "ai.error.network" | "ai.error.aborted" | "ai.error.rateLimit" | "ai.error.unavailable" | "ai.error.generic" | "ai.error.format" | "ai.error.noOutput" | "ai.placeholder" | "ai.clear" | "ai.clearConversation" | "ai.close" | "ai.closeChat" | "ai.retry" | "ai.status.searching" | "ai.status.generating" | "ai.status.found" | "ai.status.citation" | "ai.status.fallback" | "ai.prompt.techStack" | "ai.prompt.recommend" | "ai.prompt.build" | "ai.prompt.summarize" | "ai.prompt.explain" | "ai.prompt.related" | "ai.welcome.reading" | "ai.welcome.canHelp" | "ai.welcome.greeting" | "ai.welcome.demo" | "ai.welcome.demoHint" | "ai.welcome.demoPrompt" | "ai.header.reading" | "ai.header.mode" | "ai.assistantName" | "ai.status.live" | "ai.error.emptyMessage" | "ai.error.emptyContent" | "ai.error.inputTooLong" | "ai.error.timeout" | "ai.error.rateLimit.burst" | "ai.error.rateLimit.sustained" | "ai.error.rateLimit.daily" | "ai.prompt.section.responsibilities" | "ai.prompt.section.format" | "ai.prompt.section.principles" | "ai.prompt.section.constraints" | "ai.prompt.section.sourceLayers" | "ai.prompt.section.privacy" | "ai.prompt.section.answerModes" | "ai.prompt.section.preOutputChecks" | "ai.semiStatic.blogOverview" | "ai.semiStatic.totalPosts" | "ai.semiStatic.mainCategories" | "ai.semiStatic.latestArticles";
|
|
6
6
|
/**
|
|
7
7
|
* Get translation by key.
|
|
8
8
|
* @param key - Translation key (type-safe)
|
package/dist/utils/i18n.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/utils/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAExB,uBAAuB,GACvB,4BAA4B,GAC5B,sBAAsB,GAEtB,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,sBAAsB,GACtB,kBAAkB,GAClB,iBAAiB,GACjB,mBAAmB,GAEnB,gBAAgB,GAChB,UAAU,GACV,sBAAsB,GACtB,UAAU,GACV,cAAc,GACd,UAAU,GACV,qBAAqB,GACrB,sBAAsB,GACtB,iBAAiB,GACjB,oBAAoB,GACpB,oBAAoB,GAEpB,qBAAqB,GACrB,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GAEnB,oBAAoB,GACpB,oBAAoB,GACpB,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,uBAAuB,GAEvB,mBAAmB,GACnB,gBAAgB,GAEhB,kBAAkB,GAClB,gBAAgB,GAEhB,uBAAuB,GACvB,uBAAuB,GACvB,uBAAuB,GACvB,kBAAkB,GAElB,0BAA0B,GAC1B,8BAA8B,GAC9B,0BAA0B,GAE1B,oCAAoC,GACpC,0BAA0B,GAC1B,8BAA8B,GAC9B,+BAA+B,GAC/B,gCAAgC,GAChC,2BAA2B,GAC3B,+BAA+B,GAC/B,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/utils/i18n.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAExB,uBAAuB,GACvB,4BAA4B,GAC5B,sBAAsB,GAEtB,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,sBAAsB,GACtB,kBAAkB,GAClB,iBAAiB,GACjB,mBAAmB,GAEnB,gBAAgB,GAChB,UAAU,GACV,sBAAsB,GACtB,UAAU,GACV,cAAc,GACd,UAAU,GACV,qBAAqB,GACrB,sBAAsB,GACtB,iBAAiB,GACjB,oBAAoB,GACpB,oBAAoB,GAEpB,qBAAqB,GACrB,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GAEnB,oBAAoB,GACpB,oBAAoB,GACpB,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,uBAAuB,GAEvB,mBAAmB,GACnB,gBAAgB,GAEhB,kBAAkB,GAClB,gBAAgB,GAEhB,uBAAuB,GACvB,uBAAuB,GACvB,uBAAuB,GACvB,kBAAkB,GAElB,0BAA0B,GAC1B,8BAA8B,GAC9B,0BAA0B,GAE1B,oCAAoC,GACpC,0BAA0B,GAC1B,8BAA8B,GAC9B,+BAA+B,GAC/B,gCAAgC,GAChC,2BAA2B,GAC3B,+BAA+B,GAC/B,mCAAmC,GAEnC,4BAA4B,GAC5B,0BAA0B,GAC1B,8BAA8B,GAC9B,8BAA8B,CAAC;AA2InC;;;;;GAKG;AACH,wBAAgB,CAAC,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,GAAE,MAAa,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAY5G;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C"}
|
package/dist/utils/i18n.js
CHANGED
|
@@ -65,6 +65,10 @@ const translations = {
|
|
|
65
65
|
"ai.prompt.section.privacy": "Privacy Protection",
|
|
66
66
|
"ai.prompt.section.answerModes": "Answer Mode Guide (follow detected mode)",
|
|
67
67
|
"ai.prompt.section.preOutputChecks": "Pre-Output Checks (execute mentally, do not output steps)",
|
|
68
|
+
"ai.semiStatic.blogOverview": "Blog Overview",
|
|
69
|
+
"ai.semiStatic.totalPosts": "{count} posts total",
|
|
70
|
+
"ai.semiStatic.mainCategories": "Main categories: {categories}",
|
|
71
|
+
"ai.semiStatic.latestArticles": "Latest Posts",
|
|
68
72
|
},
|
|
69
73
|
zh: {
|
|
70
74
|
// Reasoning UI
|
|
@@ -128,6 +132,10 @@ const translations = {
|
|
|
128
132
|
"ai.prompt.section.privacy": "隐私保护",
|
|
129
133
|
"ai.prompt.section.answerModes": "回答模式指导(按检测到的模式执行)",
|
|
130
134
|
"ai.prompt.section.preOutputChecks": "输出前检查(在心里执行,不输出步骤)",
|
|
135
|
+
"ai.semiStatic.blogOverview": "博客概况",
|
|
136
|
+
"ai.semiStatic.totalPosts": "共有 {count} 篇文章",
|
|
137
|
+
"ai.semiStatic.mainCategories": "主要分类:{categories}",
|
|
138
|
+
"ai.semiStatic.latestArticles": "最新文章",
|
|
131
139
|
},
|
|
132
140
|
};
|
|
133
141
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astro-minimax/ai",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vendor-agnostic AI integration package with full RAG pipeline for astro-minimax blogs — supports OpenAI, Cloudflare AI, and custom providers.",
|
|
6
6
|
"author": "Souloss",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@ai-sdk/openai-compatible": "^2.0.35",
|
|
81
81
|
"ai": "^6.0.116",
|
|
82
82
|
"workers-ai-provider": "^3.1.2",
|
|
83
|
-
"@astro-minimax/notify": "0.7.
|
|
83
|
+
"@astro-minimax/notify": "0.7.1"
|
|
84
84
|
},
|
|
85
85
|
"optionalDependencies": {
|
|
86
86
|
"undici": "^6.0.0"
|