{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreie5htkgyy63emscnniygtp2b3i2eqxe4ijvcbhmfap2c2mdcn2ex4",
    "uri": "at://did:plc:pgryn3ephfd2xgft23qokfzt/app.bsky.feed.post/3mpdtg6erdyq2"
  },
  "path": "/t/creating-a-website-chat-widget-with-gradio-part-iv/177208#post_1",
  "publishedAt": "2026-06-28T10:16:50.000Z",
  "site": "https://discuss.huggingface.co",
  "tags": [
    "@John6666",
    "@gradio"
  ],
  "textContent": "A while back @John6666 help set up an AI gradio chatbot on my website. Everything was working fine, with the AI chatbot doing a great job.\n\nHowever, I’ve not been monitoring it, and sometime recently(?) it stopped working. The problem is on the client I get the error:\n\n> Access to fetch at [huggingfacespace] from origin [mywebsite] has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’.\n\nAfter looking around this seems to be related to a change to gradio where they fixed a security issue with CORS. However, the solution I found appeared to suggest the fix was to basically re-write the code to “get around” CORS rather than using it.\n\nIt that really the only solution?\n\nThis is the code that was working before the “fix” broke it:\n\n(website client code)\n\n\n    <script type=\"module\">\n        import { Client } from \"https://cdn.jsdelivr.net/npm/@gradio/client@/dist/index.min.js\";\n        import { marked } from \"https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js\";\n\n        async function initChatWidget() {\n            const client = await Client.connect(\"https://[myspace].hf.space/\");\n\n            const conversationId = crypto.randomUUID();                         // NEW FOR LOGGING\n            const chatToggle = document.getElementById('chat-toggle');\n            const chatContainer = document.getElementById('chat-container');\n            const closeChat = document.getElementById('close-chat');\n            const chatInput = document.getElementById('chat-input');\n            const sendButton = document.getElementById('send-message');\n            const messagesContainer = document.getElementById('chat-messages');\n\n            chatToggle.addEventListener('click', () => {\n                chatContainer.classList.remove('hidden');\n            });\n\n            closeChat.addEventListener('click', () => {\n                chatContainer.classList.add('hidden');\n            });\n\n            // Auto-open chat on contact page\n    if (window.location.pathname.includes('/contact') ||\n        window.location.pathname.endsWith('/contact.html') ||\n        window.location.pathname.includes('/account') ||\n        window.location.pathname.endsWith('/account.html')) {\n        chatContainer.classList.remove('hidden');\n    }\n\n            function appendMessage(text, sender) {\n                const div = document.createElement(\"div\");\n                div.className = `message ${sender}-message`;\n                div.textContent = text;  // or marked.parse(text) if you're using marked\n                messagesContainer.appendChild(div);\n                messagesContainer.scrollTop = messagesContainer.scrollHeight;\n            }\n\n            async function sendMessage() {\n                const userMessage = chatInput.value.trim();\n                if (!userMessage) return;\n\n                appendMessage(userMessage, 'user');\n                chatInput.value = '';\n\n                try {\n                    const result = await client.predict(\"/chat\", {\n                        message: {\"text\": userMessage, \"files\": []},\n                    conversation_id: conversationId,                        // NEW FOR LOGGING\n                    });\n\n          const lines = result.data[0];             // list of strings from Python\n          const botMessage = Array.isArray(lines) ? lines.join(\"\\n\") : String(lines);\n          appendMessage(botMessage, \"bot\");\n\n                } catch (error) {\n                    console.error('Error:', error);\n                    appendMessage('Sorry, there was an error processing your request.', 'bot');\n                }\n            }\n\n            sendButton.addEventListener('click', sendMessage);\n            chatInput.addEventListener('keypress', (e) => {\n                if (e.key === 'Enter') sendMessage();\n            });\n\n          // PRE-SEED: show a bot greeting as soon as the widget is ready\n          appendMessage(\"Hey there! What can I help you with today?\", \"bot\");\n          }\n\n          initChatWidget();\n    </script>\n\n\n(code on huggingface space)\n\n\n    import json\n    import requests # for API code\n    import holidays # details of UK holidays\n    from datetime import datetime, timedelta, date, time\n    from openai import OpenAI\n    import gradio as gr\n    import os\n    import uuid\n\n    say_hello = [\n        {\n            \"role\": \"assistant\",\n            \"content\": \"Hey there! What can I help you with today?\",\n        }\n    ]\n\n    # This is the main chat code called by Gradio ChatInterface on user input, sends input to AI, processes response, returns to the Gradio ChatInterface\n    def chat(message, history, conversation_id):\n        if not conversation_id:\n            conversation_id = str(uuid.uuid4())\n\n        if isinstance(message, dict): # make sure the user comment is in an acceptable format, and convert to a string\n            user_text = message.get(\"text\", \"\")\n        else:\n            user_text = str(message)\n        history = [{\"role\":h[\"role\"], \"content\":h[\"content\"]} for h in history] # clean history for some non openai models\n        messages = [{\"role\": \"system\", \"content\": system_message}] + history + [{\"role\": \"user\", \"content\": user_text}] # illusion of memory\n        response = openai.chat.completions.create(model=MODEL, messages=messages, tools=tools)\n\n        # AI STUFF HERE\n\n        response_as_a_list = [response.choices[0].message.content] # need to change reponse from string to a list of strings for the chatbot widget\n        return response_as_a_list\n\n    # Additional (hidden) input so ChatInterface exposes 'conversation_id'\n    conversation_id_input = gr.Textbox(\n        label=\"conversation_id\",\n        visible=False,\n        value=\"\",\n    )\n\n    # Use the Gradio Chatbot component to preload the chat (and history) with an initial greeting, rather than letting the user go first\n    chatbot = gr.Chatbot(\n        value=say_hello,\n        type=\"messages\",\n    )\n\n    # The main chat interface handled by Gradio\n    my_chat = gr.ChatInterface(\n        fn=chat,\n        type=\"messages\",\n        multimodal=True,\n        title=\"Widget Demo Bot\",\n        api_name=\"chat\",\n        additional_inputs=[conversation_id_input],  # extra arg to fn\n    )\n\n    if __name__ == \"__main__\":\n        my_chat.launch(ssr_mode=False)\n\n",
  "title": "Creating a Website Chat Widget with Gradio Part IV"
}