This commit is contained in:
ththu0205 2026-05-06 03:01:00 +00:00
parent 8679916ced
commit e0f2308e4d
7 changed files with 79 additions and 10 deletions

View File

@ -334,6 +334,16 @@ class SimulationManager:
elif state.enable_twitter:
realtime_output_path = os.path.join(sim_dir, "twitter_profiles.csv")
realtime_platform = "twitter"
# Nền tảng dùng cho metadata cost.
if state.enable_twitter and state.enable_reddit:
runtime_platform = "parallel"
elif state.enable_twitter:
runtime_platform = "twitter"
elif state.enable_reddit:
runtime_platform = "reddit"
else:
runtime_platform = None
profiles = generator.generate_profiles_from_entities(
entities=filtered.entities,
@ -343,6 +353,7 @@ class SimulationManager:
parallel_count=parallel_profile_count, # Số dòng luồng Async
realtime_output_path=realtime_output_path, # Lưu log thời gian thực
output_platform=realtime_platform, # Đuôi file xuất
metadata_platform=runtime_platform,
simulation_id=simulation_id,
project_id=state.project_id,
)

View File

@ -54,7 +54,7 @@ class TextProcessor:
# Xoá các dòng trống liên tiếp (Chỉ giữ lại tối đa 2 lần xuống dòng liên tiếp)
text = re.sub(r'\n{3,}', '\n\n', text)
# 移除行首行尾空白
# Loại bỏ khoảng trắng đầu và cuối
lines = [line.strip() for line in text.split('\n')]
text = '\n'.join(lines)

View File

@ -20,6 +20,36 @@ def _build_metadata(model: str) -> Dict[str, Any]:
return metadata
def _normalize_messages_for_qwen(messages: Any) -> Any:
"""Ensure Qwen-compatible ordering: a single system message at index 0."""
if not isinstance(messages, list):
return messages
if not messages:
return messages
system_contents = []
non_system_messages = []
for item in messages:
if isinstance(item, dict) and str(item.get("role", "")).lower() == "system":
content = item.get("content")
if content is not None and str(content).strip():
system_contents.append(str(content))
continue
non_system_messages.append(item)
# No system messages detected, keep original payload.
if not system_contents:
return messages
merged_system = {
"role": "system",
"content": "\n\n".join(system_contents),
}
return [merged_system] + non_system_messages
def install_openai_cost_patch(
*,
simulation_id: Optional[str],
@ -58,6 +88,9 @@ def install_openai_cost_patch(
def sync_create_wrapper(self, *args, **kwargs):
model = kwargs.get("model", "unknown_model")
if "qwen" in str(model).lower() and "messages" in kwargs:
kwargs = dict(kwargs)
kwargs["messages"] = _normalize_messages_for_qwen(kwargs.get("messages"))
response = original_sync_create(self, *args, **kwargs)
try:
record_llm_cost(
@ -71,6 +104,9 @@ def install_openai_cost_patch(
async def async_create_wrapper(self, *args, **kwargs):
model = kwargs.get("model", "unknown_model")
if "qwen" in str(model).lower() and "messages" in kwargs:
kwargs = dict(kwargs)
kwargs["messages"] = _normalize_messages_for_qwen(kwargs.get("messages"))
response = await original_async_create(self, *args, **kwargs)
try:
record_llm_cost(

View File

@ -361,7 +361,7 @@ class ParallelIPCHandler:
"""
# Nếu có chỉ định nền tảng, chỉ phỏng vấn trên nền tảng đó
if platform in ("twitter", "reddit"):
result = await self._interview_single_platform(agent_id, prompt, platform)
result = await self._interview_single_platform(agent_id, prompt, platform)
if "error" in result:
self.send_response(command_id, "failed", error=result["error"])
@ -996,11 +996,27 @@ def create_model(config: Dict[str, Any], use_boost: bool = False):
config: Dictionary cấu hình phỏng
use_boost: dùng cấu hình LLM tăng tốc hay không (nếu khả dụng)
"""
# Kiểm tra có cấu hình tăng tốc không
def _is_placeholder(value: str) -> bool:
v = (value or "").strip().lower()
return v in {"your_api_key_here", "your_base_url_here", "your_model_name_here"}
def _is_http_url(value: str) -> bool:
v = (value or "").strip().lower()
return v.startswith("http://") or v.startswith("https://")
# Kiểm tra có cấu hình tăng tốc hợp lệ không
boost_api_key = os.environ.get("LLM_BOOST_API_KEY", "")
boost_base_url = os.environ.get("LLM_BOOST_BASE_URL", "")
boost_model = os.environ.get("LLM_BOOST_MODEL_NAME", "")
has_boost_config = bool(boost_api_key)
has_boost_config = (
bool(boost_api_key.strip())
and bool(boost_model.strip())
and bool(boost_base_url.strip())
and not _is_placeholder(boost_api_key)
and not _is_placeholder(boost_base_url)
and not _is_placeholder(boost_model)
and _is_http_url(boost_base_url)
)
# Chọn LLM theo tham số và trạng thái cấu hình
if use_boost and has_boost_config:
@ -1011,6 +1027,8 @@ def create_model(config: Dict[str, Any], use_boost: bool = False):
config_label = "[Boost LLM]"
else:
# Dùng cấu hình chung
if use_boost and not has_boost_config:
print("[Boost LLM] Invalid or placeholder boost config, fallback to [General LLM].")
llm_api_key = os.environ.get("LLM_API_KEY", "")
llm_base_url = os.environ.get("LLM_BASE_URL", "")
llm_model = os.environ.get("LLM_MODEL_NAME", "")
@ -1028,6 +1046,10 @@ def create_model(config: Dict[str, Any], use_boost: bool = False):
raise ValueError("Missing API key config. Please set LLM_API_KEY in the project root .env file")
if llm_base_url:
if not _is_http_url(llm_base_url):
raise ValueError(
f"Invalid LLM base URL: {llm_base_url}. It must start with http:// or https://"
)
os.environ["OPENAI_API_BASE_URL"] = llm_base_url
print(f"{config_label} model={llm_model}, base_url={llm_base_url[:40] if llm_base_url else 'default'}...")

View File

@ -862,7 +862,7 @@ const parseInterview = (text) => {
const quotesText = quotesMatch[1]
// Prioritize matching > "text" format
let quoteMatches = quotesText.match(/> "([^"]+)"/g)
// Backtrack: Matches > "text" or > \u201Ctext\u201D (Chinese quotation marks)
// Backtrack: Matches > "text" or > \u201Ctext\u201D (Vietnamese quotation marks)
if (!quoteMatches) {
quoteMatches = quotesText.match(/> [\u201C""]([^\u201D""]+)[\u201D""]/g)
}
@ -2089,9 +2089,9 @@ const extractFinalContent = (response) => {
}
// Try to find the content after "Final Answer:"
const chineseFinalMatch = response.match(/Final Answer[:]\s*\n*([\s\S]*)$/i)
if (chineseFinalMatch) {
return chineseFinalMatch[1].trim()
const vietnameseFinalMatch = response.match(/Final Answer[:]\s*\n*([\s\S]*)$/i)
if (vietnameseFinalMatch) {
return vietnameseFinalMatch[1].trim()
}
// Nếu bt đu bng ## hoc # hoc >, có th là ni dung markdown trc tiếp

View File

@ -176,7 +176,7 @@
<textarea
v-model="formData.simulationRequirement"
class="code-input"
placeholder="// Describe your simulation or prediction request in natural language (e.g. If Wuhan University announces the revocation of disciplinary action against someone, what public opinion trends would emerge?)"
placeholder="Describe your simulation or prediction request in natural language (e.g. If Wuhan University announces the revocation of disciplinary action against someone, what public opinion trends would emerge?)"
rows="6"
:disabled="loading"
></textarea>

View File

@ -1,7 +1,7 @@
{
"name": "mirofish",
"version": "0.1.0",
"description": "MiroFish - 简洁通用的群体智能引擎,预测万物",
"description": "MiroFish - A simple and versatile swarm intelligence engine that predicts everything",
"scripts": {
"setup": "npm install && cd frontend && npm install",
"setup:backend": "cd backend && uv sync",