Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,60 +2,75 @@ import gradio as gr
|
|
| 2 |
import json
|
| 3 |
import asyncio
|
| 4 |
import edge_tts
|
|
|
|
| 5 |
import os
|
| 6 |
from huggingface_hub import InferenceClient
|
| 7 |
|
| 8 |
-
# ---
|
| 9 |
-
# We use Llama-3 for
|
| 10 |
EXTRACTOR_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct"
|
| 11 |
PERSONALITY_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct"
|
| 12 |
|
| 13 |
-
# Default
|
| 14 |
DEFAULT_LOGS = """
|
| 15 |
-
1. User: I feel
|
| 16 |
-
2. User: I
|
| 17 |
-
3. User: My desk is
|
| 18 |
-
4. User: I
|
| 19 |
-
5. User: I
|
| 20 |
-
6. User:
|
| 21 |
-
7. User: I
|
| 22 |
-
8. User:
|
| 23 |
-
9. User: I
|
| 24 |
-
10. User:
|
| 25 |
-
11. User: I
|
| 26 |
-
12. User: I hate
|
| 27 |
-
13. User: I
|
| 28 |
-
14. User:
|
| 29 |
-
15. User: I
|
| 30 |
-
16. User: I love
|
| 31 |
-
17. User: I
|
| 32 |
-
18. User: I
|
| 33 |
-
19. User:
|
| 34 |
-
20. User: I prefer
|
| 35 |
-
21. User: I
|
| 36 |
-
22. User: I
|
| 37 |
-
23. User: I
|
| 38 |
-
24. User: I am
|
| 39 |
-
25. User: I
|
| 40 |
-
26. User: I
|
| 41 |
-
27. User: I trust my gut
|
| 42 |
-
28. User: I
|
| 43 |
-
29. User: I
|
| 44 |
-
30. User: I want to
|
| 45 |
"""
|
| 46 |
|
| 47 |
-
# ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
def extract_memory(chat_logs, hf_token):
|
| 49 |
if not hf_token:
|
| 50 |
-
return
|
| 51 |
|
| 52 |
client = InferenceClient(token=hf_token)
|
| 53 |
|
|
|
|
| 54 |
system_prompt = """
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
"""
|
| 60 |
|
| 61 |
messages = [
|
|
@@ -67,48 +82,47 @@ def extract_memory(chat_logs, hf_token):
|
|
| 67 |
response = client.chat_completion(
|
| 68 |
model=EXTRACTOR_MODEL,
|
| 69 |
messages=messages,
|
| 70 |
-
max_tokens=
|
| 71 |
temperature=0.1
|
| 72 |
)
|
| 73 |
|
| 74 |
-
#
|
| 75 |
text = response.choices[0].message.content.strip()
|
| 76 |
-
|
| 77 |
-
# Cleaning potential markdown formatting from LLM response
|
| 78 |
-
if "```json" in text:
|
| 79 |
text = text.replace("```json", "").replace("```", "")
|
| 80 |
-
|
| 81 |
start = text.find("{")
|
| 82 |
end = text.rfind("}") + 1
|
| 83 |
return json.dumps(json.loads(text[start:end]), indent=2)
|
| 84 |
except Exception as e:
|
| 85 |
return json.dumps({"error": str(e)}, indent=2)
|
| 86 |
|
| 87 |
-
# ---
|
| 88 |
async def generate_response_and_audio(message, memory_json, persona, hf_token):
|
| 89 |
if not hf_token:
|
| 90 |
-
return "Please
|
| 91 |
|
| 92 |
client = InferenceClient(token=hf_token)
|
| 93 |
|
|
|
|
| 94 |
try:
|
| 95 |
memory = json.loads(memory_json)
|
| 96 |
except:
|
| 97 |
memory = {}
|
| 98 |
|
| 99 |
-
#
|
| 100 |
prompts = {
|
| 101 |
-
"Calm Mentor": "Role:
|
| 102 |
-
"Witty Friend": "Role: Friend. Tone:
|
| 103 |
-
"Therapist
|
| 104 |
}
|
| 105 |
|
| 106 |
-
#
|
| 107 |
context = f"""
|
| 108 |
-
USER
|
| 109 |
-
-
|
| 110 |
- Values: {memory.get('values', 'Unknown')}
|
| 111 |
-
-
|
| 112 |
"""
|
| 113 |
|
| 114 |
messages = [
|
|
@@ -117,7 +131,7 @@ async def generate_response_and_audio(message, memory_json, persona, hf_token):
|
|
| 117 |
]
|
| 118 |
|
| 119 |
try:
|
| 120 |
-
#
|
| 121 |
res = client.chat_completion(
|
| 122 |
model=PERSONALITY_MODEL,
|
| 123 |
messages=messages,
|
|
@@ -126,57 +140,60 @@ async def generate_response_and_audio(message, memory_json, persona, hf_token):
|
|
| 126 |
)
|
| 127 |
text_reply = res.choices[0].message.content
|
| 128 |
|
| 129 |
-
#
|
|
|
|
|
|
|
|
|
|
| 130 |
voice_map = {
|
| 131 |
-
"Calm Mentor": "en-US-ChristopherNeural",
|
| 132 |
-
"Witty Friend": "en-US-EricNeural",
|
| 133 |
-
"Therapist
|
| 134 |
}
|
| 135 |
|
|
|
|
| 136 |
output_file = "response.mp3"
|
| 137 |
-
communicate = edge_tts.Communicate(
|
| 138 |
await communicate.save(output_file)
|
| 139 |
|
| 140 |
return text_reply, output_file
|
| 141 |
|
| 142 |
except Exception as e:
|
| 143 |
-
return f"
|
| 144 |
|
| 145 |
-
# Wrapper
|
| 146 |
def process_interaction(message, memory_json, persona, hf_token):
|
| 147 |
return asyncio.run(generate_response_and_audio(message, memory_json, persona, hf_token))
|
| 148 |
|
| 149 |
-
# ---
|
| 150 |
with gr.Blocks(title="Personality Engine") as demo:
|
| 151 |
-
gr.Markdown("
|
| 152 |
|
| 153 |
with gr.Row():
|
| 154 |
-
token_input = gr.Textbox(label="Hugging Face Token", type="password"
|
| 155 |
|
| 156 |
with gr.Row():
|
| 157 |
-
#
|
| 158 |
-
with gr.Column(
|
| 159 |
-
gr.Markdown("### 1.
|
| 160 |
-
logs_input = gr.Textbox(label="Chat
|
| 161 |
-
extract_btn = gr.Button("
|
| 162 |
-
memory_output = gr.Code(label="
|
| 163 |
|
| 164 |
extract_btn.click(extract_memory, inputs=[logs_input, token_input], outputs=memory_output)
|
| 165 |
|
| 166 |
-
#
|
| 167 |
-
with gr.Column(
|
| 168 |
-
gr.Markdown("### 2.
|
| 169 |
-
user_msg = gr.Textbox(label="Your Message", value="I
|
| 170 |
persona_select = gr.Radio(
|
| 171 |
-
["Calm Mentor", "Witty Friend", "Therapist
|
| 172 |
-
label="
|
| 173 |
value="Calm Mentor"
|
| 174 |
)
|
| 175 |
-
generate_btn = gr.Button("
|
| 176 |
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
audio_output = gr.Audio(label="Voice Response")
|
| 180 |
|
| 181 |
generate_btn.click(
|
| 182 |
process_interaction,
|
|
|
|
| 2 |
import json
|
| 3 |
import asyncio
|
| 4 |
import edge_tts
|
| 5 |
+
import re
|
| 6 |
import os
|
| 7 |
from huggingface_hub import InferenceClient
|
| 8 |
|
| 9 |
+
# --- SETTINGS ---
|
| 10 |
+
# We use the Llama-3 model for everything because it is smart and free.
|
| 11 |
EXTRACTOR_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct"
|
| 12 |
PERSONALITY_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct"
|
| 13 |
|
| 14 |
+
# Default Chat History (30 messages showing different personality traits)
|
| 15 |
DEFAULT_LOGS = """
|
| 16 |
+
1. User: I feel tired after big parties. I need to be alone to recharge.
|
| 17 |
+
2. User: I like ideas more than real-world details.
|
| 18 |
+
3. User: My desk is messy, but I know where my stuff is.
|
| 19 |
+
4. User: I worry that I said the wrong thing.
|
| 20 |
+
5. User: I like to plan ahead. Surprises stress me out.
|
| 21 |
+
6. User: It is hard for me to understand why people cry over small things.
|
| 22 |
+
7. User: I start many hobbies but do not finish them.
|
| 23 |
+
8. User: I feel bad when someone criticizes me.
|
| 24 |
+
9. User: I take charge in groups to make sure work is done right.
|
| 25 |
+
10. User: Logic is more important than feelings.
|
| 26 |
+
11. User: I daydream a lot.
|
| 27 |
+
12. User: I hate fighting. I want everyone to get along.
|
| 28 |
+
13. User: I help others even if it hurts me.
|
| 29 |
+
14. User: Boring tasks make me sleepy.
|
| 30 |
+
15. User: I need proof before I believe something.
|
| 31 |
+
16. User: I love being the center of attention.
|
| 32 |
+
17. User: I am bad at talking about my feelings.
|
| 33 |
+
18. User: I wait until the last minute to do work.
|
| 34 |
+
19. User: Music makes me feel strong emotions.
|
| 35 |
+
20. User: I prefer 2 close friends over 20 acquaintances.
|
| 36 |
+
21. User: I cannot say "no" to people.
|
| 37 |
+
22. User: I always analyze why people act the way they do.
|
| 38 |
+
23. User: I like following rules and traditions.
|
| 39 |
+
24. User: People say I am too serious.
|
| 40 |
+
25. User: I have lots of energy when debating.
|
| 41 |
+
26. User: I am scared of the future.
|
| 42 |
+
27. User: I trust my gut feeling more than numbers.
|
| 43 |
+
28. User: I work better alone.
|
| 44 |
+
29. User: I hate losing games.
|
| 45 |
+
30. User: I want to know my purpose in life.
|
| 46 |
"""
|
| 47 |
|
| 48 |
+
# --- HELPER FUNCTION ---
|
| 49 |
+
def clean_text_for_audio(text):
|
| 50 |
+
"""
|
| 51 |
+
This removes text in brackets like (sighs) or *laughs*.
|
| 52 |
+
We do this so the voice robot does not read them out loud.
|
| 53 |
+
"""
|
| 54 |
+
clean = re.sub(r'[\(\[\*].*?[\)\]\*]', '', text)
|
| 55 |
+
return clean.strip()
|
| 56 |
+
|
| 57 |
+
# --- PART 1: MEMORY EXTRACTOR ---
|
| 58 |
def extract_memory(chat_logs, hf_token):
|
| 59 |
if not hf_token:
|
| 60 |
+
return "Error: Please paste your Hugging Face Token."
|
| 61 |
|
| 62 |
client = InferenceClient(token=hf_token)
|
| 63 |
|
| 64 |
+
# Instructions for the AI to find personality traits
|
| 65 |
system_prompt = """
|
| 66 |
+
Read the chat logs. Create a simple User Profile in JSON format.
|
| 67 |
+
|
| 68 |
+
Find these 3 things:
|
| 69 |
+
1. "traits": Is the user Introverted? Organized? Anxious?
|
| 70 |
+
2. "values": Do they care about Logic? Peace? Winning?
|
| 71 |
+
3. "struggles": Do they procrastinate? Have social anxiety?
|
| 72 |
+
|
| 73 |
+
Return ONLY valid JSON.
|
| 74 |
"""
|
| 75 |
|
| 76 |
messages = [
|
|
|
|
| 82 |
response = client.chat_completion(
|
| 83 |
model=EXTRACTOR_MODEL,
|
| 84 |
messages=messages,
|
| 85 |
+
max_tokens=500,
|
| 86 |
temperature=0.1
|
| 87 |
)
|
| 88 |
|
| 89 |
+
# Clean up the answer to get just the JSON data
|
| 90 |
text = response.choices[0].message.content.strip()
|
| 91 |
+
if "```" in text:
|
|
|
|
|
|
|
| 92 |
text = text.replace("```json", "").replace("```", "")
|
| 93 |
+
|
| 94 |
start = text.find("{")
|
| 95 |
end = text.rfind("}") + 1
|
| 96 |
return json.dumps(json.loads(text[start:end]), indent=2)
|
| 97 |
except Exception as e:
|
| 98 |
return json.dumps({"error": str(e)}, indent=2)
|
| 99 |
|
| 100 |
+
# --- PART 2: PERSONALITY & VOICE ---
|
| 101 |
async def generate_response_and_audio(message, memory_json, persona, hf_token):
|
| 102 |
if not hf_token:
|
| 103 |
+
return "Error: Please paste your Hugging Face Token.", None
|
| 104 |
|
| 105 |
client = InferenceClient(token=hf_token)
|
| 106 |
|
| 107 |
+
# Load the user's memory profile
|
| 108 |
try:
|
| 109 |
memory = json.loads(memory_json)
|
| 110 |
except:
|
| 111 |
memory = {}
|
| 112 |
|
| 113 |
+
# Define the 3 Personalities
|
| 114 |
prompts = {
|
| 115 |
+
"Calm Mentor": "Role: Wise Teacher. Tone: Calm, slow, patient. Advice: Focus on long-term growth.",
|
| 116 |
+
"Witty Friend": "Role: Best Friend. Tone: Funny, fast, sarcastic. Advice: Make jokes and be relatable.",
|
| 117 |
+
"Therapist": "Role: Counselor. Tone: Soft, kind, gentle. Advice: Validate their feelings and ask how they feel."
|
| 118 |
}
|
| 119 |
|
| 120 |
+
# Add User Memory to the AI's brain
|
| 121 |
context = f"""
|
| 122 |
+
ABOUT THE USER:
|
| 123 |
+
- Personality: {memory.get('traits', 'Unknown')}
|
| 124 |
- Values: {memory.get('values', 'Unknown')}
|
| 125 |
+
- Problems: {memory.get('struggles', 'Unknown')}
|
| 126 |
"""
|
| 127 |
|
| 128 |
messages = [
|
|
|
|
| 131 |
]
|
| 132 |
|
| 133 |
try:
|
| 134 |
+
# Step A: Write the text response
|
| 135 |
res = client.chat_completion(
|
| 136 |
model=PERSONALITY_MODEL,
|
| 137 |
messages=messages,
|
|
|
|
| 140 |
)
|
| 141 |
text_reply = res.choices[0].message.content
|
| 142 |
|
| 143 |
+
# Step B: Clean text for the voice engine
|
| 144 |
+
spoken_text = clean_text_for_audio(text_reply)
|
| 145 |
+
|
| 146 |
+
# Step C: Pick a voice based on the persona
|
| 147 |
voice_map = {
|
| 148 |
+
"Calm Mentor": "en-US-ChristopherNeural", # Deep Male Voice
|
| 149 |
+
"Witty Friend": "en-US-EricNeural", # Fast Male Voice
|
| 150 |
+
"Therapist": "en-US-AvaNeural" # Soft Female Voice
|
| 151 |
}
|
| 152 |
|
| 153 |
+
# Step D: Create the audio file
|
| 154 |
output_file = "response.mp3"
|
| 155 |
+
communicate = edge_tts.Communicate(spoken_text, voice_map.get(persona, "en-US-AriaNeural"))
|
| 156 |
await communicate.save(output_file)
|
| 157 |
|
| 158 |
return text_reply, output_file
|
| 159 |
|
| 160 |
except Exception as e:
|
| 161 |
+
return f"Error: {str(e)}", None
|
| 162 |
|
| 163 |
+
# Wrapper to make the async code work with Gradio
|
| 164 |
def process_interaction(message, memory_json, persona, hf_token):
|
| 165 |
return asyncio.run(generate_response_and_audio(message, memory_json, persona, hf_token))
|
| 166 |
|
| 167 |
+
# --- PART 3: THE USER INTERFACE ---
|
| 168 |
with gr.Blocks(title="Personality Engine") as demo:
|
| 169 |
+
gr.Markdown("See how Memory + Tone changes the AI response.")
|
| 170 |
|
| 171 |
with gr.Row():
|
| 172 |
+
token_input = gr.Textbox(label="Hugging Face Token (Required)", type="password")
|
| 173 |
|
| 174 |
with gr.Row():
|
| 175 |
+
# Column 1: Analyze the User
|
| 176 |
+
with gr.Column():
|
| 177 |
+
gr.Markdown("### 1. Analyze User History")
|
| 178 |
+
logs_input = gr.Textbox(label="Chat History", value=DEFAULT_LOGS, lines=10)
|
| 179 |
+
extract_btn = gr.Button("Create Profile")
|
| 180 |
+
memory_output = gr.Code(label="Result (JSON)", language="json")
|
| 181 |
|
| 182 |
extract_btn.click(extract_memory, inputs=[logs_input, token_input], outputs=memory_output)
|
| 183 |
|
| 184 |
+
# Column 2: Chat with Persona
|
| 185 |
+
with gr.Column():
|
| 186 |
+
gr.Markdown("### 2. Chat with Agent")
|
| 187 |
+
user_msg = gr.Textbox(label="Your Message", value="I am scared about the future.")
|
| 188 |
persona_select = gr.Radio(
|
| 189 |
+
["Calm Mentor", "Witty Friend", "Therapist"],
|
| 190 |
+
label="Choose Personality",
|
| 191 |
value="Calm Mentor"
|
| 192 |
)
|
| 193 |
+
generate_btn = gr.Button("Get Answer")
|
| 194 |
|
| 195 |
+
text_output = gr.Markdown(label="Text Answer")
|
| 196 |
+
audio_output = gr.Audio(label="Voice Answer")
|
|
|
|
| 197 |
|
| 198 |
generate_btn.click(
|
| 199 |
process_interaction,
|