Chainlit / chainlit

Build Conversational AI in minutes ⚡️
https://docs.chainlit.io
Apache License 2.0
6.1k stars 777 forks source link

Make browser query parameters available in `@on_chat_start` #144

Open kevinwmerritt opened 1 year ago

kevinwmerritt commented 1 year ago

Feature request for query params to be made available in the on_chat_start decorator. From there you could add them to user session or take another action.

@on_chat_start
async def main(query_params):
    document_url = query_params.get('document_url')
    if document_url:
        ....

Imagine an application that lists multiple documents and you want to design a chainlit that can Q&A one of those documents.

Possible workflow today:

  1. The user downloads the document from the application.
  2. In a separate browser tab they open the chainlit.
  3. In the chainlit they upload the file with a AskFileMessage dialog.
  4. Process the file and chat.

Possible workflow enabled by query params:

  1. User clicks a [Chat] button next the document they want to Q&A and a new browser tab opens to mychainlit.xyz?document_url=/my/doc.pdf
  2. The chainlit begins processing the file referenced in the document.

Additional scenarios could include:

andreasmartin commented 7 months ago

I would very much like to support @kevinwmerritt's idea—I think it's a feature with a big impact.

willydouhard commented 7 months ago

Noted! Will try to ship that in the 1.0.0 release

laurentiupiciu commented 5 months ago

@willydouhard do you have any updates on this matter? thanks a lot

willydouhard commented 5 months ago

Did not have the time to add it yet. I am unsure about the behaviour though. Let's say you connect to http://localhost:8000?params={...}. In this case the json would probably encoded in b64 but that's not the point.

So we send that to the socket connection headers. Now let's say I navigate in the app a few times and create a new session. Is it expected that the params are sent again? In that case that means we should store them in the local storage or something. Also what happens if I refresh the page without the ?params?

laurentiupiciu commented 5 months ago

from my perspective it should be something like in streamlit: https://docs.streamlit.io/library/api-reference/utilities/st.experimental_get_query_params

what's your opinion on this?

willydouhard commented 5 months ago

I think it works well with Streamlit since you have more freedom and control over the app. In Chainlit these url parameters will disappear as the user uses the app.

To be clear I think this is a good feature but I don't have the right design atm.

bachi76 commented 5 months ago

@willydouhard just give either the request object or at least the GET/POST/Headers as optional param to the@cl.on_chat_start method. I guess that involves forwarding the data from python to react when loading the page, and then back react to python for the handlers..

Alternatively or additionally, do the same here:

@app.post("/auth/header")
async def header_auth(request: Request):
    if not config.code.header_auth_callback:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="No header_auth_callback defined",
        )

    app_user = await config.code.header_auth_callback(request.headers, add the request here)
    ...

PS: I just tried to use cookies, but of course, with an <iframe> and Apple, that's not working at all... A bit at a loss now..

Update: We now pass the needed GET param as a header to chainlit, which involves a) overriding the /login route to inject a JS into the frontend, which in turn overrides the JS fetch() method to add the needed header with our parameter. And then we get it finally where we need it to create the users, in our header_auth_callback().

If anyone needs more details, let me know. Of course we hope for a native clean solution - but at least we managed to not do a vendor code hack here.

nmstoker commented 3 months ago

This kind of feature would be super useful for creating links with pre-populated chats, which is somewhat similar to the document Id scenario above

For instance in an app you could embed links where the user clicks them and it launches your bot with the user's input entered ready for them to submit (or to add to if they need something extra in their input). This takes some friction out of the interaction. In some cases you could imagine dynamically creating the link parameters too (eg in Excel you could have a list of company names and each row gets a custom link to ask for more about that particular company using Excel's HYPERLINK function to build the link).

I was able to get close to this with a few hacky lines of custom js to write a parameter value into the user input box but I haven't the React experience to have that feed into the message properly (so the input box quickly gets overwritten with blank text unless the user specifically types something in the input box immediately, which isn't a good user experience).

comediansd commented 3 months ago

I need this feature

AlaaSenjab commented 3 months ago

Update: We now pass the needed GET param as a header to chainlit, which involves a) overriding the /login route to inject a JS into the frontend, which in turn overrides the JS fetch() method to add the needed header with our parameter. And then we get it finally where we need it to create the users, in our header_auth_callback().

If anyone needs more details, let me know. Of course we hope for a native clean solution - but at least we managed to not do a vendor code hack here.

@bachi76 Please share:)

andreasmartin commented 2 months ago

I have found a solution that might work for others as well.

Let's assume we have the following URL with query parameter: https://xyz.ch/?agent_id=myAgentId

First, I define a custom_js with the following content:

window.addEventListener("chainlit-call-fn", (e) => {
  const { name, args, callback } = e.detail;
  if (name === "url_query_parameter") {
    callback((new URLSearchParams(window.location.search)).get(args.msg));
  }
});

And then I can use this CopilotFunction in Chainlit as follows, for example:

@cl.on_chat_start
async def main():
    agent_id = await cl.CopilotFunction(name="url_query_parameter", args={"msg": "agent_id"}).acall()
willydouhard commented 2 months ago

Would love to add this in the docs examples or advanced concepts. Do you have time for this @andreasmartin ?

comediansd commented 3 days ago

This is broken since Chainlit 1.1.300. Can anyone help me out with fastapi code that "send" the url parameter to the chainlit module?