Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import json | |
| import requests | |
| import time | |
| # --- Configuration for LM Studio API --- | |
| # Make sure your LM Studio server is running with the specified model | |
| LM_STUDIO_API_URL = "http://192.168.1.245:1234/v1/chat/completions" | |
| # Make sure to replace this with your model name from LM Studio exactly | |
| LM_MODEL_NAME = "google/gemma-3-27b" | |
| # --- Advanced System Prompt for Pharma Market Research --- | |
| system_prompt_content = """ | |
| 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. | |
| **Instructions:** | |
| 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. | |
| 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. | |
| 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. | |
| 4. **Conversation Flow:** | |
| - After each user response, analyze the sentiment and key themes. | |
| - Based on your analysis, generate **one** follow-up question to probe deeper. Do not ask multiple questions. | |
| - You must keep the conversation focused on the specified health topic. | |
| 5. **Structured Output:** After each user turn, you must respond with a JSON object. The JSON should contain two fields: | |
| - `next_question`: The text of your next question for the user. | |
| - `summary`: A brief, neutral summary of the user's last response, including key terms or concepts. | |
| **Example JSON Response for a patient interview:** | |
| ```json | |
| { | |
| "next_question": "Can you describe the biggest challenges you faced when you were first diagnosed with this condition?", | |
| "summary": "The patient shared their initial diagnosis experience, mentioning feelings of uncertainty." | |
| } | |
| """ | |
| # Global variable to store the conversation log for the current session | |
| conversation_log = [] | |
| # --- Helper Functions --- | |
| def log_conversation_turn(user_message, ai_response, ai_summary): | |
| """Appends a single turn to the in-memory conversation log.""" | |
| global conversation_log | |
| conversation_log.append({ | |
| "user_message": user_message, | |
| "ai_response": ai_response, | |
| "ai_summary": ai_summary, | |
| "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) | |
| }) | |
| def save_conversation_log(): | |
| """Saves the entire conversation log to a JSON file.""" | |
| global conversation_log | |
| if not conversation_log: | |
| return "No conversation to save." | |
| file_name = f"conversation_log_{int(time.time())}.json" | |
| try: | |
| with open(file_name, 'w', encoding='utf-8') as f: | |
| json.dump(conversation_log, f, indent=4, ensure_ascii=False) | |
| return f"Conversation saved to {file_name}" | |
| except Exception as e: | |
| return f"Failed to save conversation: {e}" | |
| def start_new_session(chatbot_history): | |
| """ | |
| Saves the current conversation and starts a new, empty session. | |
| """ | |
| global conversation_log | |
| # Save the current conversation log | |
| save_message = save_conversation_log() | |
| # Reset the in-memory log for the new session | |
| conversation_log = [] | |
| # Clear the Gradio chatbot history for a fresh start | |
| return [], gr.Textbox(value=save_message, visible=True) | |
| # --- Core Chat Logic Function --- | |
| # --- Core Chat Logic Function --- | |
| def chat_with_lm_studio(message, history): | |
| # This line ensures 'messages' is always defined at the start of the function. | |
| messages = [{"role": "system", "content": system_prompt_content}] | |
| for user_msg, assistant_msg in history: | |
| messages.append({"role": "user", "content": user_msg}) | |
| messages.append({"role": "assistant", "content": assistant_msg}) | |
| messages.append({"role": "user", "content": message}) | |
| # The rest of the function remains the same, using the now-defined 'messages' variable. | |
| try: | |
| # In your chat_with_lm_studio function | |
| # ... | |
| response = requests.post( | |
| LM_STUDIO_API_URL, | |
| json={ | |
| "model": LM_MODEL_NAME, | |
| "messages": messages, | |
| "max_tokens": 150, | |
| "temperature": 0.7, | |
| # Remove or comment out this line: | |
| # "response_format": {"type": "json_object"} | |
| } | |
| ) | |
| # ... | |
| response.raise_for_status() | |
| api_response_data = response.json() | |
| if 'choices' in api_response_data and len(api_response_data['choices']) > 0: | |
| raw_content = api_response_data['choices'][0]['message']['content'] | |
| try: | |
| parsed_response = json.loads(raw_content) | |
| next_question = parsed_response.get("next_question", "Thank you for your response.") | |
| summary = parsed_response.get("summary", "No summary provided.") | |
| log_conversation_turn(message, next_question, summary) | |
| print(f"User: {message}\nAI Summary: {summary}\nAI Question: {next_question}\n---") | |
| # The fix is here: Return both the user message and the AI response | |
| history.append((message, next_question)) | |
| # To clear the user input textbox, you need to return an empty string | |
| return "", history | |
| except json.JSONDecodeError: | |
| print("LLM failed to produce valid JSON. Raw output:", raw_content) | |
| history.append((message, "I'm sorry, I couldn't process that response. Can you please rephrase?")) | |
| return "", history | |
| else: | |
| error_message = api_response_data.get('error', 'Unknown API error.') | |
| print(f"API Error Response: {error_message}") | |
| history.append((message, f"An error occurred with the API: {error_message}. Please check the console.")) | |
| return "", history | |
| except requests.exceptions.RequestException as e: | |
| history.append((message, f"An API error occurred: {e}. Please ensure LM Studio server is running and accessible.")) | |
| return "", history | |
| except Exception as e: | |
| history.append((message, f"An unexpected error occurred: {e}")) | |
| return "", history | |
| # --- Gradio Interface Layout --- | |
| with gr.Blocks(theme=gr.themes.Soft(), title="InsightGenie Live Demo") as demo: | |
| gr.Markdown("# InsightGenie: Your AI-powered Qualitative Assistant 🧠") | |
| gr.Markdown( | |
| "Start a conversation with our AI researcher. The conversation data is " | |
| "automatically structured for analysis and can be saved to a file. " | |
| "Try asking about a patient's journey or an HCP's experience with a treatment." | |
| ) | |
| # Textbox to display status messages (e.g., "Conversation saved!") | |
| status_message = gr.Textbox(label="Status", interactive=False, visible=False) | |
| chatbot = gr.Chatbot(height=500, placeholder="Type your first message to begin the interview...") | |
| msg = gr.Textbox(label="Your message") | |
| with gr.Row(): | |
| chat_submit_btn = gr.Button("Send") | |
| chat_clear_btn = gr.Button("Clear Chat") | |
| new_session_btn = gr.Button("Start New Session") | |
| # Event handlers | |
| msg.submit(chat_with_lm_studio, [msg, chatbot], [msg, chatbot], concurrency_limit=None) | |
| chat_submit_btn.click(chat_with_lm_studio, [msg, chatbot], [msg, chatbot], concurrency_limit=None) | |
| chat_clear_btn.click(lambda: [], None, [chatbot]) # Updated to correctly clear the chatbot history | |
| new_session_btn.click(start_new_session, [chatbot], [chatbot, status_message]) | |
| # --- Launch the Demo --- | |
| if __name__ == "__main__": | |
| demo.launch(inbrowser=True) |