diff --git a/CHANGELOG.md b/CHANGELOG.md index 1672957f63..6ed062f68d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Nothing is unreleased! +## [1.0.200] - 2023-01-22 + +### Added + +- Chainlit Copilot +- Translations +- Custom font + +### Fixed + +- Tasklist flickering + ## [1.0.101] - 2023-01-12 ### Fixed diff --git a/README.md b/README.md index e791adcfba..4100de2728 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,22 @@ -# Welcome to Chainlit 👋 +# Welcome to Chainlit by Literal AI 👋 [![](https://dcbadge.vercel.app/api/server/ZThrUxbAYw?style=flat)](https://discord.gg/k73SQ3FyUh) [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/chainlit_io.svg?style=social&label=Follow%20%40chainlit_io)](https://twitter.com/chainlit_io) [![CI](https://github.com/Chainlit/chainlit/actions/workflows/ci.yaml/badge.svg)](https://github.com/Chainlit/chainlit/actions/workflows/ci.yaml) -**Build a production ready Chat GPT like application in minutes ⚡️** +**Build production-ready Conversational AI applications in minutes, not weeks ⚡️** -Chainlit is an open-source async Python framework that makes it incredibly fast to build Chat GPT like applications with your **own business logic and data**. +Chainlit is an open-source async Python framework which allows developers to build scalable Conversational AI or agentic applications. -Contact us [here](https://forms.gle/BX3UNBLmTF75KgZVA) for **Enterprise Support** and to get early access to the **Analytics & Observability** product. +- ✅ ChatGPT-like application +- ✅ Embedded Copilot +- ✅ Custom frontend +- ✅ API Endpoint +- 🛠️ Teams/Slack Integration + +Full documentation is available [here](https://docs.chainlit.io). + +Contact us [here](https://forms.gle/BX3UNBLmTF75KgZVA) for **Enterprise Support** and to get early access to Literal AI, our product to evaluate and monitor LLM applications. https://github.com/Chainlit/chainlit/assets/13104895/8882af90-fdfa-4b24-8200-1ee96c6c7490 @@ -23,14 +31,6 @@ $ chainlit hello If this opens the `hello app` in your browser, you're all set! -## 📖 Documentation - -Please see [here](https://docs.chainlit.io) for full documentation on: - -- Getting started (installation, simple examples) -- Examples -- Reference (full API docs) - ## 🚀 Quickstart ### 🐍 Pure Python @@ -78,25 +78,12 @@ $ chainlit run demo.py -w Chainlit is compatible with all Python programs and libraries. That being said, it comes with integrations for: -- [Langchain](https://docs.chainlit.io/integrations/langchain) +- [LangChain](https://docs.chainlit.io/integrations/langchain) +- [Llama Index](https://docs.chainlit.io/integrations/llama-index) - [Autogen](https://github.com/Chainlit/cookbook/tree/main/pyautogen) - [OpenAI Assistant](https://github.com/Chainlit/cookbook/tree/main/openai-assistant) -- [Llama Index](https://docs.chainlit.io/integrations/llama-index) - [Haystack](https://docs.chainlit.io/integrations/haystack) -## 🎨 Custom Frontend - -Chainlit allows you to create a custom frontend for your application, offering you the flexibility to design a unique user experience. By integrating your frontend with Chainlit's backend, you can harness the full power of Chainlit's features, including: - -- Abstractions for easier development -- Monitoring and observability -- Seamless integrations with various tools -- Robust authentication mechanisms -- Support for multi-user environments -- Efficient data streaming capabilities - -To build and connect your own frontend, check out our [Custom Frontend Cookbook](https://github.com/Chainlit/cookbook/tree/main/custom-frontend). - ## 📚 More Examples - Cookbook You can find various examples of Chainlit apps [here](https://github.com/Chainlit/cookbook) that leverage tools and services such as OpenAI, Anthropiс, LangChain, LlamaIndex, ChromaDB, Pinecone and more. diff --git a/backend/chainlit/auth.py b/backend/chainlit/auth.py index 3390fd1a92..981d33abe4 100644 --- a/backend/chainlit/auth.py +++ b/backend/chainlit/auth.py @@ -74,10 +74,10 @@ async def authenticate_user(token: str = Depends(reuseable_oauth)): if data_layer := get_data_layer(): try: persisted_user = await data_layer.get_user(user.identifier) + if persisted_user == None: + persisted_user = await data_layer.create_user(user) except Exception as e: return user - if persisted_user == None: - raise HTTPException(status_code=401, detail="User does not exist") return persisted_user else: diff --git a/backend/chainlit/server.py b/backend/chainlit/server.py index 3d4019dd5b..c726c628b3 100644 --- a/backend/chainlit/server.py +++ b/backend/chainlit/server.py @@ -183,9 +183,7 @@ def get_build_dir(local_target: str, packaged_target: str): socket = SocketManager( app, - cors_allowed_origins=[] - if config.project.allow_origins[0] == "*" - else config.project.allow_origins, + cors_allowed_origins=[], async_mode="asgi", ) diff --git a/backend/chainlit/translations/en-US.json b/backend/chainlit/translations/en-US.json index 5a7c69d364..199387de9f 100644 --- a/backend/chainlit/translations/en-US.json +++ b/backend/chainlit/translations/en-US.json @@ -82,7 +82,8 @@ "index": { "failedToUpload": "Failed to upload", "cancelledUploadOf": "Cancelled upload of", - "couldNotReachServer": "Could not reach the server" + "couldNotReachServer": "Could not reach the server", + "continuingChat": "Continuing previous chat" }, "settings": { "settingsPanel": "Settings panel", @@ -144,9 +145,6 @@ "requiredApiKeys": "Required API Keys", "requiredApiKeysInfo": "To use this app, the following API keys are required. The keys are stored on your device's local storage." }, - "Login": { - "authTitle": "Login to access the app." - }, "Page": { "notPartOfProject": "You are not part of this project." }, diff --git a/backend/chainlit/translations/pt-BR.json b/backend/chainlit/translations/pt-BR.json index cd45c9ce8e..ccbaf5e72a 100644 --- a/backend/chainlit/translations/pt-BR.json +++ b/backend/chainlit/translations/pt-BR.json @@ -1,136 +1,137 @@ { - "components": { - "atoms": { - "buttons": { - "userButton": { - "menu": { - "settings": "Configurações", - "settingsKey": "S", - "APIKeys": "Chaves de API", - "logout": "Sair" - } + "components": { + "atoms": { + "buttons": { + "userButton": { + "menu": { + "settings": "Configurações", + "settingsKey": "S", + "APIKeys": "Chaves de API", + "logout": "Sair" } } + } + }, + "molecules": { + "newChatButton": { + "newChat": "Nova Conversa" + }, + "tasklist": { + "TaskList": { + "title": "🗒️ Lista de Tarefas", + "loading": "Carregando...", + "error": "Ocorreu um erro" + } }, - "molecules": { - "newChatButton": { - "newChat": "Nova Conversa" + "attachments": { + "cancelUpload": "Cancelar envio", + "removeAttachment": "Remover anexo" + }, + "newChatDialog": { + "createNewChat": "Criar novo chat?", + "clearChat": "Isso limpará as mensagens atuais e iniciará uma nova conversa.", + "cancel": "Cancelar", + "confirm": "Confirmar" + }, + "settingsModal": { + "expandMessages": "Expandir Mensagens", + "hideChainOfThought": "Esconder Sequência de Pensamento", + "darkMode": "Modo Escuro" + } + }, + "organisms": { + "chat": { + "history": { + "index": { + "lastInputs": "Últimas Entradas", + "noInputs": "Vazio...", + "loading": "Carregando..." + } + }, + "inputBox": { + "input": { + "placeholder": "Digite sua mensagem aqui..." + }, + "speechButton": { + "start": "Iniciar gravação", + "stop": "Parar gravação" + }, + "SubmitButton": { + "sendMessage": "Enviar mensagem", + "stopTask": "Parar Tarefa" + }, + "UploadButton": { + "attachFiles": "Anexar arquivos" + }, + "waterMark": { + "text": "Construído com" + } }, - "tasklist": { - "TaskList": { - "title": "🗒️ Lista de Tarefas", - "loading": "Carregando...", - "error": "Ocorreu um erro" + "Messages": { + "index": { + "running": "Executando", + "executedSuccessfully": "executado com sucesso", + "failed": "falhou", + "feedbackUpdated": "Feedback atualizado", + "updating": "Atualizando" } }, - "attachments": { - "cancelUpload": "Cancelar envio", - "removeAttachment": "Remover anexo" + "dropScreen": { + "dropYourFilesHere": "Solte seus arquivos aqui" }, - "newChatDialog": { - "createNewChat": "Criar novo chat?", - "clearChat": "Isso limpará as mensagens atuais e iniciará uma nova conversa.", + "index": { + "failedToUpload": "Falha ao enviar", + "cancelledUploadOf": "Envio cancelado de", + "couldNotReachServer": "Não foi possível conectar ao servidor", + "continuingChat": "Continuando o chat anterior" + }, + "settings": { + "settingsPanel": "Painel de Configurações", + "reset": "Redefinir", "cancel": "Cancelar", "confirm": "Confirmar" - }, - "settingsModal": { - "expandMessages": "Expandir Mensagens", - "hideChainOfThought": "Esconder Sequência de Pensamento", - "darkMode": "Modo Escuro" } }, - "organisms": { - "chat": { - "history": { - "index": { - "lastInputs": "Últimas Entradas", - "noInputs": "Vazio...", - "loading": "Carregando..." - } - }, - "inputBox": { - "input": { - "placeholder": "Digite sua mensagem aqui..." - }, - "speechButton": { - "start": "Iniciar gravação", - "stop": "Parar gravação" - }, - "SubmitButton": { - "sendMessage": "Enviar mensagem", - "stopTask": "Parar Tarefa" - }, - "UploadButton": { - "attachFiles": "Anexar arquivos" + "threadHistory": { + "sidebar": { + "filters": { + "FeedbackSelect": { + "feedbackAll": "Feedback: Todos", + "feedbackPositive": "Feedback: Positivo", + "feedbackNegative": "Feedback: Negativo" }, - "waterMark": { - "text": "Construído com" + "SearchBar": { + "search": "Buscar" } }, - "Messages": { - "index": { - "running": "Executando", - "executedSuccessfully": "executado com sucesso", - "failed": "falhou", - "feedbackUpdated": "Feedback atualizado", - "updating": "Atualizando" - } - }, - "dropScreen": { - "dropYourFilesHere": "Solte seus arquivos aqui" + "DeleteThreadButton": { + "confirmMessage": "Isso deletará a conversa, assim como suas mensagens e elementos.", + "cancel": "Cancelar", + "confirm": "Confirmar", + "deletingChat": "Deletando conversa", + "chatDeleted": "Conversa deletada" }, "index": { - "failedToUpload": "Falha ao enviar", - "cancelledUploadOf": "Envio cancelado de", - "couldNotReachServer": "Não foi possível conectar ao servidor" + "pastChats": "Conversas Anteriores" }, - "settings": { - "settingsPanel": "Painel de Configurações", - "reset": "Redefinir", - "cancel": "Cancelar", - "confirm": "Confirmar" - } - }, - "threadHistory": { - "sidebar": { - "filters": { - "FeedbackSelect": { - "feedbackAll": "Feedback: Todos", - "feedbackPositive": "Feedback: Positivo", - "feedbackNegative": "Feedback: Negativo" - }, - "SearchBar": { - "search": "Buscar" - } - }, - "DeleteThreadButton": { - "confirmMessage": "Isso deletará a conversa, assim como suas mensagens e elementos.", - "cancel": "Cancelar", - "confirm": "Confirmar", - "deletingChat": "Deletando conversa", - "chatDeleted": "Conversa deletada" - }, - "index": { - "pastChats": "Conversas Anteriores" - }, - "ThreadList": { - "empty": "Vazio..." - }, - "TriggerButton": { - "closeSidebar": "Fechar barra lateral", - "openSidebar": "Abrir barra lateral" - } + "ThreadList": { + "empty": "Vazio..." }, - "Thread": { - "backToChat": "Voltar para a conversa", - "chatCreatedOn": "Esta conversa foi criada em" + "TriggerButton": { + "closeSidebar": "Fechar barra lateral", + "openSidebar": "Abrir barra lateral" } }, - "header": { - "chat": "Conversa", - "readme": "Leia-me" + "Thread": { + "backToChat": "Voltar para a conversa", + "chatCreatedOn": "Esta conversa foi criada em" } }, + "header": { + "chat": "Conversa", + "readme": "Leia-me" + } + }, "hooks": { "useLLMProviders": { "failedToFetchProviders": "Falha ao buscar provedores:" @@ -143,9 +144,6 @@ "requiredApiKeys": "Chaves de API necessárias", "requiredApiKeysInfo": "Para usar este aplicativo, as seguintes chaves de API são necessárias. As chaves são armazenadas localmente em seu dispositivo." }, - "Login": { - "authTitle": "Faça login para acessar o aplicativo." - }, "Page": { "notPartOfProject": "Você não faz parte deste projeto." }, @@ -154,4 +152,4 @@ } } } -} \ No newline at end of file +} diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 381c7c81f6..cf7975e896 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "chainlit" -version = "1.0.101" -keywords = ['LLM', 'Agents', 'gen ai', 'chat ui', 'chatbot ui', 'openai', 'copilot', 'langchain'] +version = "1.0.200" +keywords = ['LLM', 'Agents', 'gen ai', 'chat ui', 'chatbot ui', 'openai', 'copilot', 'langchain', 'conversational ai'] description = "Build Conversational AI." authors = ["Chainlit"] license = "Apache-2.0 license" @@ -23,7 +23,7 @@ chainlit = 'chainlit.cli:cli' [tool.poetry.dependencies] python = ">=3.8.1,<4.0.0" httpx = ">=0.23.0,<0.25.0" -literalai = "0.0.102" +literalai = "0.0.103" dataclasses_json = "^0.5.7" # FastAPI 0.109.0 breaks socketio (alway 404) fastapi = ">=0.100,<0.109.0" diff --git a/frontend/src/components/organisms/chat/index.tsx b/frontend/src/components/organisms/chat/index.tsx index c08b04a902..2c408c18c8 100644 --- a/frontend/src/components/organisms/chat/index.tsx +++ b/frontend/src/components/organisms/chat/index.tsx @@ -9,7 +9,8 @@ import { Alert, Box } from '@mui/material'; import { threadHistoryState, useChatData, - useChatInteract + useChatInteract, + useChatSession } from '@chainlit/react-client'; import { ErrorBoundary, useUpload } from '@chainlit/react-components'; @@ -27,6 +28,8 @@ import DropScreen from './dropScreen'; import InputBox from './inputBox'; const Chat = () => { + const { idToResume } = useChatSession(); + const projectSettings = useRecoilValue(projectSettingsState); const setAttachments = useSetRecoilState(attachmentsState); const setThreads = useSetRecoilState(threadHistoryState); @@ -170,7 +173,7 @@ const Chat = () => { ) : null} - {error && ( + {error ? ( { - )} + ) : null} + {idToResume ? ( + + + + + + ) : null} diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index 95071da7b0..6d97eeaac2 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -1,6 +1,5 @@ import { useAuth } from 'api/auth'; import { useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -20,8 +19,6 @@ export default function Login() { const navigate = useNavigate(); - const { t } = useTranslation(); - const handleHeaderAuth = async () => { try { const json = await apiClient.headerAuth(); @@ -71,7 +68,7 @@ export default function Login() { return ( { + setAccessToken(config.accessToken); + }, [config.accessToken]); + useEffect(() => { setApiClient(apiClient); if (!projectSettings) { @@ -39,13 +45,16 @@ export default function App({ config }: Props) { .then((res) => res.json()) .then((data: IProjectSettings) => { window.theme = data.ui.theme; - data.ui.hide_cot = config.show_cot ? false : true; - if (config.theme) { - setSettings((old) => ({ ...old, theme: config.theme! })); - } + data.ui.hide_cot = config.showCot ? data.ui.hide_cot : true; + setSettings((old) => ({ + ...old, + theme: config.theme ? config.theme : old.theme, + hideCot: data.ui.hide_cot! + })); + const _theme = overrideTheme( makeTheme(config.theme || settings.theme, config.fontFamily, { - // Hack to provoke small responsivity + // Force mobile view values: { xs: 0, sm: 10000, diff --git a/libs/copilot/src/appWrapper.tsx b/libs/copilot/src/appWrapper.tsx index 016e4ba045..9e8828d71b 100644 --- a/libs/copilot/src/appWrapper.tsx +++ b/libs/copilot/src/appWrapper.tsx @@ -12,12 +12,14 @@ interface Props { } export default function AppWrapper({ config }: Props) { + const apiClient = makeApiClient(config.chainlitServer); + return ( diff --git a/libs/copilot/src/chat/index.tsx b/libs/copilot/src/chat/index.tsx index 847dd5b64c..bc7571244a 100644 --- a/libs/copilot/src/chat/index.tsx +++ b/libs/copilot/src/chat/index.tsx @@ -12,7 +12,7 @@ export default function ChatWrapper() { connect({ client: apiClient, userEnv: {}, - accessToken + accessToken: `Bearer ${accessToken}` }); }, [connect, accessToken, apiClient]); diff --git a/libs/copilot/src/chat/messages/container.tsx b/libs/copilot/src/chat/messages/container.tsx index 52ea726a14..0c2e620df3 100644 --- a/libs/copilot/src/chat/messages/container.tsx +++ b/libs/copilot/src/chat/messages/container.tsx @@ -8,6 +8,7 @@ import { sideViewState } from '@chainlit/app/src/state/project'; import { projectSettingsState } from '@chainlit/app/src/state/project'; +import { settingsState } from '@chainlit/app/src/state/settings'; import { IAction, IAsk, @@ -51,6 +52,7 @@ const MessageContainer = memo( }: Props) => { const { apiClient } = useContext(WidgetContext); const projectSettings = useRecoilValue(projectSettingsState); + const { hideCot } = useRecoilValue(settingsState); const setSideView = useSetRecoilState(sideViewState); const highlightedMessage = useRecoilValue(highlightMessage); const { uploadFile: _uploadFile } = useChatInteract(); @@ -94,7 +96,6 @@ const MessageContainer = memo( ); const onError = useCallback((error: string) => toast.error(error), [toast]); - // Memoize the context object since it's created on each render. // This prevents unnecessary re-renders of children components when no props have changed. const memoizedContext = useMemo(() => { @@ -106,7 +107,7 @@ const MessageContainer = memo( avatars, defaultCollapseContent: true, expandAll: false, - hideCot: true, + hideCot: hideCot, highlightedMessage, loading, showFeedbackButtons: enableFeedback, diff --git a/libs/copilot/src/types.ts b/libs/copilot/src/types.ts index 1d4e6ed018..75dc0816bd 100644 --- a/libs/copilot/src/types.ts +++ b/libs/copilot/src/types.ts @@ -1,6 +1,6 @@ export interface IWidgetConfig { chainlitServer: string; - show_cot?: boolean; + showCot?: boolean; accessToken?: string; theme?: 'light' | 'dark'; fontFamily?: string;