jmisak commited on
Commit
d937c98
·
verified ·
1 Parent(s): 1f3dc7a

Upload folder using huggingface_hub

Browse files
.gradio/certificate.pem ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ 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
31
+ -----END CERTIFICATE-----
New Text Document.txt ADDED
File without changes
Project Echo One Pager.docx ADDED
Binary file (17.6 kB). View file
 
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
  title: ConversAI
3
- emoji:
4
- colorFrom: gray
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.46.1
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
  title: ConversAI
3
+ app_file: insight_genie_v021.py
 
 
4
  sdk: gradio
5
+ sdk_version: 5.45.0
 
 
6
  ---
 
 
chat,py.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import requests
4
+ import time
5
+
6
+ # Configuration for LM Studio API
7
+ LM_STUDIO_API_URL = "http://localhost:1234/v1/chat/completions"
8
+
9
+ # Advanced System Prompt for InsightGenie
10
+ system_prompt_content = """
11
+ You are InsightGenie, an AI-powered qualitative research assistant. Your purpose is to conduct a structured interview to deeply understand a user's experience with a specific topic.
12
+
13
+ **Instructions:**
14
+ 1. **Persona:** You are a professional, neutral, and empathetic research interviewer. Maintain a supportive and curious tone.
15
+ 2. **Goal:** Your primary goal is to gather rich, detailed qualitative data. Ask open-ended questions that encourage detailed responses.
16
+ 3. **Conversation Flow:**
17
+ - After each user response, analyze the sentiment and key topics.
18
+ - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions.
19
+ - You must keep the conversation focused on the topic.
20
+ 4. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields:
21
+ - `next_question`: The text of your next question for the user.
22
+ - `summary`: A brief, neutral summary of the user's last response. This helps for later analysis.
23
+
24
+ **Example JSON Response:**
25
+ ```json
26
+ {
27
+ "next_question": "Can you tell me more about why that was your favorite part?",
28
+ "summary": "The user had a positive experience and liked the fast delivery."
29
+ }
chat.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import requests
4
+ import time
5
+
6
+ # Configuration for LM Studio API
7
+ LM_STUDIO_API_URL = "http://192.168.1.245:1234/v1/chat/completions"
8
+ # Make sure to replace this with your model name from LM Studio
9
+ LM_MODEL_NAME = "google/gemma-3-27b"
10
+
11
+ # Advanced System Prompt for InsightGenie
12
+ system_prompt_content = """
13
+ You are InsightGenie, an AI-powered qualitative research assistant. Your purpose is to conduct a structured interview to deeply understand a user's experience with a specific topic.
14
+
15
+ **Instructions:**
16
+ 1. **Persona:** You are a professional, neutral, and empathetic research interviewer. Maintain a supportive and curious tone.
17
+ 2. **Goal:** Your primary goal is to gather rich, detailed qualitative data. Ask open-ended questions that encourage detailed responses.
18
+ 3. **Conversation Flow:**
19
+ - After each user response, analyze the sentiment and key topics.
20
+ - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions.
21
+ - You must keep the conversation focused on the topic.
22
+ 4. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields:
23
+ - `next_question`: The text of your next question for the user.
24
+ - `summary`: A brief, neutral summary of the user's last response. This helps for later analysis.
25
+
26
+ **Example JSON Response:**
27
+ ```json
28
+ {
29
+ "next_question": "Can you tell me more about why that was your favorite part?",
30
+ "summary": "The user had a positive experience and liked the fast delivery."
31
+ }
32
+ """
33
+
34
+ def chat_with_lm_studio(message, history):
35
+ messages = [{"role": "system", "content": system_prompt_content}]
36
+
37
+ for user_msg, assistant_msg in history:
38
+ messages.append({"role": "user", "content": user_msg})
39
+ messages.append({"role": "assistant", "content": assistant_msg})
40
+
41
+ messages.append({"role": "user", "content": message})
42
+
43
+ try:
44
+ response = requests.post(
45
+ LM_STUDIO_API_URL,
46
+ json={
47
+ "model": LM_MODEL_NAME,
48
+ "messages": messages,
49
+ "max_tokens": 150,
50
+ "temperature": 0.7
51
+ }
52
+ )
53
+ response.raise_for_status()
54
+
55
+ # Parse the JSON response
56
+ api_response_data = response.json()
57
+
58
+ # Check if 'choices' key exists in the response
59
+ if 'choices' in api_response_data and len(api_response_data['choices']) > 0:
60
+ ai_message_content = api_response_data['choices'][0]['message']['content']
61
+
62
+ # Since we removed structured output, we just return the text
63
+ return ai_message_content
64
+ else:
65
+ # If 'choices' is missing, there's likely an error.
66
+ # Look for an 'error' key or other diagnostic info.
67
+ error_message = api_response_data.get('error', 'Unknown API error.')
68
+ print(f"API Error Response: {error_message}")
69
+ return f"An error occurred with the API: {error_message}"
70
+
71
+ except requests.exceptions.RequestException as e:
72
+ return f"An API error occurred: {e}. Please ensure LM Studio server is running."
73
+ except Exception as e:
74
+ return f"An unexpected error occurred: {e}"
75
+
76
+ # Gradio interface to launch the demo
77
+ demo = gr.ChatInterface(
78
+ fn=chat_with_lm_studio,
79
+ chatbot=gr.Chatbot(height=500),
80
+ theme=gr.themes.Soft(),
81
+ title="InsightGenie Live Demo",
82
+ description="Your AI-powered qualitative research assistant.",
83
+ examples=[["I had a great experience with a new online clothing store."],
84
+ ["The delivery was slow, and the product was damaged."]],
85
+ multimodal=False
86
+ )
87
+
88
+ if __name__ == "__main__":
89
+ demo.launch(inbrowser=True)
conversation_log_1758405088.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "user_message": "Tell me about an experience with Metformin",
4
+ "ai_response": "Could you walk me through what your experience was like *immediately* after starting Metformin – within the first week or so?",
5
+ "ai_summary": "The user is being asked about the circumstances leading to their initiation of Metformin treatment.",
6
+ "timestamp": "2025-09-20 17:50:19"
7
+ },
8
+ {
9
+ "user_message": "It felt lightheaded",
10
+ "ai_response": "Can you describe what that feeling of lightheadedness was like in more detail? For example, did it come on suddenly, or was it a gradual sensation?",
11
+ "ai_summary": "The user reported experiencing lightheadedness upon starting Metformin.",
12
+ "timestamp": "2025-09-20 17:51:07"
13
+ }
14
+ ]
conversation_log_1758405091.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "user_message": "Tell me about an experience with Metformin",
4
+ "ai_response": "Could you walk me through what your experience was like *immediately* after starting Metformin – within the first week or so?",
5
+ "ai_summary": "The user is being asked about the circumstances leading to their initiation of Metformin treatment.",
6
+ "timestamp": "2025-09-20 17:50:19"
7
+ },
8
+ {
9
+ "user_message": "It felt lightheaded",
10
+ "ai_response": "Can you describe what that feeling of lightheadedness was like in more detail? For example, did it come on suddenly, or was it a gradual sensation?",
11
+ "ai_summary": "The user reported experiencing lightheadedness upon starting Metformin.",
12
+ "timestamp": "2025-09-20 17:51:07"
13
+ }
14
+ ]
insight_genie.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import requests
4
+ import time
5
+
6
+ # --- Configuration for LM Studio API ---
7
+ # Make sure your LM Studio server is running with the specified model
8
+ LM_STUDIO_API_URL = "http://192.168.1.245:1234/v1/chat/completions"
9
+ # Make sure to replace this with your model name from LM Studio exactly
10
+ LM_MODEL_NAME = "google/gemma-3-27b"
11
+
12
+ # --- Advanced System Prompt for Pharma Market Research ---
13
+ system_prompt_content = """
14
+ You are InsightGenie, an AI-powered qualitative research assistant specialized in pharmaceutical and healthcare market research. Your purpose is to conduct a structured interview to understand patient, caregiver, or healthcare professional (HCP) experiences with a specific health condition or treatment.
15
+
16
+ **Instructions:**
17
+ 1. **Persona:** You are a professional, neutral, and empathetic research interviewer. Use clear, simple language when speaking with patients and caregivers, and appropriate medical terminology when speaking with HCPs. Maintain a supportive and curious tone.
18
+ 2. **Goal:** Your primary goal is to gather rich, detailed qualitative data. Ask open-ended questions that encourage detailed responses about personal experiences, emotional impact, and decision-making processes.
19
+ 3. **Compliance:** Avoid providing any medical advice, diagnoses, or treatment recommendations. State that you are a research tool and not a substitute for a healthcare professional.
20
+ 4. **Conversation Flow:**
21
+ - After each user response, analyze the sentiment and key themes.
22
+ - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions.
23
+ - You must keep the conversation focused on the specified health topic.
24
+ 5. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields:
25
+ - `next_question`: The text of your next question for the user.
26
+ - `summary`: A brief, neutral summary of the user's last response, including key terms or concepts.
27
+
28
+ **Example JSON Response for a patient interview:**
29
+ ```json
30
+ {
31
+ "next_question": "Can you describe the biggest challenges you faced when you were first diagnosed with this condition?",
32
+ "summary": "The patient shared their initial diagnosis experience, mentioning feelings of uncertainty."
33
+ }
34
+ """
35
+
36
+ # Global variable to store the conversation log for the current session
37
+ conversation_log = []
38
+
39
+ # --- Helper Functions ---
40
+
41
+ def log_conversation_turn(user_message, ai_response, ai_summary):
42
+ """Appends a single turn to the in-memory conversation log."""
43
+ global conversation_log
44
+ conversation_log.append({
45
+ "user_message": user_message,
46
+ "ai_response": ai_response,
47
+ "ai_summary": ai_summary,
48
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
49
+ })
50
+
51
+ def save_conversation_log():
52
+ """Saves the entire conversation log to a JSON file."""
53
+ global conversation_log
54
+ if not conversation_log:
55
+ return "No conversation to save."
56
+
57
+ file_name = f"conversation_log_{int(time.time())}.json"
58
+ try:
59
+ with open(file_name, 'w', encoding='utf-8') as f:
60
+ json.dump(conversation_log, f, indent=4, ensure_ascii=False)
61
+ return f"Conversation saved to {file_name}"
62
+ except Exception as e:
63
+ return f"Failed to save conversation: {e}"
64
+
65
+ def start_new_session(chatbot_history):
66
+ """
67
+ Saves the current conversation and starts a new, empty session.
68
+ """
69
+ global conversation_log
70
+
71
+ # Save the current conversation log
72
+ save_message = save_conversation_log()
73
+
74
+ # Reset the in-memory log for the new session
75
+ conversation_log = []
76
+
77
+ # Clear the Gradio chatbot history for a fresh start
78
+ return [], gr.Textbox(value=save_message, visible=True)
79
+
80
+ # --- Core Chat Logic Function ---
81
+
82
+ # --- Core Chat Logic Function ---
83
+ def chat_with_lm_studio(message, history):
84
+ # This line ensures 'messages' is always defined at the start of the function.
85
+ messages = [{"role": "system", "content": system_prompt_content}]
86
+
87
+ for user_msg, assistant_msg in history:
88
+ messages.append({"role": "user", "content": user_msg})
89
+ messages.append({"role": "assistant", "content": assistant_msg})
90
+
91
+ messages.append({"role": "user", "content": message})
92
+
93
+ # The rest of the function remains the same, using the now-defined 'messages' variable.
94
+ try:
95
+ # In your chat_with_lm_studio function
96
+ # ...
97
+ response = requests.post(
98
+ LM_STUDIO_API_URL,
99
+ json={
100
+ "model": LM_MODEL_NAME,
101
+ "messages": messages,
102
+ "max_tokens": 150,
103
+ "temperature": 0.7,
104
+ # Remove or comment out this line:
105
+ # "response_format": {"type": "json_object"}
106
+ }
107
+ )
108
+ # ...
109
+
110
+ response.raise_for_status()
111
+
112
+ api_response_data = response.json()
113
+
114
+ if 'choices' in api_response_data and len(api_response_data['choices']) > 0:
115
+ raw_content = api_response_data['choices'][0]['message']['content']
116
+
117
+ try:
118
+ parsed_response = json.loads(raw_content)
119
+ next_question = parsed_response.get("next_question", "Thank you for your response.")
120
+ summary = parsed_response.get("summary", "No summary provided.")
121
+
122
+ log_conversation_turn(message, next_question, summary)
123
+ print(f"User: {message}\nAI Summary: {summary}\nAI Question: {next_question}\n---")
124
+
125
+ # The fix is here: Return both the user message and the AI response
126
+ history.append((message, next_question))
127
+
128
+ # To clear the user input textbox, you need to return an empty string
129
+ return "", history
130
+
131
+ except json.JSONDecodeError:
132
+ print("LLM failed to produce valid JSON. Raw output:", raw_content)
133
+ history.append((message, "I'm sorry, I couldn't process that response. Can you please rephrase?"))
134
+ return "", history
135
+
136
+ else:
137
+ error_message = api_response_data.get('error', 'Unknown API error.')
138
+ print(f"API Error Response: {error_message}")
139
+ history.append((message, f"An error occurred with the API: {error_message}. Please check the console."))
140
+ return "", history
141
+
142
+ except requests.exceptions.RequestException as e:
143
+ history.append((message, f"An API error occurred: {e}. Please ensure LM Studio server is running and accessible."))
144
+ return "", history
145
+ except Exception as e:
146
+ history.append((message, f"An unexpected error occurred: {e}"))
147
+ return "", history
148
+ # --- Gradio Interface Layout ---
149
+ with gr.Blocks(theme=gr.themes.Soft(), title="InsightGenie Live Demo") as demo:
150
+ gr.Markdown("# InsightGenie: Your AI-powered Qualitative Assistant 🧠")
151
+ gr.Markdown(
152
+ "Start a conversation with our AI researcher. The conversation data is "
153
+ "automatically structured for analysis and can be saved to a file. "
154
+ "Try asking about a patient's journey or an HCP's experience with a treatment."
155
+ )
156
+
157
+ # Textbox to display status messages (e.g., "Conversation saved!")
158
+ status_message = gr.Textbox(label="Status", interactive=False, visible=False)
159
+
160
+ chatbot = gr.Chatbot(height=500, placeholder="Type your first message to begin the interview...")
161
+ msg = gr.Textbox(label="Your message")
162
+
163
+ with gr.Row():
164
+ chat_submit_btn = gr.Button("Send")
165
+ chat_clear_btn = gr.Button("Clear Chat")
166
+ new_session_btn = gr.Button("Start New Session")
167
+
168
+ # Event handlers
169
+ msg.submit(chat_with_lm_studio, [msg, chatbot], [msg, chatbot], concurrency_limit=None)
170
+ chat_submit_btn.click(chat_with_lm_studio, [msg, chatbot], [msg, chatbot], concurrency_limit=None)
171
+ chat_clear_btn.click(lambda: [], None, [chatbot]) # Updated to correctly clear the chatbot history
172
+
173
+ new_session_btn.click(start_new_session, [chatbot], [chatbot, status_message])
174
+
175
+ # --- Launch the Demo ---
176
+ if __name__ == "__main__":
177
+ demo.launch(inbrowser=True)
insight_genie_v02.py ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import requests
4
+ import time
5
+
6
+ # --- Configuration for LM Studio API ---
7
+ LM_STUDIO_API_URL = "http://192.168.1.245:1234/v1/chat/completions"
8
+ LM_MODEL_NAME = "google/gemma-3-27b"
9
+
10
+ # --- Dynamic System Prompt ---
11
+ DEFAULT_PROMPT = """
12
+ You are InsightGenie, an AI-powered qualitative research assistant. Your purpose is to conduct a structured interview to deeply understand a user's experience with a specific topic.
13
+
14
+ **Instructions:**
15
+ 1. **Persona:** You are a professional, neutral, and empathetic research interviewer. Maintain a supportive and curious tone.
16
+ 2. **Goal:** Your primary goal is to gather rich, detailed qualitative data. Ask open-ended questions that encourage detailed responses.
17
+ 3. **Conversation Flow:**
18
+ - After each user response, analyze the sentiment and key topics.
19
+ - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions.
20
+ - You must keep the conversation focused on the topic.
21
+ 4. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields:
22
+ - `next_question`: The text of your next question for the user.
23
+ - `summary`: A brief, neutral summary of the user's last response.
24
+
25
+ **Example JSON Response:**
26
+ ```json
27
+ {
28
+ "next_question": "Can you tell me more about why that was your favorite part?",
29
+ "summary": "The user had a positive experience and liked the fast delivery."
30
+ }
31
+ """
32
+
33
+ # Global variable to store the conversation log for the current session
34
+ conversation_log = []
35
+
36
+ # --- Helper Functions ---
37
+ def handle_save_and_display_status():
38
+ save_message = save_conversation_log()
39
+ # Returns a Gradio component update
40
+ return gr.Textbox(value=save_message, visible=True)
41
+
42
+ def log_conversation_turn(user_message, ai_response, ai_summary):
43
+ """Appends a single turn to the in-memory conversation log."""
44
+ global conversation_log
45
+ conversation_log.append({
46
+ "user_message": user_message,
47
+ "ai_response": ai_response,
48
+ "ai_summary": ai_summary,
49
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
50
+ })
51
+
52
+ def save_conversation_log():
53
+ """Saves the entire conversation log to a JSON file."""
54
+ global conversation_log
55
+ if not conversation_log:
56
+ return "No conversation to save."
57
+
58
+ file_name = f"conversation_log_{int(time.time())}.json"
59
+ try:
60
+ with open(file_name, 'w', encoding='utf-8') as f:
61
+ json.dump(conversation_log, f, indent=4, ensure_ascii=False)
62
+ return f"Conversation saved to {file_name}"
63
+ except Exception as e:
64
+ return f"Failed to save conversation: {e}"
65
+
66
+ def chat_with_lm_studio(message, history, prompt_text):
67
+ messages = [{"role": "system", "content": prompt_text}]
68
+ for user_msg, assistant_msg in history:
69
+ messages.append({"role": "user", "content": user_msg})
70
+ messages.append({"role": "assistant", "content": assistant_msg})
71
+ messages.append({"role": "user", "content": message})
72
+
73
+ try:
74
+ response = requests.post(
75
+ LM_STUDIO_API_URL,
76
+ json={
77
+ "model": LM_MODEL_NAME,
78
+ "messages": messages,
79
+ "max_tokens": 250, # Increased max tokens to give the model more room
80
+ "temperature": 0.7
81
+ }
82
+ )
83
+ response.raise_for_status()
84
+
85
+ api_response_data = response.json()
86
+
87
+ if 'choices' in api_response_data and len(api_response_data['choices']) > 0:
88
+ raw_content = api_response_data['choices'][0]['message']['content']
89
+
90
+ # --- Robust JSON Extraction and Parsing Logic ---
91
+ try:
92
+ # Find the start and end of the JSON block
93
+ json_start = raw_content.find("```json")
94
+ if json_start != -1:
95
+ json_end = raw_content.find("```", json_start + 1)
96
+ if json_end != -1:
97
+ # Extract the pure JSON string
98
+ json_string = raw_content[json_start + 7:json_end].strip()
99
+ else:
100
+ # Fallback if the closing tag is missing
101
+ json_string = raw_content[json_start + 7:].strip()
102
+ else:
103
+ # Fallback to the entire response if no JSON block is found
104
+ json_string = raw_content.strip()
105
+
106
+ parsed_response = json.loads(json_string)
107
+ next_question = parsed_response.get("next_question", "Thank you for your response.")
108
+ summary = parsed_response.get("summary", "No summary provided.")
109
+
110
+ log_conversation_turn(message, next_question, summary)
111
+ print(f"User: {message}\nAI Summary: {summary}\nAI Question: {next_question}\n---")
112
+
113
+ history.append((message, next_question))
114
+ return "", history
115
+
116
+ except json.JSONDecodeError:
117
+ print("LLM failed to produce valid JSON. Raw output:", raw_content)
118
+ history.append((message, "I'm sorry, I couldn't process that. Can you please rephrase?"))
119
+ return "", history
120
+
121
+ else:
122
+ error_message = api_response_data.get('error', 'Unknown API error.')
123
+ print(f"API Error Response: {error_message}")
124
+ history.append((message, f"An API error occurred: {error_message}. Please check the console."))
125
+ return "", history
126
+
127
+ except requests.exceptions.RequestException as e:
128
+ history.append((message, f"An API error occurred: {e}. Please ensure LM Studio server is running."))
129
+ return "", history
130
+ except Exception as e:
131
+ history.append((message, f"An unexpected error occurred: {e}"))
132
+ return "", history
133
+
134
+ # --- Gradio Interface Layout ---
135
+ with gr.Blocks(theme=gr.themes.Soft(), title="InsightGenie Live Demo") as demo:
136
+ gr.Markdown("# InsightGenie: Your AI-powered Qualitative Assistant 🧠")
137
+
138
+ with gr.Tabs():
139
+ with gr.Tab("Live Demo"):
140
+ gr.Markdown(
141
+ "Start a conversation with the AI researcher. "
142
+ "The conversation data is structured for analysis and can be saved."
143
+ )
144
+ chatbot = gr.Chatbot(height=500, placeholder="Type your first message to begin the interview...")
145
+
146
+ with gr.Row():
147
+ msg = gr.Textbox(label="Your message", scale=4)
148
+ chat_submit_btn = gr.Button("Send", scale=1)
149
+
150
+ gr.Examples(
151
+ examples=[
152
+ ["I had a great experience with a new online clothing store."],
153
+ ["The delivery was slow, and the product was damaged."]
154
+ ],
155
+ inputs=msg
156
+ )
157
+
158
+ with gr.Row():
159
+ clear_btn = gr.Button("Clear Chat")
160
+ save_btn = gr.Button("Save Conversation")
161
+
162
+ save_status = gr.Textbox(label="Save Status", interactive=False, visible=False)
163
+
164
+ with gr.Tab("Prompt Settings"):
165
+ gr.Markdown(
166
+ "Customize the AI's persona and instructions. "
167
+ "Changing this prompt will affect the next conversation turn."
168
+ )
169
+ prompt_input = gr.Textbox(
170
+ label="System Prompt",
171
+ value=DEFAULT_PROMPT,
172
+ lines=20,
173
+ interactive=True
174
+ )
175
+
176
+ # Event Handlers
177
+ msg.submit(chat_with_lm_studio, [msg, chatbot, prompt_input], [msg, chatbot], concurrency_limit=None)
178
+ chat_submit_btn.click(chat_with_lm_studio, [msg, chatbot, prompt_input], [msg, chatbot], concurrency_limit=None)
179
+ clear_btn.click(lambda: [], None, [chatbot])
180
+ save_btn.click(handle_save_and_display_status, None, save_status)
181
+
182
+ # --- Launch the Demo ---
183
+ if __name__ == "__main__":
184
+ demo.launch(share=True)
insight_genie_v021.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import requests
4
+ import time
5
+
6
+ # --- Configuration for LM Studio API ---
7
+ LM_STUDIO_API_URL = "http://192.168.1.245:1234/v1/chat/completions"
8
+ LM_MODEL_NAME = "google/gemma-3-27b"
9
+
10
+ # --- Dynamic System Prompt ---
11
+ DEFAULT_PROMPT = """
12
+ You are InsightGenie, an AI-powered qualitative research assistant. Your purpose is to conduct a structured interview to deeply understand a user's experience with a specific topic.
13
+
14
+ **Instructions:**
15
+ 1. **Persona:** You are a professional, neutral, and empathetic research interviewer. Maintain a supportive and curious tone.
16
+ 2. **Goal:** Your primary goal is to gather rich, detailed qualitative data. Ask open-ended questions that encourage detailed responses.
17
+ 3. **Conversation Flow:**
18
+ - After each user response, analyze the sentiment and key topics.
19
+ - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions.
20
+ - You must keep the conversation focused on the topic.
21
+ 4. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields:
22
+ - `next_question`: The text of your next question for the user.
23
+ - `summary`: A brief, neutral summary of the user's last response.
24
+
25
+ **Example JSON Response:**
26
+ ```json
27
+ {
28
+ "next_question": "Can you tell me more about why that was your favorite part?",
29
+ "summary": "The user had a positive experience and liked the fast delivery."
30
+ }
31
+ """
32
+
33
+ # Global variable to store the conversation log for the current session
34
+ conversation_log = []
35
+
36
+ # --- Helper Functions ---
37
+ def handle_save_and_display_status():
38
+ save_message = save_conversation_log()
39
+ return gr.Textbox(value=save_message, visible=True)
40
+
41
+ def log_conversation_turn(user_message, ai_response, ai_summary):
42
+ """Appends a single turn to the in-memory conversation log."""
43
+ global conversation_log
44
+ conversation_log.append({
45
+ "user_message": user_message,
46
+ "ai_response": ai_response,
47
+ "ai_summary": ai_summary,
48
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
49
+ })
50
+
51
+ def save_conversation_log():
52
+ """Saves the entire conversation log to a JSON file."""
53
+ global conversation_log
54
+ if not conversation_log:
55
+ return "No conversation to save."
56
+
57
+ file_name = f"conversation_log_{int(time.time())}.json"
58
+ try:
59
+ with open(file_name, 'w', encoding='utf-8') as f:
60
+ json.dump(conversation_log, f, indent=4, ensure_ascii=False)
61
+ return f"Conversation saved to {file_name}"
62
+ except Exception as e:
63
+ return f"Failed to save conversation: {e}"
64
+
65
+ def chat_with_lm_studio(message, history, prompt_text):
66
+ messages = [{"role": "system", "content": prompt_text}]
67
+ for user_msg, assistant_msg in history:
68
+ messages.append({"role": "user", "content": user_msg})
69
+ messages.append({"role": "assistant", "content": assistant_msg})
70
+ messages.append({"role": "user", "content": message})
71
+
72
+ try:
73
+ response = requests.post(
74
+ LM_STUDIO_API_URL,
75
+ json={
76
+ "model": LM_MODEL_NAME,
77
+ "messages": messages,
78
+ "max_tokens": 250,
79
+ "temperature": 0.7
80
+ }
81
+ )
82
+ response.raise_for_status()
83
+
84
+ api_response_data = response.json()
85
+
86
+ if 'choices' in api_response_data and len(api_response_data['choices']) > 0:
87
+ raw_content = api_response_data['choices'][0]['message']['content']
88
+
89
+ try:
90
+ json_start = raw_content.find("```json")
91
+ if json_start != -1:
92
+ json_end = raw_content.find("```", json_start + 1)
93
+ if json_end != -1:
94
+ json_string = raw_content[json_start + 7:json_end].strip()
95
+ else:
96
+ json_string = raw_content[json_start + 7:].strip()
97
+ else:
98
+ json_string = raw_content.strip()
99
+
100
+ parsed_response = json.loads(json_string)
101
+ next_question = parsed_response.get("next_question", "Thank you for your response.")
102
+ summary = parsed_response.get("summary", "No summary provided.")
103
+
104
+ log_conversation_turn(message, next_question, summary)
105
+
106
+ transcript_message = (
107
+ f"--- New Turn ---\n"
108
+ f"User Input: {message}\n"
109
+ f"AI Summary: {summary}\n"
110
+ f"AI Question: {next_question}\n"
111
+ )
112
+ print(transcript_message)
113
+
114
+ history.append((message, next_question))
115
+ return "", history, transcript_message
116
+
117
+ except json.JSONDecodeError:
118
+ error_message = f"LLM failed to produce valid JSON. Raw output:\n{raw_content}"
119
+ print(error_message)
120
+ history.append((message, "I'm sorry, I couldn't process that. Can you please rephrase?"))
121
+ return "", history, error_message
122
+
123
+ else:
124
+ error_message = api_response_data.get('error', 'Unknown API error.')
125
+ print(f"API Error Response: {error_message}")
126
+ history.append((message, f"An API error occurred: {error_message}. Please check the console."))
127
+ return "", history, f"API Error: {error_message}"
128
+
129
+ except requests.exceptions.RequestException as e:
130
+ history.append((message, f"An API error occurred: {e}. Please ensure LM Studio server is running."))
131
+ return "", history, f"API Error: {e}"
132
+ except Exception as e:
133
+ history.append((message, f"An unexpected error occurred: {e}"))
134
+ return "", history, f"Unexpected Error: {e}"
135
+
136
+ # --- Gradio Interface Layout ---
137
+ with gr.Blocks(theme=gr.themes.Soft(), title="Project Echo Live Demo") as demo:
138
+ gr.Markdown("# Project Echo: Your AI-powered Qualitative Assistant")
139
+
140
+ with gr.Tabs():
141
+ with gr.Tab("Live Demo"):
142
+ gr.Markdown(
143
+ "Start a conversation with the AI researcher. "
144
+ "The conversation data is structured for analysis and can be saved."
145
+ )
146
+ chatbot = gr.Chatbot(height=500, placeholder="Start by telling me about your experience with a specific medication.")
147
+
148
+ with gr.Row():
149
+ msg = gr.Textbox(label="Your message", scale=4)
150
+ chat_submit_btn = gr.Button("Send", scale=1)
151
+
152
+ gr.Examples(
153
+ examples=[
154
+ ["What is a typical day like?"],
155
+ ["What was your biggest challenge when first taking drug X?"]
156
+ ],
157
+ inputs=msg
158
+ )
159
+
160
+ with gr.Row():
161
+ clear_btn = gr.Button("Clear Chat")
162
+ save_btn = gr.Button("Save Conversation")
163
+
164
+ save_status = gr.Textbox(label="Save Status", interactive=False, visible=False)
165
+
166
+ with gr.Tab("Prompt Settings"):
167
+ gr.Markdown(
168
+ "Customize the AI's persona and instructions. "
169
+ "Changing this prompt will affect the next conversation turn."
170
+ )
171
+ prompt_input = gr.Textbox(
172
+ label="System Prompt",
173
+ value=DEFAULT_PROMPT,
174
+ lines=20,
175
+ interactive=True
176
+ )
177
+
178
+ with gr.Tab("Unedited Interaction"):
179
+ log_output = gr.Textbox(
180
+ label="Backend Transcript",
181
+ interactive=False,
182
+ lines=15,
183
+ placeholder="Backend logs will appear here after each message is sent."
184
+ )
185
+
186
+ # Event Handlers
187
+ msg.submit(chat_with_lm_studio, [msg, chatbot, prompt_input], [msg, chatbot, log_output], concurrency_limit=None)
188
+ chat_submit_btn.click(chat_with_lm_studio, [msg, chatbot, prompt_input], [msg, chatbot, log_output], concurrency_limit=None)
189
+ clear_btn.click(lambda: [], None, [chatbot])
190
+ save_btn.click(handle_save_and_display_status, None, save_status)
191
+
192
+ # --- Launch the Demo ---
193
+ if __name__ == "__main__":
194
+ demo.launch(share=True)