@aj-archipelago/cortex 1.1.21 → 1.1.22
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/config/default.example.json +84 -0
- package/config.js +5 -4
- package/helper-apps/cortex-file-handler/blobHandler.js +115 -98
- package/helper-apps/cortex-file-handler/fileChunker.js +13 -8
- package/helper-apps/cortex-file-handler/index.js +48 -2
- package/package.json +2 -1
- package/pathways/categorize.js +23 -0
- package/pathways/chat.js +1 -1
- package/pathways/chat_code.js +19 -0
- package/pathways/chat_context.js +19 -0
- package/pathways/chat_jarvis.js +19 -0
- package/pathways/chat_persist.js +23 -0
- package/pathways/code_review.js +17 -0
- package/pathways/cognitive_delete.js +2 -1
- package/pathways/cognitive_insert.js +1 -0
- package/pathways/cognitive_search.js +1 -0
- package/pathways/embeddings.js +1 -1
- package/pathways/expand_story.js +12 -0
- package/pathways/format_paragraph_turbo.js +16 -0
- package/pathways/format_summarization.js +21 -0
- package/pathways/gemini_15_vision.js +20 -0
- package/pathways/gemini_vision.js +20 -0
- package/pathways/grammar.js +30 -0
- package/pathways/hashtags.js +19 -0
- package/pathways/headline.js +43 -0
- package/pathways/headline_custom.js +169 -0
- package/pathways/highlights.js +22 -0
- package/pathways/image.js +2 -1
- package/pathways/index.js +107 -17
- package/pathways/jira_story.js +18 -0
- package/pathways/keywords.js +4 -0
- package/pathways/language.js +17 -6
- package/pathways/locations.js +93 -0
- package/pathways/quotes.js +19 -0
- package/pathways/rag.js +207 -0
- package/pathways/rag_jarvis.js +254 -0
- package/pathways/rag_search_helper.js +21 -0
- package/pathways/readme.js +18 -0
- package/pathways/release_notes.js +16 -0
- package/pathways/remove_content.js +31 -0
- package/pathways/retrieval.js +23 -0
- package/pathways/run_claude35_sonnet.js +21 -0
- package/pathways/run_claude3_haiku.js +20 -0
- package/pathways/run_gpt35turbo.js +20 -0
- package/pathways/run_gpt4.js +20 -0
- package/pathways/run_gpt4_32.js +20 -0
- package/pathways/select_extension.js +6 -0
- package/pathways/select_services.js +10 -0
- package/pathways/spelling.js +3 -0
- package/pathways/story_angles.js +13 -0
- package/pathways/styleguide/styleguide.js +221 -0
- package/pathways/styleguidemulti.js +127 -0
- package/pathways/subhead.js +48 -0
- package/pathways/summarize_turbo.js +98 -0
- package/pathways/summary.js +31 -12
- package/pathways/sys_claude_35_sonnet.js +19 -0
- package/pathways/sys_claude_3_haiku.js +19 -0
- package/pathways/sys_google_chat.js +19 -0
- package/pathways/sys_google_code_chat.js +19 -0
- package/pathways/sys_google_gemini_chat.js +23 -0
- package/pathways/sys_openai_chat.js +2 -2
- package/pathways/sys_openai_chat_16.js +19 -0
- package/pathways/sys_openai_chat_gpt4.js +19 -0
- package/pathways/sys_openai_chat_gpt4_32.js +19 -0
- package/pathways/sys_openai_chat_gpt4_turbo.js +19 -0
- package/pathways/tags.js +25 -0
- package/pathways/taxonomy.js +135 -0
- package/pathways/timeline.js +51 -0
- package/pathways/topics.js +25 -0
- package/pathways/topics_sentiment.js +20 -0
- package/pathways/transcribe.js +2 -4
- package/pathways/translate.js +10 -12
- package/pathways/translate_azure.js +13 -0
- package/pathways/translate_context.js +21 -0
- package/pathways/translate_gpt4.js +19 -0
- package/pathways/translate_gpt4_turbo.js +19 -0
- package/pathways/translate_turbo.js +19 -0
- package/pathways/vision.js +9 -7
- package/server/plugins/azureCognitivePlugin.js +10 -1
- package/server/plugins/openAiVisionPlugin.js +14 -6
- package/tests/main.test.js +2 -2
- package/tests/vision.test.js +0 -34
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Prompt } from '../server/prompt.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
prompt: [
|
|
5
|
+
new Prompt({
|
|
6
|
+
messages: [
|
|
7
|
+
{ "role": "system", "content": "Assistant is a professional code writing assistant responsible for generating release notes to go in Github pull requests and releases. When user posts a list of code changes, assistant will examine the changes and determine the most relevant updates to include in the release notes. Assistant will generate only the release notes and no other response or commentary.\n\nAssistant may be generating notes for part of a larger code change, so ensure that your output is in a format that can be combined with other output to make a complete set of notes. Respond with markdown where it helps make your output more readable." },
|
|
8
|
+
{ "role": "user", "content": `Code changes:\n\n{{{text}}}`},
|
|
9
|
+
]
|
|
10
|
+
})
|
|
11
|
+
],
|
|
12
|
+
model: 'oai-gpt4o',
|
|
13
|
+
tokenRatio: 0.75,
|
|
14
|
+
enableDuplicateRequests: false,
|
|
15
|
+
}
|
|
16
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Prompt } from '../server/prompt.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
prompt: [
|
|
5
|
+
new Prompt({
|
|
6
|
+
messages: [
|
|
7
|
+
{ "role": "system", "content": "Assistant is highly skilled news editor at a prestigious international news agency. Assistant's task is to remove specific detail from a news excerpt" },
|
|
8
|
+
{ "role": "user", "content": "NEWS: After weeks of resistance, and ahead of a vote that could have compelled it to happen, Prime Minister Justin Trudeau’s office announced Tuesday that his chief of staff Katie Telford will testify about foreign election interference, before a committee that has been studying the issue for months. DELETE: Katie Telford is Trudeaus's chief of staff" },
|
|
9
|
+
{ "role": "assistant", "content": "After weeks of resistance, and ahead of a vote that could have compelled it to happen, Prime Minister Justin Trudeau’s office announced Tuesday that Katie Telford will testify about foreign election interference, before a committee that has been studying the issue for months" },
|
|
10
|
+
{ "role": "user", "content": "NEWS: It seems that the arms race in the field of missiles and anti-missiles is in full swing these days. While traditional defenses are being thwarted in conflicts such as the Ukrainian War, and increasingly appearing in US defense plans, the anti-missile measures presented at the Johar Air Show indicate that Beijing is also preparing for this vital aspect of the future of wars. DELETE: Arms race in the field of missiles and anti-missiles is in full swing" },
|
|
11
|
+
{ "role": "assistant", "content": "While traditional defenses are being thwarted in conflicts such as the Ukrainian War, and increasingly appearing in US defense plans, the anti-missile measures presented at the Johar Air Show indicate that Beijing is also preparing for this vital aspect of the future of wars." },
|
|
12
|
+
{
|
|
13
|
+
"role": "user", "content":
|
|
14
|
+
`NEWS: Sundowns leads the group with 11 points, one point ahead of Al-Hilal in second place. Al-Ahly comes in third place with 7 points, while Cotonsport of Cameroon is in last place without points.
|
|
15
|
+
|
|
16
|
+
Al-Hilal said in its statement that CAF had not responded to three previous letters and asked it to take a stance before a "new Burseid". DELETE: Cotonsport of Cameroon is in last place without points.`},
|
|
17
|
+
{
|
|
18
|
+
"role": "assistant", "content": `
|
|
19
|
+
Sundowns leads the group with 11 points, one point ahead of Al-Hilal in second place. Al-Ahly comes in third place with 7 points.
|
|
20
|
+
|
|
21
|
+
Al-Hilal said in its statement that CAF had not responded to three previous letters and asked it to take a stance before a "new Burseid". ` },
|
|
22
|
+
{ "role": "user", "content": "NEWS: {{text}}. DELETE: {{content}}" },
|
|
23
|
+
|
|
24
|
+
]
|
|
25
|
+
})],
|
|
26
|
+
inputParameters: {
|
|
27
|
+
content: "",
|
|
28
|
+
},
|
|
29
|
+
model: 'oai-gpt4o',
|
|
30
|
+
temperature: 0.0,
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Prompt } from '../server/prompt.js';
|
|
2
|
+
|
|
3
|
+
// Description: Have a chat with a bot that uses context to understand the conversation + extension for Azure
|
|
4
|
+
export default {
|
|
5
|
+
prompt:
|
|
6
|
+
[
|
|
7
|
+
new Prompt({ messages: [
|
|
8
|
+
"{{chatHistory}}",
|
|
9
|
+
]}),
|
|
10
|
+
],
|
|
11
|
+
// prompt: `{{text}}`,
|
|
12
|
+
inputParameters: {
|
|
13
|
+
chatHistory: [],
|
|
14
|
+
contextId: ``,
|
|
15
|
+
indexName: ``,
|
|
16
|
+
semanticConfiguration: ``,
|
|
17
|
+
roleInformation: ``
|
|
18
|
+
},
|
|
19
|
+
model: `azure-extension`,
|
|
20
|
+
useInputChunking: false,
|
|
21
|
+
enableDuplicateRequests: false,
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
// Import required modules
|
|
3
|
+
import { Prompt } from '../server/prompt.js';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
prompt: [
|
|
7
|
+
new Prompt({
|
|
8
|
+
messages: [
|
|
9
|
+
{ "role": "system", "content": "{{{systemPrompt}}}" },
|
|
10
|
+
{ "role": "user", "content": "{{{text}}}\n\n{{{prompt}}}" }
|
|
11
|
+
]
|
|
12
|
+
}),
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
inputParameters: {
|
|
16
|
+
prompt: "",
|
|
17
|
+
systemPrompt: "Assistant is an expert journalist's assistant for a prestigious international news agency. When a user posts a request, Assistant will come up with the best response while upholding the highest journalistic standards.",
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
model: 'claude-35-sonnet-vertex',
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Import required modules
|
|
2
|
+
import { Prompt } from '../server/prompt.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
prompt: [
|
|
6
|
+
new Prompt({
|
|
7
|
+
messages: [
|
|
8
|
+
{ "role": "system", "content": "{{{systemPrompt}}}" },
|
|
9
|
+
{ "role": "user", "content": "{{{text}}}\n\n{{{prompt}}}" }
|
|
10
|
+
]
|
|
11
|
+
}),
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
inputParameters: {
|
|
15
|
+
prompt: "",
|
|
16
|
+
systemPrompt: "Assistant is an expert journalist's assistant for a prestigious international news agency. When a user posts a request, Assistant will come up with the best response while upholding the highest journalistic standards.",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
model: 'claude-3-haiku-vertex',
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Import required modules
|
|
2
|
+
import { Prompt } from "../server/prompt.js"
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
prompt: [
|
|
6
|
+
new Prompt({
|
|
7
|
+
messages: [
|
|
8
|
+
{ "role": "system", "content": "{{{systemPrompt}}}" },
|
|
9
|
+
{ "role": "user", "content": "{{{text}}}\n\n{{{prompt}}}" }
|
|
10
|
+
]
|
|
11
|
+
}),
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
inputParameters: {
|
|
15
|
+
prompt: "",
|
|
16
|
+
systemPrompt: "Assistant is an expert journalist's assistant working for a prestigious international news agency. When a user posts a request, Assistant will come up with the best response while upholding the highest journalistic standards.",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
model: 'oai-gpturbo',
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Import required modules
|
|
2
|
+
import { Prompt } from '../server/prompt.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
prompt: [
|
|
6
|
+
new Prompt({
|
|
7
|
+
messages: [
|
|
8
|
+
{ "role": "system", "content": "{{{systemPrompt}}}" },
|
|
9
|
+
{ "role": "user", "content": "{{{text}}}\n\n{{{prompt}}}" }
|
|
10
|
+
]
|
|
11
|
+
}),
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
inputParameters: {
|
|
15
|
+
prompt: "",
|
|
16
|
+
systemPrompt: "Assistant is an expert journalist's assistant for a prestigious international news agency. When a user posts a request, Assistant will come up with the best response while upholding the highest journalistic standards.",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
model: 'oai-gpt4',
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Import required modules
|
|
2
|
+
import { Prompt } from '../server/prompt.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
prompt: [
|
|
6
|
+
new Prompt({
|
|
7
|
+
messages: [
|
|
8
|
+
{ "role": "system", "content": "{{{systemPrompt}}}" },
|
|
9
|
+
{ "role": "user", "content": "{{{text}}}\n\n{{{prompt}}}" }
|
|
10
|
+
]
|
|
11
|
+
}),
|
|
12
|
+
],
|
|
13
|
+
|
|
14
|
+
inputParameters: {
|
|
15
|
+
prompt: "",
|
|
16
|
+
systemPrompt: "Assistant is an expert journalist's assistant for a prestigious international news agency. When a user posts a request, Assistant will come up with the best response while upholding the highest journalistic standards.",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
model: 'oai-gpt4-32',
|
|
20
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Description: Have a chat with a bot that uses context to understand the conversation
|
|
2
|
+
export default {
|
|
3
|
+
prompt: `User text: {{text}}\n\n Your Instructions: Analyze user text and extract all the following information. Decide to route messages to a knowledge base expert system when the user needs some information or documents or articles, or if user asks question that require specific knowledge, or if some extra knowledge can help you reply better; also anything related to news, articles, geopolitical entities, or current events should be forwarded as those can be found in the expert system. The expert system should not be consulted if the users message is just conversational. You will reply this in field useExpertSystem with true or false. Also in the text, the user may or may not have requested one of the following services:\n{"services": ["Coding", "Translate", "Transcribe", "Summary", "Headlines", "Entities", "Spelling", "Grammar", "Style", "Entities", "Newswires", "FileOrDocumentUpload"]}\nSelect the services the user requested (or none if none were requested) and return them as a JSON object field called "services". Also return the user text's language in language field in ISO 639-3 format. You will reply with the single valid JSON object (no other text or commentary) that must include JSON fields: useExpertSystem, services, language.\n\n`,
|
|
4
|
+
model: 'oai-gpt4o',
|
|
5
|
+
useInputChunking: false,
|
|
6
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Description: Select services from a conversation fragment
|
|
2
|
+
export default {
|
|
3
|
+
temperature: 0,
|
|
4
|
+
prompt:
|
|
5
|
+
[
|
|
6
|
+
`Conversation:\n{{text}}\n\nInstructions:\nIn the above conversation fragment, the user may or may not have requested one of the following services:\n{"services": ["Coding", "Translate", "Transcribe", "Summary", "Headlines", "Entities", "Spelling", "Grammar", "Style", "Entities", "Newswires", "FileOrDocumentUpload"]}\nSelect the services the user requested (or none if none were requested) and return them as a JSON object called "services" below:\n\n`,
|
|
7
|
+
],
|
|
8
|
+
model: 'oai-gpt4o',
|
|
9
|
+
}
|
|
10
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Prompt } from "../server/prompt.js";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
prompt: [new Prompt({
|
|
5
|
+
messages: [
|
|
6
|
+
{ "role": "system", "content": "Assistant is highly skilled news editor at a prestigious international news agency. Assistant's task is to identify angles of emphasis in a news story." },
|
|
7
|
+
{ "role": "user", "content": "Give me a numbered list of angles that can be emphasized in the following news excerpt. Don't need explanations, just a short phrase (< 5 words) describing the angle. Sort them by decreasing order of relevance.\n\nNews excerpt\n{{text}}" },
|
|
8
|
+
]
|
|
9
|
+
})],
|
|
10
|
+
model: 'oai-gpt4o',
|
|
11
|
+
list: true,
|
|
12
|
+
useInputChunking: false,
|
|
13
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Prompt } from '../../server/prompt.js';
|
|
2
|
+
import * as Diff from "diff";
|
|
3
|
+
|
|
4
|
+
const prompt = new Prompt({
|
|
5
|
+
messages: [
|
|
6
|
+
{
|
|
7
|
+
"role": "system", "content": `Assistant is a highly skilled copy editor for a prestigious news agency. When the user posts any text, assistant will correct all spelling and grammar in the text and change words to British English word spellings. Assistant will preserve html tags as well as text within square brackets. Assistant will also flawlessly apply the following rules from the style guide:
|
|
8
|
+
Don't use the % sign - spell out percent instead.
|
|
9
|
+
Expand all abbreviated month names.`},
|
|
10
|
+
{ "role": "user", "content": "The total value of the deal was 12M euros." },
|
|
11
|
+
{ "role": "assistant", "content": "The total value of the deal was 12 million euros." },
|
|
12
|
+
{ "role": "user", "content": "they lost 20% of their money" },
|
|
13
|
+
{ "role": "assistant", "content": "they lost 20 percent of their money" },
|
|
14
|
+
{ "role": "system", "content": "Assistant will edit the entirety of whatever the user posts next according to the system instructions. Assistant will produce only the corrected text and no additional notes, dialog, or commentary." },
|
|
15
|
+
{ "role": "user", "content": "{{{text}}}" }
|
|
16
|
+
]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
temperature: 0,
|
|
21
|
+
prompt: [prompt],
|
|
22
|
+
// inputFormat: 'html',
|
|
23
|
+
useInputChunking: true,
|
|
24
|
+
inputChunkSize: 500,
|
|
25
|
+
enableDuplicateRequests: false,
|
|
26
|
+
useParallelChunkProcessing: true,
|
|
27
|
+
model: 'oai-gpt4o',
|
|
28
|
+
executePathway: async ({ args, runAllPrompts }) => {
|
|
29
|
+
const originalText = args.text;
|
|
30
|
+
|
|
31
|
+
const suggestions = [];
|
|
32
|
+
|
|
33
|
+
const rulesBySuspect = getStyleGuideRules();
|
|
34
|
+
addEntriesForSuspectsFromStyleGuide(originalText, rulesBySuspect, suggestions);
|
|
35
|
+
|
|
36
|
+
const correctedText = await runAllPrompts(args);
|
|
37
|
+
|
|
38
|
+
// If correctedText is null, then the call to the AI resulted in an error.
|
|
39
|
+
if (correctedText) {
|
|
40
|
+
addEntriesForAutoCorrectedWords(originalText, correctedText, suggestions);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Remove overlapping suggestions
|
|
44
|
+
suggestions.sort((a, b) => a.index - b.index);
|
|
45
|
+
for (let i = 0; i < suggestions.length; i++) {
|
|
46
|
+
const suggestion = suggestions[i];
|
|
47
|
+
const nextSuggestion = suggestions[i + 1];
|
|
48
|
+
|
|
49
|
+
if (nextSuggestion && suggestion.index + suggestion.suspect.length >= nextSuggestion.index) {
|
|
50
|
+
// remove nextSuggestion
|
|
51
|
+
suggestions.splice(i + 1, 1);
|
|
52
|
+
i--;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return JSON.stringify({ text: originalText, suggestions: suggestions })
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Adds entries to the suggestions array for words that the style guide defines as suspects.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} originalText
|
|
64
|
+
* @param {object} rulesBySuspect
|
|
65
|
+
* @param {string[]} suggestions
|
|
66
|
+
*/
|
|
67
|
+
function addEntriesForSuspectsFromStyleGuide(originalText, rulesBySuspect, suggestions) {
|
|
68
|
+
for (const suspect in rulesBySuspect) {
|
|
69
|
+
if (suspect) {
|
|
70
|
+
const suspectRegex = new RegExp(`\\b${suspect}\\b`, 'gi');
|
|
71
|
+
const suspectMatches = [...originalText.matchAll(suspectRegex)];
|
|
72
|
+
suspectMatches.forEach(m => {
|
|
73
|
+
const { notes } = rulesBySuspect[suspect];
|
|
74
|
+
|
|
75
|
+
const matchIndex = m.index;
|
|
76
|
+
|
|
77
|
+
// if this suspect falls within another, then skip it
|
|
78
|
+
// an example of this is the expression "said that"
|
|
79
|
+
// there's a rule for "said that" that and there's another rule for "that"
|
|
80
|
+
// if we don't skip the "that" rule, then we'll get two suggestions for the same word
|
|
81
|
+
if (suggestions.some(s => matchIndex >= s.index && matchIndex <= s.index + s.suspect.length)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const newSuggestion = {
|
|
86
|
+
suspect,
|
|
87
|
+
suggestions: rulesBySuspect[suspect].suggestions,
|
|
88
|
+
index: m.index,
|
|
89
|
+
notes,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const existingSuggestionIndex = suggestions.findIndex(s => s.index === newSuggestion.index);
|
|
93
|
+
|
|
94
|
+
if (existingSuggestionIndex > -1) {
|
|
95
|
+
suggestions[existingSuggestionIndex] = newSuggestion;
|
|
96
|
+
} else {
|
|
97
|
+
suggestions.push(newSuggestion);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Adds entries to the suggestions array for words that were auto-corrected by the AI.
|
|
106
|
+
* These will be used by the UI to a render a diff.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} originalText
|
|
109
|
+
* @param {string} correctedText
|
|
110
|
+
* @param {string[]} suggestions
|
|
111
|
+
*/
|
|
112
|
+
function addEntriesForAutoCorrectedWords(originalText, correctedText, suggestions) {
|
|
113
|
+
let currentIndex = 0;
|
|
114
|
+
let currentSuggestion = null;
|
|
115
|
+
|
|
116
|
+
const normalizeQuotesAndSpaces = text => text.replace(/“|”/g, '"').replace(/‘|’/g, "'").replace(/\u00A0/g, ' ');
|
|
117
|
+
|
|
118
|
+
const diffGroups = Diff.diffWordsWithSpace(normalizeQuotesAndSpaces(originalText), normalizeQuotesAndSpaces(correctedText));
|
|
119
|
+
diffGroups.forEach((part, i) => {
|
|
120
|
+
const nextToken = diffGroups[i + 1];
|
|
121
|
+
const isNextTokenChange = nextToken?.added || nextToken?.removed;
|
|
122
|
+
const isWhiteSpaceBetweenChanges = part.value === ' ' && currentSuggestion && isNextTokenChange;
|
|
123
|
+
|
|
124
|
+
if (isWhiteSpaceBetweenChanges) {
|
|
125
|
+
currentIndex += part.value.length;
|
|
126
|
+
return ' ';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (part.added) {
|
|
130
|
+
currentSuggestion = currentSuggestion || { index: currentIndex, suspect: "", suggestions: [], notes: "Suggested by AI", accepted: true, suggestionIndex: 0 };
|
|
131
|
+
currentSuggestion.suggestions[0] = currentSuggestion.suggestions[0] || "";
|
|
132
|
+
|
|
133
|
+
if (currentSuggestion.suggestions[0] && !currentSuggestion.suggestions[0].endsWith(' ')) {
|
|
134
|
+
currentSuggestion.suggestions[0] += " " + part.value;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
currentSuggestion.suggestions[0] += part.value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (part.removed) {
|
|
142
|
+
currentSuggestion = currentSuggestion || { index: currentIndex, suspect: "", suggestions: [], notes: "Suggested by AI", accepted: true, suggestionIndex: 0 };
|
|
143
|
+
|
|
144
|
+
if (currentSuggestion.suspect && !currentSuggestion.suspect.endsWith(' ')) {
|
|
145
|
+
currentSuggestion.suspect += " " + part.value;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
currentSuggestion.suspect += part.value;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
currentIndex += part.value.length;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!part.added && !part.removed) {
|
|
155
|
+
currentIndex += part.value.length;
|
|
156
|
+
if (currentSuggestion) {
|
|
157
|
+
// if a suggestion with the index exists, replace it
|
|
158
|
+
const existingSuggestionIndex = suggestions.findIndex(s => s.index === currentSuggestion.index);
|
|
159
|
+
|
|
160
|
+
if (existingSuggestionIndex > -1) {
|
|
161
|
+
suggestions[existingSuggestionIndex] = currentSuggestion;
|
|
162
|
+
} else {
|
|
163
|
+
suggestions.push(currentSuggestion);
|
|
164
|
+
}
|
|
165
|
+
currentSuggestion = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (currentSuggestion) {
|
|
171
|
+
suggestions.push(currentSuggestion);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @returns {Object} { suspect: { suggestions: string[], notes: string }
|
|
177
|
+
*/
|
|
178
|
+
function getStyleGuideRules() {
|
|
179
|
+
try {
|
|
180
|
+
const rules = [{
|
|
181
|
+
"Type": "City",
|
|
182
|
+
"Name": "al-Makha",
|
|
183
|
+
"Notes": "Port city in Yemen. First reference, include \"(Mocha)\" then go with al-Makha",
|
|
184
|
+
"Suspects": "Mokha al-Mokha Al-Mokha al Mokha Al Mokha Mocha al-Mocha Al-Mocha al Mocha Al Mocha",
|
|
185
|
+
"Suggestions": "al-Makha (Mocha)"
|
|
186
|
+
}];
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
// Group rows by suspect (since each row may have multiple suspects)
|
|
190
|
+
const rulesBySuspect = rules.reduce((acc, r) => {
|
|
191
|
+
if (r) {
|
|
192
|
+
// some suspects in the data source have 3 spaces between them, so if we split terms by 2 spaces
|
|
193
|
+
// one of the terms will have an extra space, so trim() it.
|
|
194
|
+
const suspects = r.Suspects?.split(" ").map(s => s.trim()) || [];
|
|
195
|
+
let suggestions = r.Suggestions?.split(" ") || [];
|
|
196
|
+
|
|
197
|
+
// filter suggestions in parentheses as those tend to be notes
|
|
198
|
+
suggestions = suggestions.filter(s => !s.match(/^\(.*\)$/));
|
|
199
|
+
|
|
200
|
+
// also filter suggestions that are just a note
|
|
201
|
+
suggestions = suggestions.filter(s => !s.match(/^see notes/gi));
|
|
202
|
+
|
|
203
|
+
const notes = r.Notes;
|
|
204
|
+
suspects.forEach(s => {
|
|
205
|
+
if (!acc[s]) {
|
|
206
|
+
acc[s] = [];
|
|
207
|
+
}
|
|
208
|
+
acc[s] = { suggestions, notes };
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return acc;
|
|
213
|
+
}, {});
|
|
214
|
+
|
|
215
|
+
return rulesBySuspect;
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
console.error("An error occurred while trying to read style guide rules", e);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Prompt } from '../server/prompt.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
temperature: 0,
|
|
5
|
+
prompt: [
|
|
6
|
+
new Prompt({ messages: [
|
|
7
|
+
{"role": "system", "content": "Assistant is a highly skilled copy editor for a prestigious news agency. When the user posts any text, assistant will correct all spelling and grammar in the text and change words to British English word spellings. Assistant will preserve html tags as well as text within square brackets. Assistant will also flawlessly apply the following rules from the style guide:\n Capitalization: Unless using a full official title, use lower case. Jobs are lower case. If the individuals name follows, you capitalise the title. We only capitalise the name of ministries if it is their proper name. Place names and organisations are capitalised. Police, armies, navies, air forces, coastguards etc do not require capitals. Capitalize political designations, but geographic designations remain lower case.\nDon't use the % sign - spell out percent instead.\nExpand all abbreviated month names.\nExpand monetary abbreviations.\nDo not use nouns or adjectives as verbs.\nDo not mix tenses.\nMask any profanity with the first letter of the word followed by asterisks."},
|
|
8
|
+
{"role": "user", "content": "The $20 bill was the wrong color."},
|
|
9
|
+
{"role": "assistant", "content": "The $20 bill was the wrong colour."},
|
|
10
|
+
{"role": "user", "content": "the US Secretary of State"},
|
|
11
|
+
{"role": "assistant", "content": "the US secretary of state"},
|
|
12
|
+
{"role": "user", "content": "prime minister Theresa May"},
|
|
13
|
+
{"role": "assistant", "content": "Prime Minister Theresa May"},
|
|
14
|
+
{"role": "user", "content": "the Belgian Prime Minister"},
|
|
15
|
+
{"role": "assistant", "content": "the Belgian prime minister"},
|
|
16
|
+
{"role": "user", "content": "the us state department"},
|
|
17
|
+
{"role": "assistant", "content": "the US state department"},
|
|
18
|
+
{"role": "user", "content": "Here is the podcast: [audio id=\"123\" start=\"1:23\" end=\"1:25\"]podcast[/audio]"},
|
|
19
|
+
{"role": "assistant", "content": "Here is the podcast: [audio id=\"123\" start=\"1:23\" end=\"1:25\"]podcast[/audio]"},
|
|
20
|
+
{"role": "user", "content": "<p>the US department of state</p>"},
|
|
21
|
+
{"role": "assistant", "content": "<p>the US Department of State</p>"},
|
|
22
|
+
{"role": "user", "content": "the US Air Force"},
|
|
23
|
+
{"role": "assistant", "content": "the US air force"},
|
|
24
|
+
{"role": "user", "content": "the west, western nations"},
|
|
25
|
+
{"role": "assistant", "content": "the West, Western nations"},
|
|
26
|
+
{"role": "user", "content": "they lost 20% of their money"},
|
|
27
|
+
{"role": "assistant", "content": "they lost 20 percent of their money"},
|
|
28
|
+
{"role": "user", "content": "He lost 10% of his weight between Jun and Aug."},
|
|
29
|
+
{"role": "assistant", "content": "He lost ten percent of his weight between June and August."},
|
|
30
|
+
{"role": "user", "content": "The US gave Ukraine $1bn in aid."},
|
|
31
|
+
{"role": "assistant", "content": "The US gave Ukraine one billion dollars in aid."},
|
|
32
|
+
{"role": "user", "content": "The total value of the deal was 12M euros."},
|
|
33
|
+
{"role": "assistant", "content": "The total value of the deal was 12 million euros."},
|
|
34
|
+
{"role": "user", "content": "they progress reports, they action an order"},
|
|
35
|
+
{"role": "assistant", "content": "they made progress on reports, they acted on an order"},
|
|
36
|
+
{"role": "user", "content": "The <a href=\"vote.com\">vote</a> took place Monday."},
|
|
37
|
+
{"role": "assistant", "content": "The <a href=\"vote.com\">vote</a> took place on Monday."},
|
|
38
|
+
{"role": "user", "content": "Michael wrote John."},
|
|
39
|
+
{"role": "assistant", "content": "Michael wrote to John."},
|
|
40
|
+
{"role": "user", "content": "They protested the law."},
|
|
41
|
+
{"role": "assistant", "content": "They protested against the law."},
|
|
42
|
+
{"role": "user", "content": "<p>The protests erupted yestrday.</p>"},
|
|
43
|
+
{"role": "assistant", "content": "<p>The protests erupted yesterday.</p>"},
|
|
44
|
+
{"role": "user", "content": "They protested the law."},
|
|
45
|
+
{"role": "assistant", "content": "They protested against the law."},
|
|
46
|
+
{"role": "user", "content": "He appealed the decision of the court."},
|
|
47
|
+
{"role": "assistant", "content": "He appealed against the decision of the court."},
|
|
48
|
+
{"role": "user", "content": "Yesterday, the Prime Minister announced that he will be introducing a new policy to combat climate change. The policy aims to reduce carbon emissions by 50% by 2030."},
|
|
49
|
+
{"role": "assistant", "content": "Yesterday, the Prime Minister announced that he would be introducing a new policy to combat climate change. The policy aims to reduce carbon emissions by 50 percent by 2030."},
|
|
50
|
+
{"role": "user", "content": "Why does he always want to go to the damn circus?"},
|
|
51
|
+
{"role": "assistant", "content": "Why does he always want to go to the d*** circus?"},
|
|
52
|
+
{"role": "user", "content": `June was quoted as saying "What is this shit?! I'm not a fucking idiot!"`},
|
|
53
|
+
{"role": "assistant", "content": `June was quoted as saying "What is this s***?! I'm not a f***ing idiot!"`},
|
|
54
|
+
{"role": "system", "content": "Assistant will edit the entirety of whatever the user posts next according to the system instructions. Assistant will produce only the corrected text and no additional notes, dialog, or commentary."},
|
|
55
|
+
{"role": "user", "content": "{{{text}}}"}
|
|
56
|
+
]}),
|
|
57
|
+
/*
|
|
58
|
+
new Prompt({ messages: [
|
|
59
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will correct all spelling and grammar in the text and change words to British English word spellings. Assistant will produce only the corrected text and no additional notes or commentary."},
|
|
60
|
+
{"role": "user", "content": "The $20 bill was the wrong color."},
|
|
61
|
+
{"role": "assistant", "content": "The $20 bill was the wrong colour."},
|
|
62
|
+
{"role": "user", "content": "{{{text}}}"}
|
|
63
|
+
]}),
|
|
64
|
+
new Prompt({ messages: [
|
|
65
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will flawlessly apply the following rules from the style guide: Capitalization rules: Unless using a full official title, use lower case. Jobs are lower case. If the individuals name follows, you capitalise the title. We only capitalise the name of ministries if it is their proper name. Place names and organisations are capitalised. Police, armies, navies, air forces, coastguards etc do not require capitals. Capitalize political designations, but geographic designations remain lower case."},
|
|
66
|
+
{"role": "user", "content": "the US Secretary of State"},
|
|
67
|
+
{"role": "assistant", "content": "the US secretary of state"},
|
|
68
|
+
{"role": "user", "content": "prime minister Theresa May"},
|
|
69
|
+
{"role": "assistant", "content": "Prime Minister Theresa May"},
|
|
70
|
+
{"role": "user", "content": "the us state department"},
|
|
71
|
+
{"role": "assistant", "content": "the US state department"},
|
|
72
|
+
{"role": "user", "content": "the US department of state"},
|
|
73
|
+
{"role": "assistant", "content": "the US Department of State"},
|
|
74
|
+
{"role": "user", "content": "the US Air Force"},
|
|
75
|
+
{"role": "assistant", "content": "the US air force"},
|
|
76
|
+
{"role": "user", "content": "the west, western nations"},
|
|
77
|
+
{"role": "assistant", "content": "the West, Western nations"},
|
|
78
|
+
{"role": "user", "content": "{{{previousResult}}}"}
|
|
79
|
+
]}),
|
|
80
|
+
new Prompt({ messages: [
|
|
81
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will flawlessly apply the following rule from the style guide: Don't use the % sign - spell out percent instead. Expand all abbreviated month names. Expand monetary abbreviations."},
|
|
82
|
+
{"role": "user", "content": "they lost 20% of their money"},
|
|
83
|
+
{"role": "assistant", "content": "they lost 20 percent of their money"},
|
|
84
|
+
{"role": "user", "content": "He lost 10% of his weight between Jun and Aug."},
|
|
85
|
+
{"role": "assistant", "content": "He lost ten percent of his weight between June and August."},
|
|
86
|
+
{"role": "user", "content": "The US gave Ukraine $1bn in aid."},
|
|
87
|
+
{"role": "assistant", "content": "The US gave Ukraine one billion dollars in aid."},
|
|
88
|
+
{"role": "user", "content": "The total value of the deal was 12M euros."},
|
|
89
|
+
{"role": "assistant", "content": "The total value of the deal was 12 million euros."},
|
|
90
|
+
{"role": "user", "content": "{{{previousResult}}}"}
|
|
91
|
+
]}),
|
|
92
|
+
new Prompt({ messages: [
|
|
93
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will flawlessly apply the following rule from the style guide: Do not use nouns or adjectives as verbs."},
|
|
94
|
+
{"role": "user", "content": "they progress reports, they action an order"},
|
|
95
|
+
{"role": "assistant", "content": "they made progress on reports, they acted on an order"},
|
|
96
|
+
{"role": "user", "content": "The vote took place Monday."},
|
|
97
|
+
{"role": "assistant", "content": "The vote took place on Monday."},
|
|
98
|
+
{"role": "user", "content": "Michael wrote John."},
|
|
99
|
+
{"role": "assistant", "content": "Michael wrote to John."},
|
|
100
|
+
{"role": "user", "content": "They protested the law."},
|
|
101
|
+
{"role": "assistant", "content": "They protested against the law."},
|
|
102
|
+
{"role": "user", "content": "He appealed the decision of the court."},
|
|
103
|
+
{"role": "assistant", "content": "He appealed against the decision of the court."},
|
|
104
|
+
{"role": "user", "content": "{{{previousResult}}}"}
|
|
105
|
+
]}),
|
|
106
|
+
new Prompt({ messages: [
|
|
107
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will flawlessly apply the following rule from the style guide: Do not mix tenses."},
|
|
108
|
+
{"role": "user", "content": "Yesterday, the Prime Minister announced that he will be introducing a new policy to combat climate change. The policy aims to reduce carbon emissions by 50% by 2030."},
|
|
109
|
+
{"role": "assistant", "content": "Yesterday, the Prime Minister announced that he would be introducing a new policy to combat climate change. The policy aims to reduce carbon emissions by 50 percent by 2030."},
|
|
110
|
+
{"role": "user", "content": "{{{previousResult}}}"}
|
|
111
|
+
]}),
|
|
112
|
+
new Prompt({ messages: [
|
|
113
|
+
{"role": "system", "content": "Assistant is a highly skilled multilingual copy editor for a prestigious news agency. When the user posts any text in any language, assistant will flawlessly apply the following rule from the style guide: Mask any profanity with the first letter of the word followed by asterisks."},
|
|
114
|
+
{"role": "user", "content": "Why does he always want to go to the damn circus?"},
|
|
115
|
+
{"role": "assistant", "content": "Why does he always want to go to the d*** circus?"},
|
|
116
|
+
{"role": "user", "content": `June was quoted as saying "What is this shit?! I'm not a fucking idiot!"`},
|
|
117
|
+
{"role": "assistant", "content": `June was quoted as saying "What is this s***?! I'm not a f***ing idiot!"`},
|
|
118
|
+
{"role": "user", "content": "{{{previousResult}}}"}
|
|
119
|
+
]}),*/
|
|
120
|
+
],
|
|
121
|
+
inputFormat: 'html',
|
|
122
|
+
useInputChunking: true,
|
|
123
|
+
inputChunkSize: 500,
|
|
124
|
+
useParallelChunkProcessing: true,
|
|
125
|
+
model: 'oai-gpt4o',
|
|
126
|
+
enableDuplicateRequests: false,
|
|
127
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Prompt } from '../server/prompt.js';
|
|
2
|
+
import { PathwayResolver } from '../server/pathwayResolver.js';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
prompt: [],
|
|
6
|
+
inputParameters: {
|
|
7
|
+
count: 5,
|
|
8
|
+
targetLength: 120,
|
|
9
|
+
headline: '',
|
|
10
|
+
},
|
|
11
|
+
list: true,
|
|
12
|
+
model: 'oai-gpt4o',
|
|
13
|
+
useInputChunking: false,
|
|
14
|
+
|
|
15
|
+
// Custom resolver to generate subheads by reprompting if they are too long
|
|
16
|
+
resolver: async (_parent, args, contextValue, _info) => {
|
|
17
|
+
const { config, pathway } = contextValue;
|
|
18
|
+
let targetLength = args.targetLength || 120;
|
|
19
|
+
let count = args.count || 5;
|
|
20
|
+
|
|
21
|
+
const targetWords = Math.round(targetLength / 6);
|
|
22
|
+
const MAX_ITERATIONS = 3;
|
|
23
|
+
|
|
24
|
+
let pathwayResolver = new PathwayResolver({ config, pathway, args });
|
|
25
|
+
|
|
26
|
+
pathwayResolver.pathwayPrompt = [
|
|
27
|
+
new Prompt({
|
|
28
|
+
messages: [
|
|
29
|
+
{ "role": "system", "content": `Assistant is a highly skilled multilingual writer for a prestigious international news agency. Assistant generates descriptive, informative, and engaging subheadings that are consistent with and continue the flow of the headline for the article. When the user posts a headline and an article excerpt in any language, assistant will create ${ count * 2 } subheadings for that headline in the same language as the headline. Assistant will produce only a numbered list of subheadings and no additional notes or commentary.\n\nAll subheadings must comply with all of the following instructions:\n- Subheadings must not be enclosed in quotation marks\n- Subheadings must be ${ targetWords } words or fewer.\n- Subheadings must be written in sentence-case (only the first letter of the headline and proper nouns capitalized).\n` },
|
|
30
|
+
{ "role": "user", "content": `Headline: {{{headline}}}\nArticle Excerpt:\n{{{text}}}` }
|
|
31
|
+
]
|
|
32
|
+
}),
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
let subheads = await pathwayResolver.resolve(args);
|
|
36
|
+
let shortSubheads = subheads.filter(h => h.length > 80 && h.length < targetLength).slice(0, count);
|
|
37
|
+
let i = 0;
|
|
38
|
+
|
|
39
|
+
// if some subheads do not meet the length requirement, reprompt
|
|
40
|
+
while (shortSubheads.length < count && i < MAX_ITERATIONS) {
|
|
41
|
+
let subheads = await pathwayResolver.resolve(args);
|
|
42
|
+
shortSubheads = subheads.filter(h => h.length > 80 && h.length < targetLength).slice(0, count);
|
|
43
|
+
i++;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return shortSubheads;
|
|
47
|
+
}
|
|
48
|
+
}
|