mirrors / simple_app.py
Shim
.
f095630
# -*- coding: utf-8 -*-
"""
Simplified ืžืจืื•ืช (Mirrors) app for local testing
Uses the same template-based response system as the main app
"""
import os
# Force lightweight model for testing
os.environ["FORCE_LIGHT_MODEL"] = "1"
import gradio as gr
from conversation_manager import ConversationManager
from prompt_engineering import DEFAULT_PARTS
import random
# Initialize components
conv_manager = ConversationManager()
def generate_persona_response(user_message: str, part_name: str, persona_name: str, user_context: str = None, conversation_history=None):
"""
Generate persona-based response using templates
Same system as the main app
"""
part_info = DEFAULT_PARTS.get(part_name, {})
display_name = persona_name or part_info.get("default_persona_name", "ื—ืœืง ืคื ื™ืžื™")
# Generate contextual responses based on part type
if part_name == "ื”ืงื•ืœ ื”ื‘ื™ืงื•ืจืชื™":
responses = [
f"ืื ื™ {display_name}, ื”ืงื•ืœ ื”ื‘ื™ืงื•ืจืชื™ ืฉืœืš. ืฉืžืขืชื™ ืžื” ืฉืืžืจืช ืขืœ '{user_message}' - ืื ื™ ื—ื•ืฉื‘ ืฉืฆืจื™ืš ืœื‘ื—ื•ืŸ ืืช ื–ื” ื™ื•ืชืจ ืœืขื•ืžืง. ืžื” ื‘ืืžืช ืขื•ืžื“ ืžืื—ื•ืจื™ ื”ืžื—ืฉื‘ื•ืช ื”ืืœื”?",
f"ืื ื™ {display_name}. ืžื” ืฉืืžืจืช ืžืขื•ืจืจ ื‘ื™ ืฉืืœื•ืช. '{user_message}' - ืื‘ืœ ื”ืื ื–ื” ื‘ืืžืช ื”ืžืฆื‘ ื”ืžืœื? ืื•ืœื™ ื™ืฉ ื›ืืŸ ื“ื‘ืจื™ื ืฉืืชื” ืœื ืจื•ืื”?",
f"ื–ื” {display_name} ืžื“ื‘ืจ. ืื ื™ ืฉื•ืžืข ืื•ืชืš ืื•ืžืจ '{user_message}', ืื‘ืœ ืื ื™ ืžืจื’ื™ืฉ ืฉืื ื—ื ื• ืฆืจื™ื›ื™ื ืœื”ื™ื•ืช ื™ื•ืชืจ ื‘ื™ืงื•ืจืชื™ื™ื ื›ืืŸ. ืžื” ืืชื” ืœื ืžืกืคืจ ืœืขืฆืžืš?",
f"ืื ื™ {display_name}, ื•ืื ื™ ื›ืืŸ ื›ื“ื™ ืœืขื–ื•ืจ ืœืš ืœืจืื•ืช ืืช ื”ืชืžื•ื ื” ื”ืžืœืื”. ืžื” ืฉืืžืจืช ืขืœ '{user_message}' - ื–ื” ืจืง ื—ืฆื™ ืžื”ืกื™ืคื•ืจ, ืœื? ื‘ื•ืื ื• ื ื—ืคื•ืจ ืขืžื•ืง ื™ื•ืชืจ."
]
elif part_name == "ื”ื™ืœื“/ื” ื”ืคื ื™ืžื™ืช":
responses = [
f"ืื ื™ {display_name}, ื”ื™ืœื“/ื” ื”ืคื ื™ืžื™ืช ืฉืœืš. ืžื” ืฉืืžืจืช ืขืœ '{user_message}' ื’ื•ืจื ืœื™ ืœื”ืจื’ื™ืฉ... ืงืฆืช ืคื’ื™ืข. ืืชื” ื‘ืืžืช ืฉื•ืžืข ืื•ืชื™ ืขื›ืฉื™ื•?",
f"ื–ื” {display_name}. '{user_message}' - ื–ื” ืžื‘ื”ื™ืœ ืื•ืชื™ ืงืฆืช. ืื ื™ ืฆืจื™ืš ืœื“ืขืช ืฉื”ื›ืœ ื™ื”ื™ื” ื‘ืกื“ืจ. ืืชื” ื™ื›ื•ืœ ืœื”ืจื’ื™ืข ืื•ืชื™?",
f"ืื ื™ {display_name}, ื”ื—ืœืง ื”ืฆืขื™ืจ ืฉืœืš. ืžื” ืฉืืžืจืช ื ื•ื’ืข ืœืœื‘ ืฉืœื™. '{user_message}' - ืื ื™ ืžืจื’ื™ืฉ ืฉื™ืฉ ื›ืืŸ ืžืฉื”ื• ื—ืฉื•ื‘ ืฉืื ื™ ืฆืจื™ืš ืœื”ื‘ื™ืŸ.",
f"ื–ื” {display_name} ืžื“ื‘ืจ ื‘ืฉืงื˜. ืื ื™ ืฉื•ืžืข ืืช '{user_message}' ื•ื–ื” ืžืขื•ืจืจ ื‘ื™ ืจื’ืฉื•ืช. ื”ืื ื–ื” ื‘ื˜ื•ื— ืœื—ืฉื•ื‘ ืขืœ ื–ื”? ืื ื™ ืงืฆืช ื—ืจื“."
]
elif part_name == "ื”ืžืจืฆื”":
responses = [
f"ืื ื™ {display_name}, ื”ืžืจืฆื” ืฉืœืš. ืฉืžืขืชื™ ืืช '{user_message}' ื•ืื ื™ ืจื•ืฆื” ืœื•ื•ื“ื ืฉื›ื•ืœื ื™ื”ื™ื• ื‘ืกื“ืจ ืขื ื–ื”. ืื™ืš ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœืคืชื•ืจ ืืช ื–ื” ื‘ืฆื•ืจื” ืฉืชืจืฆื” ืืช ื›ื•ืœื?",
f"ื–ื” {display_name}. ืžื” ืฉืืžืจืช ืขืœ '{user_message}' ื’ื•ืจื ืœื™ ืœื“ืื•ื’ - ื”ืื ื–ื” ื™ื›ื•ืœ ืœืคื’ื•ืข ื‘ืžื™ืฉื”ื•? ื‘ื•ืื ื• ื ืžืฆื ื“ืจืš ืขื“ื™ื ื” ื™ื•ืชืจ ืœื”ืชืžื•ื“ื“ ืขื ื–ื”.",
f"ืื ื™ {display_name}, ื•ืื ื™ ืจื•ืฆื” ืฉื›ื•ืœื ื™ื”ื™ื• ืžืจื•ืฆื™ื ื›ืืŸ. '{user_message}' - ื–ื” ื ืฉืžืข ื›ืžื• ืžืฉื”ื• ืฉื™ื›ื•ืœ ืœื™ืฆื•ืจ ืžืชื—. ืื™ืš ื ื•ื›ืœ ืœืขืฉื•ืช ืืช ื–ื” ื‘ืฆื•ืจื” ืฉื›ื•ืœื ื™ืื”ื‘ื•?",
f"ื–ื” {display_name} ืžื“ื‘ืจ. ืื ื™ ืฉื•ืžืข ืืช '{user_message}' ื•ืžื™ื“ ืื ื™ ื—ื•ืฉื‘ - ืžื” ืื—ืจื™ื ื™ื’ื™ื“ื• ืขืœ ื–ื”? ื‘ื•ืื ื• ื ื•ื•ื“ื ืฉืื ื—ื ื• ืœื ืคื•ื’ืขื™ื ื‘ืืฃ ืื—ื“."
]
elif part_name == "ื”ืžื’ืŸ":
responses = [
f"ืื ื™ {display_name}, ื”ืžื’ืŸ ืฉืœืš. '{user_message}' - ืื ื™ ืžืขืจื™ืš ืืช ื”ืžืฆื‘. ื”ืื ื–ื” ื‘ื˜ื•ื—? ืื ื™ ื›ืืŸ ื›ื“ื™ ืœืฉืžื•ืจ ืขืœื™ืš ืžื›ืœ ืžื” ืฉื™ื›ื•ืœ ืœืคื’ื•ืข ื‘ืš.",
f"ื–ื” {display_name}. ืฉืžืขืชื™ ืžื” ืฉืืžืจืช ืขืœ '{user_message}' ื•ืื ื™ ืžื™ื“ ื‘ื›ื•ื ื ื•ืช. ืžื” ื”ืื™ื•ืžื™ื ื›ืืŸ? ืื™ืš ืื ื™ ื™ื›ื•ืœ ืœื”ื’ืŸ ืขืœื™ืš ื˜ื•ื‘ ื™ื•ืชืจ?",
f"ืื ื™ {display_name}, ื”ืฉื•ืžืจ ืฉืœืš. ืžื” ืฉืืžืจืช ืžืขื•ืจืจ ื‘ื™ ืืช ื”ืื™ื ืกื˜ื™ื ืงื˜ื™ื ื”ืžื’ื ื™ื™ื. '{user_message}' - ื‘ื•ืื ื• ื ื•ื•ื“ื ืฉืืชื” ื—ื–ืง ืžืกืคื™ืง ืœื”ืชืžื•ื“ื“ ืขื ื–ื”.",
f"ื–ื” {display_name} ืžื“ื‘ืจ. ืื ื™ ืฉื•ืžืข ืืช '{user_message}' ื•ืื ื™ ื—ื•ืฉื‘ ืขืœ ืืกื˜ืจื˜ื’ื™ื•ืช ื”ื’ื ื”. ืžื” ืื ื—ื ื• ืฆืจื™ื›ื™ื ืœืขืฉื•ืช ื›ื“ื™ ืฉืชื”ื™ื” ื‘ื˜ื•ื—?"
]
elif part_name == "ื”ื ืžื ืข/ืช":
responses = [
f"ืื ื™ {display_name}, ื”ื ืžื ืข/ืช ืฉืœืš. ืžื” ืฉืืžืจืช ืขืœ '{user_message}' ื’ื•ืจื ืœื™ ืœืจืฆื•ืช ืœื”ื™ืกื•ื’ ืงืฆืช. ืื•ืœื™... ืœื ื—ื™ื™ื‘ื™ื ืœื”ืชืžื•ื“ื“ ืขื ื–ื” ืขื›ืฉื™ื•?",
f"ื–ื” {display_name}. '{user_message}' - ื–ื” ื ืฉืžืข ืžื•ืจื›ื‘ ื•ืžืคื—ื™ื“. ื”ืื ื™ืฉ ื“ืจืš ืœื”ื™ืžื ืข ืžื–ื”? ืœืคืขืžื™ื ืขื“ื™ืฃ ืœื ืœื”ื™ื›ื ืก ืœืžืฆื‘ื™ื ืงืฉื™ื.",
f"ืื ื™ {display_name}, ื•ืื ื™ ืžืจื’ื™ืฉ ืงืฆืช ื—ืจื“ื” ืž'{user_message}'. ื‘ื•ืื ื• ื ื—ื–ื•ืจ ืœื–ื” ืื—ืจ ื›ืš? ืื•ืœื™ ืขื›ืฉื™ื• ื–ื” ืœื ื”ื–ืžืŸ ื”ืžืชืื™ื.",
f"ื–ื” {display_name} ืžื“ื‘ืจ ื‘ื–ื”ื™ืจื•ืช. ืžื” ืฉืืžืจืช ืžืขื•ืจืจ ื‘ื™ ืจืฆื•ืŸ ืœื‘ืจื•ื—. '{user_message}' - ื”ืื ื‘ืืžืช ืฆืจื™ืš ืœื”ืชืžื•ื“ื“ ืขื ื–ื” ืขื›ืฉื™ื•?"
]
else:
responses = [
f"ืื ื™ {display_name}, ื—ืœืง ืคื ื™ืžื™ ืฉืœืš. ืฉืžืขืชื™ ืืช '{user_message}' ื•ืื ื™ ื›ืืŸ ื›ื“ื™ ืœืฉื•ื—ื— ืื™ืชืš ืขืœ ื–ื”. ืžื” ืขื•ื“ ืืชื” ืžืจื’ื™ืฉ ืœื’ื‘ื™ ื”ืžืฆื‘ ื”ื–ื”?",
f"ื–ื” {display_name}. ืžื” ืฉืืžืจืช ืžืขื ื™ื™ืŸ ืื•ืชื™. '{user_message}' - ื‘ื•ืื ื• ื ื—ืงื•ืจ ืืช ื–ื” ื™ื—ื“ ื•ื ื‘ื™ืŸ ืžื” ื–ื” ืื•ืžืจ ืขืœื™ืš.",
f"ืื ื™ {display_name}, ื•ืื ื™ ืจื•ืฆื” ืœื”ื‘ื™ืŸ ืื•ืชืš ื˜ื•ื‘ ื™ื•ืชืจ. '{user_message}' - ืื™ืš ื–ื” ืžืฉืคื™ืข ืขืœื™ืš ื‘ืจืžื” ื”ืจื’ืฉื™ืช?",
f"ื–ื” {display_name} ืžื“ื‘ืจ. ืื ื™ ืฉื•ืžืข ืืช '{user_message}' ื•ืื ื™ ืกืงืจืŸ ืœื“ืขืช ื™ื•ืชืจ. ืžื” ืขื•ื“ ื™ืฉ ื‘ืš ื‘ื ื•ืฉื ื”ื–ื”?"
]
# Select response based on context or randomly
if "ืคื—ื“" in user_message or "ื—ืจื“ื”" in user_message:
selected_response = responses[1] if len(responses) > 1 else responses[0]
elif "ื›ืขืก" in user_message or "ืžืจื’ื™ืฉ ืจืข" in user_message:
selected_response = responses[2] if len(responses) > 2 else responses[0]
else:
selected_response = random.choice(responses)
# Add user context if relevant
if user_context and len(conversation_history or []) < 4:
selected_response += f" ื–ื›ื•ืจ ืฉืืžืจืช ื‘ื”ืชื—ืœื”: {user_context[:100]}..."
return selected_response
def create_session():
"""Create a new conversation session"""
return conv_manager.create_new_session()
def set_context_and_part(user_context, part_choice, persona_name, state):
"""Set user context and selected part"""
# Set initial context
state = conv_manager.set_initial_context(state, "general", user_context)
# Set selected part
state = conv_manager.set_selected_part(state, part_choice, persona_name, None, None)
part_info = DEFAULT_PARTS.get(part_choice, {})
display_name = persona_name if persona_name else part_info.get("default_persona_name", "ื—ืœืง ืคื ื™ืžื™")
return state, f"๐Ÿ—ฃ๏ธ ื›ืขืช ืืชื” ืžืชืฉื•ื—ื— ืขื: **{display_name}** ({part_choice})"
def chat_with_part(message, history, state):
"""Generate response from selected part"""
if not message.strip():
return "", history, state
if not state.selected_part:
response = "ืื ื ื‘ื—ืจ ื—ืœืง ืคื ื™ืžื™ ืชื—ื™ืœื”"
else:
response = generate_persona_response(
message,
state.selected_part,
state.persona_name,
state.user_context,
state.conversation_history
)
state = conv_manager.add_to_history(state, message, response)
history.append([message, response])
return "", history, state
# Create simplified interface
with gr.Blocks(title="ืžืจืื•ืช - ืžืจื—ื‘ ืื™ืฉื™ ืœืฉื™ื— ืคื ื™ืžื™", theme=gr.themes.Soft()) as demo:
# Session state
conversation_state = gr.State(create_session())
gr.HTML("""
<div style="text-align: center; margin-bottom: 30px;">
<h1>๐Ÿชž ืžืจืื•ืช: ืžืจื—ื‘ ืื™ืฉื™ ืœืฉื™ื— ืคื ื™ืžื™</h1>
<p>ืžืงื•ื ื‘ื˜ื•ื— ืœืฉื•ื—ื— ืขื ื”ื—ืœืงื™ื ื”ืฉื•ื ื™ื ืฉืœ ืขืฆืžืš</p>
<div style="background-color: #e8f5e8; border: 1px solid #4caf50; padding: 10px; margin: 10px 0; border-radius: 5px;">
<strong>๐Ÿค– ืžืขืจื›ืช ืชื’ื•ื‘ื•ืช ืžื•ืชืืžืช ืื™ืฉื™ืช ืคืขื™ืœื”</strong>
</div>
</div>
""")
with gr.Row():
with gr.Column():
user_context = gr.Textbox(
label="ืกืคืจ ืขืœ ืขืฆืžืš ืื• ืขืœ ื”ืžืฆื‘ ืฉืœืš:",
placeholder="ืœืžืฉืœ: ืื ื™ ืžืชืžื•ื“ื“ ืขื ืœื—ืฆื™ื ื‘ืขื‘ื•ื“ื”...",
lines=3
)
part_choice = gr.Dropdown(
label="ื‘ื—ืจ ื—ืœืง ืคื ื™ืžื™ ืœืฉื™ื—ื”:",
choices=[
"ื”ืงื•ืœ ื”ื‘ื™ืงื•ืจืชื™",
"ื”ื™ืœื“/ื” ื”ืคื ื™ืžื™ืช",
"ื”ืžืจืฆื”",
"ื”ืžื’ืŸ",
"ื”ื ืžื ืข/ืช"
],
value="ื”ืงื•ืœ ื”ื‘ื™ืงื•ืจืชื™"
)
persona_name = gr.Textbox(
label="ืฉื ืื™ืฉื™ ืœื—ืœืง (ืื•ืคืฆื™ื•ื ืœื™):",
placeholder="ืœืžืฉืœ: ื“ื ื”, ืขื“ืŸ, ื ื•ืขื”..."
)
setup_btn = gr.Button("ื”ืชื—ืœ ืฉื™ื—ื”", variant="primary")
with gr.Column():
current_part = gr.Markdown("ื‘ื—ืจ ื”ื’ื“ืจื•ืช ื•ืœื—ืฅ ืขืœ 'ื”ืชื—ืœ ืฉื™ื—ื”'")
# Chat interface
with gr.Row():
with gr.Column(scale=2):
chatbot = gr.Chatbot(height=400, label="ื”ืฉื™ื—ื” ืฉืœืš", rtl=True)
with gr.Row():
msg_input = gr.Textbox(
label="ื”ื”ื•ื“ืขื” ืฉืœืš:",
placeholder="ื›ืชื•ื‘ ืืช ื”ืžื—ืฉื‘ื•ืช ืฉืœืš...",
lines=2,
scale=4
)
send_btn = gr.Button("ืฉืœื—", scale=1)
clear_btn = gr.Button("ื ืงื” ืฉื™ื—ื”")
# Event handlers
setup_btn.click(
fn=set_context_and_part,
inputs=[user_context, part_choice, persona_name, conversation_state],
outputs=[conversation_state, current_part]
)
msg_input.submit(
fn=chat_with_part,
inputs=[msg_input, chatbot, conversation_state],
outputs=[msg_input, chatbot, conversation_state]
)
send_btn.click(
fn=chat_with_part,
inputs=[msg_input, chatbot, conversation_state],
outputs=[msg_input, chatbot, conversation_state]
)
clear_btn.click(
fn=lambda state: ([], conv_manager.clear_conversation(state)),
inputs=[conversation_state],
outputs=[chatbot, conversation_state]
)
if __name__ == "__main__":
print("๐Ÿงช Starting simplified ืžืจืื•ืช app...")
# Find available port
import socket
for port in range(7864, 7874):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('127.0.0.1', port))
available_port = port
break
except OSError:
continue
else:
available_port = 7864
print(f"๐Ÿš€ Starting on port {available_port}")
demo.launch(
server_name="127.0.0.1",
server_port=available_port,
share=True,
show_api=False,
debug=False,
inbrowser=True
)