55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
66 < title > AGO Chatbot</ title >
77 < script src ="https://cdn.jsdelivr.net/npm/chart.js "> </ script >
8+ < script src ="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js "> </ script >
89 < style >
910 : root {
1011 --primary-color : # 2E7D32 ;
1112 --secondary-color : # 81C784 ;
12- --background : # F1F8E9 ;
13+ --background : # F5F5F5 ;
1314 }
1415
1516 body {
1617 font-family : 'Segoe UI' , sans-serif;
1718 margin : 0 ;
1819 padding : 20px ;
19- background-color : var (--background );
20+ background : var (--background );
2021 }
2122
22- .chat- container {
23- max-width : 800 px ;
23+ .container {
24+ max-width : 1200 px ;
2425 margin : 0 auto;
26+ display : grid;
27+ grid-template-columns : 300px 1fr ;
28+ gap : 20px ;
29+ }
30+
31+ .chat-container {
2532 background : white;
2633 border-radius : 10px ;
2734 box-shadow : 0 2px 10px rgba (0 , 0 , 0 , 0.1 );
28- }
29-
30- .chat-header {
31- background : var (--primary-color );
32- color : white;
3335 padding : 20px ;
34- border-radius : 10px 10px 0 0 ;
36+ height : 80vh ;
37+ display : flex;
38+ flex-direction : column;
3539 }
3640
3741 .chat-messages {
38- height : 500 px ;
42+ flex : 1 ;
3943 overflow-y : auto;
40- padding : 20px ;
44+ padding : 10px ;
45+ border-bottom : 1px solid # eee ;
4146 }
4247
4348 .message {
4449 margin : 10px 0 ;
45- padding : 15 px ;
46- border-radius : 8 px ;
47- max-width : 70 % ;
50+ padding : 12 px ;
51+ border-radius : 15 px ;
52+ max-width : 80 % ;
4853 }
4954
5055 .user-message {
5156 background : var (--secondary-color );
5257 margin-left : auto;
5358 }
5459
55- .system-message {
56- background : # E8F5E9 ;
57- margin-right : auto;
58- }
59-
60- .file-input-container {
61- display : flex;
62- align-items : center;
63- gap : 10px ;
64- padding : 20px ;
65- border-top : 1px solid # ddd ;
60+ .bot-message {
61+ background : var (--primary-color );
62+ color : white;
6663 }
6764
68- .input-container {
65+ .input-section {
6966 padding : 20px ;
70- border-top : 1px solid # ddd ;
7167 display : flex;
7268 gap : 10px ;
7369 }
7470
75- .chat-input {
76- flex : 1 ;
77- padding : 12px ;
78- border : 1px solid # ddd ;
79- border-radius : 5px ;
80- font-size : 16px ;
81- }
82-
83- .send-button {
84- padding : 12px 24px ;
71+ button {
8572 background : var (--primary-color );
8673 color : white;
8774 border : none;
75+ padding : 10px 20px ;
8876 border-radius : 5px ;
8977 cursor : pointer;
90- transition : background 0.3s ;
9178 }
9279
93- .send-button : hover {
94- background : # 1B5E20 ;
80+ .visualization {
81+ background : white;
82+ padding : 20px ;
83+ border-radius : 10px ;
84+ box-shadow : 0 2px 10px rgba (0 , 0 , 0 , 0.1 );
9585 }
9686
97- .thinking-indicator {
98- display : flex;
99- align-items : center;
100- gap : 8px ;
101- color : # 666 ;
102- font-style : italic;
87+ .menu {
88+ background : white;
89+ padding : 20px ;
90+ border-radius : 10px ;
91+ box-shadow : 0 2px 10px rgba (0 , 0 , 0 , 0.1 );
10392 }
10493
105- .dot-flashing {
106- display : inline-block;
107- width : 8px ;
108- height : 8px ;
109- border-radius : 50% ;
110- background-color : # 2E7D32 ;
111- animation : dotFlashing 1s infinite linear;
94+ .menu-item {
95+ padding : 15px ;
96+ margin : 10px 0 ;
97+ background : var (--background );
98+ border-radius : 5px ;
99+ cursor : pointer;
112100 }
113101
114- @keyframes dotFlashing {
115- 0% { opacity : 0.2 ; }
116- 50% { opacity : 1 ; }
117- 100% { opacity : 0.2 ; }
102+ .file-input {
103+ margin : 10px 0 ;
118104 }
119105 </ style >
120106</ head >
121107< body >
122- < div class ="chat-container ">
123- < div class ="chat-header ">
124- < h2 > AGO chatbot</ h2 >
125- < p > Ask questions about energy efficiency and carbon footprint analysis</ p >
108+ < div class ="container ">
109+ < div class ="menu ">
110+ < div class ="menu-item " onclick ="showSection('goal') "> 🏁 Set Sustainability Goal</ div >
111+ < div class ="menu-item " onclick ="showSection('bill') "> 📊 Process Energy Bill</ div >
112+ < div class ="menu-item " onclick ="showSection('recommendations') "> 💡 View Recommendations</ div >
113+ < input type ="file " id ="fileInput " class ="file-input " hidden >
126114 </ div >
127-
128- < div class ="chat-messages " id ="chatMessages "> </ div >
129-
130- < div class ="input-container ">
131- < input type ="text "
132- class ="chat-input "
133- id ="userInput "
134- placeholder ="Type your sustainability question... ">
135- < button class ="send-button " onclick ="handleUserInput() "> Send</ button >
136- </ div >
137- </ div >
138-
139- < script type ="module ">
140- import { AzureOpenAI } from "openai" ;
141- import dotenv from "dotenv" ;
142115
143- dotenv . config ( ) ;
144-
145- // Azure OpenAI Configuration
146- const endpoint = process . env [ "https://ago.openai.azure.com/" ] || "https://ago.openai.azure.com/" ;
147- const apiKey = process . env [ "895wldthT3YtWIfqrJVloEuSW5C3mA7Q14qq00iEpNvJYDfsfTeTJQQJ99BDACHYHv6XJ3w3AAABACOGT1IT" ] || "<REPLACE_YOUR_API_KEY>" ;
148- const apiVersion = "2024-05-01-preview" ;
149- const deployment = "gpt-4o" ;
150-
151- const client = new AzureOpenAI ( { endpoint, apiKey, apiVersion, deployment } ) ;
116+ < div class ="chat-container ">
117+ < div class ="chat-messages " id ="chatMessages "> </ div >
118+ < div class ="input-section ">
119+ < input type ="text " id ="userInput " placeholder ="Type your question... ">
120+ < button onclick ="sendMessage() "> Send</ button >
121+ </ div >
122+ </ div >
152123
153- // Function to handle user input
154- async function handleUserInput ( ) {
155- const inputField = document . getElementById ( 'userInput' ) ;
156- const question = inputField . value . trim ( ) ;
124+ < div class ="visualization ">
125+ < canvas id ="co2Chart "> </ canvas >
126+ < div id ="recommendations "> </ div >
127+ </ div >
128+ </ div >
157129
158- if ( ! question ) return ;
130+ < script >
131+ const API_CONFIG = {
132+ endpoint : "https://ago.openai.azure.com" ,
133+ deployment : "gpt-4o" ,
134+ apiVersion : "2024-12-01-preview" ,
135+ subscriptionKey : "895wldthT3YtWIfqrJVloEuSW5C3mA7Q14qq00iEpNvJYDfsfTeTJQQJ99BDACHYHv6XJ3w3AAABACOGT1IT"
136+ } ;
159137
160- // Clear input and add user message
161- inputField . value = '' ;
162- addMessage ( question , true ) ;
138+ let currentScope = null ;
139+ let billAnalysis = null ;
140+ let chartInstance = null ;
163141
164- // Add thinking indicator
165- const thinkingId = addThinkingIndicator ( ) ;
142+ function appendMessage ( content , isUser = false ) {
143+ const messagesDiv = document . getElementById ( 'chatMessages' ) ;
144+ const message = document . createElement ( 'div' ) ;
145+ message . className = `message ${ isUser ? 'user-message' : 'bot-message' } ` ;
146+ message . innerHTML = content ;
147+ messagesDiv . appendChild ( message ) ;
148+ messagesDiv . scrollTop = messagesDiv . scrollHeight ;
149+ }
166150
151+ async function generateResponse ( prompt ) {
167152 try {
168- // Fetch AI response
169- const result = await client . chat . completions . create ( {
170- messages : [
171- { role : "system" , content : "You are an expert assistant specializing in sustainability and energy efficiency." } ,
172- { role : "user" , content : question }
173- ] ,
174- max_tokens : 800 ,
175- temperature : 0.7 ,
176- top_p : 0.95 ,
177- frequency_penalty : 0 ,
178- presence_penalty : 0
179- } ) ;
180-
181- // Remove thinking indicator and display response
182- removeThinkingIndicator ( thinkingId ) ;
183- addMessage ( result . choices [ 0 ] . message . content ) ;
153+ const response = await axios . post (
154+ `${ API_CONFIG . endpoint } /openai/deployments/${ API_CONFIG . deployment } /chat/completions?api-version=${ API_CONFIG . apiVersion } ` ,
155+ {
156+ messages : [
157+ { role : "system" , content : SYSTEM_PROMPT } ,
158+ { role : "user" , content : prompt }
159+ ] ,
160+ temperature : 1.0 ,
161+ top_p : 1.0 ,
162+ max_tokens : 4096
163+ } ,
164+ {
165+ headers : {
166+ 'Content-Type' : 'application/json' ,
167+ 'api-key' : API_CONFIG . subscriptionKey
168+ }
169+ }
170+ ) ;
171+ return response . data . choices [ 0 ] . message . content . trim ( ) ;
184172 } catch ( error ) {
185- console . error ( "API Error:" , error ) ;
186- removeThinkingIndicator ( thinkingId ) ;
187- addMessage ( "Failed to get a response. Please try again." ) ;
173+ return error . response ?. data ?. error ?. message . includes ( 'content filter' )
174+ ? CONTENT_FILTER_MESSAGE
175+ : `API Error: ${ error . message } ` ;
188176 }
189177 }
190178
191- // Function to add a message to the chat
192- function addMessage ( content , isUser = false ) {
193- const messageDiv = document . createElement ( 'div' ) ;
194- messageDiv . className = `message ${ isUser ? "user-message" : "system-message" } ` ;
195- messageDiv . textContent = content ;
196-
197- const chatMessages = document . getElementById ( 'chatMessages' ) ;
198- chatMessages . appendChild ( messageDiv ) ;
199- chatMessages . scrollTop = chatMessages . scrollHeight ;
200- }
201-
202- // Function to add a thinking indicator
203- function addThinkingIndicator ( ) {
204- const thinkingId = Date . now ( ) ;
205- const thinkingDiv = document . createElement ( 'div' ) ;
206- thinkingDiv . className = 'message system-message thinking-indicator' ;
207- thinkingDiv . id = `thinking-${ thinkingId } ` ;
208- thinkingDiv . innerHTML = `
209- <div class="dot-flashing"></div>
210- Thinking...
211- ` ;
212-
213- const chatMessages = document . getElementById ( 'chatMessages' ) ;
214- chatMessages . appendChild ( thinkingDiv ) ;
215- chatMessages . scrollTop = chatMessages . scrollHeight ;
216-
217- return thinkingId ;
179+ async function handleSustainabilityGoal ( ) {
180+ const scope = await selectScope ( ) ;
181+ const prompt = `As a sustainability consultant, explain ${ scope } implementation...` ;
182+ const response = await generateResponse ( prompt ) ;
183+ appendMessage ( formatResponse ( response ) ) ;
184+ updateChart ( [ 30 , 40 , 30 ] ) ; // Example chart data
185+ }
186+
187+ function updateChart ( data ) {
188+ const ctx = document . getElementById ( 'co2Chart' ) . getContext ( '2d' ) ;
189+ if ( chartInstance ) chartInstance . destroy ( ) ;
190+
191+ chartInstance = new Chart ( ctx , {
192+ type : 'bar' ,
193+ data : {
194+ labels : [ 'Scope 1' , 'Scope 2' , 'Scope 3' ] ,
195+ datasets : [ {
196+ label : 'CO2 Emissions (tons)' ,
197+ data : data ,
198+ backgroundColor : [ '#2E7D32' , '#81C784' , '#C8E6C9' ]
199+ } ]
200+ }
201+ } ) ;
202+ }
203+
204+ function formatResponse ( text ) {
205+ // Add formatting for math equations and markdown
206+ return text . replace ( / \$ \$ ( .* ?) \$ \$ / g, '<div class="math">$1</div>' )
207+ . replace ( / # { 3 } / g, '<h3>' )
208+ . replace ( / # { 2 } / g, '<h2>' ) ;
209+ }
210+
211+ async function handleFileUpload ( file ) {
212+ const reader = new FileReader ( ) ;
213+ reader . onload = async ( e ) => {
214+ const kwh = parseFloat ( e . target . result ) ;
215+ const analysis = await generateAnalysis ( kwh ) ;
216+ appendMessage ( analysis ) ;
217+ } ;
218+ reader . readAsText ( file ) ;
219+ }
220+
221+ document . getElementById ( 'fileInput' ) . addEventListener ( 'change' , ( e ) => {
222+ handleFileUpload ( e . target . files [ 0 ] ) ;
223+ } ) ;
224+
225+ function showSection ( section ) {
226+ if ( section === 'bill' ) {
227+ document . getElementById ( 'fileInput' ) . click ( ) ;
228+ }
218229 }
219230
220- // Function to remove a thinking indicator
221- function removeThinkingIndicator ( id ) {
222- const element = document . getElementById ( `thinking- ${ id } ` ) ;
223- if ( element ) element . remove ( ) ;
224- }
231+ // Initialization
232+ const SYSTEM_PROMPT = `You are a sustainability expert...` ;
233+ const CONTENT_FILTER_MESSAGE = "Response blocked..." ;
234+
235+ appendMessage ( "Welcome to Carbon Footprint Analysis! How can I help you today?" , false ) ;
225236 </ script >
226237</ body >
227238</ html >
0 commit comments