Spaces:
Running
Running
Upload 9 files
Browse files- agents/__init__.py +0 -0
- agents/frameworks.py +27 -0
- agents/greenwash_utils.py +73 -0
- agents/module1_template.py +98 -0
- agents/module2_planner.py +130 -0
- agents/module3_report.py +99 -0
- agents/module4_compliance.py +137 -0
- agents/module5_score.py +106 -0
- agents/module6_greenwash.py +85 -0
agents/__init__.py
ADDED
|
File without changes
|
agents/frameworks.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
TEMPLATE_FRAMEWORKS = {
|
| 2 |
+
"GRI": "GRI Standards template: [Include here detailed GRI ESG report template structure...]",
|
| 3 |
+
"TCFD": "Task Force on Climate-related Financial Disclosures (TCFD) template: [...]",
|
| 4 |
+
"TNFD": "Taskforce on Nature-related Financial Disclosures (TNFD) template: [...]",
|
| 5 |
+
"CDP": "Carbon Disclosure Project (CDP) template: [...]",
|
| 6 |
+
"SASB": "Sustainability Accounting Standards Board (SASB) template: [...]",
|
| 7 |
+
"CSRD": "Corporate Sustainability Reporting Directive (CSRD) template: [...]",
|
| 8 |
+
"CSDDD": "Corporate Sustainability Due Diligence Directive (CSDDD) template: [...]",
|
| 9 |
+
"IFRS": "International Financial Reporting Standards (IFRS) ESG template: [...]",
|
| 10 |
+
"Gold Standard": "Gold Standard for carbon projects template: [...]",
|
| 11 |
+
"CBAM": "Carbon Border Adjustment Mechanism (CBAM) reporting template: [...]",
|
| 12 |
+
"GHG Protocol": "GHG Protocol reporting template: [...]",
|
| 13 |
+
"SBTi": "Science Based Targets initiative (SBTi) reporting template: [...]",
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
FRAMEWORKS = {
|
| 17 |
+
"GRI": [
|
| 18 |
+
"Disclose total energy consumption.",
|
| 19 |
+
"Report on greenhouse gas emissions (Scope 1 & 2).",
|
| 20 |
+
"Describe water consumption and conservation measures.",
|
| 21 |
+
"Provide information on workforce diversity.",
|
| 22 |
+
"Describe anti-corruption policies and actions."
|
| 23 |
+
],
|
| 24 |
+
# ... other frameworks as before ...
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
|
agents/greenwash_utils.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fitz # PyMuPDF for PDF extraction
|
| 2 |
+
import docx # python-docx for DOCX extraction
|
| 3 |
+
import requests
|
| 4 |
+
import json
|
| 5 |
+
import streamlit as st
|
| 6 |
+
|
| 7 |
+
def extract_text(uploaded_file):
|
| 8 |
+
"""Extracts text from an uploaded file (PDF or DOCX)."""
|
| 9 |
+
try:
|
| 10 |
+
if uploaded_file.type == "application/pdf":
|
| 11 |
+
with fitz.open(stream=uploaded_file.read(), filetype="pdf") as doc:
|
| 12 |
+
return "\n".join(page.get_text() for page in doc)
|
| 13 |
+
elif uploaded_file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
| 14 |
+
doc = docx.Document(uploaded_file)
|
| 15 |
+
return "\n".join(para.text for para in doc.paragraphs)
|
| 16 |
+
else:
|
| 17 |
+
return "Error: Unsupported file type."
|
| 18 |
+
except Exception as e:
|
| 19 |
+
return f"Error processing file: {e}"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def chunk_text(text, chunk_size=4000, overlap=200):
|
| 23 |
+
"""Splits text into overlapping chunks."""
|
| 24 |
+
if not isinstance(text, str):
|
| 25 |
+
return []
|
| 26 |
+
chunks = []
|
| 27 |
+
start = 0
|
| 28 |
+
while start < len(text):
|
| 29 |
+
end = start + chunk_size
|
| 30 |
+
chunks.append(text[start:end])
|
| 31 |
+
start += chunk_size - overlap
|
| 32 |
+
return chunks
|
| 33 |
+
|
| 34 |
+
def analyze_chunk(chunk):
|
| 35 |
+
"""Analyzes a single text chunk for greenwashing using the Groq API."""
|
| 36 |
+
try:
|
| 37 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 38 |
+
except FileNotFoundError:
|
| 39 |
+
return [{"type": "Configuration Error", "excerpt": "N/A", "explanation": "GROQ_API_KEY secret not found.", "suggestion": "Please ensure the GROQ_API_KEY is set in your Streamlit secrets."}]
|
| 40 |
+
|
| 41 |
+
prompt = f"""
|
| 42 |
+
You are a critical ESG analyst specializing in identifying greenwashing. Analyze the following text for potential greenwashing. For each issue, identify the type of greenwashing (e.g., Vague Language, Irrelevant Claims, Hidden Trade-offs, No Proof), extract the specific sentence or phrase, explain why it's a potential issue, and suggest a more transparent alternative.
|
| 43 |
+
|
| 44 |
+
Text to analyze:
|
| 45 |
+
'''{chunk}'''
|
| 46 |
+
|
| 47 |
+
Format your response as a valid JSON list of objects. Each object must have the keys: "type", "excerpt", "explanation", and "suggestion". If no issues are found, return an empty list [].
|
| 48 |
+
"""
|
| 49 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 50 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 51 |
+
payload = {
|
| 52 |
+
"model": "llama3-8b-8192",
|
| 53 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 54 |
+
"response_format": {"type": "json_object"},
|
| 55 |
+
"max_tokens": 2048,
|
| 56 |
+
"temperature": 0.4
|
| 57 |
+
}
|
| 58 |
+
try:
|
| 59 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 60 |
+
response.raise_for_status()
|
| 61 |
+
data = response.json()
|
| 62 |
+
issues_str = data["choices"][0]["message"]["content"]
|
| 63 |
+
# The content itself is a JSON string, so we parse it
|
| 64 |
+
parsed_issues = json.loads(issues_str)
|
| 65 |
+
# The actual list might be nested inside a key like 'issues'
|
| 66 |
+
if isinstance(parsed_issues, dict) and 'issues' in parsed_issues:
|
| 67 |
+
return parsed_issues['issues']
|
| 68 |
+
return parsed_issues # Assume it's the list itself
|
| 69 |
+
|
| 70 |
+
except requests.exceptions.RequestException:
|
| 71 |
+
return [{"type": "API Error", "excerpt": "N/A", "explanation": "Could not connect to the analysis service.", "suggestion": "Check your API key and network connection."}]
|
| 72 |
+
except (json.JSONDecodeError, KeyError, IndexError):
|
| 73 |
+
return [{"type": "API Response Error", "excerpt": "N/A", "explanation": "The analysis service returned an invalid response.", "suggestion": "This may be a temporary issue. Please try again."}]
|
agents/module1_template.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# --- Constants ---
|
| 6 |
+
TEMPLATE_DICT = {
|
| 7 |
+
"GRI": "Global Reporting Initiative Standards",
|
| 8 |
+
"SASB": "Sustainability Accounting Standards Board",
|
| 9 |
+
"TCFD": "Task Force on Climate-related Financial Disclosures",
|
| 10 |
+
"IIRC": "International Integrated Reporting Council",
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
# --- Main Function ---
|
| 14 |
+
def generate_esg_template(framework_key, lang_code, template_dict):
|
| 15 |
+
try:
|
| 16 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 17 |
+
except FileNotFoundError:
|
| 18 |
+
return "Error: GROQ_API_KEY secret not found. Please add it to your Streamlit secrets."
|
| 19 |
+
|
| 20 |
+
template_info = template_dict.get(framework_key, "")
|
| 21 |
+
if not template_info:
|
| 22 |
+
return "Unsupported or unknown ESG framework."
|
| 23 |
+
|
| 24 |
+
prompt = f"""
|
| 25 |
+
You are an expert ESG specialist. Provide a detailed, professional ESG reporting template strictly aligned with the {framework_key} framework. Include headings, subheadings, and instructions clearly aligned with the {framework_key} standard requirements.
|
| 26 |
+
|
| 27 |
+
Base information provided: "{template_info}"
|
| 28 |
+
|
| 29 |
+
Respond clearly formatted as a template in {'English' if lang_code == 'en' else 'Vietnamese'}.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 33 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 34 |
+
payload = {
|
| 35 |
+
"model": "llama3-8b-8192",
|
| 36 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 37 |
+
"max_tokens": 2048,
|
| 38 |
+
"temperature": 0.6
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
try:
|
| 42 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 43 |
+
response.raise_for_status()
|
| 44 |
+
return response.json()["choices"][0]["message"]["content"]
|
| 45 |
+
except requests.exceptions.RequestException as e:
|
| 46 |
+
return f"Error: API request failed: {e}"
|
| 47 |
+
except (KeyError, IndexError) as e:
|
| 48 |
+
return f"Error: Invalid API response format: {e}"
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
# --- Streamlit UI ---
|
| 52 |
+
def show_module1_ui():
|
| 53 |
+
"""Renders the Streamlit UI for Module 1: ESG Template Generation."""
|
| 54 |
+
st.subheader("Tạo mẫu báo cáo ESG theo các framework quốc tế")
|
| 55 |
+
st.markdown(
|
| 56 |
+
"""
|
| 57 |
+
Module này giúp bạn nhanh chóng tạo ra các mẫu báo cáo ESG (Môi trường - Xã hội - Quản trị)
|
| 58 |
+
dựa trên các framework báo cáo bền vững phổ biến nhất trên thế giới.
|
| 59 |
+
"""
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
# --- User Inputs ---
|
| 63 |
+
col1, col2 = st.columns(2)
|
| 64 |
+
with col1:
|
| 65 |
+
framework_key = st.selectbox(
|
| 66 |
+
"📊 Chọn Framework Báo cáo",
|
| 67 |
+
options=list(TEMPLATE_DICT.keys()),
|
| 68 |
+
help="Chọn framework bạn muốn tạo mẫu báo cáo.",
|
| 69 |
+
)
|
| 70 |
+
with col2:
|
| 71 |
+
lang_code = st.selectbox(
|
| 72 |
+
"🌐 Chọn Ngôn ngữ",
|
| 73 |
+
options=["vi", "en"],
|
| 74 |
+
format_func=lambda x: "Tiếng Việt" if x == "vi" else "English",
|
| 75 |
+
help="Chọn ngôn ngữ cho mẫu báo cáo.",
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
# --- Generation ---
|
| 79 |
+
if st.button("Tạo Mẫu Báo cáo", use_container_width=True):
|
| 80 |
+
with st.spinner("Đang tạo mẫu báo cáo, vui lòng chờ..."):
|
| 81 |
+
generated_template = generate_esg_template(
|
| 82 |
+
framework_key, lang_code, TEMPLATE_DICT
|
| 83 |
+
)
|
| 84 |
+
st.session_state.generated_template = generated_template
|
| 85 |
+
|
| 86 |
+
# --- Display Result ---
|
| 87 |
+
if "generated_template" in st.session_state:
|
| 88 |
+
st.markdown("---")
|
| 89 |
+
st.subheader("Mẫu Báo cáo ESG đã tạo")
|
| 90 |
+
st.markdown(st.session_state.generated_template)
|
| 91 |
+
|
| 92 |
+
st.download_button(
|
| 93 |
+
label="Tải mẫu về máy",
|
| 94 |
+
data=st.session_state.generated_template,
|
| 95 |
+
file_name=f"esg_template_{framework_key}.md",
|
| 96 |
+
mime="text/markdown",
|
| 97 |
+
use_container_width=True,
|
| 98 |
+
)
|
agents/module2_planner.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
# --- Constants ---
|
| 5 |
+
FRAMEWORK_OPTIONS = {
|
| 6 |
+
"GRI": "Global Reporting Initiative",
|
| 7 |
+
"SASB": "Sustainability Accounting Standards Board",
|
| 8 |
+
"TCFD": "Task Force on Climate-related Financial Disclosures",
|
| 9 |
+
"IIRC": "International Integrated Reporting Council",
|
| 10 |
+
"Custom": "Kế hoạch tùy chỉnh theo mục tiêu"
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
# --- Backend Logic ---
|
| 14 |
+
def generate_sustainability_plan(profile, objectives, framework, lang_code):
|
| 15 |
+
try:
|
| 16 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 17 |
+
except FileNotFoundError:
|
| 18 |
+
return "Error: GROQ_API_KEY secret not found. Please add it to your Streamlit secrets."
|
| 19 |
+
|
| 20 |
+
prompt = f"""
|
| 21 |
+
You are an expert sustainability advisor. Based on the following organization profile and ESG objectives, generate a comprehensive, actionable sustainability plan strictly aligned with the {framework} framework.
|
| 22 |
+
|
| 23 |
+
Organization Profile:
|
| 24 |
+
- Geographic area: {profile['province']}
|
| 25 |
+
- Sector: {profile['sector']}
|
| 26 |
+
- Size: {profile['size']}
|
| 27 |
+
- Key operations: {profile['operations']}
|
| 28 |
+
|
| 29 |
+
ESG Objectives:
|
| 30 |
+
- Environmental: {objectives['environmental']}
|
| 31 |
+
- Social: {objectives['social']}
|
| 32 |
+
- Governance: {objectives['governance']}
|
| 33 |
+
|
| 34 |
+
Please structure the plan with sections matching the ESG pillars, include clear recommended actions, timelines, KPIs, and assign each action to a responsible role where possible. Respond in {'English' if lang_code == 'en' else 'Vietnamese'}.
|
| 35 |
+
"""
|
| 36 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 37 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 38 |
+
payload = {
|
| 39 |
+
"model": "llama3-8b-8192",
|
| 40 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 41 |
+
"max_tokens": 2048,
|
| 42 |
+
"temperature": 0.6
|
| 43 |
+
}
|
| 44 |
+
try:
|
| 45 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 46 |
+
response.raise_for_status()
|
| 47 |
+
return response.json()["choices"][0]["message"]["content"]
|
| 48 |
+
except requests.exceptions.RequestException as e:
|
| 49 |
+
return f"Error: API request failed: {e}"
|
| 50 |
+
except (KeyError, IndexError) as e:
|
| 51 |
+
return f"Error: Invalid API response format: {e}"
|
| 52 |
+
|
| 53 |
+
# --- Streamlit UI ---
|
| 54 |
+
def show_module2_ui():
|
| 55 |
+
"""Renders the Streamlit UI for Module 2: Sustainability Planner."""
|
| 56 |
+
st.subheader("Tinh chỉnh kế hoạch phát triển bền vững chi tiết")
|
| 57 |
+
st.markdown(
|
| 58 |
+
"""
|
| 59 |
+
Module này giúp bạn xây dựng một kế hoạch hành động ESG chi tiết, phù hợp với bối cảnh
|
| 60 |
+
và mục tiêu của tổ chức, dựa trên các framework quốc tế.
|
| 61 |
+
"""
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
# --- User Inputs ---
|
| 65 |
+
st.markdown("#### **Thông tin tổ chức**")
|
| 66 |
+
col1, col2 = st.columns(2)
|
| 67 |
+
with col1:
|
| 68 |
+
province = st.text_input("Tỉnh/Thành phố", "TP. Hồ Chí Minh")
|
| 69 |
+
sector = st.text_input("Lĩnh vực hoạt động", "Công nghệ thông tin")
|
| 70 |
+
with col2:
|
| 71 |
+
size = st.selectbox("Quy mô", ["<50 nhân viên", "50-250 nhân viên", "250-1000 nhân viên", ">1000 nhân viên"])
|
| 72 |
+
operations = st.text_area("Hoạt động chính", "Phát triển phần mềm, tư vấn giải pháp CNTT.")
|
| 73 |
+
|
| 74 |
+
st.markdown("#### **Mục tiêu ESG**")
|
| 75 |
+
col1, col2, col3 = st.columns(3)
|
| 76 |
+
with col1:
|
| 77 |
+
environmental_obj = st.text_area("Mục tiêu Môi trường (E)", "Giảm 15% lượng khí thải carbon trong 2 năm.")
|
| 78 |
+
with col2:
|
| 79 |
+
social_obj = st.text_area("Mục tiêu Xã hội (S)", "Tăng tỷ lệ nữ giới trong vai trò lãnh đạo lên 40%.")
|
| 80 |
+
with col3:
|
| 81 |
+
governance_obj = st.text_area("Mục tiêu Quản trị (G)", "Thành lập ủy ban giám sát ESG độc lập.")
|
| 82 |
+
|
| 83 |
+
st.markdown("#### **Tùy chọn Kế hoạch**")
|
| 84 |
+
col1, col2 = st.columns(2)
|
| 85 |
+
with col1:
|
| 86 |
+
framework = st.selectbox(
|
| 87 |
+
"📊 Chọn Framework",
|
| 88 |
+
options=list(FRAMEWORK_OPTIONS.keys()),
|
| 89 |
+
help="Chọn framework để xây dựng kế hoạch."
|
| 90 |
+
)
|
| 91 |
+
with col2:
|
| 92 |
+
lang_code = st.selectbox(
|
| 93 |
+
"🌐 Chọn Ngôn ngữ",
|
| 94 |
+
options=["vi", "en"],
|
| 95 |
+
format_func=lambda x: "Tiếng Việt" if x == "vi" else "English",
|
| 96 |
+
help="Chọn ngôn ngữ cho kế hoạch."
|
| 97 |
+
)
|
| 98 |
+
|
| 99 |
+
# --- Generation ---
|
| 100 |
+
if st.button("Tạo Kế hoạch Hành động", use_container_width=True):
|
| 101 |
+
profile = {
|
| 102 |
+
'province': province,
|
| 103 |
+
'sector': sector,
|
| 104 |
+
'size': size,
|
| 105 |
+
'operations': operations
|
| 106 |
+
}
|
| 107 |
+
objectives = {
|
| 108 |
+
'environmental': environmental_obj,
|
| 109 |
+
'social': social_obj,
|
| 110 |
+
'governance': governance_obj
|
| 111 |
+
}
|
| 112 |
+
with st.spinner("Đang xây dựng kế hoạch, vui lòng chờ..."):
|
| 113 |
+
generated_plan = generate_sustainability_plan(
|
| 114 |
+
profile, objectives, framework, lang_code
|
| 115 |
+
)
|
| 116 |
+
st.session_state.generated_plan_m2 = generated_plan
|
| 117 |
+
|
| 118 |
+
# --- Display Result ---
|
| 119 |
+
if "generated_plan_m2" in st.session_state:
|
| 120 |
+
st.markdown("---")
|
| 121 |
+
st.subheader("Kế hoạch Phát triển Bền vững đã tạo")
|
| 122 |
+
st.markdown(st.session_state.generated_plan_m2)
|
| 123 |
+
|
| 124 |
+
st.download_button(
|
| 125 |
+
label="Tải kế hoạch về máy",
|
| 126 |
+
data=st.session_state.generated_plan_m2,
|
| 127 |
+
file_name=f"sustainability_plan_{framework}.md",
|
| 128 |
+
mime="text/markdown",
|
| 129 |
+
use_container_width=True,
|
| 130 |
+
)
|
agents/module3_report.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
# --- Backend Logic ---
|
| 5 |
+
def generate_esg_report(input_data, lang_code):
|
| 6 |
+
try:
|
| 7 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 8 |
+
except FileNotFoundError:
|
| 9 |
+
return "Error: GROQ_API_KEY secret not found. Please add it to your Streamlit secrets."
|
| 10 |
+
|
| 11 |
+
prompt = f"""
|
| 12 |
+
You are an ESG Reporting Assistant. Create a comprehensive ESG report for the company using the following data:
|
| 13 |
+
|
| 14 |
+
Industry: {input_data.get('industry', '')}
|
| 15 |
+
Environmental Metrics: {input_data.get('e_metrics', '')}
|
| 16 |
+
Social Metrics: {input_data.get('s_metrics', '')}
|
| 17 |
+
Governance Metrics: {input_data.get('g_metrics', '')}
|
| 18 |
+
Policy/Initiatives: {input_data.get('policy', '')}
|
| 19 |
+
|
| 20 |
+
Write the report with an Introduction and sections for Environmental, Social, and Governance performance. Summarize key strengths and suggest improvements.
|
| 21 |
+
Respond in {'English' if lang_code == 'en' else 'Vietnamese'}.
|
| 22 |
+
"""
|
| 23 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 24 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 25 |
+
payload = {
|
| 26 |
+
"model": "llama3-8b-8192",
|
| 27 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 28 |
+
"max_tokens": 2048,
|
| 29 |
+
"temperature": 0.7
|
| 30 |
+
}
|
| 31 |
+
try:
|
| 32 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 33 |
+
response.raise_for_status()
|
| 34 |
+
return response.json()["choices"][0]["message"]["content"]
|
| 35 |
+
except requests.exceptions.RequestException as e:
|
| 36 |
+
return f"Error: API request failed: {e}"
|
| 37 |
+
except (KeyError, IndexError) as e:
|
| 38 |
+
return f"Error: Invalid API response format: {e}"
|
| 39 |
+
|
| 40 |
+
# --- Streamlit UI ---
|
| 41 |
+
def show_module3_ui():
|
| 42 |
+
"""Renders the Streamlit UI for Module 3: ESG Report Generation."""
|
| 43 |
+
st.subheader("Tạo báo cáo ESG tự động từ dữ liệu nội bộ")
|
| 44 |
+
st.markdown(
|
| 45 |
+
"""
|
| 46 |
+
Module này cho phép bạn nhập các số liệu ESG thô của công ty để tự động tạo ra một
|
| 47 |
+
báo cáo ESG hoàn chỉnh, có cấu trúc chuyên nghiệp.
|
| 48 |
+
"""
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
# --- User Inputs ---
|
| 52 |
+
st.markdown("#### **Nhập dữ liệu ESG của bạn**")
|
| 53 |
+
industry = st.text_input("Ngành công nghiệp", "Sản xuất hàng tiêu dùng")
|
| 54 |
+
|
| 55 |
+
col1, col2 = st.columns(2)
|
| 56 |
+
with col1:
|
| 57 |
+
e_metrics = st.text_area("Số liệu Môi trường (E)", "Lượng phát thải CO2: 1,500 tấn/năm\nTiêu thụ nước: 50,000 m3/năm\nTỷ lệ tái chế: 60%")
|
| 58 |
+
with col2:
|
| 59 |
+
s_metrics = st.text_area("Số liệu Xã hội (S)", "Tỷ lệ tai nạn lao động: 0.2%\nGiờ đào tạo trung bình/nhân viên: 20 giờ/năm\nĐóng góp cho cộng đồng: 500 triệu VNĐ")
|
| 60 |
+
|
| 61 |
+
col1, col2 = st.columns(2)
|
| 62 |
+
with col1:
|
| 63 |
+
g_metrics = st.text_area("Số liệu Quản trị (G)", "Tỷ lệ thành viên HĐQT độc lập: 30%\nSố cuộc họp của ủy ban kiểm toán: 4/năm\nChênh lệch lương trung bình nam/nữ: 5%")
|
| 64 |
+
with col2:
|
| 65 |
+
policy = st.text_area("Chính sách & Sáng kiến", "Chính sách làm việc linh hoạt\nSáng kiến chuỗi cung ứng bền vững\nChương trình sức khỏe tinh thần cho nhân viên")
|
| 66 |
+
|
| 67 |
+
lang_code = st.selectbox(
|
| 68 |
+
"🌐 Chọn Ngôn ngữ Báo cáo",
|
| 69 |
+
options=["vi", "en"],
|
| 70 |
+
format_func=lambda x: "Tiếng Việt" if x == "vi" else "English",
|
| 71 |
+
key="module3_lang"
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
# --- Generation ---
|
| 75 |
+
if st.button("Tạo Báo cáo ESG", use_container_width=True):
|
| 76 |
+
input_data = {
|
| 77 |
+
'industry': industry,
|
| 78 |
+
'e_metrics': e_metrics,
|
| 79 |
+
's_metrics': s_metrics,
|
| 80 |
+
'g_metrics': g_metrics,
|
| 81 |
+
'policy': policy
|
| 82 |
+
}
|
| 83 |
+
with st.spinner("Đang tổng hợp và viết báo cáo, vui lòng chờ..."):
|
| 84 |
+
generated_report = generate_esg_report(input_data, lang_code)
|
| 85 |
+
st.session_state.generated_report_m3 = generated_report
|
| 86 |
+
|
| 87 |
+
# --- Display Result ---
|
| 88 |
+
if "generated_report_m3" in st.session_state:
|
| 89 |
+
st.markdown("---")
|
| 90 |
+
st.subheader("Báo cáo ESG đã tạo")
|
| 91 |
+
st.markdown(st.session_state.generated_report_m3)
|
| 92 |
+
|
| 93 |
+
st.download_button(
|
| 94 |
+
label="Tải báo cáo về máy",
|
| 95 |
+
data=st.session_state.generated_report_m3,
|
| 96 |
+
file_name="esg_report.md",
|
| 97 |
+
mime="text/markdown",
|
| 98 |
+
use_container_width=True,
|
| 99 |
+
)
|
agents/module4_compliance.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
# --- Constants ---
|
| 5 |
+
FRAMEWORKS_DICT = {
|
| 6 |
+
"GRI": [
|
| 7 |
+
"Report on stakeholder engagement processes.",
|
| 8 |
+
"Disclose the process for determining material topics.",
|
| 9 |
+
"Report on management approach for each material topic.",
|
| 10 |
+
"Provide data for economic, environmental, and social impacts."
|
| 11 |
+
],
|
| 12 |
+
"SASB": [
|
| 13 |
+
"Disclose performance on industry-specific sustainability topics.",
|
| 14 |
+
"Provide metrics that are financially material.",
|
| 15 |
+
"Report data in a standardized format for comparability.",
|
| 16 |
+
"Explain how sustainability performance affects financial condition."
|
| 17 |
+
],
|
| 18 |
+
"TCFD": [
|
| 19 |
+
"Describe the board's oversight of climate-related risks and opportunities.",
|
| 20 |
+
"Disclose actual and potential impacts of climate risks on the business.",
|
| 21 |
+
"Describe the resilience of the strategy, taking into consideration different climate scenarios.",
|
| 22 |
+
"Disclose the metrics and targets used to assess and manage climate-related risks."
|
| 23 |
+
],
|
| 24 |
+
"IIRC": [
|
| 25 |
+
"Provide an overview of the organization and its external environment.",
|
| 26 |
+
"Explain the governance structure and how it supports value creation.",
|
| 27 |
+
"Describe the business model, including inputs, activities, and outputs.",
|
| 28 |
+
"Report on performance and outcomes in terms of the six capitals (Financial, Manufactured, Intellectual, Human, Social, Natural)."
|
| 29 |
+
]
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
# --- Backend Logic ---
|
| 33 |
+
def check_multi_framework_compliance(report_text, framework_keys, lang_code, frameworks_dict):
|
| 34 |
+
try:
|
| 35 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 36 |
+
except FileNotFoundError:
|
| 37 |
+
return "Error: GROQ_API_KEY secret not found. Please add it to your Streamlit secrets."
|
| 38 |
+
|
| 39 |
+
all_results = []
|
| 40 |
+
for framework_key in framework_keys:
|
| 41 |
+
requirements = frameworks_dict.get(framework_key, [])
|
| 42 |
+
if not requirements:
|
| 43 |
+
all_results.append(f"Framework '{framework_key}' is not supported or has no requirements defined.\n")
|
| 44 |
+
continue
|
| 45 |
+
checklist = "\n".join([f"- {req}" for req in requirements])
|
| 46 |
+
prompt = f"""
|
| 47 |
+
You are an ESG Compliance Checker. Review the following organization's *actual ESG report/results* and compare them to this ESG framework's requirements:
|
| 48 |
+
|
| 49 |
+
Framework: {framework_key}
|
| 50 |
+
Requirements:
|
| 51 |
+
{checklist}
|
| 52 |
+
|
| 53 |
+
ESG Report Text:
|
| 54 |
+
\"\"\"{report_text}\"\"\"
|
| 55 |
+
|
| 56 |
+
Task:
|
| 57 |
+
For each requirement, state whether the report fully meets, partially meets, or does not meet it. Clearly explain any gaps or missing evidence. Suggest specific improvements for non-compliance areas. Respond in {'English' if lang_code == 'en' else 'Vietnamese'}.
|
| 58 |
+
"""
|
| 59 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 60 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 61 |
+
payload = {
|
| 62 |
+
"model": "llama3-8b-8192",
|
| 63 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 64 |
+
"max_tokens": 2048,
|
| 65 |
+
"temperature": 0.5
|
| 66 |
+
}
|
| 67 |
+
try:
|
| 68 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 69 |
+
response.raise_for_status()
|
| 70 |
+
result = response.json()["choices"][0]["message"]["content"]
|
| 71 |
+
all_results.append(f"### Phân tích Tuân thủ Framework: {framework_key}\n\n{result}\n")
|
| 72 |
+
except requests.exceptions.RequestException as e:
|
| 73 |
+
all_results.append(f"Lỗi khi kiểm tra framework {framework_key}: {e}\n")
|
| 74 |
+
except (KeyError, IndexError) as e:
|
| 75 |
+
all_results.append(f"Lỗi định dạng phản hồi API cho framework {framework_key}: {e}\n")
|
| 76 |
+
return "\n---\n".join(all_results)
|
| 77 |
+
|
| 78 |
+
# --- Streamlit UI ---
|
| 79 |
+
def show_module4_ui():
|
| 80 |
+
"""Renders the Streamlit UI for Module 4: Multi-Framework Compliance Check."""
|
| 81 |
+
st.subheader("Kiểm tra tuân thủ đa khung báo cáo")
|
| 82 |
+
st.markdown(
|
| 83 |
+
"""
|
| 84 |
+
Dán nội dung báo cáo ESG của bạn vào đây để đối chiếu với các yêu cầu chính
|
| 85 |
+
của nhiều framework báo cáo bền vững cùng một lúc.
|
| 86 |
+
"""
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
# --- User Inputs ---
|
| 90 |
+
report_text = st.text_area(
|
| 91 |
+
"📝 Dán nội dung báo cáo ESG của bạn vào đây",
|
| 92 |
+
height=300,
|
| 93 |
+
placeholder="Ví dụ: Công ty chúng tôi đã giảm 10% lượng nước tiêu thụ trong năm qua..."
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
col1, col2 = st.columns(2)
|
| 97 |
+
with col1:
|
| 98 |
+
framework_keys = st.multiselect(
|
| 99 |
+
"📊 Chọn các Framework để đối chiếu",
|
| 100 |
+
options=list(FRAMEWORKS_DICT.keys()),
|
| 101 |
+
default=["GRI", "TCFD"],
|
| 102 |
+
help="Bạn có thể chọn một hoặc nhiều framework."
|
| 103 |
+
)
|
| 104 |
+
with col2:
|
| 105 |
+
lang_code = st.selectbox(
|
| 106 |
+
"🌐 Chọn Ngôn ngữ Phân tích",
|
| 107 |
+
options=["vi", "en"],
|
| 108 |
+
format_func=lambda x: "Tiếng Việt" if x == "vi" else "English",
|
| 109 |
+
key="module4_lang"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
# --- Generation ---
|
| 113 |
+
if st.button("Kiểm tra Tuân thủ", use_container_width=True):
|
| 114 |
+
if not report_text:
|
| 115 |
+
st.warning("Vui lòng dán nội dung báo cáo của bạn.")
|
| 116 |
+
elif not framework_keys:
|
| 117 |
+
st.warning("Vui lòng chọn ít nhất một framework để kiểm tra.")
|
| 118 |
+
else:
|
| 119 |
+
with st.spinner("Đang phân tích báo cáo của bạn, vui lòng chờ..."):
|
| 120 |
+
compliance_result = check_multi_framework_compliance(
|
| 121 |
+
report_text, framework_keys, lang_code, FRAMEWORKS_DICT
|
| 122 |
+
)
|
| 123 |
+
st.session_state.compliance_result_m4 = compliance_result
|
| 124 |
+
|
| 125 |
+
# --- Display Result ---
|
| 126 |
+
if "compliance_result_m4" in st.session_state:
|
| 127 |
+
st.markdown("---")
|
| 128 |
+
st.subheader("Kết quả Phân tích Tuân thủ")
|
| 129 |
+
st.markdown(st.session_state.compliance_result_m4)
|
| 130 |
+
|
| 131 |
+
st.download_button(
|
| 132 |
+
label="Tải kết quả phân tích",
|
| 133 |
+
data=st.session_state.compliance_result_m4,
|
| 134 |
+
file_name="esg_compliance_analysis.md",
|
| 135 |
+
mime="text/markdown",
|
| 136 |
+
use_container_width=True,
|
| 137 |
+
)
|
agents/module5_score.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
|
| 4 |
+
# --- Backend Logic ---
|
| 5 |
+
def evaluate_esg_score(esg_report_text, lang_code, benchmarks=None):
|
| 6 |
+
try:
|
| 7 |
+
groq_api_key = st.secrets["GROQ_API_KEY"]
|
| 8 |
+
except FileNotFoundError:
|
| 9 |
+
return "Error: GROQ_API_KEY secret not found. Please add it to your Streamlit secrets."
|
| 10 |
+
|
| 11 |
+
benchmark_text = f"Compare the results to these benchmarks for the sector: {benchmarks}" if benchmarks else ''
|
| 12 |
+
prompt = f"""
|
| 13 |
+
You are an independent ESG scoring analyst. Based on the following *actual, implemented* ESG report, rate the organization's performance in each ESG pillar (Environmental, Social, Governance), and provide an overall ESG score (out of 100).
|
| 14 |
+
|
| 15 |
+
For each pillar, score from 0-100 and provide a rationale. Summarize major strengths and weaknesses based on the data.
|
| 16 |
+
{benchmark_text}
|
| 17 |
+
Be transparent about scoring logic (e.g., low environmental score if no GHG disclosure; high governance score if independent board, etc).
|
| 18 |
+
|
| 19 |
+
ESG Report:
|
| 20 |
+
\"\"\"{esg_report_text}\"\"\"
|
| 21 |
+
|
| 22 |
+
Format your answer as:
|
| 23 |
+
- Environmental Score: X/100
|
| 24 |
+
Explanation: ...
|
| 25 |
+
- Social Score: X/100
|
| 26 |
+
Explanation: ...
|
| 27 |
+
- Governance Score: X/100
|
| 28 |
+
Explanation: ...
|
| 29 |
+
- **Overall ESG Score:** X/100
|
| 30 |
+
Summary: ...
|
| 31 |
+
Respond in {'English' if lang_code == 'en' else 'Vietnamese'}.
|
| 32 |
+
"""
|
| 33 |
+
api_url = "https://api.groq.com/openai/v1/chat/completions"
|
| 34 |
+
headers = {"Authorization": f"Bearer {groq_api_key}", "Content-Type": "application/json"}
|
| 35 |
+
payload = {
|
| 36 |
+
"model": "llama3-8b-8192",
|
| 37 |
+
"messages": [{"role": "user", "content": prompt}],
|
| 38 |
+
"max_tokens": 1500,
|
| 39 |
+
"temperature": 0.6
|
| 40 |
+
}
|
| 41 |
+
try:
|
| 42 |
+
response = requests.post(api_url, json=payload, headers=headers)
|
| 43 |
+
response.raise_for_status()
|
| 44 |
+
return response.json()["choices"][0]["message"]["content"]
|
| 45 |
+
except requests.exceptions.RequestException as e:
|
| 46 |
+
return f"Error: API request failed: {e}"
|
| 47 |
+
except (KeyError, IndexError) as e:
|
| 48 |
+
return f"Error: Invalid API response format: {e}"
|
| 49 |
+
|
| 50 |
+
# --- Streamlit UI ---
|
| 51 |
+
def show_module5_ui():
|
| 52 |
+
"""Renders the Streamlit UI for Module 5: ESG Scoring."""
|
| 53 |
+
st.subheader("Đánh giá và chấm điểm báo cáo ESG")
|
| 54 |
+
st.markdown(
|
| 55 |
+
"""
|
| 56 |
+
Module này hoạt động như một nhà phân tích độc lập, chấm điểm báo cáo ESG của bạn
|
| 57 |
+
trên thang điểm 100 và cung cấp lý giải chi tiết cho từng trụ cột.
|
| 58 |
+
"""
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
# --- User Inputs ---
|
| 62 |
+
esg_report_text = st.text_area(
|
| 63 |
+
"📝 Dán nội dung báo cáo ESG của bạn vào đây",
|
| 64 |
+
height=300,
|
| 65 |
+
placeholder="Ví dụ: Báo cáo bền vững năm 2023 của công ty ABC..."
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
col1, col2 = st.columns(2)
|
| 69 |
+
with col1:
|
| 70 |
+
benchmarks = st.text_area(
|
| 71 |
+
"📈 Nhập benchmarks (tùy chọn)",
|
| 72 |
+
height=150,
|
| 73 |
+
help="Cung cấp các chỉ số tham chiếu của ngành để so sánh. Ví dụ: 'Tỷ lệ phát thải trung bình ngành: 1.2 tấn CO2/sản phẩm'"
|
| 74 |
+
)
|
| 75 |
+
with col2:
|
| 76 |
+
lang_code = st.selectbox(
|
| 77 |
+
"🌐 Chọn Ngôn ngữ Phân tích",
|
| 78 |
+
options=["vi", "en"],
|
| 79 |
+
format_func=lambda x: "Tiếng Việt" if x == "vi" else "English",
|
| 80 |
+
key="module5_lang"
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
# --- Generation ---
|
| 84 |
+
if st.button("Chấm điểm ESG", use_container_width=True):
|
| 85 |
+
if not esg_report_text:
|
| 86 |
+
st.warning("Vui lòng dán nội dung báo cáo của bạn.")
|
| 87 |
+
else:
|
| 88 |
+
with st.spinner("Đang phân tích và chấm điểm, vui lòng chờ..."):
|
| 89 |
+
scoring_result = evaluate_esg_score(
|
| 90 |
+
esg_report_text, lang_code, benchmarks if benchmarks else None
|
| 91 |
+
)
|
| 92 |
+
st.session_state.scoring_result_m5 = scoring_result
|
| 93 |
+
|
| 94 |
+
# --- Display Result ---
|
| 95 |
+
if "scoring_result_m5" in st.session_state:
|
| 96 |
+
st.markdown("---")
|
| 97 |
+
st.subheader("Kết quả Chấm điểm ESG")
|
| 98 |
+
st.markdown(st.session_state.scoring_result_m5)
|
| 99 |
+
|
| 100 |
+
st.download_button(
|
| 101 |
+
label="Tải kết quả chấm điểm",
|
| 102 |
+
data=st.session_state.scoring_result_m5,
|
| 103 |
+
file_name="esg_score_analysis.md",
|
| 104 |
+
mime="text/markdown",
|
| 105 |
+
use_container_width=True,
|
| 106 |
+
)
|
agents/module6_greenwash.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from agents.greenwash_utils import extract_text, chunk_text, analyze_chunk
|
| 3 |
+
import json
|
| 4 |
+
|
| 5 |
+
def show_module6_ui():
|
| 6 |
+
"""Renders the Streamlit UI for Module 6: Greenwashing Check."""
|
| 7 |
+
st.subheader("Phân tích và phát hiện Greenwashing")
|
| 8 |
+
st.markdown(
|
| 9 |
+
"""
|
| 10 |
+
Tải lên báo cáo bền vững (PDF, DOCX) hoặc dán một đoạn văn bản để AI phân tích,
|
| 11 |
+
xác định các tuyên bố có khả năng gây hiểu lầm (greenwashing).
|
| 12 |
+
"""
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
# --- User Inputs ---
|
| 16 |
+
uploaded_file = st.file_uploader(
|
| 17 |
+
"Tải lên báo cáo ESG (PDF, DOCX)",
|
| 18 |
+
type=["pdf", "docx"]
|
| 19 |
+
)
|
| 20 |
+
manual_text = st.text_area(
|
| 21 |
+
"Hoặc dán một đoạn văn bản (tuyên bố, quảng cáo...) vào đây:",
|
| 22 |
+
height=200,
|
| 23 |
+
placeholder="Ví dụ: Sản phẩm của chúng tôi 100% thân thiện với môi trường..."
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
# --- Analysis ---
|
| 27 |
+
if st.button("Phân tích Greenwashing", use_container_width=True):
|
| 28 |
+
text_to_analyze = ""
|
| 29 |
+
if uploaded_file:
|
| 30 |
+
with st.spinner(f"Đang trích xuất văn bản từ file {uploaded_file.name}..."):
|
| 31 |
+
text_to_analyze = extract_text(uploaded_file)
|
| 32 |
+
elif manual_text:
|
| 33 |
+
text_to_analyze = manual_text
|
| 34 |
+
else:
|
| 35 |
+
st.warning("Vui lòng tải file lên hoặc dán văn bản để phân tích.")
|
| 36 |
+
st.stop()
|
| 37 |
+
|
| 38 |
+
if "Error:" in text_to_analyze:
|
| 39 |
+
st.error(text_to_analyze)
|
| 40 |
+
st.stop()
|
| 41 |
+
|
| 42 |
+
chunks = chunk_text(text_to_analyze)
|
| 43 |
+
if not chunks:
|
| 44 |
+
st.warning("Không tìm thấy nội dung văn bản để phân tích.")
|
| 45 |
+
st.stop()
|
| 46 |
+
|
| 47 |
+
all_issues = []
|
| 48 |
+
progress_bar = st.progress(0, text="Bắt đầu phân tích...")
|
| 49 |
+
|
| 50 |
+
for i, chunk in enumerate(chunks):
|
| 51 |
+
progress_text = f"Đang phân tích phần {i + 1}/{len(chunks)}..."
|
| 52 |
+
progress_bar.progress((i + 1) / len(chunks), text=progress_text)
|
| 53 |
+
|
| 54 |
+
# Analyze the chunk (API key is now handled by the utility function)
|
| 55 |
+
issues = analyze_chunk(chunk)
|
| 56 |
+
if isinstance(issues, list):
|
| 57 |
+
all_issues.extend(issues)
|
| 58 |
+
|
| 59 |
+
progress_bar.empty()
|
| 60 |
+
st.session_state.greenwash_results_m6 = all_issues
|
| 61 |
+
|
| 62 |
+
# --- Display Results ---
|
| 63 |
+
if "greenwash_results_m6" in st.session_state:
|
| 64 |
+
st.markdown("---")
|
| 65 |
+
st.subheader("Kết quả Phân tích Greenwashing")
|
| 66 |
+
results = st.session_state.greenwash_results_m6
|
| 67 |
+
|
| 68 |
+
if not results:
|
| 69 |
+
st.success("Không tìm thấy dấu hiệu greenwashing đáng kể trong văn bản.")
|
| 70 |
+
else:
|
| 71 |
+
st.info(f"Tìm thấy {len(results)} vấn đề tiềm ẩn.")
|
| 72 |
+
for idx, issue in enumerate(results, 1):
|
| 73 |
+
issue_type = issue.get('type', 'Không xác định')
|
| 74 |
+
with st.expander(f"Vấn đề {idx}: **{issue_type}**"):
|
| 75 |
+
st.markdown(f"> **Trích đoạn:** *...{issue.get('excerpt', 'N/A')}...*")
|
| 76 |
+
st.write("**Giải thích:**", issue.get("explanation", ""))
|
| 77 |
+
st.write("**Gợi ý:**", issue.get("suggestion", ""))
|
| 78 |
+
|
| 79 |
+
st.download_button(
|
| 80 |
+
label="Tải kết quả phân tích",
|
| 81 |
+
data=json.dumps(results, indent=2, ensure_ascii=False),
|
| 82 |
+
file_name="greenwashing_analysis.json",
|
| 83 |
+
mime="application/json",
|
| 84 |
+
use_container_width=True,
|
| 85 |
+
)
|