Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A11y/labels landmark contrast #1

Draft
wants to merge 34 commits into
base: a11y-upstream
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
80773d0
🗝️ fix: update `webcrypto` algorithm name as `aes-256-cbc` is unrecog…
danny-avila Aug 5, 2024
6879de0
🔧 fix: API Key Handling for GoogleSearch and TavilySearch Tools (#3541)
jung0han Aug 5, 2024
c2a79ae
⏬ feat: Optimize Scroll Handling with Intersection Observer (#3564)
danny-avila Aug 6, 2024
270c6d2
📜 fix: Better OpenAI Assistants Annotation Processing (#3565)
danny-avila Aug 6, 2024
01a8899
🎛️ refactor: Add keyboard command toggles & only trigger for the 1st …
danny-avila Aug 7, 2024
b390ba7
🗣️ feat: Edge TTS engine (#3358)
berry-13 Aug 7, 2024
2bb0842
🅰️ feat: Dynamic Font Size (#3568)
danny-avila Aug 7, 2024
b3821c1
🎨 style: Enhance UI/UX for Font Size, Mentions, and Prompts (#3575)
danny-avila Aug 8, 2024
5c99d93
🛂 feat: Added Security for Conversation Access (#3588)
danny-avila Aug 8, 2024
cf393b1
🎨 style: overall UI improvements (#3576)
berry-13 Aug 8, 2024
6ea2628
🌡️ feat: Periodic Health Check to prevent UI Inactivity Connection Er…
danny-avila Aug 8, 2024
016ed86
🏷️ fix: Address Statefulness Issues for Bookmarks (#3590)
danny-avila Aug 9, 2024
e05a6d3
🪙 feat: Update Token Values for `gpt-4o-2024-08-06` and AWS Models (#…
danny-avila Aug 9, 2024
473859b
🧹 chore: pre-release cleanup (#3595)
danny-avila Aug 9, 2024
59ae291
🐋 ci: deploy test server post-dev image build (#3596)
danny-avila Aug 9, 2024
8a9476a
ci: deploy test server post-dev image build pt. 2
danny-avila Aug 9, 2024
6fead10
ci: deploy test server post-dev image build pt. 3
danny-avila Aug 9, 2024
1ff4841
🧹 chore: pre-release cleanup 2 (#3600)
danny-avila Aug 9, 2024
22c8b6f
💭 fix: Message Labels and Typing Issues (#3602)
danny-avila Aug 9, 2024
3a5f57f
✨ v0.7.4 (#3603)
danny-avila Aug 10, 2024
cf69b7e
✨ v0.7.4
danny-avila Aug 10, 2024
02847af
📜 refactor: Optimize Longer Message Thread Performance (#3610)
danny-avila Aug 11, 2024
8cbb6ba
📧 fix: @/+command timing for click selections - closes #3613 (#3617)
berry-13 Aug 12, 2024
0569623
🎛️ fix: Improve Frontend Practices for Audio Settings (#3624)
danny-avila Aug 13, 2024
6655304
🎙️ a11y: Screen Reader Support for Dynamic Content Updates (#3625)
danny-avila Aug 13, 2024
e3ebcfd
🎙️ fix: Optimize and Fix Browser TTS Incompatibility (firefox) (#3627)
danny-avila Aug 13, 2024
f1cf787
add landmark contentinfo to footer
Tanvez Aug 13, 2024
dc8d30a
🎧 fix(TTS): Improve State of audio playback, hook patterns, and fix u…
danny-avila Aug 13, 2024
d037ea8
fix aria-label ai model menuitem for issue #3587
Tanvez Aug 13, 2024
741e3e8
🚀 Update README - v0.7.4
berry-13 Aug 15, 2024
bcde0be
🛠️ feat: Azure OpenAI Assistants File Downloads (#3653)
danny-avila Aug 15, 2024
dba7040
🔀 refactor: Modularize TTS Logic for Improved Browser support (#3657)
danny-avila Aug 15, 2024
41edbda
changed group/today text color to #535353
Tanvez Aug 15, 2024
12e59fa
Merge branch 'main' into a11y/labels-landmark-contrast
Tanvez Aug 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Update Test Server

on:
workflow_run:
workflows: ["Docker Dev Images Build"]
types:
- completed
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
if: |
github.repository == 'danny-avila/LibreChat' &&
(github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success')
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install SSH Key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.DO_SSH_PRIVATE_KEY }}
known_hosts: ${{ secrets.DO_KNOWN_HOSTS }}

- name: Run update script on DigitalOcean Droplet
env:
DO_HOST: ${{ secrets.DO_HOST }}
DO_USER: ${{ secrets.DO_USER }}
run: |
ssh -o StrictHostKeyChecking=no ${DO_USER}@${DO_HOST} << EOF
sudo -i -u danny bash << EEOF
cd ~/LibreChat && \
git fetch origin main && \
npm run update:deployed && \
git checkout do-deploy && \
git rebase main && \
npm run start:deployed && \
echo "Update completed. Application should be running now."
EEOF
EOF
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch LibreChat (debug)",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/api/server/index.js",
"env": {
"NODE_ENV": "production"
},
"console": "integratedTerminal"
}
]
}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# v0.7.3
# v0.7.4

# Base node image
FROM node:20-alpine AS node
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.multi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# v0.7.3
# v0.7.4

# Build API, Client and Data Provider
FROM node:20-alpine AS base
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ LibreChat brings together the future of assistant AIs with the revolutionary tec

With LibreChat, you no longer need to opt for ChatGPT Plus and can instead use free or pay-per-call APIs. We welcome contributions, cloning, and forking to enhance the capabilities of this advanced chatbot platform.

[![Watch the video](https://img.youtube.com/vi/bSVHEbVPNl4/maxresdefault.jpg)](https://www.youtube.com/watch?v=bSVHEbVPNl4)
[![Watch the video](https://raw.githubusercontent.com/LibreChat-AI/librechat.ai/main/public/images/changelog/v0.7.4.png)](https://www.youtube.com/watch?v=cvosUxogdpI)
Click on the thumbnail to open the video☝️

---
Expand Down
10 changes: 8 additions & 2 deletions api/app/clients/tools/structured/GoogleSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ class GoogleSearchResults extends Tool {
this.envVarApiKey = 'GOOGLE_SEARCH_API_KEY';
this.envVarSearchEngineId = 'GOOGLE_CSE_ID';
this.override = fields.override ?? false;
this.apiKey = fields.apiKey ?? getEnvironmentVariable(this.envVarApiKey);
this.apiKey = fields[this.envVarApiKey] ?? getEnvironmentVariable(this.envVarApiKey);
this.searchEngineId =
fields.searchEngineId ?? getEnvironmentVariable(this.envVarSearchEngineId);
fields[this.envVarSearchEngineId] ?? getEnvironmentVariable(this.envVarSearchEngineId);

if (!this.override && (!this.apiKey || !this.searchEngineId)) {
throw new Error(
`Missing ${this.envVarApiKey} or ${this.envVarSearchEngineId} environment variable.`,
);
}

this.kwargs = fields?.kwargs ?? {};
this.name = 'google';
Expand Down
2 changes: 1 addition & 1 deletion api/app/clients/tools/structured/TavilySearchResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TavilySearchResults extends Tool {
this.envVar = 'TAVILY_API_KEY';
/* Used to initialize the Tool without necessary variables. */
this.override = fields.override ?? false;
this.apiKey = fields.apiKey ?? this.getApiKey();
this.apiKey = fields[this.envVar] ?? this.getApiKey();

this.kwargs = fields?.kwargs ?? {};
this.name = 'tavily_search_results_json';
Expand Down
50 changes: 50 additions & 0 deletions api/app/clients/tools/structured/specs/GoogleSearch.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const GoogleSearch = require('../GoogleSearch');

jest.mock('node-fetch');
jest.mock('@langchain/core/utils/env');

describe('GoogleSearch', () => {
let originalEnv;
const mockApiKey = 'mock_api';
const mockSearchEngineId = 'mock_search_engine_id';

beforeAll(() => {
originalEnv = { ...process.env };
});

beforeEach(() => {
jest.resetModules();
process.env = {
...originalEnv,
GOOGLE_SEARCH_API_KEY: mockApiKey,
GOOGLE_CSE_ID: mockSearchEngineId,
};
});

afterEach(() => {
jest.clearAllMocks();
process.env = originalEnv;
});

it('should use mockApiKey and mockSearchEngineId when environment variables are not set', () => {
const instance = new GoogleSearch({
GOOGLE_SEARCH_API_KEY: mockApiKey,
GOOGLE_CSE_ID: mockSearchEngineId,
});
expect(instance.apiKey).toBe(mockApiKey);
expect(instance.searchEngineId).toBe(mockSearchEngineId);
});

it('should throw an error if GOOGLE_SEARCH_API_KEY or GOOGLE_CSE_ID is missing', () => {
delete process.env.GOOGLE_SEARCH_API_KEY;
expect(() => new GoogleSearch()).toThrow(
'Missing GOOGLE_SEARCH_API_KEY or GOOGLE_CSE_ID environment variable.',
);

process.env.GOOGLE_SEARCH_API_KEY = mockApiKey;
delete process.env.GOOGLE_CSE_ID;
expect(() => new GoogleSearch()).toThrow(
'Missing GOOGLE_SEARCH_API_KEY or GOOGLE_CSE_ID environment variable.',
);
});
});
38 changes: 38 additions & 0 deletions api/app/clients/tools/structured/specs/TavilySearchResults.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const TavilySearchResults = require('../TavilySearchResults');

jest.mock('node-fetch');
jest.mock('@langchain/core/utils/env');

describe('TavilySearchResults', () => {
let originalEnv;
const mockApiKey = 'mock_api_key';

beforeAll(() => {
originalEnv = { ...process.env };
});

beforeEach(() => {
jest.resetModules();
process.env = {
...originalEnv,
TAVILY_API_KEY: mockApiKey,
};
});

afterEach(() => {
jest.clearAllMocks();
process.env = originalEnv;
});

it('should throw an error if TAVILY_API_KEY is missing', () => {
delete process.env.TAVILY_API_KEY;
expect(() => new TavilySearchResults()).toThrow('Missing TAVILY_API_KEY environment variable.');
});

it('should use mockApiKey when TAVILY_API_KEY is not set in the environment', () => {
const instance = new TavilySearchResults({
TAVILY_API_KEY: mockApiKey,
});
expect(instance.apiKey).toBe(mockApiKey);
});
});
5 changes: 3 additions & 2 deletions api/cache/getLogStores.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ const messages = isEnabled(USE_REDIS)
? new Keyv({ store: keyvRedis, ttl: Time.FIVE_MINUTES })
: new Keyv({ namespace: CacheKeys.MESSAGES, ttl: Time.FIVE_MINUTES });

const tokenConfig = isEnabled(USE_REDIS) // ttl: 30 minutes
const tokenConfig = isEnabled(USE_REDIS)
? new Keyv({ store: keyvRedis, ttl: Time.THIRTY_MINUTES })
: new Keyv({ namespace: CacheKeys.TOKEN_CONFIG, ttl: Time.THIRTY_MINUTES });

const genTitle = isEnabled(USE_REDIS) // ttl: 2 minutes
const genTitle = isEnabled(USE_REDIS)
? new Keyv({ store: keyvRedis, ttl: Time.TWO_MINUTES })
: new Keyv({ namespace: CacheKeys.GEN_TITLE, ttl: Time.TWO_MINUTES });

Expand Down Expand Up @@ -69,6 +69,7 @@ const namespaces = {
registrations: createViolationInstance('registrations'),
[ViolationTypes.TTS_LIMIT]: createViolationInstance(ViolationTypes.TTS_LIMIT),
[ViolationTypes.STT_LIMIT]: createViolationInstance(ViolationTypes.STT_LIMIT),
[ViolationTypes.CONVO_ACCESS]: createViolationInstance(ViolationTypes.CONVO_ACCESS),
[ViolationTypes.FILE_UPLOAD_LIMIT]: createViolationInstance(ViolationTypes.FILE_UPLOAD_LIMIT),
[ViolationTypes.VERIFY_EMAIL_LIMIT]: createViolationInstance(ViolationTypes.VERIFY_EMAIL_LIMIT),
[ViolationTypes.RESET_PASSWORD_LIMIT]: createViolationInstance(
Expand Down
15 changes: 15 additions & 0 deletions api/models/Conversation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ const Conversation = require('./schema/convoSchema');
const { getMessages, deleteMessages } = require('./Message');
const logger = require('~/config/winston');

/**
* Searches for a conversation by conversationId and returns a lean document with only conversationId and user.
* @param {string} conversationId - The conversation's ID.
* @returns {Promise<{conversationId: string, user: string} | null>} The conversation object with selected fields or null if not found.
*/
const searchConversation = async (conversationId) => {
try {
return await Conversation.findOne({ conversationId }, 'conversationId user').lean();
} catch (error) {
logger.error('[searchConversation] Error searching conversation', error);
throw new Error('Error searching conversation');
}
};

/**
* Retrieves a single conversation for a given user and conversation ID.
* @param {string} user - The user's ID.
Expand All @@ -19,6 +33,7 @@ const getConvo = async (user, conversationId) => {

module.exports = {
Conversation,
searchConversation,
/**
* Saves a conversation to the database.
* @param {Object} req - The request object.
Expand Down
Loading
Loading