/** * Welcome to your first AI Worker! * This version has been updated to use the modern, recommended streaming approach. * This provides a faster, more responsive experience for the end-user. */ // --- CORS Configuration --- // A reusable object for the core CORS headers. const corsHeaders = { 'Access-Control-Allow-Origin': '*', // Allow any origin to access this worker 'Access-Control-Allow-Methods': 'POST, OPTIONS', // Only allow POST and OPTIONS requests 'Access-Control-Max-Age': '86400', // Cache preflight response for 24 hours }; /** * Handles the browser's preflight OPTIONS request. * The browser sends this automatically before the actual POST request to check permissions. * @param {Request} request The incoming request. * @returns {Response} */ function handleOptions(request) { // Get the headers the browser is asking for permission to use const requestHeaders = request.headers.get('Access-Control-Request-Headers'); // Create a new set of headers for our response, starting with the base CORS headers let responseHeaders = { ...corsHeaders, }; // If the browser specified headers, we dynamically allow them. // This is a robust way to handle CORS. if (requestHeaders) { responseHeaders['Access-Control-Allow-Headers'] = requestHeaders; } // Return a response with a 204 status code (No Content) and the calculated headers. return new Response(null, { status: 204, headers: responseHeaders, }); } // This is the main entry point for your Worker. export default { async fetch(request, env, ctx) { // --- 1. Handle CORS Preflight Request --- // If the request method is OPTIONS, it's a preflight request. // We handle it and return immediately. if (request.method === 'OPTIONS') { return handleOptions(request); } // --- 2. Validate Request Method --- // We only want to process POST requests for the main logic. if (request.method !== 'POST') { const response = new Response('Please send a POST request.', { status: 405 }); // Add CORS headers to the error response Object.entries(corsHeaders).forEach(([key, value]) => { response.headers.set(key, value); }); return response; } try { // --- 3. Get User Prompt --- const { prompt } = await request.json(); if (!prompt) { const response = new Response('Please provide a "prompt" in your request body.', { status: 400 }); Object.entries(corsHeaders).forEach(([key, value]) => { response.headers.set(key, value); }); return response; } // --- 4. Define System Prompt & RAG Context --- const system_prompt = ` You are an expert AI assistant for the property restoration industry. Your personality is professional, concise, and helpful. You MUST follow these rules: 1. You are strictly forbidden from giving any legal or financial advice. 2. If a user asks a question that contains words like "sue," "legal," "profitable," "investment," or asks for financial recommendations, you MUST respond ONLY with: "I cannot provide legal or financial advice. Please consult a qualified professional." Do not provide any other information. 3. You must base your answers on the "Context" provided. If the context does not contain the answer, you must say "I do not have enough information to answer that question." 4. Keep your answers clear and focused on practical steps and industry standards. `; const queryVector = await env.AI.run('@cf/baai/bge-base-en-v1.5', { text: [prompt] }); const searchResults = await env.KNOWLEDGE_BASE.query(queryVector.data[0], { topK: 3 }); const context = searchResults.matches.map(match => match.metadata.text).join('\n---\n'); const finalPrompt = ` Context: ${context} --- Question: ${prompt} `; const messages = [ { role: 'system', content: system_prompt }, { role: 'user', content: finalPrompt } ]; // --- 5. Execute AI Model with Streaming --- // This is the key change. We set `stream: true`. // `env.AI.run` now returns a ReadableStream, not a complete response object. const stream = await env.AI.run( '@cf/meta/llama-3.1-8b-instruct', { messages, stream: true } ); // --- 6. Return the Stream --- // We create a new Response object, passing the stream directly as the body. // The browser will handle reading from this stream as data arrives. const response = new Response(stream, { headers: { // This Content-Type is crucial for the browser to understand it's a stream. 'Content-Type': 'text/event-stream', // Add the essential CORS origin header. 'Access-Control-Allow-Origin': '*', }, }); return response; } catch (e) { // --- 7. Handle Errors --- // Ensure even error responses have the correct CORS headers. const errorResponse = new Response(e.message || 'An unexpected error occurred.', { status: 500 }); Object.entries(corsHeaders).forEach(([key, value]) => { errorResponse.headers.set(key, value); }); return errorResponse; } }, };