update prompts, comment

This commit is contained in:
ththu0205 2026-05-24 13:20:08 +00:00
parent ec26745e08
commit 5771253b43
14 changed files with 3207 additions and 2675 deletions

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ Chức năng:
import os
import json
import time
import re
from typing import Dict, Any, List, Optional, Callable
from dataclasses import dataclass, field
@ -23,10 +22,25 @@ from ..utils.llm_client import LLMClient
from ..utils.logger import get_logger
from .zep_tools import (
ZepToolsService,
SearchResult,
InsightForgeResult,
PanoramaResult,
InterviewResult
)
from ..prompts.report_agent import (
PLAN_SYSTEM_PROMPT,
PLAN_USER_PROMPT_TEMPLATE,
SECTION_SYSTEM_PROMPT_TEMPLATE,
TOOL_DESC_INSIGHT_FORGE,
TOOL_DESC_PANORAMA_SEARCH,
TOOL_DESC_QUICK_SEARCH,
TOOL_DESC_INTERVIEW_AGENTS,
SECTION_USER_PROMPT_TEMPLATE,
REACT_OBSERVATION_TEMPLATE,
REACT_INSUFFICIENT_TOOLS_MSG,
REACT_INSUFFICIENT_TOOLS_MSG_ALT,
REACT_TOOL_LIMIT_MSG,
REACT_UNUSED_TOOLS_HINT,
REACT_FORCE_FINAL_MSG,
CHAT_SYSTEM_PROMPT_TEMPLATE,
CHAT_OBSERVATION_SUFFIX
)
logger = get_logger('mirofish.report_agent')
@ -466,824 +480,6 @@ class Report:
}
# ═══════════════════════════════════════════════════════════════
# Hằng số Prompt Mẫu
# ═══════════════════════════════════════════════════════════════
# ── Mô tả Công cụ ──
# ═══════════════════════════════════════════════════════════════
# Prompt English
# TOOL_DESC_INSIGHT_FORGE = """\
# [Deep Insight Retrieval - Powerful Retrieval Tool]
# This is our powerful retrieval function, specifically designed for deep analysis. It will:
# 1. Automatically decompose your question into multiple sub-questions
# 2. Retrieve information from the simulation graph across multiple dimensions
# 3. Integrate the results of semantic search, entity analysis, and relationship chain tracking
# 4. Return the most comprehensive and deeply retrieved content
# [Usage Scenarios]
# - When you need to analyze a topic deeply
# - When you need to understand multiple aspects of an event
# - When you need rich material to support a report section
# [Returned Content]
# - Relevant original facts (can be cited directly)
# - Core entity insights
# - Relationship chain analysis
# """
# Prompt Vietnamese
TOOL_DESC_INSIGHT_FORGE = """\
[Truy xuất sâu - Công cụ truy xuất mạnh mẽ]
Đây chức năng truy xuất mạnh mẽ của chúng tôi, được thiết kế chuyên cho phân tích sâu. sẽ:
1. Tự động chia câu hỏi của bạn thành nhiều câu hỏi con
2. Truy xuất thông tin từ đồ thị phỏng theo nhiều chiều
3. Tích hợp kết quả từ tìm kiếm ngữ nghĩa, phân tích thực thể, theo dõi chuỗi quan hệ
4. Trả về nội dung truy xuất toàn diện sâu sắc nhất
[Trường hợp sử dụng]
- Cần phân tích sâu một chủ đề
- Cần hiểu nhiều khía cạnh của một sự kiện
- Cần lấy tài liệu phong phú để hỗ trợ các chương báo cáo
[Nội dung trả về]
- Các sự thật liên quan gốc ( thể trích dẫn trực tiếp)
- Sự sâu sắc về thực thể cốt lõi
- Phân tích chuỗi quan hệ
"""
# ═══════════════════════════════════════════════════════════════
# TOOL_DESC_PANORAMA_SEARCH = """\
# [Panoramic Search - Get Complete Overview]
# This tool is used to get a complete overview of the simulation results, especially suitable for understanding the evolution of of events. It will:
# 1. Get all relevant nodes and relationships
# 2. Distinguish between current valid facts and historical/expired facts
# 3. Help you understand how public opinion has evolved
# [Usage Scenarios]
# - Need to understand the complete development trajectory of an event
# - Need to compare public opinion changes across different stages
# - Need comprehensive entity and relationship information
# [Returned Content]
# - Current valid facts (latest simulation results)
# - Historical/expired facts (evolution records)
# - All involved entities
# """
TOOL_DESC_PANORAMA_SEARCH = """\
[Tìm kiếm toàn cảnh - Lấy tổng quan hoàn chỉnh]
Công cụ này được sử dụng để lấy tổng quan hoàn chỉnh của kết quả phỏng, đặc biệt phù hợp để hiểu quá trình tiến hóa của sự kiện. sẽ:
1. Lấy tất cả các nút quan hệ liên quan
2. Phân biệt giữa các sự kiện hợp lệ hiện tại các sự kiện lịch sử/hết hạn
3. Giúp bạn hiểu luận đã tiến hóa như thế nào
[Trường hợp sử dụng]
- Cần hiểu quỹ đạo phát triển hoàn chỉnh của một sự kiện
- Cần so sánh thay đổi luận các giai đoạn khác nhau
- Cần lấy thông tin thực thể quan hệ toàn diện
[Nội dung trả về]
- Các sự kiện hợp lệ hiện tại (kết quả phỏng mới nhất)
- Các sự kiện lịch sử/hết hạn (ghi lại tiến hóa)
- Tất cả các thực thể liên quan
"""
# ═══════════════════════════════════════════════════════════════
# TOOL_DESC_QUICK_SEARCH = """\
# [Quick Search - Fast Retrieval]
# A lightweight fast retrieval tool, suitable for simple, direct information queries.
# [Usage Scenarios]
# - Need to quickly look up a specific piece of information
# - Need to verify a fact
# - Simple information retrieval
# [Returned Content]
# - List of facts most relevant to the query
# """
TOOL_DESC_QUICK_SEARCH = """\
[Tìm kiếm đơn giản - Truy xuất nhanh]
Công cụ truy xuất nhanh nhẹn, phù hợp cho các truy vấn thông tin đơn giản, trực tiếp.
[Trường hợp sử dụng]
- Cần tìm nhanh thông tin cụ thể
- Cần xác minh một sự kiện
- Truy xuất thông tin đơn giản
[Nội dung trả về]
- Danh sách các sự kiện liên quan nhất đến truy vấn
"""
# ═══════════════════════════════════════════════════════════════
# TOOL_DESC_INTERVIEW_AGENTS = """\
# [Deep Interview - Real Agent Interview (Dual Platform)]
# Call the OASIS simulation environment's interview API to conduct real interviews with currently running simulation Agents!
# This is not an LLM simulation, but calls the real interview endpoint to get the simulation Agent's original answer.
# By default, interviews are conducted simultaneously on both Twitter and Reddit platforms to get more comprehensive perspectives.
# Functional Process:
# 1. Automatically reads persona files to understand all simulation Agents
# 2. Intelligently select agents most relevant to the interview topic (such as students, media, officials, etc.)
# 3. Automatically generates interview questions
# 2. Intelligently select agents most relevant to the interview topic (such as students, media, officials, etc.)
# 5. Integrates all interview results, providing multi-perspective analysis
# [Usage Scenarios]
# - Need to understand event views from different role perspectives (How do students see it? How does media see it? How do officials say it?)
# - Need to collect multi-party opinions and positions
# - Need to get real responses from simulation agents (from OASIS simulation environment)
# - Want to make the report more vivid, including "interview records"
# [Returned Content]
# - Identity information of interviewed agents
# - Interview responses of each agent on Twitter and Reddit platforms
# - Key quotes (can be cited directly)
# - Interview summary and perspective comparison
# [IMPORTANT] Requires OASIS simulation environment to be running to use this function!
# """
TOOL_DESC_INTERVIEW_AGENTS = """\
[Phỏng vấn sâu - Phỏng vấn Agent thực (Nền tảng kép)]
Gọi API phỏng vấn của môi trường phỏng OASIS để tiến hành phỏng vấn thực với các agent phỏng đang chạy!
Đây không phải phỏng LLM, gọi các giao diện phỏng vấn thực để lấy phản hồi gốc từ các agent phỏng.
Mặc định, phỏng vấn được tiến hành đồng thời trên cả hai nền tảng Twitter Reddit để được góc nhìn toàn diện hơn.
Quy trình chức năng:
1. Tự động đọc file nhân cách để hiểu tất cả các agent phỏng
2. Chọn thông minh các agent liên quan nhất đến chủ đề phỏng vấn (như sinh viên, truyền thông, quan chức, v.v.)
3. Tự động tạo câu hỏi phỏng vấn
4. Gọi giao diện /api/simulation/interview/batch để tiến hành phỏng vấn thực trên nền tảng kép
5. Tích hợp tất cả kết quả phỏng vấn để cung cấp phân tích đa góc nhìn
[Trường hợp sử dụng]
- Cần hiểu quan điểm sự kiện từ các góc nhìn vai trò khác nhau (Sinh viên nghĩ ? Truyền thông nghĩ ? Quan chức nói ?)
- Cần thu thập ý kiến lập trường đa phương
- Cần lấy phản hồi thực từ các agent phỏng (từ môi trường phỏng OASIS)
- Muốn làm cho báo cáo sống động hơn, bao gồm "ghi chép phỏng vấn"
[Nội dung trả về]
- Thông tin danh tính của các agent được phỏng vấn
- Phản hồi phỏng vấn của mỗi agent trên nền tảng Twitter Reddit
- Các trích dẫn chính ( thể trích dẫn trực tiếp)
- Tóm tắt phỏng vấn so sánh góc nhìn
[QUAN TRỌNG] Yêu cầu môi trường phỏng OASIS đang chạy để sử dụng chức năng này!
"""
# ═══════════════════════════════════════════════════════════════
# PLAN_SYSTEM_PROMPT = """\
# You are a writing expert for "Future Prediction Reports", possessing a "God's eye view" of the simulated world - you can observe the behaviors, speeches, and interactions of every Agent in the simulation.
# [Core Concept]
# We have built a simulated world and injected specific "simulation requirements" into it as variables. The evolutionary outcome of the simulated world is the prediction of what might happen in the future. What you are observing is not "experimental data", but a "preview of the future".
# [Your Task]
# Write a "Future Prediction Report" to answer:
# 1. Under our set conditions, what happened in the future?
# 2. How did various Agents (groups) react and act?
# 3. What noteworthy future trends and risks did this simulation reveal?
# [Report Positioning]
# - ✅ This is a simulation-based future prediction report, revealing "if this, what will the future be like"
# - ✅ Focus on prediction results: event trends, group reactions, emergent phenomena, potential risks
# - ✅ The actions and words of Agents in the simulated world are predictions of future human behavior
# - ❌ Not an analysis of the current real-world situation
# - ❌ Not a general public opinion summary
# [Chapter Quantity Limit]
# - Minimum of 2 chapters, maximum of 5 chapters
# - No sub-chapters needed, write complete content directly for each chapter
# - Content should be refined, focusing on core prediction findings
# - Chapter structure should be designed by you independently based on prediction results
# Please output the report outline in JSON format as follows:
# {
# "title": "Report Title",
# "summary": "Report Summary (One sentence summarizing the core prediction findings)",
# "sections": [
# {
# "title": "Chapter Title",
# "description": "Chapter Content Description"
# }
# ]
# }
# Note: The sections array must have a minimum of 2 and a maximum of 5 elements!
# """
PLAN_SYSTEM_PROMPT = """\
Bạn một chuyên gia viết "Báo cáo Dự báo Tương lai", với "góc nhìn của Chúa" về thế giới phỏng bạn thể thấu hiểu hành vi, lời nói, tương tác của mọi agent trong phỏng.
[Khái niệm Cốt lõi]
Chúng tôi đã xây dựng một thế giới phỏng tiêm các "yêu cầu mô phỏng" cụ thể làm biến số. Kết quả tiến hóa của thế giới phỏng một dự báo về những thể xảy ra trong tương lai. Những bạn đang quan sát không phải "dữ liệu thử nghiệm," "bản xem trước của tương lai."
[Nhiệm vụ của bạn]
Viết một "Báo cáo Dự báo Tương lai" để trả lời:
1. Trong điều kiện chúng tôi đặt ra, tương lai đã xảy ra điều ?
2. Các agent (nhóm) khác nhau đã phản ứng hành động như thế nào?
3. phỏng này tiết lộ những xu hướng rủi ro tương lai nào đáng chú ý?
[Định vị Báo cáo]
- Đây báo cáo dự báo tương lai dựa trên phỏng, tiết lộ "nếu thế này, thì sẽ thế nào"
- Tập trung vào kết quả dự báo: xu hướng sự kiện, phản ứng nhóm, hiện tượng nổi lên, rủi ro tiềm ẩn
- Lời nói hành động của các agent trong thế giới phỏng dự báo về hành vi con người tương lai
- Không phải phân tích tình hình thế giới thực hiện tại
- Không phải tóm tắt luận chung chung
[Giới hạn Số lượng Chương]
- Tối thiểu 2 chương, tối đa 5 chương
- Không cần chương con, viết nội dung hoàn chỉnh trực tiếp cho mỗi chương
- Nội dung nên được tinh gọn, tập trung vào các phát hiện dự báo cốt lõi
- Cấu trúc chương do bạn thiết kế dựa trên kết quả dự báo
Vui lòng xuất cấu trúc báo cáo theo định dạng JSON như sau:
{
"title": "Tiêu đề Báo cáo",
"summary": "Tóm tắt Báo cáo (một câu tóm tắt các phát hiện dự báo cốt lõi)",
"sections": [
{
"title": "Tiêu đề Chương",
"description": "Mô tả Nội dung Chương"
}
]
}
Lưu ý: Mảng sections phải ít nhất 2 tối đa 5 phần tử!
"""
# PLAN_USER_PROMPT_TEMPLATE = """\
# [Prediction Scenario Setting]
# The variables (simulation requirements) we injected into the simulated world: {simulation_requirement}
# [Simulated World Scale]
# - Number of entities participating in the simulation: {total_nodes}
# - Number of relationships generated between entities: {total_edges}
# - Entity type distribution: {entity_types}
# - Number of active Agents: {total_entities}
# [Sample Future Facts Predicted by Simulation]
# {related_facts_json}
# Please examine this future preview from a "God's eye view":
# 1. Under our set conditions, what state did the future present?
# 2. How did various groups (Agents) react and act?
# 3. What noteworthy future trends did this simulation reveal?
# Based on the prediction results, design the most suitable report chapter structure.
# [Reminder again] Report chapter quantity: Minimum 2, maximum 5, content should be concise and focused on core prediction findings.
# """
PLAN_USER_PROMPT_TEMPLATE = """\
[Cài đặt kịch bản dự báo]
Các biến số (yêu cầu phỏng) chúng tôi tiêm vào thế giới phỏng: {simulation_requirement}
[Quy Thế giới phỏng]
- Số lượng thực thể tham gia phỏng: {total_nodes}
- Số lượng quan hệ được tạo giữa các thực thể: {total_edges}
- Phân phối loại thực thể: {entity_types}
- Số lượng agent hoạt động: {total_entities}
[Mẫu sự kiện tương lai được dự báo bởi phỏng]
{related_facts_json}
Vui lòng xem xét bản xem trước tương lai này từ "góc nhìn của Chúa":
1. Trong điều kiện chúng tôi đặt ra, tương lai đã trình bày trạng thái ?
2. Các nhóm (agent) khác nhau đã phản ứng hành động như thế nào?
3. phỏng này tiết lộ những xu hướng tương lai nào?
Dựa trên kết quả dự báo, thiết kế cấu trúc chương báo cáo phù hợp nhất.
[Nhắc lại] Số lượng chương báo cáo: tối thiểu 2, tối đa 5, nội dung nên được tinh gọn tập trung vào các phát hiện dự báo cốt lõi.
"""
# ═══════════════════════════════════════════════════════════════
# SECTION_SYSTEM_PROMPT_TEMPLATE = """\
# You are a writing expert for "Future Prediction Reports", currently writing one section of the report.
# Report Title: {report_title}
# Report Summary: {report_summary}
# Prediction Scenario (Simulation Requirement): {simulation_requirement}
# Section currently being written: {section_title}
# ═══════════════════════════════════════════════════════════════
# [Core Concept]
# ═══════════════════════════════════════════════════════════════
# The simulated world is a preview of the future. We injected specific conditions (simulation requirements) into the simulated world.
# The behaviors and interactions of Agents in the simulation are predictions of future human behavior.
# Your task is to:
# - Reveal what happened in the future under the set conditions
# - Predict how various groups (Agents) reacted and acted
# - Discover noteworthy future trends, risks, and opportunities
# ❌ Do not write this as an analysis of the real world's current status
# ✅ Focus on "what the future will be" - the simulation results are the predicted future
# ═══════════════════════════════════════════════════════════════
# [Most Important Rules - MUST Obey]
# ═══════════════════════════════════════════════════════════════
# 1. [MUST use tools to observe the simulated world]
# - You are observing the future preview from a "God's eye view"
# - All content MUST come from events, words, and actions of Agents occurred in the simulated world
# - It is strictly forbidden to use your own knowledge to write report content
# - For each chapter, you MUST call tools at least 3 times (maximum 5 times) to observe the simulated world, which represents the future
# 2. [MUST quote the exact original words and actions of Agents]
# - The Agent's statements and behaviors are predictions of future human behavior
# - Use quote formatting in the report to display these predictions, for example:
# > "A certain group of people will say: Original content..."
# - These quotes are the core evidence of the simulation prediction
# 3. [Language Consistency - Quoted Content Must Be Translated to Report Language]
# - The content returned by the tools may contain English or mixed Vietnamese and English expressions
# - If the simulation requirements and original materials are in Vietnamese, the report must be written entirely in Vietnamese
# - When you quote English or mixed content returned by the tool, you must translate it into fluent Vietnamese before writing it into the report
# - Keep the original meaning unchanged when translating, and ensure the expression is natural and fluent
# - This rule applies to both the main text and the content in the quote block (> format)
# 4. [Faithful Presentation of Prediction Results]
# - Report content must reflect the simulation results representing the future in the simulated world
# - Do not add information that does not exist in the simulation
# - If information in a certain aspect is insufficient, state it truthfully
# ═══════════════════════════════════════════════════════════════
# [⚠️ Formatting Specifications - Extremely Important!]
# ═══════════════════════════════════════════════════════════════
# [One Chapter = Minimum Content Unit]
# - Each chapter is the minimum blocking unit of the report
# - ❌ Do not use any Markdown headings (#, ##, ###, ####, etc.) within the chapter
# - ❌ Do not add a main chapter heading at the beginning of the content
# - ✅ Chapter titles are added automatically by the system, you only need to write the plain text content
# - ✅ Use **bold text**, paragraph breaks, quotes, and lists to organize content, but do not use headings
# [Correct Example]
# ```
# This chapter analyzes the public opinion dissemination trend of the event. Through deep analysis of simulation data, we found...
# **Initial Outbreak Stage**
# Weibo, as the first scene of public opinion, assumed the core function of initial information release:
# > "Weibo contributed 68% of the initial buzz..."
# **Emotion Amplification Stage**
# The Douyin platform further amplified the event's impact:
# - Strong visual impact
# - High emotional resonance
# ```
# [Incorrect Example]
# ```
# ## Executive Summary ← Error! Do not add any headings
# ### 1. Initial Stage ← Error! Do not use ### for sub-sections
# #### 1.1 Detailed Analysis ← Error! Do not use #### for further division
# This chapter analyzes...
# ```
# ═══════════════════════════════════════════════════════════════
# [Available Retrieval Tools] (Call 3-5 times per section)
# ═══════════════════════════════════════════════════════════════
# {tools_description}
# [Tool Usage Suggestions - Please mix different tools, do not just use one]
# - insight_forge: Deep insight analysis, automatically decomposes questions and retrieves facts and relationships from multiple dimensions
# - panorama_search: Wide-angle panoramic search, understands the whole picture, timeline, and evolution process of an event
# - quick_search: Quickly verifies a specific information point
# - interview_agents: Interviews simulation Agents to get first-person views and real reactions from different roles
# ═══════════════════════════════════════════════════════════════
# [Workflow]
# ═══════════════════════════════════════════════════════════════
# For each reply you can only do one of the following two things (not both simultaneously):
# Option A - Call a tool:
# Output your thoughts, then use the following format to call a tool:
# <tool_call>
# {{"name": "Tool Name", "parameters": {{"Parameter Name": "Parameter Value"}}}}
# </tool_call>
# The system will execute the tool and return the result to you. You do not need to and cannot write the tool return result yourself.
# Option B - Output Final Content:
# When you have obtained enough information through tools, output the chapter content starting with "Final Answer:".
# ⚠️ Strictly Forbidden:
# - Forbidden to include both tool calls and Final Answer in a single reply
# - Forbidden to fabricate tool return results (Observation) yourself, all tool results are injected by the system
# - Call a maximum of one tool per reply
# ═══════════════════════════════════════════════════════════════
# [Chapter Content Requirements]
# ═══════════════════════════════════════════════════════════════
# 1. Content must be based on simulation data retrieved by tools
# 2. Quote the original text extensively to demonstrate the simulation effect
# 3. Use Markdown format (but forbid using headings):
# - Use **bold text** to mark key points (instead of subheadings)
# - Use lists (- or 1. 2. 3.) to organize points
# - Use blank lines to separate different paragraphs
# - ❌ Forbidden to use #, ##, ###, #### and any other heading syntax
# 4. [Quote Formatting Specifications - Must be a separate paragraph]
# Quotes must be an independent paragraph, with a blank line before and after, cannot be mixed in the paragraph:
# ✅ Correct format:
# ```
# The school's response was considered to lack substantive content.
# > "The school's response model appears rigid and slow in the rapidly changing social media environment."
# This evaluation reflects the general dissatisfaction of the public.
# ```
# ❌ Incorrect format:
# ```
# The school's response was considered to lack substantive content. > "The school's response model..." This evaluation reflects...
# ```
# 5. Maintain logical coherence with other chapters
# 6. [Avoid Repetition] Carefully read the completed chapter content below, do not repeat the same information
# 7. [Emphasize Again] Do not add any headings! Use **bold** instead of section headings"""
# SECTION_USER_PROMPT_TEMPLATE = """\
# Completed Chapter Content (Please read carefully to avoid duplication):
# {previous_content}
# ═══════════════════════════════════════════════════════════════
# [Current Task] Writing Chapter: {section_title}
# ═══════════════════════════════════════════════════════════════
# [Important Reminders]
# 1. Read the completed chapters above carefully to avoid repeating the same content!
# 2. Must call tools first to get simulation data before starting
# 3. Please mix different tools, do not use only one
# 4. Report content must come from retrieval results, do not use your own knowledge
# [⚠️ Formatting Warning - Must be Obeyed]
# - ❌ Do not write any headings (no #, ##, ###, ####)
# - ❌ Do not write "{section_title}" as the beginning
# - ✅ Chapter titles are automatically added by the system
# - ✅ Write the main text directly, use **bold** instead of section headings
# Please begin:
# 1. First, think (Thought) what information this chapter needs
# 2. Then, call tools (Action) to get simulation data
# 3. After collecting enough information, output Final Answer (plain text, no headings)
# """
SECTION_SYSTEM_PROMPT_TEMPLATE = """\
Bạn một chuyên gia viết "Báo cáo Dự đoán Tương lai", hiện đang viết một phần trong báo cáo đó.
Tiêu đề báo cáo: {report_title}
Tóm tắt báo cáo: {report_summary}
Kịch bản Dự đoán (Yêu cầu phỏng): {simulation_requirement}
Phần đang được viết: {section_title}
[Khái niệm Cốt lõi]
Thế giới phỏng một bản xem trước của tương lai. Chúng tôi đã đưa các điều kiện cụ thể (yêu cầu phỏng) vào thế giới này.
Các hành vi tương tác của các Tác nhân (Agents) trong quá trình phỏng chính những dự đoán về hành vi của con người trong tương lai.
Nhiệm vụ của bạn :
- Tiết lộ những đã xảy ra trong tương lai theo các điều kiện đã thiết lập
- Dự đoán cách các nhóm khác nhau (Agents) đã phản ứng hành động
- Phát hiện các xu hướng, rủi ro hội đáng chú ý trong tương lai
Không viết nội dung này như một bài phân tích về hiện trạng của thế giới thực
Tập trung vào "tương lai sẽ như thế nào" - kết quả phỏng chính tương lai được dự đoán
[Quy tắc QUAN TRỌNG NHẤT - PHẢI Tuân thủ]
1. [PHẢI sử dụng công cụ để quan sát thế giới phỏng]
- Bạn đang quan sát bản xem trước tương lai từ "góc nhìn của Chúa"
- Tất cả nội dung PHẢI đến từ các sự kiện, lời nói hành động của các Tác nhân đã xảy ra trong thế giới phỏng
- Nghiêm cấm sử dụng kiến thức nhân của bạn để viết nội dung báo cáo
- Đối với mỗi chương, bạn PHẢI gọi công cụ ít nhất 3 lần (tối đa 5 lần) để quan sát thế giới phỏng
2. [PHẢI trích dẫn chính xác nguyên văn lời nói hành động của các Tác nhân]
- Các tuyên bố hành vi của Tác nhân những dự đoán về hành vi con người trong tương lai
- Sử dụng định dạng trích dẫn trong báo cáo để hiển thị các dự đoán này, dụ:
> "Một nhóm người nhất định sẽ nói: [Nội dung gốc]..."
- Những trích dẫn này bằng chứng cốt lõi của dự đoán phỏng
3. [Tính nhất quán về Ngôn ngữ - Nội dung trích dẫn phải được dịch sang ngôn ngữ báo cáo]
- Nội dung trả về từ các công cụ thể chứa tiếng Anh hoặc hỗn hợp tiếng Việt tiếng Anh.
- **Báo cáo phải được viết hoàn toàn bằng tiếng Việt.**
- Khi bạn trích dẫn nội dung tiếng Anh hoặc hỗn hợp từ công cụ, bạn phải dịch sang tiếng Việt lưu loát trước khi đưa vào báo cáo
- Giữ nguyên ý nghĩa gốc khi dịch đảm bảo cách diễn đạt tự nhiên
- Quy tắc này áp dụng cho cả văn bản chính nội dung trong khối trích dẫn (định dạng >)
4. [Trình bày trung thực kết quả dự đoán]
- Nội dung báo cáo phải phản ánh kết quả phỏng đại diện cho tương lai
- Không thêm thông tin không tồn tại trong phỏng
- Nếu thông tin một khía cạnh nào đó không đủ, hãy nêu sự thật
[ Quy cách Định dạng - Cực kỳ Quan trọng!]
[Một Chương = Đơn vị Nội dung Tối thiểu]
- Mỗi chương đơn vị chặn tối thiểu của báo cáo
- Không sử dụng bất kỳ tiêu đề Markdown nào (#, ##, ###, ####, v.v.) trong chương
- Không thêm tiêu đề chương chính đầu nội dung
- Tiêu đề chương được hệ thống tự động thêm vào, bạn chỉ cần viết nội dung văn bản thuần túy
- Sử dụng **chữ đậm**, ngắt đoạn, trích dẫn danh sách để tổ chức nội dung, nhưng không dùng tiêu đề (headings)
[ dụ Đúng]
```
Chương này phân tích xu hướng lan truyền luận của sự kiện. Thông qua phân tích sâu dữ liệu phỏng, chúng tôi nhận thấy...
**Giai đoạn bùng phát ban đầu**
Weibo, với cách bối cảnh đầu tiên của luận, đã đảm nhận chức năng cốt lõi phát hành thông tin ban đầu:
> "Weibo đã đóng góp 68% mức độ thảo luận ban đầu..."
**Giai đoạn khuếch đại cảm xúc**
Nền tảng Douyin đã khuếch đại thêm tác động của sự kiện:
- Tác động thị giác mạnh mẽ
- Cộng hưởng cảm xúc cao
```
[ dụ Sai]
```
## Tóm tắt Điều hành ← Lỗi! Không thêm bất kỳ tiêu đề nào
### 1. Giai đoạn đầu ← Lỗi! Không sử dụng ### cho các mục con
#### 1.1 Phân tích chi tiết ← Lỗi! Không sử dụng #### để chia nhỏ hơn nữa
Chương này phân tích...
```
[Các công cụ truy xuất hiện ] (Gọi 3-5 lần mỗi phần)
{tools_description}
[Gợi ý Sử dụng Công cụ - Vui lòng phối hợp nhiều công cụ, không chỉ dùng một loại]
- insight_forge: Phân tích chuyên sâu, tự động phân tách câu hỏi truy xuất sự thật cũng như các mối quan hệ từ nhiều chiều
- panorama_search: Tìm kiếm toàn cảnh góc rộng, hiểu bức tranh tổng thể, dòng thời gian quá trình diễn biến của một sự kiện
- quick_search: Xác minh nhanh một điểm thông tin cụ thể
- interview_agents: Phỏng vấn các Tác nhân (Agents) phỏng để lấy góc nhìn thứ nhất phản ứng thực tế từ các vai trò khác nhau
[Quy trình làm việc]
Đối với mỗi phản hồi, bạn chỉ thể thực hiện một trong hai việc sau (không làm đồng thời):
Lựa chọn A - Gọi công cụ:
Đưa ra suy nghĩ (Thought) của bạn, sau đó sử dụng định dạng sau để gọi công cụ:
<tool_call>
{{"name": "Tên công cụ", "parameters": {{"Tên tham số": "Giá trị tham số"}}}}
</tool_call>
Hệ thống sẽ thực thi công cụ trả về kết quả cho bạn. Bạn không cần không được phép tự viết kết quả trả về của công cụ.
Lựa chọn B - Xuất nội dung cuối cùng:
Khi bạn đã thu thập đủ thông tin thông qua các công cụ, hãy xuất nội dung chương bắt đầu bằng "Final Answer:".
Nghiêm cấm:
- Cấm bao gồm cả lệnh gọi công cụ Final Answer trong cùng một phản hồi
- Cấm tự bịa đặt kết quả trả về của công cụ (Quan sát), tất cả kết quả công cụ đều do hệ thống đưa vào
- Chỉ gọi tối đa một công cụ cho mỗi phản hồi
[Yêu cầu Nội dung Chương]
1. Nội dung phải dựa trên dữ liệu phỏng do công cụ truy xuất.
2. Trích dẫn rộng rãi văn bản gốc để chứng minh hiệu quả phỏng.
3. Sử dụng định dạng Markdown (nhưng cấm sử dụng tiêu đề):
- Sử dụng **chữ đậm** để đánh dấu các điểm chính (thay dùng tiêu đề phụ).
- Sử dụng danh sách (- hoặc 1. 2. 3.) để tổ chức các ý.
- Sử dụng các dòng trống để phân tách các đoạn văn khác nhau.
- Cấm sử dụng #, ##, ###, #### và bất kỳ cú pháp tiêu đề nào khác.
4. [Quy cách Định dạng Trích dẫn - Phải một đoạn riêng biệt]
Trích dẫn phải một đoạn văn độc lập, dòng trống trước sau, không được viết lẫn vào trong đoạn văn:
Định dạng đúng:
```
Phản ứng của nhà trường bị coi thiếu nội dung thực chất.
> "Mô hình phản ứng của nhà trường có vẻ cứng nhắc và chậm chạp trong môi trường mạng xã hội thay đổi nhanh chóng."
Đánh giá này phản ánh sự không hài lòng chung của công chúng.
```
Định dạng sai:
```
Phản ứng của nhà trường bị coi thiếu nội dung thực chất. > "Mô hình phản ứng của nhà trường..." Đánh giá này phản ánh...
```
5. Duy trì tính logic nhất quán với các chương khác.
6. [Tránh Lặp lại] Đọc kỹ nội dung các chương đã hoàn thành bên dưới, không lặp lại cùng một thông tin.
7. [Nhấn mạnh lại lần nữa] Không thêm bất kỳ tiêu đề nào! Sử dụng **chữ đậm** thay cho tiêu đề mục.
"""
# ═══════════════════════════════════════════════════════════════
# SECTION_USER_PROMPT_TEMPLATE = """\
# Completed Chapter Content (Please read carefully to avoid duplication):
# {previous_content}
# ═══════════════════════════════════════════════════════════════
# [Current Task] Writing Chapter: {section_title}
# ═══════════════════════════════════════════════════════════════
# [Important Reminders]
# 1. Read the completed chapters above carefully to avoid repeating the same content!
# 2. Must call tools first to get simulation data before starting
# 3. Please mix different tools, do not use only one
# 4. Report content must come from retrieval results, do not use your own knowledge
# [⚠️ Formatting Warning - Must be Obeyed]
# - ❌ Do not write any headings (no #, ##, ###, ####)
# - ❌ Do not write "{section_title}" as the beginning
# - ✅ Chapter titles are automatically added by the system
# - ✅ Write the main text directly, use **bold** instead of section headings
# Please begin:
# 1. First, think (Thought) what information this chapter needs
# 2. Then, call tools (Action) to get simulation data
# 3. After collecting enough information, output Final Answer (plain text, no headings)
# """
SECTION_USER_PROMPT_TEMPLATE = """\
Nội dung Chương đã Hoàn thành (Vui lòng đọc kỹ để tránh trùng lặp):
{previous_content}
[Nhiệm vụ Hiện tại] Viết Chương: {section_title}
[Nhắc nhở Quan trọng]
1. Đọc kỹ các chương đã hoàn thành trên để tránh lặp lại nội dung!
2. Phải gọi công cụ trước để lấy dữ liệu phỏng trước khi bắt đầu viết.
3. Vui lòng sử dụng kết hợp nhiều công cụ khác nhau, không chỉ dùng một loại.
4. Nội dung báo cáo phải đến từ kết quả truy xuất, không sử dụng kiến thức nhân của bạn.
[ Cảnh báo Định dạng - Phải Tuân thủ Tuyệt đối]
- Không viết bất kỳ tiêu đề nào (không dùng các tự #, ##, ###, ####).
- Không viết "{section_title}" phần bắt đầu nội dung.
- Tiêu đề chương sẽ được hệ thống tự động thêm vào sau đó.
- Viết trực tiếp vào nội dung chính, sử dụng văn bản **in đậm** thay cho tiêu đề các mục.
Vui lòng bắt đầu:
1. Đầu tiên, hãy suy nghĩ (Thought) xem chương này cần những thông tin .
2. Sau đó, gọi công cụ (Action) để lấy dữ liệu phỏng.
3. Sau khi thu thập đủ thông tin, xuất Câu trả lời cuối cùng (Final Answer) dưới dạng văn bản thuần túy, không chứa tiêu đề.
"""
# ═══════════════════════════════════════════════════════════════
# REACT_OBSERVATION_TEMPLATE = """\
# Observation (Retrieval Result):
# ═══ Tool {tool_name} Returned ═══
# {result}
# ═══════════════════════════════════════════════════════════════
# Tool called {tool_calls_count}/{max_tool_calls} times (Used: {used_tools_str}) {unused_hint}
# - If information is sufficient: Output section content starting with "Final Answer:" (Must quote the above original text)
# - If more information is needed: Call a tool to continue retrieving
# ═══════════════════════════════════════════════════════════════
# """
REACT_OBSERVATION_TEMPLATE = """\
Quan sát (Kết quả Truy xuất):
Công cụ {tool_name} đã trả về
{result}
Công cụ đã được gọi {tool_calls_count}/{max_tool_calls} lần (Đã dùng: {used_tools_str}) {unused_hint}
- Nếu thông tin đã đủ: Xuất nội dung phần báo cáo bắt đầu bằng "Final Answer:" (Bắt buộc trích dẫn văn bản gốc trên)
- Nếu cần thêm thông tin: Tiếp tục gọi công cụ để truy xuất
"""
# ═══════════════════════════════════════════════════════════════
# REACT_INSUFFICIENT_TOOLS_MSG = (
# "[Notice] You only called the tool {tool_calls_count} times, at least {min_tool_calls} times are needed. "
# "Please call the tool again to fetch more simulation data, and then output Final Answer. {unused_hint}"
# )
REACT_INSUFFICIENT_TOOLS_MSG = (
"[Thông báo] Bạn mới chỉ gọi công cụ {tool_calls_count} lần, trong khi yêu cầu tối thiểu là {min_tool_calls} lần. "
"Vui lòng gọi lại công cụ để lấy thêm dữ liệu mô phỏng, sau đó mới xuất Câu trả lời cuối cùng (Final Answer). {unused_hint}"
)
# ═══════════════════════════════════════════════════════════════
# REACT_INSUFFICIENT_TOOLS_MSG_ALT = (
# "Currently tool called {tool_calls_count} times, at least {min_tool_calls} times are needed. "
# "Please call tools to fetch simulation data. {unused_hint}"
# )
REACT_INSUFFICIENT_TOOLS_MSG_ALT = (
"Hiện tại công cụ mới được gọi {tool_calls_count} lần, yêu cầu ít nhất {min_tool_calls} lần. "
"Vui lòng gọi các công cụ để truy xuất dữ liệu mô phỏng. {unused_hint}"
)
# ═══════════════════════════════════════════════════════════════
# REACT_TOOL_LIMIT_MSG = (
# "Tool call limit reached ({tool_calls_count}/{max_tool_calls}), cannot call tools anymore. "
# 'Please output your section content starting with "Final Answer:" immediately based on retrieved information.'
# )
REACT_TOOL_LIMIT_MSG = (
"Đã đạt giới hạn gọi công cụ ({tool_calls_count}/{max_tool_calls}), không thể gọi thêm công cụ nữa. "
'Vui lòng xuất nội dung phần báo cáo bắt đầu bằng "Final Answer:" ngay lập tức dựa trên những thông tin đã truy xuất được.'
)
# ═══════════════════════════════════════════════════════════════
# REACT_UNUSED_TOOLS_HINT = "\n💡 You haven't used: {unused_list}, suggesting trying different tools for multiple perspectives"
REACT_UNUSED_TOOLS_HINT = "\n💡 Bạn chưa sử dụng: {unused_list}, hãy thử các công cụ khác nhau để có cái nhìn đa chiều hơn"
# ═══════════════════════════════════════════════════════════════
# REACT_FORCE_FINAL_MSG = "Tool call limit reached, please output Final Answer: and generate section content directly."
REACT_FORCE_FINAL_MSG = "Đã đạt giới hạn gọi công cụ, vui lòng xuất Final Answer: và trực tiếp tạo nội dung cho phần này."
# ═══════════════════════════════════════════════════════════════
# CHAT_SYSTEM_PROMPT_TEMPLATE = """\
# You are a concise and efficient simulation prediction assistant.
# [Background]
# Prediction condition: {simulation_requirement}
# [Generated Analysis Report]
# {report_content}
# [Rules]
# 1. Prioritize answering based on the report content above
# 2. Answer the question directly, avoid lengthy reasoning
# 3. Only call tools to retrieve more data if the report content is insufficient to answer
# 4. Answers must be concise, clear, and organized
# [Available Tools] (Use only when necessary, call 1-2 times max)
# {tools_description}
# [Tool Call Format]
# <tool_call>
# {{"name": "Tool Name", "parameters": {{"Parameter Name": "Parameter Value"}}}}
# </tool_call>
# [Answering Style]
# - Concise and direct, avoid long paragraphs
# - Use > format to quote key content
# - Provide conclusion first, then explain the reason
# """
CHAT_SYSTEM_PROMPT_TEMPLATE = """
Bạn một trợ dự đoán phỏng súc tích hiệu quả.
[Bối cảnh]
Điều kiện dự đoán: {simulation_requirement}
[Báo cáo Phân tích Đã tạo]
{report_content}
[Quy tắc]
1. Ưu tiên trả lời dựa trên nội dung báo cáo trên.
2. Trả lời câu hỏi trực tiếp, tránh lập luận dài dòng.
3. Chỉ gọi công cụ để truy xuất thêm dữ liệu nếu nội dung báo cáo không đủ để trả lời.
4. Câu trả lời phải súc tích, ràng tổ chức.
[Các Công cụ Hiện ] (Chỉ sử dụng khi cần thiết, gọi tối đa 1-2 lần)
{tools_description}
[Định dạng Gọi Công cụ]
<tool_call>
{{"name": "Tên Công cụ", "parameters": {{"Tên Tham số": "Giá trị Tham số"}}}}
</tool_call>
[Phong cách Trả lời]
- Ngắn gọn trực tiếp, tránh các đoạn văn dài.
- Sử dụng định dạng > để trích dẫn nội dung chính.
- Đưa ra kết luận trước, sau đó mới giải thích do.
"""
# ═══════════════════════════════════════════════════════════════
# CHAT_OBSERVATION_SUFFIX = "\n\nPlease answer the question concisely."
CHAT_OBSERVATION_SUFFIX = "\n\nVui lòng trả lời câu hỏi một cách súc tích."
# ═══════════════════════════════════════════════════════════════
# Class chính: ReportAgent
# ═══════════════════════════════════════════════════════════════

File diff suppressed because it is too large Load Diff

View File

@ -137,7 +137,7 @@ class SimulationIPCClient:
TimeoutError: Lỗi quá thời gian chờ phản hồi
"""
command_id = str(uuid.uuid4())
command = IPCCommand(
command = s(
command_id=command_id,
command_type=command_type,
args=args

File diff suppressed because it is too large Load Diff

View File

@ -1741,7 +1741,7 @@ Trả về định dạng JSON: {"questions": ["Câu hỏi 1", "Câu hỏi 2", .
Bối cảnh phỏng: {simulation_requirement if simulation_requirement else "Not provided"}
Vai trò của đối tượng phỏng vấ: {', '.join(agent_roles)}
Vai trò của đối tượng phỏng vấn: {', '.join(agent_roles)}
Hãy tạo từ 3-5 câu hỏi phỏng vấn."""

View File

@ -41,7 +41,7 @@ class LLMClient:
self,
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 4096,
max_tokens: int = 16000,
response_format: Optional[Dict] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> str:

View File

@ -22,6 +22,7 @@ from typing import Any, Dict, Optional
MODEL_COSTS_PER_1M_TOKENS: Dict[str, Dict[str, float]] = {
"Qwen/Qwen3.5-27B": {"input": 0.5, "output": 3.0},
"Qwen/Qwen3.6-27B": {"input": 0.5, "output": 3.0},
"gemini-3-flash": {"input": 0.5, "output": 3.0},
"gemini-3.1-flash-lite": {"input": 0.25, "output": 1.5},
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "1606cd6c",
"metadata": {},
"outputs": [],
"source": [
"import json"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "69ce47c3",
"metadata": {},
"outputs": [],
"source": [
"input = \"/home/anman/intern/MiroFish/backend/logs/proj_ac763defa255/cost_Qwen_Qwen3.6-27B-FP8.jsonl\"\n",
"\n",
"data=[]\n",
"with open(input, 'r', encoding='utf-8') as f:\n",
" data = [json.loads(line.strip()) for line in f if line.strip()]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "6f1fe377",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Input Tokens: 49830604\n",
"Output Tokens: 5432209\n"
]
}
],
"source": [
"input_tokens = 0\n",
"output_tokens = 0\n",
"for item in data:\n",
" input_tokens += item['input_tokens']\n",
" output_tokens += item['output_tokens']\n",
"\n",
"print(f\"Input Tokens: {input_tokens}\")\n",
"print(f\"Output Tokens: {output_tokens}\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "95cce20c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Total Cost: $41.2119\n",
"Cost Breakdown: Input Cost = $24.9153, Output Cost = $16.2966\n"
]
}
],
"source": [
"cost_1M_input = 0.5\n",
"cost_1M_output = 3.0\n",
"\n",
"total_cost = (input_tokens / 1_000_000) * cost_1M_input + (output_tokens / 1_000_000) * cost_1M_output\n",
"print(f\"Total Cost: ${total_cost:.4f}\")\n",
"print(f\"Cost Breakdown: Input Cost = ${(input_tokens / 1_000_000) * cost_1M_input:.4f}, Output Cost = ${(output_tokens / 1_000_000) * cost_1M_output:.4f}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "273cd657",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "mirofish_v1",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.15"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -100,6 +100,8 @@ Lưu lại đường dẫn `combined_file` để dùng ở bước tiếp theo.
```bash
COMBINED_FILE="/home/anman/intern/MiroFish/test_code_backend/full_pipeline/data/articles_combined.md"
COMBINED_FILE="/home/anman/intern/MiroFish/data/news/2026-02/2026-02-03_oil-prices-add-gains-after-report-says_0178c4.md"
curl -s http://localhost:5001/api/graph/ontology/generate \
-F "files=@${COMBINED_FILE};filename=articles.md" \
-F "simulation_requirement=Analyze how these oil and financial market news articles affect investor sentiment and market dynamics. Predict how different market participants (traders, analysts, retail investors) will react and what the overall price trend will be." \
@ -248,6 +250,38 @@ curl -s http://localhost:5001/api/report/$REPORT_ID/download -o report.md
echo "Saved to report.md"
```
Nếu sim đã có report rồi mà muốn chạy lại thì dùng như sau
```bash
SIM_ID="sim_xxxxxxxxxxxx"
SIM_ID="sim_07ab325b3818"
# 1. Bắt đầu generate → lấy task_id và report_id
RESP=$(curl -s http://localhost:5001/api/report/generate \
-H "Content-Type: application/json" \
-d "{\"simulation_id\": \"$SIM_ID\", \"force_regenerate\": true}")
TASK_ID=$(echo "$RESP" | jq -r '.data.task_id')
REPORT_ID=$(echo "$RESP" | jq -r '.data.report_id')
echo "task_id=$TASK_ID report_id=$REPORT_ID"
# 2. Poll đến khi completed (chạy lặp lại, ~515 phút)
while true; do
R=$(curl -s http://localhost:5001/api/report/generate/status \
-H "Content-Type: application/json" \
-d "{\"task_id\": \"$TASK_ID\"}")
ST=$(echo "$R" | jq -r '.data.status')
PG=$(echo "$R" | jq -r '.data.progress')
echo "$ST ${PG}%"
[[ "$ST" == "completed" ]] && break
[[ "$ST" == "failed" ]] && { echo "FAILED"; break; }
sleep 15
done
# 3. Download file Markdown
curl -s http://localhost:5001/api/report/$REPORT_ID/download -o report.md
echo "Saved to report.md"
```
---
## Output files

View File

@ -10,7 +10,7 @@ full_content = False
# start_time = 2026-02-09
# end_time = 2026-02-12
start_time = 2026-04-13
end_time = 2026-04-16
end_time = 2026-04-14
# ─── Simulation settings ──────────────────────────────────────────────────────
# What the simulation should analyse / predict (sent to the LLM)

View File

@ -1,197 +0,0 @@
"""
Test: Knowledge Graph build on Zep Cloud
Input : - output/ontology/ontology_*.json (latest, or pass path as arg)
- news articles (same date range as ontology)
Output: output/graph/
graph_<graph_id>.json build summary (node/edge count, timing)
entities_<graph_id>.json entity detail: raw nodes + filtered result
Run:
python build_graph.py # auto-picks latest ontology
python build_graph.py output/ontology/ontology_xyz.json # specific ontology file
"""
import sys
import json
import time
import argparse
from datetime import datetime, date
from pathlib import Path
# ── Path setup ───────────────────────────────────────────────────────────────
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent.parent
BACKEND_DIR = PROJECT_ROOT / "backend"
ONTOLOGY_DIR = SCRIPT_DIR.parent / "output" / "ontology"
GRAPH_DIR = SCRIPT_DIR.parent / "output" / "graph"
NEWS_DIR = PROJECT_ROOT / "data" / "news" / "2026-04"
sys.path.insert(0, str(BACKEND_DIR))
GRAPH_DIR.mkdir(parents=True, exist_ok=True)
# ── Config ───────────────────────────────────────────────────────────────────
START_DATE = date(2026, 4, 20)
END_DATE = date(2026, 4, 22)
GRAPH_NAME = "MiroFish_Test_Apr2026"
CHUNK_SIZE = 500
CHUNK_OVERLAP = 50
BATCH_SIZE = 3
POLL_TIMEOUT = 600
# ── Helpers ──────────────────────────────────────────────────────────────────
def log(msg: str):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
def extract_body(md_text: str) -> str:
s = md_text.strip()
if s.startswith("---"):
end = s.find("---", 3)
if end != -1:
return s[end + 3:].strip()
return s
def load_combined_text(news_dir: Path, start: date, end: date) -> str:
parts = []
for md_file in sorted(news_dir.glob("*.md")):
try:
file_date = date.fromisoformat(md_file.stem.split("_")[0])
except ValueError:
continue
if not (start <= file_date <= end):
continue
body = extract_body(md_file.read_text(encoding="utf-8"))
if body:
parts.append(body)
return "\n\n---\n\n".join(parts)
def pick_ontology_file(arg_path: str | None) -> Path:
if arg_path:
p = Path(arg_path)
if not p.is_absolute():
p = ONTOLOGY_DIR / p
if not p.exists():
raise FileNotFoundError(f"Ontology file not found: {p}")
return p
candidates = sorted(ONTOLOGY_DIR.glob("ontology_*.json"), key=lambda f: f.stat().st_mtime)
if not candidates:
raise FileNotFoundError(
f"No ontology_*.json found in {ONTOLOGY_DIR}. Run gen_ontology.py first."
)
return candidates[-1] # latest
# ── Main ─────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(description="Build Zep Knowledge Graph from ontology")
parser.add_argument("ontology_file", nargs="?", help="Path to ontology JSON (default: latest in output/)")
args = parser.parse_args()
from app.services.graph_builder import GraphBuilderService
from app.services.text_processor import TextProcessor
from app.services.zep_entity_reader import ZepEntityReader
# Load ontology
ontology_path = pick_ontology_file(args.ontology_file)
log(f"Using ontology: {ontology_path.name}")
with open(ontology_path, encoding="utf-8") as f:
payload = json.load(f)
ontology = payload["ontology"]
# Load news text
log(f"Loading news text: {START_DATE}{END_DATE}")
combined_text = load_combined_text(NEWS_DIR, START_DATE, END_DATE)
log(f" Text length: {len(combined_text):,} chars")
svc = GraphBuilderService()
t_total = time.time()
# Create graph
log("Creating Zep graph...")
graph_id = svc.create_graph(GRAPH_NAME)
log(f" graph_id = {graph_id}")
# Apply ontology
log("Applying ontology schema...")
svc.set_ontology(graph_id, ontology)
# Chunk & upload
chunks = TextProcessor.split_text(combined_text, CHUNK_SIZE, CHUNK_OVERLAP)
log(f"Uploading {len(chunks)} chunks (batch_size={BATCH_SIZE})...")
episode_uuids = svc.add_text_batches(
graph_id, chunks, BATCH_SIZE,
progress_callback=lambda msg, _: log(f" {msg}"),
)
log(f" {len(episode_uuids)} episodes uploaded")
# Wait for processing
log("Waiting for Zep to process episodes...")
svc._wait_for_episodes(
episode_uuids,
progress_callback=lambda msg, _: log(f" {msg}"),
timeout=POLL_TIMEOUT,
)
# Fetch result
log("Fetching graph stats...")
graph_info = svc._get_graph_info(graph_id)
elapsed = round(time.time() - t_total, 2)
log(f"Done in {elapsed}s — nodes={graph_info.node_count}, edges={graph_info.edge_count}")
log(f" Entity types: {graph_info.entity_types}")
out_path = GRAPH_DIR / f"graph_{graph_id}.json"
with open(out_path, "w", encoding="utf-8") as f:
json.dump({
"graph_id": graph_id,
"graph_name": GRAPH_NAME,
"built_at": datetime.now().isoformat(),
"elapsed_seconds": elapsed,
"ontology_source": ontology_path.name,
"date_range": {"start": str(START_DATE), "end": str(END_DATE)},
"chunks_uploaded": len(chunks),
"node_count": graph_info.node_count,
"edge_count": graph_info.edge_count,
"entity_types": graph_info.entity_types,
}, f, ensure_ascii=False, indent=2)
log(f"Saved → {out_path.name}")
# ── Entity detail ─────────────────────────────────────────────────────────
# Raw graph data — lưu nguyên output của get_graph_data()
log("Fetching raw graph data...")
graph_data = svc.get_graph_data(graph_id)
log(f" nodes={graph_data['node_count']}, edges={graph_data['edge_count']}")
# Filtered entities — lưu nguyên output của filter_defined_entities().to_dict()
log("Running entity filter...")
defined_types = [e["name"] for e in ontology.get("entity_types", [])]
reader = ZepEntityReader()
filtered = reader.filter_defined_entities(
graph_id=graph_id,
defined_entity_types=defined_types,
enrich_with_edges=True,
)
log(f" total={filtered.total_count}, matched={filtered.filtered_count}")
log(f" types found: {sorted(filtered.entity_types)}")
entities_path = GRAPH_DIR / f"entities_{graph_id}.json"
with open(entities_path, "w", encoding="utf-8") as f:
json.dump({
"graph_id": graph_id,
"fetched_at": datetime.now().isoformat(),
"ontology_entity_types": defined_types,
"raw_graph_data": graph_data,
"filtered_entities": filtered.to_dict(),
}, f, ensure_ascii=False, indent=2)
log(f"Saved → {entities_path.name}")
if __name__ == "__main__":
main()

View File

@ -1,109 +0,0 @@
"""
Test: Ontology generation from news articles
Input : data/news/2026-04/ (date range configured below)
Output: test_code_backend/output/ontology/ontology_<daterange>_<timestamp>.json
Run:
python gen_ontology.py
"""
import sys
import json
import time
from datetime import datetime, date
from pathlib import Path
# ── Path setup ───────────────────────────────────────────────────────────────
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent.parent
BACKEND_DIR = PROJECT_ROOT / "backend"
ONTOLOGY_DIR = SCRIPT_DIR.parent / "output" / "ontology"
NEWS_DIR = PROJECT_ROOT / "data" / "news" / "2026-04"
sys.path.insert(0, str(BACKEND_DIR))
ONTOLOGY_DIR.mkdir(parents=True, exist_ok=True)
# ── Config ───────────────────────────────────────────────────────────────────
START_DATE = date(2026, 4, 20)
END_DATE = date(2026, 4, 22)
SIMULATION_REQUIREMENT = (
"Simulate social media public opinion dynamics around global oil/energy markets "
"and US-Iran geopolitical tensions during April 2026. "
"Focus on how governments, corporations, media outlets, financial analysts, and "
"ordinary citizens react and interact on platforms like Twitter and Reddit."
)
# ── Helpers ──────────────────────────────────────────────────────────────────
def log(msg: str):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
def extract_body(md_text: str) -> str:
"""Strip YAML frontmatter (---...---), return only article body."""
s = md_text.strip()
if s.startswith("---"):
end = s.find("---", 3)
if end != -1:
return s[end + 3:].strip()
return s
def load_articles(news_dir: Path, start: date, end: date) -> list[dict]:
articles = []
for md_file in sorted(news_dir.glob("*.md")):
try:
file_date = date.fromisoformat(md_file.stem.split("_")[0])
except ValueError:
continue
if not (start <= file_date <= end):
continue
body = extract_body(md_file.read_text(encoding="utf-8"))
if body:
articles.append({"filename": md_file.name, "date": str(file_date), "body": body})
return articles
# ── Main ─────────────────────────────────────────────────────────────────────
def main():
from app.services.ontology_generator import OntologyGenerator
log(f"Loading news: {START_DATE}{END_DATE}")
articles = load_articles(NEWS_DIR, START_DATE, END_DATE)
log(f" {len(articles)} articles loaded")
log("Calling LLM to generate ontology...")
t0 = time.time()
ontology = OntologyGenerator().generate(
document_texts=[a["body"] for a in articles],
simulation_requirement=SIMULATION_REQUIREMENT,
)
elapsed = round(time.time() - t0, 2)
entity_names = [e["name"] for e in ontology.get("entity_types", [])]
edge_names = [e["name"] for e in ontology.get("edge_types", [])]
log(f"Done in {elapsed}s")
log(f" Entities ({len(entity_names)}): {entity_names}")
log(f" Edges ({len(edge_names)}): {edge_names}")
date_range = f"{START_DATE.strftime('%Y%m%d')}-{END_DATE.strftime('%Y%m%d')}"
ts = datetime.now().strftime("%H%M%S")
out_path = ONTOLOGY_DIR / f"ontology_{date_range}_{ts}.json"
with open(out_path, "w", encoding="utf-8") as f:
json.dump({
"meta": {
"generated_at": datetime.now().isoformat(),
"elapsed_seconds": elapsed,
"date_range": {"start": str(START_DATE), "end": str(END_DATE)},
"article_count": len(articles),
},
"ontology": ontology,
}, f, ensure_ascii=False, indent=2)
log(f"Saved → {out_path.name}")
if __name__ == "__main__":
main()