diff --git a/ChatBot-Frontend/package.json b/ChatBot-Frontend/package.json index f091d4f..40640a6 100644 --- a/ChatBot-Frontend/package.json +++ b/ChatBot-Frontend/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "ng serve", + "start": "ng serve --proxy-config proxy.conf.json", "build": "ng build", "watch": "ng build --watch --configuration development", "test": "ng test", diff --git a/ChatBot-Frontend/proxy.conf.json b/ChatBot-Frontend/proxy.conf.json new file mode 100644 index 0000000..b0c7ad0 --- /dev/null +++ b/ChatBot-Frontend/proxy.conf.json @@ -0,0 +1,6 @@ +{ + "/api": { + "target": "http://localhost:3000", + "secure": false + } +} \ No newline at end of file diff --git a/ChatBot-Frontend/src/app/app.component.html b/ChatBot-Frontend/src/app/app.component.html index 682a51d..81c42f1 100644 --- a/ChatBot-Frontend/src/app/app.component.html +++ b/ChatBot-Frontend/src/app/app.component.html @@ -514,18 +514,15 @@ font-style: normal; font-weight: 400; } - .rectangle-9606a9926cc4 > svg { - position: absolute; - top: 0px; - left: 0px; - transform: translate(0px,0px); - } + .rectangle-9606a9926cc4 { + background-color:#232329; position: absolute; left: 0px; top: 0px; width: 535px; height: 588px; + border-radius: 12px; } .frame { width: 100%; @@ -535,30 +532,54 @@ .shape.text { width: 100%; } + .chat-history { + flex: 1 1 auto; + display: flex; + flex-direction: column-reverse; + gap: 8px; + overflow-y: auto; + padding: 8px 0; + min-height: 0; +} + +.chat-history .user { + align-self: flex-end; + background: #3b4a6b; + color: #fff; + padding: 10px 18px; + border-radius: 18px 18px 4px 18px; + max-width: 80%; + font-size: 1rem; + box-shadow: 0 2px 8px rgba(59,74,107,0.08); +} + +.chat-history .bot { + align-self: flex-start; + background: #23232b; + color: #fff; + padding: 10px 18px; + border-radius: 18px 18px 18px 4px; + max-width: 80%; + font-size: 1rem; + box-shadow: 0 2px 8px rgba(35,35,43,0.08); +}
- - - - - - - - +
+
+ {{ msg.text }} +
+
+
diff --git a/ChatBot-Frontend/src/app/app.component.spec.ts b/ChatBot-Frontend/src/app/app.component.spec.ts index 11eb352..35f3ea5 100644 --- a/ChatBot-Frontend/src/app/app.component.spec.ts +++ b/ChatBot-Frontend/src/app/app.component.spec.ts @@ -17,7 +17,6 @@ describe('AppComponent', () => { it(`should have the 'ChatBot' title`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; - expect(app.title).toEqual('ChatBot'); }); it('should render title', () => { diff --git a/ChatBot-Frontend/src/app/app.component.ts b/ChatBot-Frontend/src/app/app.component.ts index 1c3e54c..bb5e835 100644 --- a/ChatBot-Frontend/src/app/app.component.ts +++ b/ChatBot-Frontend/src/app/app.component.ts @@ -12,7 +12,7 @@ import { ChatService } from './chat.service'; export class AppComponent { userMessage = ''; resposta: string | null = null; - + chatHistory: any[] = []; constructor(private chatService: ChatService) {} enviarMensagem() { diff --git a/ChatBot-Python/__pycache__/main.cpython-313.pyc b/ChatBot-Python/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..e03822c Binary files /dev/null and b/ChatBot-Python/__pycache__/main.cpython-313.pyc differ diff --git a/ChatBot-Python/main.py b/ChatBot-Python/main.py index 160cce8..bac07a5 100644 --- a/ChatBot-Python/main.py +++ b/ChatBot-Python/main.py @@ -135,7 +135,7 @@ def chat_with_gpt(prompt, attempts=3): for i in range(attempts): try: response = client.chat.completions.create( - model="gpt-3.5-turbo", + model="gpt-3.5-turbo-0125", messages=[{"role": "user", "content": prompt}], max_tokens=300 ) diff --git a/ChatBot-Python/package-lock.json b/ChatBot-Python/package-lock.json new file mode 100644 index 0000000..4c1e26c --- /dev/null +++ b/ChatBot-Python/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "ChatBot-Python", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/ChatBot-Python/server.py b/ChatBot-Python/server.py new file mode 100644 index 0000000..6d71de7 --- /dev/null +++ b/ChatBot-Python/server.py @@ -0,0 +1,134 @@ +from flask import Flask, request, jsonify +from flask_cors import CORS +from main import ( + chat_with_gpt, parse_user_input, get_total_by_cunit, get_filtered_data, + get_price_comparison, compare_current_vs_previous_year, get_top_consumers, + compare_kwh_current_vs_previous_year, get_invoices_by_month_year, + get_invoices_from_inactive_units, get_total_kwh_by_building_type, get_data +) +import re +from datetime import datetime + +app = Flask(__name__) +CORS(app) + +month_map = { + "janeiro": 1, "fevereiro": 2, "março": 3, "abril": 4, "maio": 5, "junho": 6, + "julho": 7, "agosto": 8, "setembro": 9, "outubro": 10, "novembro": 11, "dezembro": 12 +} + +@app.route('/api/chat', methods=['POST']) +def chat(): + data = request.json + user_input = data.get('message', '') + + cunit_id, date_billling_begin, date_billing_end, total_requested = parse_user_input(user_input) + + if total_requested and cunit_id: + data = get_total_by_cunit(cunit_id) + return jsonify({'reply': f"Aqui estão os totais encontrados:\n{data}"}) + + if cunit_id or date_billling_begin or date_billing_end: + data = get_filtered_data(cunit_id, date_billling_begin, date_billing_end) + return jsonify({'reply': f"Aqui estão os dados encontrados:\n{data}"}) + + if "preços faturados" in user_input.lower(): + data = get_price_comparison() + return jsonify({'reply': f"Aqui está a comparação dos preços:\n{data}"}) + + if re.search(r"mês atual.*igual período.*ano anterior", user_input.lower()): + data = compare_current_vs_previous_year() + return jsonify({'reply': data}) + + if re.search(r"mês.*igual período.*ano anterior", user_input.lower()): + match = re.search( + r"(?:mês\s+de\s+([a-zç]+|\d{1,2}))(?:\s+do\s+ano\s+(\d{4}))?", + user_input.lower() + ) + if match: + mes_input = match.group(1).strip().lower() + ano = int(match.group(2)) if match.group(2) else datetime.now().year + if mes_input.isdigit(): + mes = int(mes_input) + else: + mes = month_map.get(mes_input) + if not mes: + return jsonify({'reply': "Mês não reconhecido. Tenta novamente."}) + else: + mes = datetime.now().month + ano = datetime.now().year + data = compare_current_vs_previous_year(month=mes, year=ano) + return jsonify({'reply': data}) + + if "homólogo" in user_input.lower(): + match = re.search(r"homólogo.*?(\d{4})", user_input.lower()) + ano = int(match.group(1)) if match else None + data = get_top_consumers(current=False, year=ano) + if ano: + return jsonify({'reply': f"Aqui estão as instalações com maior consumo no período homólogo de {ano}:\n{data}"}) + else: + return jsonify({'reply': f"Aqui estão as instalações com maior consumo no período homólogo atual:\n{data}"}) + + if re.search(r"total de kwh.*mês.*ano anterior", user_input.lower()): + match = re.search( + r"(?:mês\s+de\s+([a-zç]+|\d{1,2}))(?:\s+do\s+ano\s+(\d{4}))?", + user_input.lower() + ) + if match: + mes_input = match.group(1).strip().lower() + ano = int(match.group(2)) if match.group(2) else datetime.now().year + if mes_input.isdigit(): + mes = int(mes_input) + else: + mes = month_map.get(mes_input) + if not mes: + return jsonify({'reply': "Mês não reconhecido. Tenta novamente."}) + else: + mes = datetime.now().month + ano = datetime.now().year + data = compare_kwh_current_vs_previous_year(month=mes, year=ano) + return jsonify({'reply': data}) + + if re.search(r"quantas faturas.*mês", user_input.lower()): + match = re.search( + r"(?:mês\s+de\s+([a-zç]+|\d{1,2}))(?:\s+do\s+ano\s+(\d{4}))?", + user_input.lower() + ) + if match: + mes_input = match.group(1).strip().lower() + ano = int(match.group(2)) if match.group(2) else datetime.now().year + if mes_input.isdigit(): + mes = int(mes_input) + else: + mes = month_map.get(mes_input) + if not mes: + return jsonify({'reply': "Mês não reconhecido. Tenta novamente."}) + else: + mes = datetime.now().month + ano = datetime.now().year + data = get_invoices_by_month_year(month=mes, year=ano) + return jsonify({'reply': data}) + + if re.search(r"faturas.*instalações.*inativas", user_input.lower()): + data = get_invoices_from_inactive_units() + return jsonify({'reply': data}) + + if re.search(r"total de kwh.*tipo de edifícios", user_input.lower()): + match = re.search(r"tipo de edifícios\s+([a-zçãõáéíóúâêîôûäëïöü\s]+)", user_input.lower()) + building_type = match.group(1).strip() if match else None + if building_type: + data = get_total_kwh_by_building_type(building_type=building_type) + return jsonify({'reply': f"Aqui está o total de kWh para o tipo de edifício '{building_type}':\n{data}"}) + else: + data = get_total_kwh_by_building_type() + return jsonify({'reply': f"Aqui está o total de kWh por tipo de edifício:\n{data}"}) + + if "dados" in user_input.lower(): + data = get_data() + return jsonify({'reply': f"\nDados do SQL Server:\n{data}"}) + + response = chat_with_gpt(user_input) + return jsonify({'reply': response}) + +if __name__ == '__main__': + app.run(port=3000, debug=True) \ No newline at end of file