fix6
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -213,8 +213,11 @@ def handle_meeting_detail(meeting_id):
|
|||||||
return jsonify(meeting.to_dict())
|
return jsonify(meeting.to_dict())
|
||||||
|
|
||||||
if request.method == 'DELETE':
|
if request.method == 'DELETE':
|
||||||
if get_jwt().get('role') != 'admin':
|
current_user_id = get_jwt_identity()
|
||||||
return jsonify({"msg": "Administration rights required"}), 403
|
is_admin = get_jwt().get('role') == 'admin'
|
||||||
|
|
||||||
|
if not is_admin and str(meeting.created_by_id) != str(current_user_id):
|
||||||
|
return jsonify({"msg": "Only the meeting creator or an admin can delete this meeting."}), 403
|
||||||
db.session.delete(meeting)
|
db.session.delete(meeting)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return jsonify({"msg": "Meeting and associated action items deleted"}), 200
|
return jsonify({"msg": "Meeting and associated action items deleted"}), 200
|
||||||
@@ -235,9 +238,9 @@ def summarize_meeting(meeting_id):
|
|||||||
@jwt_required()
|
@jwt_required()
|
||||||
def preview_actions(meeting_id):
|
def preview_actions(meeting_id):
|
||||||
meeting = Meeting.query.get_or_404(meeting_id)
|
meeting = Meeting.query.get_or_404(meeting_id)
|
||||||
text_content = meeting.summary or meeting.transcript
|
text_content = meeting.transcript # Always use the full transcript
|
||||||
if not text_content:
|
if not text_content:
|
||||||
return jsonify({'error': 'Meeting has no summary or transcript to analyze.'}), 400
|
return jsonify({'error': 'Meeting has no transcript to analyze.'}), 400
|
||||||
|
|
||||||
task = preview_action_items_task.delay(text_content)
|
task = preview_action_items_task.delay(text_content)
|
||||||
return jsonify({'task_id': task.id, 'status_url': f'/status/{task.id}'}), 202
|
return jsonify({'task_id': task.id, 'status_url': f'/status/{task.id}'}), 202
|
||||||
|
@@ -40,6 +40,7 @@ const MeetingDetailPage = () => {
|
|||||||
const [isAddActionItemOpen, setIsAddActionItemOpen] = useState(false);
|
const [isAddActionItemOpen, setIsAddActionItemOpen] = useState(false);
|
||||||
const [newActionItem, setNewActionItem] = useState({ action: '', owner_id: '', due_date: '', item: '' });
|
const [newActionItem, setNewActionItem] = useState({ action: '', owner_id: '', due_date: '', item: '' });
|
||||||
const [previewedItems, setPreviewedItems] = useState([]);
|
const [previewedItems, setPreviewedItems] = useState([]);
|
||||||
|
const [previewMessage, setPreviewMessage] = useState(''); // State for the preview result message
|
||||||
|
|
||||||
const fetchMeetingData = useCallback(async () => {
|
const fetchMeetingData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -94,7 +95,11 @@ const MeetingDetailPage = () => {
|
|||||||
} else if (previewTask) { // Handle preview success
|
} else if (previewTask) { // Handle preview success
|
||||||
setPreviewTask(null);
|
setPreviewTask(null);
|
||||||
if (updatedTask.state === 'SUCCESS' && updatedTask.info.items) {
|
if (updatedTask.state === 'SUCCESS' && updatedTask.info.items) {
|
||||||
setPreviewedItems(updatedTask.info.items);
|
if (updatedTask.info.items.length > 0) {
|
||||||
|
setPreviewedItems(updatedTask.info.items);
|
||||||
|
} else {
|
||||||
|
setPreviewMessage('文本中未找到可提取的行動項目。');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,6 +146,8 @@ const MeetingDetailPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePreviewActionItems = async () => {
|
const handlePreviewActionItems = async () => {
|
||||||
|
setPreviewedItems([]); // Clear previous results
|
||||||
|
setPreviewMessage(''); // Clear previous messages
|
||||||
setPreviewTask({ state: 'PENDING', info: 'Initializing preview task...' });
|
setPreviewTask({ state: 'PENDING', info: 'Initializing preview task...' });
|
||||||
try {
|
try {
|
||||||
// This now calls the async task endpoint
|
// This now calls the async task endpoint
|
||||||
@@ -244,9 +251,10 @@ const MeetingDetailPage = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{canManageMeeting && (<Box sx={{ mt: 3 }}>
|
{canManageMeeting && (<Box sx={{ mt: 3 }}>
|
||||||
<Button variant="outlined" startIcon={<PreviewIcon />} onClick={handlePreviewActionItems} disabled={previewTask || summaryTask || isEditingSummary || (!meeting.summary && !meeting.transcript)}>
|
<Button variant="outlined" startIcon={<PreviewIcon />} onClick={handlePreviewActionItems} disabled={previewTask || summaryTask || isEditingSummary || !meeting.transcript}>
|
||||||
{previewTask ? <CircularProgress size={24} /> : "Preview Action Items"}
|
{previewTask ? <CircularProgress size={24} /> : "Preview Action Items"}
|
||||||
</Button>
|
</Button>
|
||||||
|
{previewMessage && <Alert severity="info" sx={{ mt: 2 }}>{previewMessage}</Alert>}
|
||||||
{previewedItems.length > 0 && (<Box>
|
{previewedItems.length > 0 && (<Box>
|
||||||
<TableContainer component={Paper} sx={{ mt: 2 }}><Table size="small">
|
<TableContainer component={Paper} sx={{ mt: 2 }}><Table size="small">
|
||||||
<TableHead><TableRow><TableCell>Context/Item</TableCell><TableCell>Action</TableCell><TableCell>Owner</TableCell><TableCell>Due Date</TableCell></TableRow></TableHead>
|
<TableHead><TableRow><TableCell>Context/Item</TableCell><TableCell>Action</TableCell><TableCell>Owner</TableCell><TableCell>Due Date</TableCell></TableRow></TableHead>
|
||||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
|||||||
# services/dify_client.py
|
# services/dify_client.py
|
||||||
import os, json, re, requests
|
import os, json, re, requests
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -19,12 +20,13 @@ def _post_request(endpoint: str, api_key: str, payload: dict):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# For debugging the exact payload sent to the API
|
# For debugging the exact payload sent to the API
|
||||||
print(f"Sending Dify request to {url}: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
current_app.logger.debug(f"Sending Dify request to {url}: {json.dumps(payload, indent=2, ensure_ascii=False)}")
|
||||||
|
|
||||||
resp = requests.post(url, headers=headers, json=payload, timeout=TIMEOUT)
|
resp = requests.post(url, headers=headers, json=payload, timeout=TIMEOUT)
|
||||||
|
|
||||||
|
current_app.logger.debug(f"Dify API Response ({resp.status_code}): {resp.text}")
|
||||||
|
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
print(f"Dify API Error Response: {resp.text}")
|
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
@@ -59,11 +61,14 @@ def summarize_text(text: str, user_id: str = "system") -> str:
|
|||||||
|
|
||||||
def extract_action_items(text: str, user_id: str = "system") -> list[dict]:
|
def extract_action_items(text: str, user_id: str = "system") -> list[dict]:
|
||||||
api_key = os.getenv("DIFY_ACTION_EXTRACTOR_API_KEY")
|
api_key = os.getenv("DIFY_ACTION_EXTRACTOR_API_KEY")
|
||||||
|
|
||||||
|
query = f"請從以下會議記錄中,提取所有行動項目(action items),並嚴格以JSON格式返回。會議記錄如下:\n\n{text}"
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"response_mode": "blocking",
|
"response_mode": "blocking",
|
||||||
"user": user_id,
|
"user": user_id,
|
||||||
"query": text,
|
"query": query,
|
||||||
}
|
}
|
||||||
raw = _post_request("/chat-messages", api_key, payload)
|
raw = _post_request("/chat-messages", api_key, payload)
|
||||||
|
|
||||||
@@ -90,4 +95,4 @@ def extract_action_items(text: str, user_id: str = "system") -> list[dict]:
|
|||||||
"owner": i["owner"],
|
"owner": i["owner"],
|
||||||
"due_date": i["duedate"],
|
"due_date": i["duedate"],
|
||||||
})
|
})
|
||||||
return normalized
|
return normalized
|
||||||
|
29
tasks.py
29
tasks.py
@@ -362,37 +362,26 @@ def summarize_text_task(self, meeting_id):
|
|||||||
def preview_action_items_task(self, text_content):
|
def preview_action_items_task(self, text_content):
|
||||||
from app import app
|
from app import app
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
|
from services.dify_client import extract_action_items
|
||||||
try:
|
try:
|
||||||
self.update_progress(10, 100, "Requesting Dify for action items...")
|
self.update_progress(10, 100, "Requesting Dify for action items...")
|
||||||
api_key = app.config.get("DIFY_ACTION_EXTRACTOR_API_KEY")
|
|
||||||
|
# We can reuse the logic from the summarizer to strip timestamps
|
||||||
plain_text = re.sub(r'^(\s*\[.*?\])\s*', '', text_content, flags=re.MULTILINE)
|
plain_text = re.sub(r'^(\s*\[.*?\])\s*', '', text_content, flags=re.MULTILINE)
|
||||||
|
|
||||||
if not plain_text.strip():
|
if not plain_text.strip():
|
||||||
|
self.update_progress(100, 100, "Preview skipped, content is empty.")
|
||||||
return {'status': 'Success', 'items': []}
|
return {'status': 'Success', 'items': []}
|
||||||
|
|
||||||
response = ask_dify(api_key, plain_text)
|
# Use the robust client function
|
||||||
answer_text = response.get("answer", "")
|
parsed_items = extract_action_items(plain_text)
|
||||||
self.update_progress(80, 100, "Parsing response...")
|
|
||||||
|
|
||||||
parsed_items = []
|
|
||||||
try:
|
|
||||||
# Find the JSON array within the response string
|
|
||||||
match = re.search(r'\[.*\]', answer_text, re.DOTALL)
|
|
||||||
if match:
|
|
||||||
json_str = match.group(0)
|
|
||||||
parsed_items = json.loads(json_str)
|
|
||||||
|
|
||||||
# Ensure it's a list, otherwise reset to empty
|
|
||||||
if not isinstance(parsed_items, list):
|
|
||||||
parsed_items = []
|
|
||||||
|
|
||||||
except (json.JSONDecodeError, TypeError):
|
|
||||||
# If parsing fails, leave it as an empty list
|
|
||||||
parsed_items = []
|
|
||||||
|
|
||||||
self.update_progress(100, 100, "Action item preview generated.")
|
self.update_progress(100, 100, "Action item preview generated.")
|
||||||
return {'status': 'Success', 'items': parsed_items}
|
return {'status': 'Success', 'items': parsed_items}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# Log the exception for better debugging
|
||||||
|
import logging
|
||||||
|
logging.error(f"Error in preview_action_items_task: {e}", exc_info=True)
|
||||||
self.update_state(
|
self.update_state(
|
||||||
state='FAILURE',
|
state='FAILURE',
|
||||||
meta={'exc_type': type(e).__name__, 'exc_message': str(e)}
|
meta={'exc_type': type(e).__name__, 'exc_message': str(e)}
|
||||||
|
Reference in New Issue
Block a user