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())
|
||||
|
||||
if request.method == 'DELETE':
|
||||
if get_jwt().get('role') != 'admin':
|
||||
return jsonify({"msg": "Administration rights required"}), 403
|
||||
current_user_id = get_jwt_identity()
|
||||
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.commit()
|
||||
return jsonify({"msg": "Meeting and associated action items deleted"}), 200
|
||||
@@ -235,9 +238,9 @@ def summarize_meeting(meeting_id):
|
||||
@jwt_required()
|
||||
def preview_actions(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:
|
||||
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)
|
||||
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 [newActionItem, setNewActionItem] = useState({ action: '', owner_id: '', due_date: '', item: '' });
|
||||
const [previewedItems, setPreviewedItems] = useState([]);
|
||||
const [previewMessage, setPreviewMessage] = useState(''); // State for the preview result message
|
||||
|
||||
const fetchMeetingData = useCallback(async () => {
|
||||
try {
|
||||
@@ -94,7 +95,11 @@ const MeetingDetailPage = () => {
|
||||
} else if (previewTask) { // Handle preview success
|
||||
setPreviewTask(null);
|
||||
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 () => {
|
||||
setPreviewedItems([]); // Clear previous results
|
||||
setPreviewMessage(''); // Clear previous messages
|
||||
setPreviewTask({ state: 'PENDING', info: 'Initializing preview task...' });
|
||||
try {
|
||||
// This now calls the async task endpoint
|
||||
@@ -244,9 +251,10 @@ const MeetingDetailPage = () => {
|
||||
)}
|
||||
|
||||
{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"}
|
||||
</Button>
|
||||
{previewMessage && <Alert severity="info" sx={{ mt: 2 }}>{previewMessage}</Alert>}
|
||||
{previewedItems.length > 0 && (<Box>
|
||||
<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>
|
||||
|
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
# services/dify_client.py
|
||||
import os, json, re, requests
|
||||
from dotenv import load_dotenv
|
||||
from flask import current_app
|
||||
|
||||
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
|
||||
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)
|
||||
|
||||
current_app.logger.debug(f"Dify API Response ({resp.status_code}): {resp.text}")
|
||||
|
||||
if resp.status_code != 200:
|
||||
print(f"Dify API Error Response: {resp.text}")
|
||||
resp.raise_for_status()
|
||||
|
||||
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]:
|
||||
api_key = os.getenv("DIFY_ACTION_EXTRACTOR_API_KEY")
|
||||
|
||||
query = f"請從以下會議記錄中,提取所有行動項目(action items),並嚴格以JSON格式返回。會議記錄如下:\n\n{text}"
|
||||
|
||||
payload = {
|
||||
"inputs": {},
|
||||
"response_mode": "blocking",
|
||||
"user": user_id,
|
||||
"query": text,
|
||||
"query": query,
|
||||
}
|
||||
raw = _post_request("/chat-messages", api_key, payload)
|
||||
|
||||
|
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):
|
||||
from app import app
|
||||
with app.app_context():
|
||||
from services.dify_client import extract_action_items
|
||||
try:
|
||||
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)
|
||||
|
||||
if not plain_text.strip():
|
||||
self.update_progress(100, 100, "Preview skipped, content is empty.")
|
||||
return {'status': 'Success', 'items': []}
|
||||
|
||||
response = ask_dify(api_key, plain_text)
|
||||
answer_text = response.get("answer", "")
|
||||
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 = []
|
||||
# Use the robust client function
|
||||
parsed_items = extract_action_items(plain_text)
|
||||
|
||||
self.update_progress(100, 100, "Action item preview generated.")
|
||||
return {'status': 'Success', 'items': parsed_items}
|
||||
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(
|
||||
state='FAILURE',
|
||||
meta={'exc_type': type(e).__name__, 'exc_message': str(e)}
|
||||
|
Reference in New Issue
Block a user