feat: 新增股票数据波形图和截图功能
refactor: 重构数据库和LLM分析器逻辑 fix: 修复爬虫解析和UI显示问题 docs: 更新配置文件和注释 style: 优化代码格式和日志输出
This commit is contained in:
66
database.py
66
database.py
@@ -7,6 +7,7 @@ import json
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class DatabaseManager:
|
||||
@@ -15,9 +16,11 @@ class DatabaseManager:
|
||||
def __init__(self, db_path: str = "guba.db"):
|
||||
self.db_path = Path(db_path)
|
||||
self._init_db()
|
||||
logger.info(f"数据库管理器初始化完成,数据库路径: {db_path}")
|
||||
|
||||
def _init_db(self):
|
||||
"""初始化数据库表"""
|
||||
logger.debug("初始化数据库表")
|
||||
conn = self._get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
@@ -59,6 +62,7 @@ class DatabaseManager:
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.debug("数据库表初始化完成")
|
||||
|
||||
def _get_connection(self) -> sqlite3.Connection:
|
||||
"""获取数据库连接"""
|
||||
@@ -83,6 +87,7 @@ class DatabaseManager:
|
||||
content_hash = self.hash_content(content)
|
||||
|
||||
if self.is_comment_exists(content_hash):
|
||||
logger.debug(f"评论已存在,跳过: {content[:30]}...")
|
||||
return None # 已存在
|
||||
|
||||
conn = self._get_connection()
|
||||
@@ -94,6 +99,7 @@ class DatabaseManager:
|
||||
comment_id = cursor.lastrowid
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"添加新评论,ID: {comment_id}")
|
||||
return comment_id
|
||||
|
||||
def add_comments_batch(self, comments: List[Dict]) -> List[int]:
|
||||
@@ -108,16 +114,23 @@ class DatabaseManager:
|
||||
content_hash = self.hash_content(content)
|
||||
|
||||
if self.is_comment_exists(content_hash):
|
||||
logger.debug(f"评论已存在,跳过: {content[:30]}...")
|
||||
continue
|
||||
|
||||
cursor.execute('''
|
||||
INSERT INTO comments (content, content_hash, url, created_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
''', (content, content_hash, url, datetime.now().isoformat()))
|
||||
new_ids.append(cursor.lastrowid)
|
||||
try:
|
||||
cursor.execute('''
|
||||
INSERT OR IGNORE INTO comments (content, content_hash, url, created_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
''', (content, content_hash, url, datetime.now().isoformat()))
|
||||
if cursor.rowcount > 0:
|
||||
new_ids.append(cursor.lastrowid)
|
||||
except Exception as e:
|
||||
logger.warning(f"插入评论失败(可能已存在): {e}")
|
||||
continue
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info(f"批量添加评论完成,新增 {len(new_ids)} 条")
|
||||
return new_ids
|
||||
|
||||
def get_unanalyzed_comments(self, limit: int = 50) -> List[Dict]:
|
||||
@@ -132,7 +145,9 @@ class DatabaseManager:
|
||||
''', (limit,))
|
||||
rows = cursor.fetchall()
|
||||
conn.close()
|
||||
return [{'id': row[0], 'content': row[1], 'url': row[2]} for row in rows]
|
||||
result = [{'id': row[0], 'content': row[1], 'url': row[2]} for row in rows]
|
||||
logger.debug(f"获取到 {len(result)} 条未分析评论")
|
||||
return result
|
||||
|
||||
def mark_analyzed(self, comment_id: int, sentiment_score: float, analysis_text: str):
|
||||
"""标记评论已分析"""
|
||||
@@ -154,6 +169,7 @@ class DatabaseManager:
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.debug(f"标记评论 {comment_id} 已分析,分数: {sentiment_score}")
|
||||
|
||||
def get_latest_sentiment_score(self) -> Optional[float]:
|
||||
"""获取最新的情感分数"""
|
||||
@@ -167,20 +183,34 @@ class DatabaseManager:
|
||||
''')
|
||||
row = cursor.fetchone()
|
||||
conn.close()
|
||||
return row[0] if row else None
|
||||
score = row[0] if row else None
|
||||
logger.debug(f"最新情感分数: {score}")
|
||||
return score
|
||||
|
||||
def get_all_scores(self) -> List[float]:
|
||||
"""获取所有已分析的分数"""
|
||||
def get_all_scores(self, limit: int = None) -> List[float]:
|
||||
"""获取已分析的分数,可指定数量限制"""
|
||||
conn = self._get_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute('''
|
||||
SELECT sentiment_score FROM comments
|
||||
WHERE analyzed = 1 AND sentiment_score IS NOT NULL
|
||||
ORDER BY analyzed_at DESC
|
||||
''')
|
||||
|
||||
if limit:
|
||||
cursor.execute('''
|
||||
SELECT sentiment_score FROM comments
|
||||
WHERE analyzed = 1 AND sentiment_score IS NOT NULL
|
||||
ORDER BY analyzed_at DESC
|
||||
LIMIT ?
|
||||
''', (limit,))
|
||||
else:
|
||||
cursor.execute('''
|
||||
SELECT sentiment_score FROM comments
|
||||
WHERE analyzed = 1 AND sentiment_score IS NOT NULL
|
||||
ORDER BY analyzed_at DESC
|
||||
''')
|
||||
|
||||
rows = cursor.fetchall()
|
||||
conn.close()
|
||||
return [row[0] for row in rows if row[0] is not None]
|
||||
scores = [row[0] for row in rows if row[0] is not None]
|
||||
logger.debug(f"获取到 {len(scores)} 个分数")
|
||||
return scores
|
||||
|
||||
def get_comment_count(self) -> int:
|
||||
"""获取评论总数"""
|
||||
@@ -189,6 +219,7 @@ class DatabaseManager:
|
||||
cursor.execute('SELECT COUNT(*) FROM comments')
|
||||
count = cursor.fetchone()[0]
|
||||
conn.close()
|
||||
logger.debug(f"评论总数: {count}")
|
||||
return count
|
||||
|
||||
def get_analyzed_count(self) -> int:
|
||||
@@ -198,6 +229,7 @@ class DatabaseManager:
|
||||
cursor.execute('SELECT COUNT(*) FROM comments WHERE analyzed = 1')
|
||||
count = cursor.fetchone()[0]
|
||||
conn.close()
|
||||
logger.debug(f"已分析评论数: {count}")
|
||||
return count
|
||||
|
||||
def get_recent_comments(self, limit: int = 10) -> List[Dict]:
|
||||
@@ -212,8 +244,10 @@ class DatabaseManager:
|
||||
''', (limit,))
|
||||
rows = cursor.fetchall()
|
||||
conn.close()
|
||||
return [
|
||||
result = [
|
||||
{'id': row[0], 'content': row[1][:50] + '...' if len(row[1]) > 50 else row[1],
|
||||
'score': row[2], 'analyzed_at': row[3]}
|
||||
for row in rows
|
||||
]
|
||||
logger.debug(f"获取到 {len(result)} 条最近评论")
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user