feat:为表达添加创建时间

This commit is contained in:
SengokuCola
2025-07-24 00:36:53 +08:00
parent 936091fe7f
commit b4a92ee5d5
5 changed files with 86 additions and 13 deletions

View File

@@ -2,6 +2,7 @@ import time
import random import random
import json import json
import os import os
from datetime import datetime
from typing import List, Dict, Optional, Any, Tuple from typing import List, Dict, Optional, Any, Tuple
@@ -21,6 +22,16 @@ DECAY_MIN = 0.01 # 最小衰减值
logger = get_logger("expressor") logger = get_logger("expressor")
def format_create_date(timestamp: float) -> str:
"""
将时间戳格式化为可读的日期字符串
"""
try:
return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
except (ValueError, OSError):
return "未知时间"
def init_prompt() -> None: def init_prompt() -> None:
learn_style_prompt = """ learn_style_prompt = """
{chat_str} {chat_str}
@@ -77,6 +88,7 @@ class ExpressionLearner:
) )
self.llm_model = None self.llm_model = None
self._auto_migrate_json_to_db() self._auto_migrate_json_to_db()
self._migrate_old_data_create_date()
def _auto_migrate_json_to_db(self): def _auto_migrate_json_to_db(self):
""" """
@@ -127,6 +139,7 @@ class ExpressionLearner:
last_active_time=last_active_time, last_active_time=last_active_time,
chat_id=chat_id, chat_id=chat_id,
type=type_str, type=type_str,
create_date=last_active_time, # 迁移时使用last_active_time作为创建时间
) )
logger.info(f"已迁移 {expr_file} 到数据库") logger.info(f"已迁移 {expr_file} 到数据库")
except Exception as e: except Exception as e:
@@ -139,6 +152,27 @@ class ExpressionLearner:
except Exception as e: except Exception as e:
logger.error(f"写入done.done标记文件失败: {e}") logger.error(f"写入done.done标记文件失败: {e}")
def _migrate_old_data_create_date(self):
"""
为没有create_date的老数据设置创建日期
使用last_active_time作为create_date的默认值
"""
try:
# 查找所有create_date为空的表达方式
old_expressions = Expression.select().where(Expression.create_date.is_null())
updated_count = 0
for expr in old_expressions:
# 使用last_active_time作为create_date
expr.create_date = expr.last_active_time
expr.save()
updated_count += 1
if updated_count > 0:
logger.info(f"已为 {updated_count} 个老的表达方式设置创建日期")
except Exception as e:
logger.error(f"迁移老数据创建日期失败: {e}")
def get_expression_by_chat_id(self, chat_id: str) -> Tuple[List[Dict[str, float]], List[Dict[str, float]]]: def get_expression_by_chat_id(self, chat_id: str) -> Tuple[List[Dict[str, float]], List[Dict[str, float]]]:
""" """
获取指定chat_id的style和grammar表达方式 获取指定chat_id的style和grammar表达方式
@@ -150,6 +184,8 @@ class ExpressionLearner:
# 直接从数据库查询 # 直接从数据库查询
style_query = Expression.select().where((Expression.chat_id == chat_id) & (Expression.type == "style")) style_query = Expression.select().where((Expression.chat_id == chat_id) & (Expression.type == "style"))
for expr in style_query: for expr in style_query:
# 确保create_date存在如果不存在则使用last_active_time
create_date = expr.create_date if expr.create_date is not None else expr.last_active_time
learnt_style_expressions.append( learnt_style_expressions.append(
{ {
"situation": expr.situation, "situation": expr.situation,
@@ -158,10 +194,13 @@ class ExpressionLearner:
"last_active_time": expr.last_active_time, "last_active_time": expr.last_active_time,
"source_id": chat_id, "source_id": chat_id,
"type": "style", "type": "style",
"create_date": create_date,
} }
) )
grammar_query = Expression.select().where((Expression.chat_id == chat_id) & (Expression.type == "grammar")) grammar_query = Expression.select().where((Expression.chat_id == chat_id) & (Expression.type == "grammar"))
for expr in grammar_query: for expr in grammar_query:
# 确保create_date存在如果不存在则使用last_active_time
create_date = expr.create_date if expr.create_date is not None else expr.last_active_time
learnt_grammar_expressions.append( learnt_grammar_expressions.append(
{ {
"situation": expr.situation, "situation": expr.situation,
@@ -170,10 +209,40 @@ class ExpressionLearner:
"last_active_time": expr.last_active_time, "last_active_time": expr.last_active_time,
"source_id": chat_id, "source_id": chat_id,
"type": "grammar", "type": "grammar",
"create_date": create_date,
} }
) )
return learnt_style_expressions, learnt_grammar_expressions return learnt_style_expressions, learnt_grammar_expressions
def get_expression_create_info(self, chat_id: str, limit: int = 10) -> List[Dict[str, Any]]:
"""
获取指定chat_id的表达方式创建信息按创建日期排序
"""
try:
expressions = (Expression.select()
.where(Expression.chat_id == chat_id)
.order_by(Expression.create_date.desc())
.limit(limit))
result = []
for expr in expressions:
create_date = expr.create_date if expr.create_date is not None else expr.last_active_time
result.append({
"situation": expr.situation,
"style": expr.style,
"type": expr.type,
"count": expr.count,
"create_date": create_date,
"create_date_formatted": format_create_date(create_date),
"last_active_time": expr.last_active_time,
"last_active_formatted": format_create_date(expr.last_active_time),
})
return result
except Exception as e:
logger.error(f"获取表达方式创建信息失败: {e}")
return []
def is_similar(self, s1: str, s2: str) -> bool: def is_similar(self, s1: str, s2: str) -> bool:
""" """
判断两个字符串是否相似只考虑长度大于5且有80%以上重合,不考虑子串) 判断两个字符串是否相似只考虑长度大于5且有80%以上重合,不考虑子串)
@@ -350,6 +419,7 @@ class ExpressionLearner:
last_active_time=current_time, last_active_time=current_time,
chat_id=chat_id, chat_id=chat_id,
type=type, type=type,
create_date=current_time, # 手动设置创建日期
) )
# 限制最大数量 # 限制最大数量
exprs = list( exprs = list(

View File

@@ -132,7 +132,8 @@ class ExpressionSelector:
"count": expr.count, "count": expr.count,
"last_active_time": expr.last_active_time, "last_active_time": expr.last_active_time,
"source_id": cid, "source_id": cid,
"type": "style" "type": "style",
"create_date": expr.create_date if expr.create_date is not None else expr.last_active_time,
} for expr in style_query } for expr in style_query
]) ])
grammar_exprs.extend([ grammar_exprs.extend([
@@ -142,7 +143,8 @@ class ExpressionSelector:
"count": expr.count, "count": expr.count,
"last_active_time": expr.last_active_time, "last_active_time": expr.last_active_time,
"source_id": cid, "source_id": cid,
"type": "grammar" "type": "grammar",
"create_date": expr.create_date if expr.create_date is not None else expr.last_active_time,
} for expr in grammar_query } for expr in grammar_query
]) ])
style_num = int(total_num * style_percentage) style_num = int(total_num * style_percentage)

View File

@@ -630,9 +630,7 @@ class StatisticOutputTask(AsyncTask):
logger.warning(f"获取聊天显示名称失败: {e}") logger.warning(f"获取聊天显示名称失败: {e}")
return chat_id return chat_id
def _generate_versions_tab(self, stat: dict) -> str: # 移除_generate_versions_tab方法
"""版本对比功能占位符,防止报错"""
return '<div id="versions" class="tab-content"><h2>版本对比</h2><p>暂未实现版本对比功能。</p></div>'
def _generate_html_report(self, stat: dict[str, Any], now: datetime): def _generate_html_report(self, stat: dict[str, Any], now: datetime):
""" """
@@ -642,6 +640,7 @@ class StatisticOutputTask(AsyncTask):
:return: HTML格式的统计报告 :return: HTML格式的统计报告
""" """
# 移除版本对比内容相关tab和内容
tab_list = [ tab_list = [
f'<button class="tab-link" onclick="showTab(event, \'{period[0]}\')">{period[2]}</button>' f'<button class="tab-link" onclick="showTab(event, \'{period[0]}\')">{period[2]}</button>'
for period in self.stat_period for period in self.stat_period
@@ -771,10 +770,7 @@ class StatisticOutputTask(AsyncTask):
_format_stat_data(stat["all_time"], "all_time", datetime.fromtimestamp(local_storage["deploy_time"])) # type: ignore _format_stat_data(stat["all_time"], "all_time", datetime.fromtimestamp(local_storage["deploy_time"])) # type: ignore
) )
# 添加版本对比内容 # 不再添加版本对比内容
versions_tab = self._generate_versions_tab(stat)
tab_content_list.append(versions_tab)
# 添加图表内容 # 添加图表内容
chart_data = self._generate_chart_data(stat) chart_data = self._generate_chart_data(stat)
tab_content_list.append(self._generate_chart_tab(chart_data)) tab_content_list.append(self._generate_chart_tab(chart_data))

View File

@@ -2,6 +2,7 @@ from peewee import Model, DoubleField, IntegerField, BooleanField, TextField, Fl
from .database import db from .database import db
import datetime import datetime
from src.common.logger import get_logger from src.common.logger import get_logger
import time
logger = get_logger("database_model") logger = get_logger("database_model")
# 请在此处定义您的数据库实例。 # 请在此处定义您的数据库实例。
@@ -306,6 +307,7 @@ class Expression(BaseModel):
last_active_time = FloatField() last_active_time = FloatField()
chat_id = TextField(index=True) chat_id = TextField(index=True)
type = TextField() type = TextField()
create_date = FloatField(null=True) # 创建日期,允许为空以兼容老数据
class Meta: class Meta:
table_name = "expression" table_name = "expression"
@@ -449,9 +451,12 @@ def initialize_database():
alter_sql = f"ALTER TABLE {table_name} ADD COLUMN {field_name} {sql_type}" alter_sql = f"ALTER TABLE {table_name} ADD COLUMN {field_name} {sql_type}"
alter_sql += " NULL" if field_obj.null else " NOT NULL" alter_sql += " NULL" if field_obj.null else " NOT NULL"
if hasattr(field_obj, "default") and field_obj.default is not None: if hasattr(field_obj, "default") and field_obj.default is not None:
# 正确处理不同类型的默认值 # 正确处理不同类型的默认值跳过lambda函数
default_value = field_obj.default default_value = field_obj.default
if isinstance(default_value, str): if callable(default_value):
# 跳过lambda函数或其他可调用对象这些无法在SQL中表示
pass
elif isinstance(default_value, str):
alter_sql += f" DEFAULT '{default_value}'" alter_sql += f" DEFAULT '{default_value}'"
elif isinstance(default_value, bool): elif isinstance(default_value, bool):
alter_sql += f" DEFAULT {int(default_value)}" alter_sql += f" DEFAULT {int(default_value)}"

View File

@@ -1,5 +1,5 @@
[inner] [inner]
version = "4.4.5" version = "4.4.6"
#----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读----
#如果你想要修改配置文件请在修改后将version的值进行变更 #如果你想要修改配置文件请在修改后将version的值进行变更
@@ -151,7 +151,7 @@ mood_decay_rate = 0.95 # 情绪衰减率
mood_intensity_factor = 1.0 # 情绪强度因子 mood_intensity_factor = 1.0 # 情绪强度因子
[lpmm_knowledge] # lpmm知识库配置 [lpmm_knowledge] # lpmm知识库配置
enable = true # 是否启用lpmm知识库 enable = false # 是否启用lpmm知识库
rag_synonym_search_top_k = 10 # 同义词搜索TopK rag_synonym_search_top_k = 10 # 同义词搜索TopK
rag_synonym_threshold = 0.8 # 同义词阈值(相似度高于此阈值的词语会被认为是同义词) rag_synonym_threshold = 0.8 # 同义词阈值(相似度高于此阈值的词语会被认为是同义词)
info_extraction_workers = 3 # 实体提取同时执行线程数非Pro模型不要设置超过5 info_extraction_workers = 3 # 实体提取同时执行线程数非Pro模型不要设置超过5