mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Send hash of user ID in OpenAI API requests
Summary: Following recommendation in https://platform.openai.com/docs/guides/safety-best-practices/end-user-ids Test Plan: Checked that running server test shows log of hash of 'user id' (which is null because it's a fake session) Reviewers: dsagal Reviewed By: dsagal Subscribers: paulfitz, georgegevoian Differential Revision: https://phab.getgrist.com/D3958
This commit is contained in:
parent
0a34292536
commit
5a703a1972
@ -6,9 +6,11 @@ import {AssistanceMessage, AssistanceRequest, AssistanceResponse} from 'app/comm
|
|||||||
import {delay} from 'app/common/delay';
|
import {delay} from 'app/common/delay';
|
||||||
import {DocAction} from 'app/common/DocActions';
|
import {DocAction} from 'app/common/DocActions';
|
||||||
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
import {ActiveDoc} from 'app/server/lib/ActiveDoc';
|
||||||
import {OptDocSession} from 'app/server/lib/DocSession';
|
import {getDocSessionUser, OptDocSession} from 'app/server/lib/DocSession';
|
||||||
import log from 'app/server/lib/log';
|
import log from 'app/server/lib/log';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
|
import {createHash} from "crypto";
|
||||||
|
import {getLogMetaFromDocSession} from "./serverUtils";
|
||||||
|
|
||||||
// These are mocked/replaced in tests.
|
// These are mocked/replaced in tests.
|
||||||
// fetch is also replacing in the runCompletion script to add caching.
|
// fetch is also replacing in the runCompletion script to add caching.
|
||||||
@ -179,7 +181,8 @@ export class OpenAIAssistant implements Assistant {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const completion: string = await this._getCompletion(messages);
|
const userIdHash = getUserHash(optSession);
|
||||||
|
const completion: string = await this._getCompletion(messages, userIdHash);
|
||||||
const response = await completionToResponse(doc, request, completion, completion);
|
const response = await completionToResponse(doc, request, completion, completion);
|
||||||
if (chatMode) {
|
if (chatMode) {
|
||||||
response.state = {messages};
|
response.state = {messages};
|
||||||
@ -198,7 +201,7 @@ export class OpenAIAssistant implements Assistant {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchCompletion(messages: AssistanceMessage[], longerContext: boolean) {
|
private async _fetchCompletion(messages: AssistanceMessage[], userIdHash: string, longerContext: boolean) {
|
||||||
const apiResponse = await DEPS.fetch(
|
const apiResponse = await DEPS.fetch(
|
||||||
this._endpoint,
|
this._endpoint,
|
||||||
{
|
{
|
||||||
@ -214,6 +217,7 @@ export class OpenAIAssistant implements Assistant {
|
|||||||
temperature: 0,
|
temperature: 0,
|
||||||
model: longerContext ? OpenAIAssistant.LONGER_CONTEXT_MODEL : OpenAIAssistant.DEFAULT_MODEL,
|
model: longerContext ? OpenAIAssistant.LONGER_CONTEXT_MODEL : OpenAIAssistant.DEFAULT_MODEL,
|
||||||
stop: this._chatMode ? undefined : ["\n\n"],
|
stop: this._chatMode ? undefined : ["\n\n"],
|
||||||
|
user: userIdHash,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -240,14 +244,16 @@ export class OpenAIAssistant implements Assistant {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchCompletionWithRetries(messages: AssistanceMessage[], longerContext: boolean): Promise<any> {
|
private async _fetchCompletionWithRetries(
|
||||||
|
messages: AssistanceMessage[], userIdHash: string, longerContext: boolean
|
||||||
|
): Promise<any> {
|
||||||
const maxAttempts = 3;
|
const maxAttempts = 3;
|
||||||
for (let attempt = 1; ; attempt++) {
|
for (let attempt = 1; ; attempt++) {
|
||||||
try {
|
try {
|
||||||
return await this._fetchCompletion(messages, longerContext);
|
return await this._fetchCompletion(messages, userIdHash, longerContext);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof SwitchToLongerContext) {
|
if (e instanceof SwitchToLongerContext) {
|
||||||
return await this._fetchCompletionWithRetries(messages, true);
|
return await this._fetchCompletionWithRetries(messages, userIdHash, true);
|
||||||
} else if (e instanceof NonRetryableError) {
|
} else if (e instanceof NonRetryableError) {
|
||||||
throw e;
|
throw e;
|
||||||
} else if (attempt === maxAttempts) {
|
} else if (attempt === maxAttempts) {
|
||||||
@ -259,8 +265,8 @@ export class OpenAIAssistant implements Assistant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getCompletion(messages: AssistanceMessage[]) {
|
private async _getCompletion(messages: AssistanceMessage[], userIdHash: string) {
|
||||||
const result = await this._fetchCompletionWithRetries(messages, false);
|
const result = await this._fetchCompletionWithRetries(messages, userIdHash, false);
|
||||||
const completion: string = String(this._chatMode ? result.choices[0].message.content : result.choices[0].text);
|
const completion: string = String(this._chatMode ? result.choices[0].message.content : result.choices[0].text);
|
||||||
if (this._chatMode) {
|
if (this._chatMode) {
|
||||||
messages.push(result.choices[0].message);
|
messages.push(result.choices[0].message);
|
||||||
@ -433,3 +439,15 @@ async function completionToResponse(doc: AssistanceDoc, request: AssistanceReque
|
|||||||
reply,
|
reply,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getUserHash(session: OptDocSession): string {
|
||||||
|
const user = getDocSessionUser(session);
|
||||||
|
// Make it a bit harder to guess the user ID.
|
||||||
|
const salt = "7a8sb6987asdb678asd687sad6boas7f8b6aso7fd";
|
||||||
|
const hashSource = `${user?.id} ${user?.ref} ${salt}`;
|
||||||
|
const hash = createHash('sha256').update(hashSource).digest('base64');
|
||||||
|
// So that if we get feedback about a user ID hash, we can
|
||||||
|
// search for the hash in the logs to find the original user ID.
|
||||||
|
log.rawInfo("getUserHash", {...getLogMetaFromDocSession(session), userRef: user?.ref, hash});
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user