feat: 自动提交 - 周五 2025/09/19 19:42:44.04
This commit is contained in:
@@ -1,64 +0,0 @@
|
||||
# Git相关
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Python相关
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
env
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
.tox
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.log
|
||||
.git
|
||||
.mypy_cache
|
||||
.pytest_cache
|
||||
.hypothesis
|
||||
|
||||
# 开发环境
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# 系统文件
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# 备份和日志
|
||||
backups/
|
||||
logs/
|
||||
*.log
|
||||
|
||||
# 数据库文件
|
||||
*.db
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
|
||||
# 临时文件
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# 文档
|
||||
*.md
|
||||
docs/
|
||||
|
||||
# 测试文件
|
||||
test_*
|
||||
*_test.py
|
||||
tests/
|
||||
|
||||
# 配置文件(敏感信息)
|
||||
.env
|
||||
config.local.py
|
||||
80
auto_push.bat
Normal file
80
auto_push.bat
Normal file
@@ -0,0 +1,80 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo TSP智能助手 - 自动推送脚本
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
:: 检查Git状态
|
||||
echo [1/4] 检查Git状态...
|
||||
git status --porcelain >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo ❌ Git未初始化或不在Git仓库中
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: 显示当前状态
|
||||
echo 📋 当前Git状态:
|
||||
git status --short
|
||||
echo.
|
||||
|
||||
:: 询问是否继续
|
||||
set /p confirm="是否继续推送? (y/n): "
|
||||
if /i "%confirm%" neq "y" (
|
||||
echo 操作已取消
|
||||
pause
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
:: 添加所有更改
|
||||
echo.
|
||||
echo [2/4] 添加所有更改到暂存区...
|
||||
git add .
|
||||
if %errorlevel% neq 0 (
|
||||
echo ❌ 添加文件失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ 文件已添加到暂存区
|
||||
|
||||
:: 生成提交信息
|
||||
echo.
|
||||
echo [3/4] 生成提交信息...
|
||||
for /f "tokens=*" %%i in ('git log --oneline -1') do set last_commit=%%i
|
||||
set /p commit_msg="请输入提交信息 (直接回车使用默认): "
|
||||
if "%commit_msg%"=="" (
|
||||
set commit_msg=feat: 自动提交 - %date% %time%
|
||||
)
|
||||
|
||||
:: 提交更改
|
||||
echo 提交信息: %commit_msg%
|
||||
git commit -m "%commit_msg%"
|
||||
if %errorlevel% neq 0 (
|
||||
echo ❌ 提交失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ 提交成功
|
||||
|
||||
:: 推送到远程仓库
|
||||
echo.
|
||||
echo [4/4] 推送到远程仓库...
|
||||
git push origin main
|
||||
if %errorlevel% neq 0 (
|
||||
echo ❌ 推送失败
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo ✅ 推送完成!
|
||||
echo ========================================
|
||||
echo 📊 提交统计:
|
||||
git log --oneline -1
|
||||
echo.
|
||||
echo 🌐 远程仓库状态:
|
||||
git status
|
||||
echo.
|
||||
pause
|
||||
192
auto_push.ps1
Normal file
192
auto_push.ps1
Normal file
@@ -0,0 +1,192 @@
|
||||
# TSP智能助手 - 自动推送脚本 (PowerShell版本)
|
||||
# 使用方法: .\auto_push.ps1 [提交信息]
|
||||
|
||||
param(
|
||||
[string]$CommitMessage = "",
|
||||
[switch]$Force = $false,
|
||||
[switch]$NoConfirm = $false
|
||||
)
|
||||
|
||||
# 设置控制台编码
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# 颜色输出函数
|
||||
function Write-ColorOutput {
|
||||
param(
|
||||
[string]$Message,
|
||||
[string]$Color = "White"
|
||||
)
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
|
||||
function Write-Step {
|
||||
param(
|
||||
[int]$Step,
|
||||
[int]$Total,
|
||||
[string]$Message
|
||||
)
|
||||
Write-ColorOutput "[$Step/$Total] $Message" "Cyan"
|
||||
}
|
||||
|
||||
function Show-GitStatus {
|
||||
Write-ColorOutput "`n📋 当前Git状态:" "Yellow"
|
||||
$status = git status --porcelain
|
||||
if ($status) {
|
||||
$status | ForEach-Object {
|
||||
$line = $_
|
||||
if ($line.StartsWith("??")) {
|
||||
Write-ColorOutput " + $($line.Substring(3))" "Green"
|
||||
} elseif ($line.StartsWith(" M")) {
|
||||
Write-ColorOutput " ~ $($line.Substring(3))" "Yellow"
|
||||
} elseif ($line.StartsWith(" D")) {
|
||||
Write-ColorOutput " - $($line.Substring(3))" "Red"
|
||||
} else {
|
||||
Write-ColorOutput " $line" "White"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-ColorOutput " 工作区干净,无更改" "Green"
|
||||
}
|
||||
}
|
||||
|
||||
function Get-CommitMessage {
|
||||
if ($CommitMessage) {
|
||||
return $CommitMessage
|
||||
}
|
||||
|
||||
# 尝试从最近提交生成智能消息
|
||||
$lastCommit = git log --oneline -1 2>$null
|
||||
if ($lastCommit) {
|
||||
$suggested = "feat: 自动提交更新 - $(Get-Date -Format 'yyyy-MM-dd HH:mm')"
|
||||
} else {
|
||||
$suggested = "feat: 初始提交 - $(Get-Date -Format 'yyyy-MM-dd HH:mm')"
|
||||
}
|
||||
|
||||
Write-ColorOutput "`n💡 建议的提交信息: $suggested" "Cyan"
|
||||
$custom = Read-Host "请输入自定义提交信息 (直接回车使用建议)"
|
||||
|
||||
if ($custom) {
|
||||
return $custom
|
||||
} else {
|
||||
return $suggested
|
||||
}
|
||||
}
|
||||
|
||||
function Test-GitRepository {
|
||||
try {
|
||||
git status --porcelain >$null 2>&1
|
||||
return $LASTEXITCODE -eq 0
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Show-CommitStats {
|
||||
Write-ColorOutput "`n📊 提交统计:" "Yellow"
|
||||
$commitHash = git log --oneline -1 | Select-String -Pattern "^\w+" | ForEach-Object { $_.Matches[0].Value }
|
||||
$filesChanged = git diff --cached --numstat | Measure-Object | Select-Object -ExpandProperty Count
|
||||
$insertions = git diff --cached --numstat | ForEach-Object {
|
||||
$parts = $_ -split '\s+'
|
||||
if ($parts[0] -match '^\d+$') { [int]$parts[0] } else { 0 }
|
||||
} | Measure-Object -Sum | Select-Object -ExpandProperty Sum
|
||||
$deletions = git diff --cached --numstat | ForEach-Object {
|
||||
$parts = $_ -split '\s+'
|
||||
if ($parts[1] -match '^\d+$') { [int]$parts[1] } else { 0 }
|
||||
} | Measure-Object -Sum | Select-Object -ExpandProperty Sum
|
||||
|
||||
Write-ColorOutput " 提交哈希: $commitHash" "White"
|
||||
Write-ColorOutput " 文件变更: $filesChanged 个文件" "White"
|
||||
Write-ColorOutput " 新增行数: $insertions 行" "Green"
|
||||
Write-ColorOutput " 删除行数: $deletions 行" "Red"
|
||||
Write-ColorOutput " 净增加: $($insertions - $deletions) 行" "Cyan"
|
||||
}
|
||||
|
||||
# 主程序开始
|
||||
Write-ColorOutput "========================================" "Magenta"
|
||||
Write-ColorOutput "TSP智能助手 - 自动推送脚本 v2.0" "Magenta"
|
||||
Write-ColorOutput "========================================" "Magenta"
|
||||
|
||||
# 检查Git仓库
|
||||
Write-Step 1 4 "检查Git仓库状态"
|
||||
if (-not (Test-GitRepository)) {
|
||||
Write-ColorOutput "❌ Git未初始化或不在Git仓库中" "Red"
|
||||
Write-ColorOutput "请确保在正确的Git仓库目录中运行此脚本" "Yellow"
|
||||
Read-Host "按任意键退出"
|
||||
exit 1
|
||||
}
|
||||
Write-ColorOutput "✅ Git仓库状态正常" "Green"
|
||||
|
||||
# 显示状态
|
||||
Show-GitStatus
|
||||
|
||||
# 检查是否有更改
|
||||
$hasChanges = git status --porcelain | Measure-Object | Select-Object -ExpandProperty Count
|
||||
if ($hasChanges -eq 0) {
|
||||
Write-ColorOutput "`n✅ 工作区干净,无需提交" "Green"
|
||||
Read-Host "按任意键退出"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# 确认操作
|
||||
if (-not $NoConfirm) {
|
||||
Write-ColorOutput "`n❓ 是否继续推送?" "Yellow"
|
||||
$confirm = Read-Host "输入 'y' 继续,其他键取消"
|
||||
if ($confirm -ne 'y') {
|
||||
Write-ColorOutput "操作已取消" "Yellow"
|
||||
Read-Host "按任意键退出"
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
|
||||
# 添加文件
|
||||
Write-Step 2 4 "添加所有更改到暂存区"
|
||||
try {
|
||||
git add .
|
||||
Write-ColorOutput "✅ 文件已添加到暂存区" "Green"
|
||||
} catch {
|
||||
Write-ColorOutput "❌ 添加文件失败: $($_.Exception.Message)" "Red"
|
||||
Read-Host "按任意键退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 生成提交信息
|
||||
Write-Step 3 4 "生成提交信息"
|
||||
$finalCommitMessage = Get-CommitMessage
|
||||
Write-ColorOutput "提交信息: $finalCommitMessage" "Cyan"
|
||||
|
||||
# 提交更改
|
||||
try {
|
||||
git commit -m $finalCommitMessage
|
||||
Write-ColorOutput "✅ 提交成功" "Green"
|
||||
} catch {
|
||||
Write-ColorOutput "❌ 提交失败: $($_.Exception.Message)" "Red"
|
||||
Read-Host "按任意键退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 推送到远程
|
||||
Write-Step 4 4 "推送到远程仓库"
|
||||
try {
|
||||
git push origin main
|
||||
Write-ColorOutput "✅ 推送成功" "Green"
|
||||
} catch {
|
||||
Write-ColorOutput "❌ 推送失败: $($_.Exception.Message)" "Red"
|
||||
Write-ColorOutput "请检查网络连接和远程仓库权限" "Yellow"
|
||||
Read-Host "按任意键退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 显示结果
|
||||
Write-ColorOutput "`n========================================" "Magenta"
|
||||
Write-ColorOutput "✅ 推送完成!" "Green"
|
||||
Write-ColorOutput "========================================" "Magenta"
|
||||
|
||||
Show-CommitStats
|
||||
|
||||
Write-ColorOutput "`n🌐 远程仓库状态:" "Yellow"
|
||||
git status --short
|
||||
|
||||
Write-ColorOutput "`n🎉 所有操作完成!" "Green"
|
||||
if (-not $NoConfirm) {
|
||||
Read-Host "按任意键退出"
|
||||
}
|
||||
28
quick_push.bat
Normal file
28
quick_push.bat
Normal file
@@ -0,0 +1,28 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo 🚀 TSP智能助手 - 快速推送
|
||||
echo.
|
||||
|
||||
:: 检查是否有参数
|
||||
if "%1"=="" (
|
||||
set commit_msg=feat: 快速提交 - %date% %time%
|
||||
) else (
|
||||
set commit_msg=%1
|
||||
)
|
||||
|
||||
echo 📝 提交信息: %commit_msg%
|
||||
echo.
|
||||
|
||||
:: 执行推送
|
||||
git add . && git commit -m "%commit_msg%" && git push origin main
|
||||
|
||||
if %errorlevel% equ 0 (
|
||||
echo.
|
||||
echo ✅ 推送完成!
|
||||
) else (
|
||||
echo.
|
||||
echo ❌ 推送失败,请检查错误信息
|
||||
)
|
||||
|
||||
echo.
|
||||
pause
|
||||
@@ -11,9 +11,10 @@ from datetime import datetime, timedelta
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..core.database import db_manager
|
||||
from ..core.models import Conversation
|
||||
from ..core.models import Conversation, WorkOrder, WorkOrderSuggestion, KnowledgeEntry
|
||||
from ..core.redis_manager import redis_manager
|
||||
from ..config.config import Config
|
||||
from sqlalchemy import and_, or_, desc
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -375,3 +376,330 @@ class ConversationHistoryManager:
|
||||
except Exception as e:
|
||||
logger.error(f"清理旧对话记录失败: {e}")
|
||||
return 0
|
||||
|
||||
def get_workorder_complete_timeline(
|
||||
self,
|
||||
work_order_id: int,
|
||||
include_ai_suggestions: bool = True,
|
||||
include_feishu_sync: bool = True,
|
||||
limit: int = 20
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取工单的完整时间线(包含对话、AI建议、飞书同步)"""
|
||||
try:
|
||||
timeline = []
|
||||
|
||||
with db_manager.get_session() as session:
|
||||
# 1. 获取基础对话记录
|
||||
conversations = session.query(Conversation).filter(
|
||||
Conversation.work_order_id == work_order_id
|
||||
).order_by(Conversation.timestamp.desc()).limit(limit).all()
|
||||
|
||||
for conv in conversations:
|
||||
timeline.append({
|
||||
"id": conv.id,
|
||||
"type": "conversation",
|
||||
"timestamp": conv.timestamp,
|
||||
"user_message": conv.user_message,
|
||||
"assistant_response": conv.assistant_response,
|
||||
"confidence_score": conv.confidence_score,
|
||||
"response_time": conv.response_time,
|
||||
"knowledge_used": json.loads(conv.knowledge_used) if conv.knowledge_used else []
|
||||
})
|
||||
|
||||
# 2. 获取AI建议记录
|
||||
if include_ai_suggestions:
|
||||
suggestions = session.query(WorkOrderSuggestion).filter(
|
||||
WorkOrderSuggestion.work_order_id == work_order_id
|
||||
).order_by(WorkOrderSuggestion.created_at.desc()).limit(limit).all()
|
||||
|
||||
for suggestion in suggestions:
|
||||
timeline.append({
|
||||
"id": f"suggestion_{suggestion.id}",
|
||||
"type": "ai_suggestion",
|
||||
"timestamp": suggestion.created_at,
|
||||
"ai_suggestion": suggestion.ai_suggestion,
|
||||
"human_resolution": suggestion.human_resolution,
|
||||
"ai_similarity": suggestion.ai_similarity,
|
||||
"approved": suggestion.approved,
|
||||
"use_human_resolution": suggestion.use_human_resolution,
|
||||
"updated_at": suggestion.updated_at
|
||||
})
|
||||
|
||||
# 3. 获取飞书同步记录(从工单的feishu_record_id推断)
|
||||
if include_feishu_sync:
|
||||
work_order = session.query(WorkOrder).filter(
|
||||
WorkOrder.id == work_order_id
|
||||
).first()
|
||||
|
||||
if work_order and work_order.feishu_record_id:
|
||||
timeline.append({
|
||||
"id": f"feishu_{work_order.feishu_record_id}",
|
||||
"type": "feishu_sync",
|
||||
"timestamp": work_order.created_at,
|
||||
"feishu_record_id": work_order.feishu_record_id,
|
||||
"order_id": work_order.order_id,
|
||||
"title": work_order.title,
|
||||
"description": work_order.description,
|
||||
"category": work_order.category,
|
||||
"priority": work_order.priority,
|
||||
"status": work_order.status,
|
||||
"source": work_order.source
|
||||
})
|
||||
|
||||
# 按时间排序
|
||||
timeline.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
|
||||
return timeline[:limit]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工单完整时间线失败: {e}")
|
||||
return []
|
||||
|
||||
def get_ai_suggestion_context(
|
||||
self,
|
||||
work_order_id: int,
|
||||
suggestion_id: Optional[int] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""获取AI建议的对话上下文"""
|
||||
try:
|
||||
context = {
|
||||
"work_order_info": {},
|
||||
"conversation_history": [],
|
||||
"ai_suggestions": [],
|
||||
"knowledge_base": []
|
||||
}
|
||||
|
||||
with db_manager.get_session() as session:
|
||||
# 1. 获取工单信息
|
||||
work_order = session.query(WorkOrder).filter(
|
||||
WorkOrder.id == work_order_id
|
||||
).first()
|
||||
|
||||
if work_order:
|
||||
context["work_order_info"] = {
|
||||
"id": work_order.id,
|
||||
"order_id": work_order.order_id,
|
||||
"title": work_order.title,
|
||||
"description": work_order.description,
|
||||
"category": work_order.category,
|
||||
"priority": work_order.priority,
|
||||
"status": work_order.status,
|
||||
"created_at": work_order.created_at.isoformat(),
|
||||
"feishu_record_id": work_order.feishu_record_id
|
||||
}
|
||||
|
||||
# 2. 获取相关对话历史
|
||||
conversations = session.query(Conversation).filter(
|
||||
Conversation.work_order_id == work_order_id
|
||||
).order_by(Conversation.timestamp.desc()).limit(10).all()
|
||||
|
||||
for conv in conversations:
|
||||
context["conversation_history"].append({
|
||||
"id": conv.id,
|
||||
"user_message": conv.user_message,
|
||||
"assistant_response": conv.assistant_response,
|
||||
"timestamp": conv.timestamp.isoformat(),
|
||||
"confidence_score": conv.confidence_score
|
||||
})
|
||||
|
||||
# 3. 获取AI建议历史
|
||||
suggestions = session.query(WorkOrderSuggestion).filter(
|
||||
WorkOrderSuggestion.work_order_id == work_order_id
|
||||
).order_by(WorkOrderSuggestion.created_at.desc()).limit(5).all()
|
||||
|
||||
for suggestion in suggestions:
|
||||
context["ai_suggestions"].append({
|
||||
"id": suggestion.id,
|
||||
"ai_suggestion": suggestion.ai_suggestion,
|
||||
"human_resolution": suggestion.human_resolution,
|
||||
"ai_similarity": suggestion.ai_similarity,
|
||||
"approved": suggestion.approved,
|
||||
"use_human_resolution": suggestion.use_human_resolution,
|
||||
"created_at": suggestion.created_at.isoformat()
|
||||
})
|
||||
|
||||
# 4. 获取相关知识库条目
|
||||
if work_order:
|
||||
knowledge_entries = session.query(KnowledgeEntry).filter(
|
||||
and_(
|
||||
KnowledgeEntry.is_active == True,
|
||||
or_(
|
||||
KnowledgeEntry.category == work_order.category,
|
||||
KnowledgeEntry.question.contains(work_order.title[:20])
|
||||
)
|
||||
)
|
||||
).limit(5).all()
|
||||
|
||||
for entry in knowledge_entries:
|
||||
context["knowledge_base"].append({
|
||||
"id": entry.id,
|
||||
"question": entry.question,
|
||||
"answer": entry.answer,
|
||||
"category": entry.category,
|
||||
"confidence_score": entry.confidence_score,
|
||||
"is_verified": entry.is_verified
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取AI建议对话上下文失败: {e}")
|
||||
return {}
|
||||
|
||||
def search_conversations_by_content(
|
||||
self,
|
||||
search_query: str,
|
||||
work_order_id: Optional[int] = None,
|
||||
conversation_type: Optional[str] = None,
|
||||
limit: int = 20
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""根据内容搜索对话记录(包含AI建议)"""
|
||||
try:
|
||||
results = []
|
||||
|
||||
with db_manager.get_session() as session:
|
||||
# 搜索基础对话
|
||||
conv_query = session.query(Conversation)
|
||||
if work_order_id:
|
||||
conv_query = conv_query.filter(Conversation.work_order_id == work_order_id)
|
||||
|
||||
conversations = conv_query.filter(
|
||||
or_(
|
||||
Conversation.user_message.contains(search_query),
|
||||
Conversation.assistant_response.contains(search_query)
|
||||
)
|
||||
).order_by(Conversation.timestamp.desc()).limit(limit).all()
|
||||
|
||||
for conv in conversations:
|
||||
results.append({
|
||||
"id": conv.id,
|
||||
"type": "conversation",
|
||||
"timestamp": conv.timestamp,
|
||||
"user_message": conv.user_message,
|
||||
"assistant_response": conv.assistant_response,
|
||||
"work_order_id": conv.work_order_id,
|
||||
"confidence_score": conv.confidence_score
|
||||
})
|
||||
|
||||
# 搜索AI建议
|
||||
if not conversation_type or conversation_type == "ai_suggestion":
|
||||
suggestion_query = session.query(WorkOrderSuggestion)
|
||||
if work_order_id:
|
||||
suggestion_query = suggestion_query.filter(
|
||||
WorkOrderSuggestion.work_order_id == work_order_id
|
||||
)
|
||||
|
||||
suggestions = suggestion_query.filter(
|
||||
or_(
|
||||
WorkOrderSuggestion.ai_suggestion.contains(search_query),
|
||||
WorkOrderSuggestion.human_resolution.contains(search_query)
|
||||
)
|
||||
).order_by(WorkOrderSuggestion.created_at.desc()).limit(limit).all()
|
||||
|
||||
for suggestion in suggestions:
|
||||
results.append({
|
||||
"id": f"suggestion_{suggestion.id}",
|
||||
"type": "ai_suggestion",
|
||||
"timestamp": suggestion.created_at,
|
||||
"ai_suggestion": suggestion.ai_suggestion,
|
||||
"human_resolution": suggestion.human_resolution,
|
||||
"work_order_id": suggestion.work_order_id,
|
||||
"ai_similarity": suggestion.ai_similarity,
|
||||
"approved": suggestion.approved
|
||||
})
|
||||
|
||||
# 按时间排序
|
||||
results.sort(key=lambda x: x["timestamp"], reverse=True)
|
||||
|
||||
return results[:limit]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"搜索对话记录失败: {e}")
|
||||
return []
|
||||
|
||||
def get_conversation_analytics(
|
||||
self,
|
||||
work_order_id: Optional[int] = None,
|
||||
days: int = 7
|
||||
) -> Dict[str, Any]:
|
||||
"""获取对话分析数据(包含AI建议统计)"""
|
||||
try:
|
||||
cutoff_date = datetime.now() - timedelta(days=days)
|
||||
|
||||
with db_manager.get_session() as session:
|
||||
analytics = {
|
||||
"period_days": days,
|
||||
"conversations": {},
|
||||
"ai_suggestions": {},
|
||||
"performance": {}
|
||||
}
|
||||
|
||||
# 对话统计
|
||||
conv_query = session.query(Conversation)
|
||||
if work_order_id:
|
||||
conv_query = conv_query.filter(Conversation.work_order_id == work_order_id)
|
||||
|
||||
conversations = conv_query.filter(
|
||||
Conversation.timestamp >= cutoff_date
|
||||
).all()
|
||||
|
||||
analytics["conversations"] = {
|
||||
"total": len(conversations),
|
||||
"avg_confidence": 0,
|
||||
"avg_response_time": 0,
|
||||
"high_confidence_count": 0
|
||||
}
|
||||
|
||||
if conversations:
|
||||
confidences = [c.confidence_score for c in conversations if c.confidence_score]
|
||||
response_times = [c.response_time for c in conversations if c.response_time]
|
||||
|
||||
if confidences:
|
||||
analytics["conversations"]["avg_confidence"] = sum(confidences) / len(confidences)
|
||||
analytics["conversations"]["high_confidence_count"] = len([c for c in confidences if c >= 0.8])
|
||||
|
||||
if response_times:
|
||||
analytics["conversations"]["avg_response_time"] = sum(response_times) / len(response_times)
|
||||
|
||||
# AI建议统计
|
||||
suggestion_query = session.query(WorkOrderSuggestion)
|
||||
if work_order_id:
|
||||
suggestion_query = suggestion_query.filter(
|
||||
WorkOrderSuggestion.work_order_id == work_order_id
|
||||
)
|
||||
|
||||
suggestions = suggestion_query.filter(
|
||||
WorkOrderSuggestion.created_at >= cutoff_date
|
||||
).all()
|
||||
|
||||
analytics["ai_suggestions"] = {
|
||||
"total": len(suggestions),
|
||||
"approved_count": len([s for s in suggestions if s.approved]),
|
||||
"avg_similarity": 0,
|
||||
"human_resolution_count": len([s for s in suggestions if s.use_human_resolution])
|
||||
}
|
||||
|
||||
if suggestions:
|
||||
similarities = [s.ai_similarity for s in suggestions if s.ai_similarity]
|
||||
if similarities:
|
||||
analytics["ai_suggestions"]["avg_similarity"] = sum(similarities) / len(similarities)
|
||||
|
||||
# 性能指标
|
||||
analytics["performance"] = {
|
||||
"conversation_success_rate": 0,
|
||||
"ai_suggestion_approval_rate": 0,
|
||||
"knowledge_base_usage_rate": 0
|
||||
}
|
||||
|
||||
if conversations:
|
||||
successful_convs = len([c for c in conversations if c.confidence_score and c.confidence_score >= 0.5])
|
||||
analytics["performance"]["conversation_success_rate"] = successful_convs / len(conversations)
|
||||
|
||||
if suggestions:
|
||||
analytics["performance"]["ai_suggestion_approval_rate"] = len([s for s in suggestions if s.approved]) / len(suggestions)
|
||||
|
||||
return analytics
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取对话分析数据失败: {e}")
|
||||
return {}
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
对话管理蓝图
|
||||
处理对话相关的API路由
|
||||
处理对话相关的API路由,整合飞书工单和AI建议
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
from src.core.database import db_manager
|
||||
from src.core.models import Conversation
|
||||
from src.core.models import Conversation, WorkOrder, WorkOrderSuggestion
|
||||
from src.core.query_optimizer import query_optimizer
|
||||
from src.dialogue.conversation_history import ConversationHistoryManager
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
conversations_bp = Blueprint('conversations', __name__, url_prefix='/api/conversations')
|
||||
|
||||
# 初始化对话历史管理器
|
||||
history_manager = ConversationHistoryManager()
|
||||
|
||||
@conversations_bp.route('')
|
||||
def get_conversations():
|
||||
"""获取对话历史列表(分页)- 优化版"""
|
||||
@@ -197,3 +203,136 @@ def migrate_merge_conversations():
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@conversations_bp.route('/workorder/<int:work_order_id>/timeline')
|
||||
def get_workorder_timeline(work_order_id):
|
||||
"""获取工单的完整对话时间线(包含AI建议和飞书同步)"""
|
||||
try:
|
||||
include_ai_suggestions = request.args.get('include_ai_suggestions', 'true').lower() == 'true'
|
||||
include_feishu_sync = request.args.get('include_feishu_sync', 'true').lower() == 'true'
|
||||
limit = request.args.get('limit', 20, type=int)
|
||||
|
||||
timeline = history_manager.get_workorder_complete_timeline(
|
||||
work_order_id=work_order_id,
|
||||
include_ai_suggestions=include_ai_suggestions,
|
||||
include_feishu_sync=include_feishu_sync,
|
||||
limit=limit
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'work_order_id': work_order_id,
|
||||
'timeline': timeline,
|
||||
'total_count': len(timeline)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工单时间线失败: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@conversations_bp.route('/workorder/<int:work_order_id>/context')
|
||||
def get_workorder_context(work_order_id):
|
||||
"""获取工单的AI建议对话上下文"""
|
||||
try:
|
||||
suggestion_id = request.args.get('suggestion_id', type=int)
|
||||
|
||||
context = history_manager.get_ai_suggestion_context(
|
||||
work_order_id=work_order_id,
|
||||
suggestion_id=suggestion_id
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'work_order_id': work_order_id,
|
||||
'context': context
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工单上下文失败: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@conversations_bp.route('/workorder/<int:work_order_id>/summary')
|
||||
def get_workorder_summary(work_order_id):
|
||||
"""获取工单对话摘要"""
|
||||
try:
|
||||
# 获取时间线数据
|
||||
timeline = history_manager.get_workorder_complete_timeline(
|
||||
work_order_id=work_order_id,
|
||||
include_ai_suggestions=True,
|
||||
include_feishu_sync=True,
|
||||
limit=50
|
||||
)
|
||||
|
||||
if not timeline:
|
||||
return jsonify({"error": "没有找到对话记录"}), 404
|
||||
|
||||
# 生成简单摘要
|
||||
summary = {
|
||||
"work_order_id": work_order_id,
|
||||
"total_interactions": len(timeline),
|
||||
"conversations": len([t for t in timeline if t["type"] == "conversation"]),
|
||||
"ai_suggestions": len([t for t in timeline if t["type"] == "ai_suggestion"]),
|
||||
"feishu_syncs": len([t for t in timeline if t["type"] == "feishu_sync"]),
|
||||
"generated_at": timeline[0]["timestamp"].isoformat() if timeline else None
|
||||
}
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'work_order_id': work_order_id,
|
||||
'summary': summary
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取工单摘要失败: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@conversations_bp.route('/search')
|
||||
def search_conversations():
|
||||
"""搜索对话记录(包含AI建议)"""
|
||||
try:
|
||||
search_query = request.args.get('q', '')
|
||||
work_order_id = request.args.get('work_order_id', type=int)
|
||||
conversation_type = request.args.get('type') # conversation, ai_suggestion, all
|
||||
limit = request.args.get('limit', 20, type=int)
|
||||
|
||||
if not search_query:
|
||||
return jsonify({"error": "搜索查询不能为空"}), 400
|
||||
|
||||
results = history_manager.search_conversations_by_content(
|
||||
search_query=search_query,
|
||||
work_order_id=work_order_id,
|
||||
conversation_type=conversation_type,
|
||||
limit=limit
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'query': search_query,
|
||||
'results': results,
|
||||
'total_count': len(results)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"搜索对话记录失败: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@conversations_bp.route('/analytics')
|
||||
def get_conversation_analytics():
|
||||
"""获取对话分析数据"""
|
||||
try:
|
||||
work_order_id = request.args.get('work_order_id', type=int)
|
||||
days = request.args.get('days', 7, type=int)
|
||||
|
||||
analytics = history_manager.get_conversation_analytics(
|
||||
work_order_id=work_order_id,
|
||||
days=days
|
||||
)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'analytics': analytics
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取对话分析数据失败: {e}")
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
181
推送脚本使用说明.md
Normal file
181
推送脚本使用说明.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# TSP智能助手 - 推送脚本使用说明
|
||||
|
||||
## 📁 脚本文件说明
|
||||
|
||||
### 1. `auto_push.bat` - 标准自动推送脚本
|
||||
**功能**: 完整的Git推送流程,包含状态检查、确认、提交和推送
|
||||
**特点**:
|
||||
- 显示详细的Git状态
|
||||
- 用户确认机制
|
||||
- 自定义提交信息
|
||||
- 错误处理和状态反馈
|
||||
|
||||
**使用方法**:
|
||||
```bash
|
||||
# 直接运行
|
||||
auto_push.bat
|
||||
|
||||
# 运行后会提示输入提交信息
|
||||
```
|
||||
|
||||
### 2. `auto_push.ps1` - PowerShell高级版本
|
||||
**功能**: 功能最全面的推送脚本,支持参数和高级功能
|
||||
**特点**:
|
||||
- 彩色输出和美观的界面
|
||||
- 支持命令行参数
|
||||
- 智能提交信息生成
|
||||
- 详细的统计信息
|
||||
- 错误处理和回滚
|
||||
|
||||
**使用方法**:
|
||||
```powershell
|
||||
# 基本使用
|
||||
.\auto_push.ps1
|
||||
|
||||
# 指定提交信息
|
||||
.\auto_push.ps1 "feat: 添加新功能"
|
||||
|
||||
# 强制推送(跳过确认)
|
||||
.\auto_push.ps1 -NoConfirm
|
||||
|
||||
# 强制推送并指定信息
|
||||
.\auto_push.ps1 "紧急修复" -Force -NoConfirm
|
||||
```
|
||||
|
||||
### 3. `quick_push.bat` - 快速推送脚本
|
||||
**功能**: 最简单的推送方式,适合日常快速提交
|
||||
**特点**:
|
||||
- 一键推送
|
||||
- 自动生成提交信息
|
||||
- 最小化交互
|
||||
|
||||
**使用方法**:
|
||||
```bash
|
||||
# 使用默认提交信息
|
||||
quick_push.bat
|
||||
|
||||
# 指定提交信息
|
||||
quick_push.bat "修复bug"
|
||||
```
|
||||
|
||||
## 🚀 推荐使用场景
|
||||
|
||||
### 日常开发
|
||||
```bash
|
||||
# 快速提交日常更改
|
||||
quick_push.bat "日常更新"
|
||||
```
|
||||
|
||||
### 功能开发
|
||||
```bash
|
||||
# 使用PowerShell版本,获得最佳体验
|
||||
.\auto_push.ps1 "feat: 添加用户管理功能"
|
||||
```
|
||||
|
||||
### 紧急修复
|
||||
```bash
|
||||
# 快速修复
|
||||
quick_push.bat "hotfix: 修复登录问题"
|
||||
```
|
||||
|
||||
### 团队协作
|
||||
```bash
|
||||
# 使用标准版本,确保流程规范
|
||||
auto_push.bat
|
||||
```
|
||||
|
||||
## ⚙️ 脚本特性对比
|
||||
|
||||
| 特性 | quick_push.bat | auto_push.bat | auto_push.ps1 |
|
||||
|------|----------------|---------------|---------------|
|
||||
| 执行速度 | ⚡ 最快 | 🐌 中等 | 🐌 中等 |
|
||||
| 用户交互 | 最少 | 中等 | 最多 |
|
||||
| 错误处理 | 基础 | 完整 | 完整 |
|
||||
| 状态显示 | 基础 | 详细 | 最详细 |
|
||||
| 参数支持 | 基础 | 无 | 完整 |
|
||||
| 彩色输出 | 无 | 无 | ✅ |
|
||||
| 统计信息 | 无 | 基础 | 详细 |
|
||||
|
||||
## 🔧 自定义配置
|
||||
|
||||
### 修改默认提交信息格式
|
||||
编辑 `auto_push.bat` 第25行:
|
||||
```batch
|
||||
set commit_msg=feat: 自动提交 - %date% %time%
|
||||
```
|
||||
|
||||
### 修改远程分支
|
||||
编辑所有脚本中的 `origin main` 为你的分支:
|
||||
```batch
|
||||
git push origin your-branch
|
||||
```
|
||||
|
||||
### 添加预提交检查
|
||||
在 `auto_push.ps1` 中添加检查函数:
|
||||
```powershell
|
||||
function Test-PreCommit {
|
||||
# 运行测试
|
||||
python -m pytest
|
||||
# 代码格式化检查
|
||||
python -m black --check .
|
||||
# 类型检查
|
||||
python -m mypy .
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **PowerShell执行策略错误**
|
||||
```powershell
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
```
|
||||
|
||||
2. **Git认证失败**
|
||||
```bash
|
||||
# 检查远程仓库配置
|
||||
git remote -v
|
||||
|
||||
# 重新设置认证
|
||||
git config --global credential.helper store
|
||||
```
|
||||
|
||||
3. **编码问题**
|
||||
```bash
|
||||
# 确保控制台支持UTF-8
|
||||
chcp 65001
|
||||
```
|
||||
|
||||
### 错误代码说明
|
||||
|
||||
- `退出代码 0`: 成功
|
||||
- `退出代码 1`: Git操作失败
|
||||
- `退出代码 2`: 用户取消操作
|
||||
|
||||
## 📝 最佳实践
|
||||
|
||||
1. **提交前检查**: 使用 `auto_push.ps1` 查看详细状态
|
||||
2. **提交信息规范**: 使用 `feat:`, `fix:`, `docs:` 等前缀
|
||||
3. **定期推送**: 避免长时间不推送导致冲突
|
||||
4. **分支管理**: 在功能分支开发,合并到主分支
|
||||
|
||||
## 🎯 示例工作流
|
||||
|
||||
```bash
|
||||
# 1. 开发功能
|
||||
# ... 编写代码 ...
|
||||
|
||||
# 2. 快速推送
|
||||
quick_push.bat "feat: 添加AI建议功能"
|
||||
|
||||
# 3. 或者详细推送
|
||||
.\auto_push.ps1 "feat: 添加AI建议功能
|
||||
- 实现语义相似度计算
|
||||
- 优化前端UI显示
|
||||
- 添加配置化阈值"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**提示**: 建议将脚本文件添加到项目根目录,并设置适当的执行权限。对于团队使用,建议统一使用 `auto_push.ps1` 以确保流程一致性。
|
||||
Reference in New Issue
Block a user