changes
Browse files
app.py
CHANGED
@@ -337,6 +337,47 @@ class VisualConsensusEngine:
|
|
337 |
pass
|
338 |
return 5.0
|
339 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
def run_visual_consensus_session(self, question: str, discussion_rounds: int = 3,
|
341 |
decision_protocol: str = "consensus", role_assignment: str = "balanced",
|
342 |
topology: str = "full_mesh", moderator_model: str = "mistral",
|
@@ -357,7 +398,7 @@ class VisualConsensusEngine:
|
|
357 |
|
358 |
# Log the start
|
359 |
log_event('phase', content=f"π Starting Discussion: {question}")
|
360 |
-
log_event('phase', content=f"π Configuration: {len(available_models)} models, {decision_protocol} protocol, {role_assignment} roles")
|
361 |
|
362 |
# Initialize visual state
|
363 |
self.update_visual_state({
|
@@ -469,20 +510,23 @@ Your response should include:
|
|
469 |
if not enable_step_by_step:
|
470 |
time.sleep(1)
|
471 |
|
472 |
-
#
|
473 |
-
|
474 |
-
for other_model in available_models:
|
475 |
-
if other_model != model:
|
476 |
-
other_responses += f"\n**{self.models[other_model]['name']}**: [Previous response]\n"
|
477 |
|
478 |
-
|
|
|
|
|
|
|
|
|
|
|
479 |
|
480 |
-
|
481 |
|
482 |
-
|
483 |
-
|
|
|
|
|
484 |
|
485 |
-
Please provide your updated analysis considering the discussion so far.
|
486 |
END WITH: "Confidence: X/10" """
|
487 |
|
488 |
log_event('speaking', speaker=self.models[model]['name'])
|
@@ -531,7 +575,7 @@ END WITH: "Confidence: X/10" """
|
|
531 |
else:
|
532 |
time.sleep(1)
|
533 |
|
534 |
-
# Phase 3: Final consensus
|
535 |
log_event('phase', content=f"π― Phase 3: Final Consensus ({decision_protocol})")
|
536 |
log_event('thinking', speaker="All participants", content="Building consensus...")
|
537 |
|
@@ -545,45 +589,69 @@ END WITH: "Confidence: X/10" """
|
|
545 |
if not enable_step_by_step:
|
546 |
time.sleep(2)
|
547 |
|
548 |
-
# Generate consensus
|
549 |
moderator = self.moderator_model if self.models[self.moderator_model]['available'] else available_models[0]
|
550 |
|
551 |
-
#
|
552 |
-
|
553 |
-
all_responses = ""
|
554 |
confidence_scores = []
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
560 |
|
561 |
avg_confidence = sum(confidence_scores) / len(confidence_scores) if confidence_scores else 5.0
|
562 |
-
consensus_threshold = 7.0
|
563 |
|
564 |
-
consensus_prompt = f"""You are synthesizing the final result from this AI discussion.
|
565 |
-
|
566 |
-
ORIGINAL QUESTION: {question}
|
567 |
|
568 |
-
ALL PARTICIPANT RESPONSES:
|
569 |
{all_responses}
|
570 |
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
AVERAGE CONFIDENCE LEVEL: {avg_confidence:.1f}/10
|
|
|
572 |
|
573 |
Your task:
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
|
579 |
Be honest about the level of consensus achieved. Do not force agreement where none exists.
|
580 |
|
581 |
Format your response as:
|
582 |
**CONSENSUS STATUS:** [Reached/Partial/Not Reached]
|
583 |
|
584 |
-
**FINAL ANSWER:** [Your synthesis]
|
|
|
|
|
585 |
|
586 |
-
**
|
|
|
|
|
587 |
|
588 |
log_event('speaking', speaker="Consilium", content="Analyzing consensus and synthesizing final answer...")
|
589 |
self.update_visual_state({
|
@@ -602,7 +670,7 @@ Format your response as:
|
|
602 |
|
603 |
**AREAS OF DISAGREEMENT:** Analysis could not be completed due to technical issues."""
|
604 |
|
605 |
-
consensus_reached = "CONSENSUS STATUS
|
606 |
|
607 |
if consensus_reached:
|
608 |
visual_summary = "β
Consensus reached!"
|
@@ -696,6 +764,7 @@ def run_consensus_discussion_session(question: str, discussion_rounds: int = 3,
|
|
696 |
### π Discussion Summary
|
697 |
- **Question:** {question}
|
698 |
- **Protocol:** {decision_protocol.replace('_', ' ').title()}
|
|
|
699 |
- **Participants:** {len(available_models)} AI models
|
700 |
- **Roles:** {role_assignment.title()}
|
701 |
- **Session ID:** {session_id[:8]}...
|
@@ -763,11 +832,11 @@ def check_model_status_session(session_id_state: str = None, request: gr.Request
|
|
763 |
'DeepSeek-R1': sambanova_key,
|
764 |
'Meta-Llama-3.1-8B': sambanova_key,
|
765 |
'QwQ-32B': sambanova_key,
|
766 |
-
'
|
767 |
}
|
768 |
|
769 |
for model_name, available in models.items():
|
770 |
-
if model_name == '
|
771 |
status = "β
Available (Built-in)"
|
772 |
else:
|
773 |
if available:
|
@@ -827,7 +896,8 @@ with gr.Blocks(title="π Consilium: Visual AI Consensus Platform", theme=gr.th
|
|
827 |
topology = gr.Dropdown(
|
828 |
choices=["full_mesh", "star", "ring"],
|
829 |
value="full_mesh",
|
830 |
-
label="π Communication Pattern"
|
|
|
831 |
)
|
832 |
|
833 |
moderator_model = gr.Dropdown(
|
@@ -938,7 +1008,7 @@ with gr.Blocks(title="π Consilium: Visual AI Consensus Platform", theme=gr.th
|
|
938 |
outputs=[step_status]
|
939 |
)
|
940 |
|
941 |
-
# Auto-refresh the roundtable state every
|
942 |
def refresh_roundtable(session_id_state, request: gr.Request = None):
|
943 |
session_id = get_session_id(request) if not session_id_state else session_id_state
|
944 |
if session_id in user_sessions:
|
@@ -1116,6 +1186,23 @@ with gr.Blocks(title="π Consilium: Visual AI Consensus Platform", theme=gr.th
|
|
1116 |
- **Ranked Choice**: Preference-based selection
|
1117 |
- **Unanimity**: All must agree completely
|
1118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1119 |
## π Session Isolation
|
1120 |
|
1121 |
**Each user gets their own private space:**
|
|
|
337 |
pass
|
338 |
return 5.0
|
339 |
|
340 |
+
# FIXED: Proper conversation context building based on topology
|
341 |
+
def build_conversation_context(self, all_messages: List[Dict], current_model: str, question: str, round_num: int, topology: str = "full_mesh") -> str:
|
342 |
+
"""Build proper conversation context based on topology"""
|
343 |
+
|
344 |
+
current_model_name = self.models[current_model]['name']
|
345 |
+
|
346 |
+
if topology == "full_mesh":
|
347 |
+
# Everyone sees everyone's responses (except their own)
|
348 |
+
context = f"ORIGINAL QUESTION: {question}\n\nCONVERSATION SO FAR:\n"
|
349 |
+
|
350 |
+
for msg in all_messages:
|
351 |
+
if msg["speaker"] != current_model_name: # Don't include own messages in context
|
352 |
+
context += f"\n**{msg['speaker']}** ({msg.get('role', 'standard')}):\n{msg['text']}\n"
|
353 |
+
if 'confidence' in msg:
|
354 |
+
context += f"*Confidence: {msg['confidence']}/10*\n"
|
355 |
+
|
356 |
+
elif topology == "star":
|
357 |
+
# Only see moderator and own previous responses
|
358 |
+
context = f"ORIGINAL QUESTION: {question}\n\nRELEVANT RESPONSES:\n"
|
359 |
+
moderator_name = self.models[self.moderator_model]['name']
|
360 |
+
|
361 |
+
for msg in all_messages:
|
362 |
+
if msg["speaker"] == moderator_name:
|
363 |
+
context += f"\n**{msg['speaker']} (Moderator)**:\n{msg['text']}\n"
|
364 |
+
|
365 |
+
elif topology == "ring":
|
366 |
+
# Only see previous model in the ring
|
367 |
+
context = f"ORIGINAL QUESTION: {question}\n\nPREVIOUS RESPONSE:\n"
|
368 |
+
available_models = [model for model, info in self.models.items() if info['available']]
|
369 |
+
current_idx = available_models.index(current_model)
|
370 |
+
prev_idx = (current_idx - 1) % len(available_models)
|
371 |
+
prev_model_name = self.models[available_models[prev_idx]]['name']
|
372 |
+
|
373 |
+
# Get the most recent message from the previous model
|
374 |
+
for msg in reversed(all_messages):
|
375 |
+
if msg["speaker"] == prev_model_name:
|
376 |
+
context += f"\n**{msg['speaker']}**:\n{msg['text']}\n"
|
377 |
+
break
|
378 |
+
|
379 |
+
return context
|
380 |
+
|
381 |
def run_visual_consensus_session(self, question: str, discussion_rounds: int = 3,
|
382 |
decision_protocol: str = "consensus", role_assignment: str = "balanced",
|
383 |
topology: str = "full_mesh", moderator_model: str = "mistral",
|
|
|
398 |
|
399 |
# Log the start
|
400 |
log_event('phase', content=f"π Starting Discussion: {question}")
|
401 |
+
log_event('phase', content=f"π Configuration: {len(available_models)} models, {decision_protocol} protocol, {role_assignment} roles, {topology} topology")
|
402 |
|
403 |
# Initialize visual state
|
404 |
self.update_visual_state({
|
|
|
510 |
if not enable_step_by_step:
|
511 |
time.sleep(1)
|
512 |
|
513 |
+
# FIXED: Build proper conversation context based on topology
|
514 |
+
conversation_context = self.build_conversation_context(all_messages, model, question, round_num + 1, topology)
|
|
|
|
|
|
|
515 |
|
516 |
+
role = model_roles[model]
|
517 |
+
role_context = self.roles[role]
|
518 |
+
|
519 |
+
discussion_prompt = f"""{role_context}
|
520 |
+
|
521 |
+
{conversation_context}
|
522 |
|
523 |
+
ROUND {round_num + 1} of {discussion_rounds}
|
524 |
|
525 |
+
Please provide your updated analysis considering the discussion so far.
|
526 |
+
- Address any points raised by other participants
|
527 |
+
- Refine or adjust your position based on new information
|
528 |
+
- Maintain your assigned role perspective
|
529 |
|
|
|
530 |
END WITH: "Confidence: X/10" """
|
531 |
|
532 |
log_event('speaking', speaker=self.models[model]['name'])
|
|
|
575 |
else:
|
576 |
time.sleep(1)
|
577 |
|
578 |
+
# Phase 3: Final consensus - IMPROVED WITH PROPER ANALYSIS
|
579 |
log_event('phase', content=f"π― Phase 3: Final Consensus ({decision_protocol})")
|
580 |
log_event('thinking', speaker="All participants", content="Building consensus...")
|
581 |
|
|
|
589 |
if not enable_step_by_step:
|
590 |
time.sleep(2)
|
591 |
|
592 |
+
# Generate consensus with proper conversation analysis
|
593 |
moderator = self.moderator_model if self.models[self.moderator_model]['available'] else available_models[0]
|
594 |
|
595 |
+
# FIXED: Group messages by speaker for better analysis
|
596 |
+
speaker_positions = {}
|
|
|
597 |
confidence_scores = []
|
598 |
+
|
599 |
+
for msg in all_messages:
|
600 |
+
speaker = msg["speaker"]
|
601 |
+
if speaker not in speaker_positions:
|
602 |
+
speaker_positions[speaker] = []
|
603 |
+
speaker_positions[speaker].append(msg)
|
604 |
+
if 'confidence' in msg:
|
605 |
+
confidence_scores.append(msg['confidence'])
|
606 |
+
|
607 |
+
# Build comprehensive context for consensus
|
608 |
+
all_responses = f"ORIGINAL QUESTION: {question}\n\nTOPOLOGY: {topology}\nDECISION PROTOCOL: {decision_protocol}\n\n"
|
609 |
+
|
610 |
+
for speaker, messages in speaker_positions.items():
|
611 |
+
if speaker != 'Consilium': # Skip previous consensus attempts
|
612 |
+
all_responses += f"\n{'='*50}\n**{speaker}** (Role: {messages[0].get('role', 'standard')}):\n\n"
|
613 |
+
for i, msg in enumerate(messages):
|
614 |
+
if i == 0:
|
615 |
+
all_responses += f"Initial Response: {msg['text']}\n\n"
|
616 |
+
else:
|
617 |
+
all_responses += f"Round {i}: {msg['text']}\n\n"
|
618 |
+
|
619 |
+
if messages[-1].get('confidence'):
|
620 |
+
all_responses += f"Final Confidence: {messages[-1]['confidence']}/10\n"
|
621 |
|
622 |
avg_confidence = sum(confidence_scores) / len(confidence_scores) if confidence_scores else 5.0
|
|
|
623 |
|
624 |
+
consensus_prompt = f"""You are synthesizing the final result from this multi-AI discussion.
|
|
|
|
|
625 |
|
|
|
626 |
{all_responses}
|
627 |
|
628 |
+
ANALYSIS REQUIREMENTS:
|
629 |
+
1. Identify areas where AIs agree vs disagree
|
630 |
+
2. Assess the quality and strength of arguments presented
|
631 |
+
3. Note any evolution in positions across discussion rounds
|
632 |
+
4. Determine if genuine consensus was reached based on the {decision_protocol} protocol
|
633 |
+
|
634 |
AVERAGE CONFIDENCE LEVEL: {avg_confidence:.1f}/10
|
635 |
+
CONSENSUS THRESHOLD: 7.0/10
|
636 |
|
637 |
Your task:
|
638 |
+
- Analyze if the participants reached genuine consensus or if there are significant disagreements
|
639 |
+
- If there IS consensus: Provide a comprehensive final answer incorporating all insights
|
640 |
+
- If there is NO consensus: Clearly state the disagreements and present the main conflicting positions
|
641 |
+
- If partially aligned: Identify areas of agreement and areas of disagreement
|
642 |
|
643 |
Be honest about the level of consensus achieved. Do not force agreement where none exists.
|
644 |
|
645 |
Format your response as:
|
646 |
**CONSENSUS STATUS:** [Reached/Partial/Not Reached]
|
647 |
|
648 |
+
**FINAL ANSWER:** [Your comprehensive synthesis]
|
649 |
+
|
650 |
+
**AREAS OF AGREEMENT:** [Points where participants aligned]
|
651 |
|
652 |
+
**REMAINING DISAGREEMENTS:** [If any - explain the key points of contention]
|
653 |
+
|
654 |
+
**CONFIDENCE ASSESSMENT:** [Analysis of certainty levels and reliability]"""
|
655 |
|
656 |
log_event('speaking', speaker="Consilium", content="Analyzing consensus and synthesizing final answer...")
|
657 |
self.update_visual_state({
|
|
|
670 |
|
671 |
**AREAS OF DISAGREEMENT:** Analysis could not be completed due to technical issues."""
|
672 |
|
673 |
+
consensus_reached = "CONSENSUS STATUS:** Reached" in consensus_result or avg_confidence >= 7.0
|
674 |
|
675 |
if consensus_reached:
|
676 |
visual_summary = "β
Consensus reached!"
|
|
|
764 |
### π Discussion Summary
|
765 |
- **Question:** {question}
|
766 |
- **Protocol:** {decision_protocol.replace('_', ' ').title()}
|
767 |
+
- **Topology:** {topology.replace('_', ' ').title()}
|
768 |
- **Participants:** {len(available_models)} AI models
|
769 |
- **Roles:** {role_assignment.title()}
|
770 |
- **Session ID:** {session_id[:8]}...
|
|
|
832 |
'DeepSeek-R1': sambanova_key,
|
833 |
'Meta-Llama-3.1-8B': sambanova_key,
|
834 |
'QwQ-32B': sambanova_key,
|
835 |
+
'Search': True
|
836 |
}
|
837 |
|
838 |
for model_name, available in models.items():
|
839 |
+
if model_name == 'Search':
|
840 |
status = "β
Available (Built-in)"
|
841 |
else:
|
842 |
if available:
|
|
|
896 |
topology = gr.Dropdown(
|
897 |
choices=["full_mesh", "star", "ring"],
|
898 |
value="full_mesh",
|
899 |
+
label="π Communication Pattern",
|
900 |
+
info="Full mesh: all see all, Star: only moderator, Ring: chain communication"
|
901 |
)
|
902 |
|
903 |
moderator_model = gr.Dropdown(
|
|
|
1008 |
outputs=[step_status]
|
1009 |
)
|
1010 |
|
1011 |
+
# Auto-refresh the roundtable state every 0.5 seconds during discussion
|
1012 |
def refresh_roundtable(session_id_state, request: gr.Request = None):
|
1013 |
session_id = get_session_id(request) if not session_id_state else session_id_state
|
1014 |
if session_id in user_sessions:
|
|
|
1186 |
- **Ranked Choice**: Preference-based selection
|
1187 |
- **Unanimity**: All must agree completely
|
1188 |
|
1189 |
+
## π Communication Topologies (NOW IMPLEMENTED!)
|
1190 |
+
|
1191 |
+
### πΈοΈ **Full Mesh** (Default)
|
1192 |
+
- Every AI sees responses from ALL other AIs
|
1193 |
+
- Maximum information sharing
|
1194 |
+
- Best for comprehensive consensus
|
1195 |
+
|
1196 |
+
### β **Star**
|
1197 |
+
- AIs only see the moderator's responses
|
1198 |
+
- Centralized communication pattern
|
1199 |
+
- Good for controlled discussions
|
1200 |
+
|
1201 |
+
### π **Ring**
|
1202 |
+
- Each AI only sees the previous AI's response
|
1203 |
+
- Sequential information flow
|
1204 |
+
- Interesting for building on ideas
|
1205 |
+
|
1206 |
## π Session Isolation
|
1207 |
|
1208 |
**Each user gets their own private space:**
|