Skip to content

Commit

Permalink
feat(husky): modified ai prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
Thangaraj-Ideas2it authored and madan-ideas2it committed Jan 6, 2025
1 parent 2b3f9f9 commit e5940ef
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 230 deletions.
25 changes: 12 additions & 13 deletions apps/web-api/src/husky/husky-ai.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class HuskyAiService {
}

// If Context is valid, then create prompt and stream the response
const chatSummaryFromDb = await this.getChatSummary(uid);
const chatSummaryFromDb = await this.huskyCacheDbService.get(`${uid}:summary`);
const prompt = this.createPromptForHuskyChat(question, context, chatSummaryFromDb || '', actionDocs);
return streamObject({
model: openai(process.env.OPENAI_LLM_MODEL || ''),
Expand Down Expand Up @@ -89,13 +89,9 @@ export class HuskyAiService {
return embedding;
}

async getChatSummary(uid: string) {
const chatHistory = await this.huskyCacheDbService.get(`${uid}:summary`);
return chatHistory;
}

async getRephrasedQuestionBasedOnHistory(chatId: string, question: string) {
const chatHistory = await this.getChatSummary(`${chatId}:summary`);
const chatHistory = await this.huskyCacheDbService.get(`${chatId}:summary`);

if (chatHistory) {
const aiPrompt = Handlebars.compile(rephraseQuestionTemplate)({ chatHistory, question });
const { text } = await generateText({
Expand All @@ -111,9 +107,8 @@ export class HuskyAiService {
const formattedChat = `user: ${rawChatHistory.user}\n system: ${rawChatHistory.system}`;
const previousSummary = await this.huskyCacheDbService.get(`${chatId}:summary`);
const aiPrompt = previousSummary
? Handlebars.compile(chatSummaryWithHistoryTemplate)({ previousSummary, formattedChat })
: Handlebars.compile(chatSummaryTemplate)({ formattedChat });

? Handlebars.compile(chatSummaryWithHistoryTemplate)({ previousSummary, currentConversation: formattedChat })
: Handlebars.compile(chatSummaryTemplate)({ currentConversation: formattedChat });
const { text } = await generateText({
model: openai(process.env.OPENAI_LLM_MODEL || ''),
prompt: aiPrompt,
Expand Down Expand Up @@ -173,7 +168,7 @@ export class HuskyAiService {
};
}

async getMatchingEmbeddingsBySource(source: string, embedding: any, limit = 15) {
async getMatchingEmbeddingsBySource(source: string, embedding: any, limit = 25) {
const collection =
source === HUSKY_SOURCES.TWITTER
? process.env.QDRANT_TWITTER_COLLECTION || ''
Expand All @@ -192,7 +187,11 @@ export class HuskyAiService {
});
}

const sortedResults = formattedResults.sort((a, b) => b?.score - a?.score).slice(0, 10);
const sortedResults = formattedResults
.sort((a, b) => b?.score - a?.score)
.filter((v) => v.score > 0.4)
.slice(0, 10);

const context = sortedResults
.filter((result) => result?.text?.length > 5)
.map((result) => `${result?.text}${result?.source ? ` (Source:${result?.source})` : ''}`)
Expand All @@ -201,7 +200,7 @@ export class HuskyAiService {
}

createPromptForHuskyChat(question: string, context: string, chatSummary: string, allDocs: any) {
const contextLength = Math.min(Math.max(60, context.split(' ').length / 2), 500);
const contextLength = Math.min(Math.max(60, context.split(' ').length / 1.5), 600);
const aiPrompt = Handlebars.compile(aiPromptTemplate)({
context,
contextLength,
Expand Down
158 changes: 0 additions & 158 deletions apps/web-api/src/husky/husky.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,162 +153,4 @@ export class HuskyService {
}
throw error;
}



/*************** HUSKY *****************/
/*
async persistChatHistory(uid: string, prompt: string, rephrasedPrompt: string, response: any) {
await this.huskyPersistentDbService.create(process.env.MONGO_CONVERSATION_COLLECTION || '', {
chatThreadId: uid,
prompt,
rephrasedPrompt,
response: response || '',
createdAt: Date.now(),
});
}
async getEmbeddingForText(text: string) {
const embeddingModel = openai.embedding(process.env.OPENAI_EMBEDDING_MODEL || '');
const { embedding } = await embed({
model: embeddingModel,
value: text,
});
return embedding;
}
async getChatSummary(uid: string) {
const chatHistory = await this.huskyCacheDbService.get(`${uid}:summary`);
return chatHistory;
}
async getRephrasedQuesBasedOnHistory(chatId: string, question: string) {
const chatHistory = await this.getChatSummary(`${chatId}:summary`);
if (chatHistory) {
const { text } = await generateText({
model: openai(process.env.OPENAI_LLM_MODEL || ''),
prompt: `Given the chat summary - ${chatHistory} and the new question - ${question}, Rephrase the new question if its missing any context. If its not missing any context, return the same question. If its a completely new context, return the new question as it is.`,
});
return text;
}
return question;
}
async updateChatSummary(chatId: string, rawChatHistory: any) {
const currentConversation = `user: ${rawChatHistory.user}\n system: ${rawChatHistory.system}`;
const previousSummary = await this.huskyCacheDbService.get(`${chatId}:summary`);
const { text } = await generateText({
model: openai(process.env.OPENAI_LLM_MODEL || ''),
prompt: `${
previousSummary ? `Given the previous chat history - ${previousSummary} and the new` : ''
} Conversation: ${currentConversation}. \n Summarize the above chat conversation to as short as possible without losing any context or details but also maintain the thread of user and system responses`,
});
await this.huskyCacheDbService.set(`${chatId}:summary`, text);
}
streamHuskyResponse(
chatId: string,
question: string,
rephrasedQuestion: string,
res: Response,
prompt: string | null
) {
const aiStreamingResponse = streamObject({
model: openai(process.env.OPENAI_LLM_MODEL || ''),
schema: HuskyResponseSchema,
prompt: prompt || HUSKY_NO_INFO_PROMPT,
onFinish: async (response) => {
if (prompt) {
await this.updateChatSummary(chatId, { user: question, system: response?.object?.content });
}
await this.persistChatHistory(chatId, question, rephrasedQuestion, response?.object?.content);
},
});
aiStreamingResponse.pipeTextStreamToResponse(res);
}
private async fetchAndFormatActionDocsByType(type: string, collectionName: string, embedding: any) {
const actionDocs = await this.huskyVectorDbService.searchEmbeddings(collectionName, embedding, 5, true);
return actionDocs.map((doc) => {
return {
name: doc?.payload?.name ?? '',
directoryLink: doc?.payload?.directoryLink ?? '',
info: doc?.payload?.content ?? '',
type: type,
score: doc.score,
};
});
}
async getActionDocs(embedding: any) {
const [memberDocs, teamDocs, projectDocs] = await Promise.all([
this.fetchAndFormatActionDocsByType(
HUSKY_ACTION_TYPES.MEMBER,
process.env.QDRANT_MEMBERS_COLLECTION || '',
embedding
),
this.fetchAndFormatActionDocsByType(
HUSKY_ACTION_TYPES.TEAM,
process.env.QDRANT_TEAMS_COLLECTION || '',
embedding
),
this.fetchAndFormatActionDocsByType(
HUSKY_ACTION_TYPES.PROJECT,
process.env.QDRANT_PROJECTS_COLLECTION || '',
embedding
),
]);
return {
memberDocs,
teamDocs,
projectDocs,
};
}
async getMatchingEmbeddingsBySource(source: string, embedding: any, limit = 15) {
const collection =
source === HUSKY_SOURCES.TWITTER
? process.env.QDRANT_TWITTER_COLLECTION || ''
: process.env.QDRANT_ALL_DOCS_COLLECTION || '';
return this.huskyVectorDbService.searchEmbeddings(collection, embedding, limit, true);
}
createContextForMatchingDocs(matchingDocs: any[]) {
const formattedResults: any[] = [];
for (const result of matchingDocs) {
formattedResults.push({
score: result.score,
text: result?.payload?.page_content ?? '',
source: result?.payload?.metadata?.url ?? '',
});
}
const sortedResults = formattedResults.sort((a, b) => b?.score - a?.score).slice(0, 5);
const context = sortedResults.map((result) => `${result?.text}(Source:${result?.source})`).join('\n');
return context;
}
createPromptForHuskyChat(question: string, context: string, chatSummary: string, allDocs: any) {
const contextLength = Math.min(Math.max(60, context.split(' ').length / 2), 500);
const aiPrompt = `Given the question - ${question}, And following 'Context' and 'Chat History Summary' (if available)
Generate a JSON object with the following structure. Make sure you have the content, followUpQuestions, actions and sources separate in the JSON object. Dont add everything in the content itself.:
sources: Array of sources of the information from the 'Source' available in the context. Remove any duplicate and invalid sources. If no sources are available, return an empty array.
content: Respond based on the context provided with alteast ${contextLength} words. You can rearrange the sentences to make it meaningful with proper english but Only use the provided information. If you dont have the information user asked for in the text. Just inform - 'Information not available currently' Dont add any other details. Have citations using the 'Source' url from context if available and place it near the corresponding information. Have the citations as links and have the names as [1](Source url), [2](Source url), [3](Source url), etc in ascending order for each citation added. But the numbering order should be for entire context and not just for paragraphs. Avoid duplicate citations i.e. if a source is already cited, dont cite it again. Use sub-headings to make the content more readable.
followUpQuestions: An array containing exactly 3 follow-up questions that are relevant to the retrieved information.
actions: An array of objects with the following structure: {name: 'Name of the member', directoryLink: 'Link to the directory site', type: 'Member/Team/Project'}. Choose max 6 from the 'action list' that is appropriate for this context. Have least preference for someone with role - Contributor. If list items are not available or doesn't looks appropriate for the context, return an empty array.
Dont add any additional information from your Pretrained knowledge. And citation it is important dont miss it.
If the context is empty, return content as 'No information available' strictly.
"Strictly" dont add sources, followUpQuestions, actions into content.
Context: ${context}
Chat Conversation Summary: ${chatSummary}
action list: ${JSON.stringify(allDocs)}
`;
return aiPrompt;
} */
}
66 changes: 7 additions & 59 deletions apps/web-api/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ STRICT REQUIREMENTS for the output json: Follow the below requirements strictly.
- First citation of source1.com → 1
- First citation of source2.com → 2
- Second citation of source1.com → 1 (not 3).
- Strictly Never add the 'sources' in the 'content' like - Sources \n 1. example1.com \n 2. example2.com \n 3.example3.com
- Strictly Never add the 'followUpQuestions' in the 'content'.
- Strictly Never add the 'actions' in the 'content'
- **Strictly** Never add the 'sources' in the 'content' like - Sources \n 1. example1.com \n 2. example2.com \n 3.example3.com
- **Strictly** Never add the 'followUpQuestions' in the 'content'.
- **Strictly** Never add the 'actions' in the 'content'
2. 'sources' FORMATTING:
- Include only unique, valid URLs f rom context
Expand Down Expand Up @@ -182,59 +182,7 @@ action list: {{allDocs}};
`;

export const rephraseQuestionTemplate = `
Given:
Chat Summary: {{chatHistory}}
New Question: {{question}}
Task:
1. Check if question needs context from chat history
2. If context missing: Add relevant context to question
3. If context complete: Return original question
4. If new topic: Return original question
Return only the final question with no explanations.
`
export const chatSummaryTemplate = `
Given conversation: {{currentConversation}}, generate concise summary in the below format:
TOPICS:
[Topic- Brief topic label]
- User: Key points/questions
- System: Core responses/solutions
Example format:
Redis
- User: Setup, cache size, security
- System: Config steps, 2GB recommended, firewall rules
Baking
- User: Chocolate cake recipe
- System: Instructions provided
Rules:
- Keep entries telegram-style - brief but complete
`
export const chatSummaryWithHistoryTemplate = `
Given previous summary {{previousSummary}} and new messages {{currentConversation}}, generate concise summary:
TOPICS:
[Topic ID]: [Brief topic label] ([message range])
- User: Key points/questions
- System: Core responses/solutions
Example format:
Topic 1: Redis
- User: Setup, cache size, security
- System: Config steps, 2GB recommended, firewall rules
Topic 2: Baking
- User: Chocolate cake recipe
- System: Instructions provided
Rules:
- Start new topic if context/subject clearly changes
- Link to previous topic if referenced (format: see Topic 1)
- Keep entries telegram-style - brief but complete
`
export const rephraseQuestionTemplate = `Given the chat summary - {{chatHistory}} and the new question - {{question}}, Rephrase the new question if its missing any context. If its not missing any context, return the same question. If its a completely new context, return the new question as it is.`;

export const chatSummaryWithHistoryTemplate = `Given the summary of chat history - {{previousSummary}}, and the new conversation - {{currentConversation}}, Summarize all the system responses into one and also all user queries into one as short as possible but without losing any context or detail`;
export const chatSummaryTemplate = `Given that chat conversation - {{currentConversation}}, Summarize all the system responses into one and also all user queries into one as short as possible but without losing any context or detail`;

0 comments on commit e5940ef

Please sign in to comment.