jmisak commited on
Commit
d38e6a5
·
verified ·
1 Parent(s): 0ebfb23

Upload 8 files

Browse files
Files changed (8) hide show
  1. CHANGELOG.md +73 -0
  2. README.md +189 -171
  3. USER_GUIDE.md +1339 -0
  4. app.py +398 -1
  5. conversation_flow.py +197 -0
  6. conversation_moderator.py +243 -0
  7. conversation_session.py +226 -0
  8. export_utils.py +105 -0
CHANGELOG.md CHANGED
@@ -2,6 +2,79 @@
2
 
3
  All notable changes to ConversAI will be documented in this file.
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  ## [1.2.0] - 2025-11-XX
6
 
7
  ### Changed - MAJOR UPDATE
 
2
 
3
  All notable changes to ConversAI will be documented in this file.
4
 
5
+ ## [2.0.0] - 2025-10-26
6
+
7
+ ### Added - MAJOR FEATURE: Conversational Research
8
+ - **💬 New Conversational Research Module**: AI-moderated interviews with dynamic adaptation
9
+ - **Design custom conversation flows** with scripted questions
10
+ - **AI moderator** conducts real-time interviews with intelligent probing
11
+ - **Dynamic follow-up questions** generated based on respondent answers
12
+ - **Intelligent probing logic**: Asks follow-ups when detecting interesting keywords or every N responses
13
+ - **Automatic summarization** of conversation insights
14
+ - **Export capabilities**: Transcripts, JSON, and CSV formats
15
+
16
+ ### New Files
17
+ - **conversation_flow.py** - Conversation flow design and management
18
+ - `ConversationNode` class for individual conversation steps
19
+ - `ConversationFlow` class for managing complete flows
20
+ - Flow validation and persistence (save/load JSON)
21
+ - Example flow generator for quick start
22
+
23
+ - **conversation_session.py** - Live conversation session tracking
24
+ - `ConversationTurn` class for tracking individual messages
25
+ - `ConversationSession` class for managing live interviews
26
+ - `SessionManager` for handling multiple concurrent sessions
27
+ - Conversation transcript generation
28
+ - Session statistics and analytics
29
+
30
+ - **conversation_moderator.py** - AI-powered interview moderator
31
+ - Conducts interviews following conversation flows
32
+ - Decides when to ask scripted questions vs. dynamic follow-ups
33
+ - Generates contextual follow-up questions using LLM
34
+ - Probes on interesting keywords (emotional/reasoning indicators)
35
+ - Configurable follow-up threshold (default: every 3rd response)
36
+ - Conversation summarization capability
37
+
38
+ ### UI Enhancements
39
+ - **New Tab: "💬 Conversational Research"** with two sub-interfaces:
40
+ - **🎨 Design Flow**: Create and manage conversation flows
41
+ - Create new flows or load example templates
42
+ - Add conversation nodes (questions, branches, endings)
43
+ - Live flow preview
44
+ - Save flows to JSON files
45
+
46
+ - **🎙️ Conduct Interview**: Chat-based interview interface
47
+ - Start conversation sessions from designed flows
48
+ - Real-time chat with AI moderator
49
+ - Session status tracking
50
+ - Export conversations in multiple formats
51
+
52
+ ### Export Utilities Enhanced
53
+ - Added `conversation_to_transcript()` - Export as readable text
54
+ - Added `conversation_to_json()` - Export session data as JSON
55
+ - Added `conversation_to_csv()` - Export conversation turns as CSV
56
+ - Added `flow_to_markdown()` - Document conversation flows
57
+
58
+ ### Technical Details
59
+ - Seamless integration with existing Phi-2 LLM backend
60
+ - Session state management with unique IDs
61
+ - Timestamp tracking for all conversation turns
62
+ - Node-based conversation flow with linked questions
63
+ - Probing logic triggers on:
64
+ - Response length (>5 words)
65
+ - Turn count (every 3rd user response)
66
+ - Interesting keywords (emotional/reasoning words)
67
+
68
+ ### Use Cases
69
+ - Qualitative research interviews
70
+ - Customer feedback sessions
71
+ - User experience research
72
+ - Market research interviews
73
+ - Product discovery conversations
74
+ - Exploratory research with adaptive questioning
75
+
76
+ ---
77
+
78
  ## [1.2.0] - 2025-11-XX
79
 
80
  ### Changed - MAJOR UPDATE
README.md CHANGED
@@ -1,171 +1,189 @@
1
- ---
2
- title: Project Echo - Qualitative Research Assistant
3
- emoji: 🔬
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- # ConversAI - AI-Powered Qualitative Research Assistant
14
-
15
- Battle the blank page, reach global audiences, and uncover insights with AI assistance.
16
-
17
- ---
18
-
19
- > **✨ UPDATED (Nov 2025):** Now uses **local transformers** with **Microsoft Phi-2** - Fast, contextual, and **completely FREE**! No API dependencies, runs directly on HuggingFace Spaces. Generates actual topic-specific questions (not generic templates).
20
-
21
- ---
22
-
23
- ## 🌟 Features
24
-
25
- ### 📝 Survey Generation
26
- - Generate professional surveys from simple outlines
27
- - Follow industry best practices automatically
28
- - Choose from qualitative, quantitative, or mixed methods
29
- - Customize number of questions and target audience
30
-
31
- ### 🌍 Survey Translation
32
- - Translate surveys to 18+ languages
33
- - Maintain cultural appropriateness and meaning
34
- - Reach global audiences effortlessly
35
- - Batch translation support
36
-
37
- ### 📊 Data Analysis
38
- - AI-assisted thematic analysis
39
- - Sentiment analysis and emotional insights
40
- - Automatic pattern and trend detection
41
- - Generate actionable insights and recommendations
42
- - Export detailed analysis reports
43
-
44
- ## 🚀 Quick Start
45
-
46
- **On HuggingFace Spaces:** Works immediately with zero configuration! Uses the free HF Inference API.
47
-
48
- **Workflow:**
49
- 1. **Generate a Survey**: Start with an outline or topic description
50
- 2. **Translate**: Select target languages to reach global audiences
51
- 3. **Collect Responses**: Use the generated survey with your participants
52
- 4. **Analyze**: Upload responses to uncover key findings and trends
53
-
54
- ## 🔧 Configuration
55
-
56
- ### Default: Local Transformers (Completely FREE!)
57
-
58
- **✨ Zero configuration needed!** ConversAI works out-of-the-box on HuggingFace Spaces using local model loading.
59
-
60
- **Default Model:** microsoft/phi-2
61
- - **100% Free** - No API keys, no costs, ever
62
- - **Excellent quality** - 2.7GB causal language model, great at creative text generation
63
- - ✅ **Good speed** - Typically 5-10 seconds per request after initial load
64
- - ✅ **No API dependencies** - Runs entirely on your Space's compute
65
- - **Private** - All processing happens locally, nothing sent to external APIs
66
- - **Contextual** - Generates relevant, topic-specific questions (not generic)
67
-
68
- **Setup for HuggingFace Spaces:**
69
- - Just deploy - models download automatically on first run
70
- - **No API keys or tokens required!**
71
- - Models are cached after first download for faster subsequent loads
72
-
73
- ### Alternative Free Models
74
-
75
- You can try different free models by setting the `LLM_MODEL` environment variable:
76
-
77
- **Recommended Free Models (Local Transformers):**
78
-
79
- | Model | Best For | Speed | Quality | Model Size |
80
- |-------|----------|-------|---------|------------|
81
- | **TinyLlama/TinyLlama-1.1B-Chat-v1.0** | Quick testing | ⚡⚡⚡ Very Fast | ⭐⭐ Fair | 1.1GB |
82
- | **google/gemma-2b-it** | Faster alternative | ⚡⚡ Fast | ⭐⭐⭐ Good | 2GB |
83
- | **microsoft/phi-2** (default) | **Recommended** - best balance | ⚡ Good | ⭐⭐⭐⭐ Excellent | 2.7GB |
84
- | **mistralai/Mistral-7B-Instruct-v0.2** | Maximum quality | Slower | ⭐⭐⭐⭐⭐ Best | 7GB |
85
-
86
- **Note:** These are causal language models (decoder-only) designed for text generation. **Do NOT use Flan-T5 models** - they copy examples instead of generating contextual questions.
87
-
88
- **To change model:**
89
- ```bash
90
- # In Space Settings Variables
91
- LLM_MODEL=google/gemma-2b-it # Faster alternative
92
-
93
- # Or for maximum quality (requires more memory)
94
- LLM_MODEL=mistralai/Mistral-7B-Instruct-v0.2
95
- ```
96
-
97
- **Why Local Transformers?**
98
- - **No API dependencies** - runs entirely on your Space
99
- - **No 404 errors** - no network issues
100
- - ✅ **Fast after loading** - models cached in memory
101
- - **Instruction-tuned** - designed for following prompts
102
- - ✅ **Privacy** - all processing happens locally
103
-
104
- ### Tips for Best Performance with Local Models
105
-
106
- 1. **Use Phi-2 (default)** - Best balance of quality and resource usage
107
- 2. **First load takes time** - Model downloads and loads (~2-3 minutes for Phi-2)
108
- 3. **Subsequent requests are fast** - Model stays in memory (5-10 seconds)
109
- 4. **For maximum quality** - Use Mistral-7B-Instruct (requires 8GB+ RAM)
110
- 5. **For faster loading** - Use Gemma-2B-IT or TinyLlama (good quality, smaller)
111
- 6. **Avoid Flan-T5 models** - They copy examples instead of generating contextual questions
112
- 7. **Be specific in outlines** - More detail helps model generate better questions
113
-
114
- ## 📦 Installation
115
-
116
- ```bash
117
- # Install dependencies
118
- pip install -r requirements.txt
119
-
120
- # Check environment setup (optional but recommended)
121
- python check_env.py
122
-
123
- # Run the app
124
- python app.py
125
- ```
126
-
127
- ## 🏗️ Architecture
128
-
129
- ConversAI is built with a modular architecture:
130
-
131
- - **llm_backend.py** - Unified LLM interface supporting multiple providers
132
- - **survey_generator.py** - AI-powered survey generation
133
- - **survey_translator.py** - Multi-language translation engine
134
- - **data_analyzer.py** - Qualitative data analysis and insights
135
- - **app.py** - Gradio-based web interface
136
- - **export_utils.py** - Export to JSON, CSV, Markdown
137
-
138
- ## 📄 Data Privacy
139
-
140
- - All processing is done through your configured LLM provider
141
- - No data is stored permanently by this application
142
- - Survey data and responses remain in your control
143
- - Suitable for sensitive research projects
144
-
145
- ## 🤝 Contributing
146
-
147
- Contributions are welcome! This is a production-grade application designed for real-world qualitative research.
148
-
149
- ## 📝 License
150
-
151
- MIT License - Feel free to use for research and commercial purposes.
152
-
153
- ---
154
-
155
- ## 📚 Documentation
156
-
157
- **New to ConversAI?** Start with **[USER_GUIDE.md](USER_GUIDE.md)** for a complete walkthrough.
158
-
159
- **Quick Links:**
160
- - 📖 [Complete User Guide](USER_GUIDE.md) - How to use ConversAI (START HERE)
161
- - [Quick Start for HF Spaces](QUICK_START_HF_SPACES.md) - 5-minute deployment
162
- - 🔧 [Troubleshooting](TROUBLESHOOTING.md) - Common issues and solutions
163
- - 🆓 [Free Models Guide](FREE_MODELS.md) - Best free models to use
164
-
165
- **Diagnostic Tools:**
166
- - Run `python check_env.py` - Check your environment setup
167
- - Run `python test_hf_backend.py` - Test HuggingFace connection
168
-
169
- ---
170
-
171
- Built with ❤️ using Gradio and state-of-the-art open-source LLMs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: ConversAI - Qualitative Research Assistant
3
+ emoji: 🔬
4
+ colorFrom: blue
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.45.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # ConversAI - AI-Powered Qualitative Research Assistant
14
+
15
+ Battle the blank page, reach global audiences, and uncover insights with AI assistance.
16
+
17
+ ---
18
+
19
+ > **✨ UPDATED (Nov 2025):** Now uses **local transformers** with **Microsoft Phi-2** - Fast, contextual, and **completely FREE**! No API dependencies, runs directly on HuggingFace Spaces. Generates actual topic-specific questions (not generic templates).
20
+
21
+ ---
22
+
23
+ ## 🌟 Features
24
+
25
+ ### 📝 Survey Generation
26
+ - Generate professional surveys from simple outlines
27
+ - Follow industry best practices automatically
28
+ - Choose from qualitative, quantitative, or mixed methods
29
+ - Customize number of questions and target audience
30
+
31
+ ### 🌍 Survey Translation
32
+ - Translate surveys to 18+ languages
33
+ - Maintain cultural appropriateness and meaning
34
+ - Reach global audiences effortlessly
35
+ - Batch translation support
36
+
37
+ ### 📊 Data Analysis
38
+ - AI-assisted thematic analysis
39
+ - Sentiment analysis and emotional insights
40
+ - Automatic pattern and trend detection
41
+ - Generate actionable insights and recommendations
42
+ - Export detailed analysis reports
43
+
44
+ ### 💬 Conversational Research
45
+ - Design custom conversation flows with scripted questions
46
+ - AI-moderated interviews with dynamic follow-up questions
47
+ - Real-time adaptation based on respondent answers
48
+ - Intelligent probing for deeper insights
49
+ - Automatic conversation summarization and export
50
+ - Export conversations as transcripts, JSON, or CSV
51
+
52
+ ## 🚀 Quick Start
53
+
54
+ **On HuggingFace Spaces:** Works immediately with zero configuration! Uses the free HF Inference API.
55
+
56
+ **Workflow:**
57
+
58
+ **Static Surveys:**
59
+ 1. **Generate a Survey**: Start with an outline or topic description
60
+ 2. **Translate**: Select target languages to reach global audiences
61
+ 3. **Collect Responses**: Use the generated survey with your participants
62
+ 4. **Analyze**: Upload responses to uncover key findings and trends
63
+
64
+ **Conversational Research:**
65
+ 1. **Design Flow**: Create a conversation flow with scripted questions
66
+ 2. **Conduct Interview**: AI moderator engages with respondents in real-time
67
+ 3. **Export & Analyze**: Export transcripts and analyze conversation insights
68
+
69
+ ## 🔧 Configuration
70
+
71
+ ### Default: Local Transformers (Completely FREE!)
72
+
73
+ **✨ Zero configuration needed!** ConversAI works out-of-the-box on HuggingFace Spaces using local model loading.
74
+
75
+ **Default Model:** microsoft/phi-2
76
+ - ✅ **100% Free** - No API keys, no costs, ever
77
+ - ✅ **Excellent quality** - 2.7GB causal language model, great at creative text generation
78
+ - ✅ **Good speed** - Typically 5-10 seconds per request after initial load
79
+ - **No API dependencies** - Runs entirely on your Space's compute
80
+ - ✅ **Private** - All processing happens locally, nothing sent to external APIs
81
+ - **Contextual** - Generates relevant, topic-specific questions (not generic)
82
+
83
+ **Setup for HuggingFace Spaces:**
84
+ - Just deploy - models download automatically on first run
85
+ - **No API keys or tokens required!**
86
+ - Models are cached after first download for faster subsequent loads
87
+
88
+ ### Alternative Free Models
89
+
90
+ You can try different free models by setting the `LLM_MODEL` environment variable:
91
+
92
+ **Recommended Free Models (Local Transformers):**
93
+
94
+ | Model | Best For | Speed | Quality | Model Size |
95
+ |-------|----------|-------|---------|------------|
96
+ | **TinyLlama/TinyLlama-1.1B-Chat-v1.0** | Quick testing | ⚡⚡⚡ Very Fast | ⭐⭐ Fair | 1.1GB |
97
+ | **google/gemma-2b-it** | Faster alternative | ⚡⚡ Fast | ⭐⭐⭐ Good | 2GB |
98
+ | **microsoft/phi-2** (default) | **Recommended** - best balance | Good | ⭐⭐⭐⭐ Excellent | 2.7GB |
99
+ | **mistralai/Mistral-7B-Instruct-v0.2** | Maximum quality | Slower | ⭐⭐⭐⭐⭐ Best | 7GB |
100
+
101
+ **Note:** These are causal language models (decoder-only) designed for text generation. **Do NOT use Flan-T5 models** - they copy examples instead of generating contextual questions.
102
+
103
+ **To change model:**
104
+ ```bash
105
+ # In Space Settings → Variables
106
+ LLM_MODEL=google/gemma-2b-it # Faster alternative
107
+
108
+ # Or for maximum quality (requires more memory)
109
+ LLM_MODEL=mistralai/Mistral-7B-Instruct-v0.2
110
+ ```
111
+
112
+ **Why Local Transformers?**
113
+ - ✅ **No API dependencies** - runs entirely on your Space
114
+ - **No 404 errors** - no network issues
115
+ - ✅ **Fast after loading** - models cached in memory
116
+ - ✅ **Instruction-tuned** - designed for following prompts
117
+ - **Privacy** - all processing happens locally
118
+
119
+ ### Tips for Best Performance with Local Models
120
+
121
+ 1. **Use Phi-2 (default)** - Best balance of quality and resource usage
122
+ 2. **First load takes time** - Model downloads and loads (~2-3 minutes for Phi-2)
123
+ 3. **Subsequent requests are fast** - Model stays in memory (5-10 seconds)
124
+ 4. **For maximum quality** - Use Mistral-7B-Instruct (requires 8GB+ RAM)
125
+ 5. **For faster loading** - Use Gemma-2B-IT or TinyLlama (good quality, smaller)
126
+ 6. **Avoid Flan-T5 models** - They copy examples instead of generating contextual questions
127
+ 7. **Be specific in outlines** - More detail helps model generate better questions
128
+
129
+ ## 📦 Installation
130
+
131
+ ```bash
132
+ # Install dependencies
133
+ pip install -r requirements.txt
134
+
135
+ # Check environment setup (optional but recommended)
136
+ python check_env.py
137
+
138
+ # Run the app
139
+ python app.py
140
+ ```
141
+
142
+ ## 🏗️ Architecture
143
+
144
+ ConversAI is built with a modular architecture:
145
+
146
+ - **llm_backend.py** - Unified LLM interface supporting multiple providers
147
+ - **survey_generator.py** - AI-powered survey generation
148
+ - **survey_translator.py** - Multi-language translation engine
149
+ - **data_analyzer.py** - Qualitative data analysis and insights
150
+ - **conversation_flow.py** - Conversation flow design and management
151
+ - **conversation_session.py** - Live conversation session tracking
152
+ - **conversation_moderator.py** - AI-powered interview moderator
153
+ - **app.py** - Gradio-based web interface
154
+ - **export_utils.py** - Export to JSON, CSV, Markdown
155
+
156
+ ## 📄 Data Privacy
157
+
158
+ - All processing is done through your configured LLM provider
159
+ - No data is stored permanently by this application
160
+ - Survey data and responses remain in your control
161
+ - Suitable for sensitive research projects
162
+
163
+ ## 🤝 Contributing
164
+
165
+ Contributions are welcome! This is a production-grade application designed for real-world qualitative research.
166
+
167
+ ## 📝 License
168
+
169
+ MIT License - Feel free to use for research and commercial purposes.
170
+
171
+ ---
172
+
173
+ ## 📚 Documentation
174
+
175
+ **New to ConversAI?** Start with **[USER_GUIDE.md](USER_GUIDE.md)** for a complete walkthrough.
176
+
177
+ **Quick Links:**
178
+ - 📖 [Complete User Guide](USER_GUIDE.md) - How to use ConversAI (START HERE)
179
+ - ⚡ [Quick Start for HF Spaces](QUICK_START_HF_SPACES.md) - 5-minute deployment
180
+ - 🔧 [Troubleshooting](TROUBLESHOOTING.md) - Common issues and solutions
181
+ - 🆓 [Free Models Guide](FREE_MODELS.md) - Best free models to use
182
+
183
+ **Diagnostic Tools:**
184
+ - Run `python check_env.py` - Check your environment setup
185
+ - Run `python test_hf_backend.py` - Test HuggingFace connection
186
+
187
+ ---
188
+
189
+ Built with ❤️ using Gradio and state-of-the-art open-source LLMs
USER_GUIDE.md ADDED
@@ -0,0 +1,1339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ConversAI User Guide
2
+
3
+ ## Your AI-Powered Qualitative Research Assistant
4
+
5
+ ConversAI is a professional-grade research platform that transforms how you create surveys, reach global audiences, and analyze qualitative data. Powered by advanced AI, it automates hours of manual work while maintaining the quality and rigor expected in professional research.
6
+
7
+ ---
8
+
9
+ ## 🎯 What ConversAI Does
10
+
11
+ ConversAI provides three powerful capabilities that work together to streamline your entire research workflow:
12
+
13
+ ### 1. 📝 Generate Professional Surveys in Minutes
14
+ Turn a simple outline into a complete, research-ready survey with industry best practices automatically applied.
15
+
16
+ **What you get:**
17
+ - Well-structured questions that avoid common biases
18
+ - Professional introduction and closing messages
19
+ - Appropriate question types for your research goals
20
+ - Ready-to-deploy surveys that save hours of manual work
21
+
22
+ **Perfect for:**
23
+ - Market researchers launching new studies
24
+ - UX researchers gathering user feedback
25
+ - Academic researchers designing questionnaires
26
+ - Product teams validating ideas
27
+ - Healthcare professionals conducting patient surveys
28
+
29
+ ### 2. 🌍 Translate Surveys to Reach Global Audiences
30
+ Instantly translate your surveys into 18+ languages while maintaining cultural appropriateness and meaning.
31
+
32
+ **What you get:**
33
+ - Professionally translated surveys in minutes
34
+ - Cultural adaptation, not just word-for-word translation
35
+ - Support for major world languages
36
+ - Batch translation to multiple languages at once
37
+
38
+ **Perfect for:**
39
+ - International market research
40
+ - Multi-country product launches
41
+ - Global user studies
42
+ - Diverse demographic research
43
+ - Multilingual community surveys
44
+
45
+ ### 3. 📊 Uncover Insights from Qualitative Data
46
+ Transform open-ended responses into actionable insights with AI-assisted analysis.
47
+
48
+ **What you get:**
49
+ - Thematic analysis identifying key patterns
50
+ - Sentiment analysis and emotional insights
51
+ - Executive summaries highlighting findings
52
+ - Trend detection across responses
53
+ - Exportable reports ready for presentations
54
+
55
+ **Perfect for:**
56
+ - Analyzing customer feedback
57
+ - Understanding user pain points
58
+ - Identifying product opportunities
59
+ - Reporting research findings
60
+ - Making data-driven decisions
61
+
62
+ ---
63
+
64
+ ## 💼 Why ConversAI is Production-Grade
65
+
66
+ ### Enterprise-Quality Features
67
+
68
+ **1. Flexible LLM Backend**
69
+ - Support for multiple AI providers (OpenAI, Anthropic, HuggingFace)
70
+ - Automatic failover and provider selection
71
+ - No vendor lock-in - switch providers anytime
72
+ - Works with both free and premium AI services
73
+
74
+ **2. Robust Error Handling**
75
+ - Graceful degradation when services are unavailable
76
+ - Clear, actionable error messages
77
+ - Automatic retry logic for transient failures
78
+ - Validation at every step to prevent bad data
79
+
80
+ **3. Data Privacy & Security**
81
+ - No permanent data storage by default
82
+ - All processing through your chosen AI provider
83
+ - Complete control over your research data
84
+ - Suitable for sensitive research projects
85
+ - Environment-based credential management
86
+
87
+ **4. Professional Export Options**
88
+ - JSON format for programmatic access
89
+ - Markdown reports for documentation
90
+ - CSV export for spreadsheet analysis
91
+ - Ready for integration with other tools
92
+
93
+ **5. Scalability**
94
+ - Handle small pilot studies or large-scale research
95
+ - Batch operations for efficiency
96
+ - Optimized for performance
97
+ - Rate limiting and cost controls
98
+
99
+ **6. Production-Ready Architecture**
100
+ - Modular, maintainable codebase
101
+ - Clean separation of concerns
102
+ - Comprehensive error handling
103
+ - Extensive documentation
104
+ - Easy deployment options
105
+
106
+ ### Quality Assurance
107
+
108
+ **Research Best Practices:**
109
+ - Questions designed to minimize bias
110
+ - Appropriate question types for different data needs
111
+ - Logical survey flow from general to specific
112
+ - Culturally sensitive translations
113
+ - Rigorous analytical methods
114
+
115
+ **Technical Excellence:**
116
+ - Comprehensive input validation
117
+ - Type checking and error prevention
118
+ - Graceful handling of edge cases
119
+ - Performance optimization
120
+ - Security-first design
121
+
122
+ **User Experience:**
123
+ - Intuitive interface requiring no technical knowledge
124
+ - Clear status messages and progress indicators
125
+ - Helpful examples and templates
126
+ - Responsive design for any device
127
+ - Accessibility considerations
128
+
129
+ ---
130
+
131
+ ## 🚀 How to Use ConversAI
132
+
133
+ ### Getting Started
134
+
135
+ **Step 1: Access ConversAI**
136
+ - On HuggingFace Spaces: Open the Space URL (works immediately)
137
+ - Self-hosted: Launch with `python app.py`
138
+
139
+ **Step 2: Verify Setup**
140
+ - Look for the green status banner at the top
141
+ - Should show: "✅ Active LLM Provider: [Provider Name]"
142
+ - If you see a warning, check the About tab for setup instructions
143
+
144
+ **Step 3: Choose Your Task**
145
+ - Navigate between tabs based on what you want to do
146
+ - Start with survey generation, then translate, then analyze
147
+
148
+ ---
149
+
150
+ ## 📝 Feature Guide: Survey Generation
151
+
152
+ ### Creating Your First Survey
153
+
154
+ **1. Navigate to the "Generate Survey" Tab**
155
+
156
+ **2. Describe Your Research**
157
+
158
+ Enter your outline in the text box. Be specific about:
159
+ - **Topic**: What are you researching?
160
+ - **Goals**: What do you want to learn?
161
+ - **Focus Areas**: What specific aspects matter?
162
+
163
+ **Example Outlines:**
164
+
165
+ ```
166
+ Good: "I want to understand patient experiences with a new
167
+ diabetes medication, focusing on effectiveness in managing
168
+ blood sugar, side effects experienced, and impact on daily
169
+ quality of life."
170
+
171
+ Better: "We're studying user satisfaction with our mobile
172
+ banking app. Key areas: ease of use for common transactions,
173
+ trust in security features, pain points in the account setup
174
+ process, and feature requests for future versions."
175
+ ```
176
+
177
+ **3. Configure Survey Settings**
178
+
179
+ - **Survey Type**:
180
+ - *Qualitative*: Open-ended questions for deep insights
181
+ - *Quantitative*: Structured questions with measurable responses
182
+ - *Mixed*: Combination of both
183
+
184
+ - **Number of Questions**:
185
+ - Start with 10-15 for most studies
186
+ - 5-8 for quick feedback surveys
187
+ - 15-25 for comprehensive research
188
+
189
+ - **Target Audience**:
190
+ - Be specific: "Adults 25-45 who use fitness apps daily"
191
+ - Not just: "General public"
192
+
193
+ **4. Generate and Review**
194
+
195
+ Click "🚀 Generate Survey" and wait 10-30 seconds.
196
+
197
+ Review the generated survey:
198
+ - ✅ Questions are clear and unbiased
199
+ - ✅ Appropriate question types are used
200
+ - ✅ Logical flow from general to specific
201
+ - ✅ Professional introduction and closing
202
+
203
+ **5. Download and Deploy**
204
+
205
+ - Download the JSON file for your survey platform
206
+ - Copy questions to your preferred survey tool
207
+ - Customize further if needed
208
+
209
+ ### Tips for Better Surveys
210
+
211
+ **Do:**
212
+ - ✅ Be specific about your research goals
213
+ - ✅ Mention your target audience characteristics
214
+ - ✅ Specify key topics or themes to explore
215
+ - ✅ Include context about why you're researching
216
+
217
+ **Don't:**
218
+ - ❌ Use vague descriptions like "customer feedback"
219
+ - ❌ Request too many questions (causes fatigue)
220
+ - ❌ Skip the target audience field
221
+ - ❌ Forget to review before deploying
222
+
223
+ **Example Use Cases:**
224
+
225
+ 1. **Product Feedback**
226
+ ```
227
+ Outline: "Gather feedback from beta users of our project
228
+ management software. Focus on: workflow improvements over
229
+ previous tools, collaboration features effectiveness,
230
+ learning curve challenges, and missing features that would
231
+ increase productivity."
232
+ ```
233
+
234
+ 2. **Customer Experience**
235
+ ```
236
+ Outline: "Understand customer experience at our retail
237
+ stores. Key areas: staff helpfulness, product selection
238
+ satisfaction, checkout process efficiency, store
239
+ cleanliness, and likelihood to recommend."
240
+ ```
241
+
242
+ 3. **Academic Research**
243
+ ```
244
+ Outline: "Study remote work impact on work-life balance
245
+ among knowledge workers. Topics: boundary management,
246
+ productivity changes, social isolation, communication
247
+ challenges, and preferences for future work arrangements."
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 🌍 Feature Guide: Survey Translation
253
+
254
+ ### Translating Surveys to Multiple Languages
255
+
256
+ **1. Generate or Upload a Survey**
257
+ - Create a survey using the generation feature, OR
258
+ - Have your existing survey in the correct JSON format
259
+
260
+ **2. Navigate to "Translate Survey" Tab**
261
+
262
+ **3. Select Target Languages**
263
+
264
+ Choose from 18+ supported languages:
265
+ - **European**: Spanish, French, German, Italian, Portuguese, Dutch, Swedish, Polish
266
+ - **Asian**: Chinese, Japanese, Korean, Vietnamese, Thai, Indonesian, Hindi
267
+ - **Middle Eastern**: Arabic, Turkish
268
+ - **Eastern European**: Russian
269
+
270
+ **Pro Tip**: Select multiple languages at once for batch translation
271
+
272
+ **4. Generate Translations**
273
+
274
+ Click "🌐 Translate Survey" and wait.
275
+
276
+ Processing time:
277
+ - 1-2 languages: 20-40 seconds
278
+ - 3-5 languages: 1-2 minutes
279
+ - 6+ languages: 2-3 minutes
280
+
281
+ **5. Review and Download**
282
+
283
+ - Each translation appears in a separate section
284
+ - Check for cultural appropriateness
285
+ - Download JSON file containing all translations
286
+
287
+ ### Translation Best Practices
288
+
289
+ **Quality Assurance:**
290
+
291
+ 1. **Back-Translation Testing**
292
+ - For critical surveys, have a native speaker back-translate
293
+ - Compare with original to ensure meaning preserved
294
+
295
+ 2. **Cultural Adaptation**
296
+ - Review idioms and expressions
297
+ - Check that examples make sense in target culture
298
+ - Verify formality level is appropriate
299
+
300
+ 3. **Pilot Testing**
301
+ - Test with small group of native speakers
302
+ - Gather feedback on clarity and appropriateness
303
+ - Refine before full deployment
304
+
305
+ **When to Use Each Language:**
306
+
307
+ | Language | When to Use | Notes |
308
+ |----------|------------|-------|
309
+ | Spanish | Latin America, Spain | Specify region for dialect |
310
+ | French | France, Canada, Africa | Consider regional variations |
311
+ | German | DACH region | Formal vs informal matters |
312
+ | Chinese | China, Taiwan, Singapore | Simplified vs Traditional |
313
+ | Arabic | MENA region | Right-to-left formatting needed |
314
+ | Portuguese | Brazil, Portugal | Brazilian vs European Portuguese |
315
+
316
+ ### Use Cases
317
+
318
+ 1. **Global Product Launch**
319
+ ```
320
+ Scenario: Launching mobile app in 5 countries
321
+ Languages: English, Spanish, French, German, Japanese
322
+ Questions: 12 (mix of usability and satisfaction)
323
+ Time saved: ~8 hours of professional translation
324
+ ```
325
+
326
+ 2. **Multinational Employee Survey**
327
+ ```
328
+ Scenario: Annual engagement survey across offices
329
+ Languages: English, Chinese, Hindi, Spanish, Portuguese
330
+ Questions: 15 (engagement, culture, development)
331
+ Time saved: ~10 hours + faster deployment
332
+ ```
333
+
334
+ 3. **Academic International Study**
335
+ ```
336
+ Scenario: Cross-cultural research project
337
+ Languages: English, French, German, Italian, Spanish
338
+ Questions: 20 (detailed qualitative questions)
339
+ Time saved: Professional translation would cost $500+
340
+ ```
341
+
342
+ ---
343
+
344
+ ## 📊 Feature Guide: Data Analysis
345
+
346
+ ### Analyzing Survey Responses
347
+
348
+ **1. Prepare Your Data**
349
+
350
+ Format responses as JSON array:
351
+
352
+ ```json
353
+ [
354
+ {
355
+ "q1": "First respondent's answer to question 1",
356
+ "q2": "First respondent's answer to question 2",
357
+ "q3": "First respondent's answer to question 3"
358
+ },
359
+ {
360
+ "q1": "Second respondent's answer to question 1",
361
+ "q2": "Second respondent's answer to question 2",
362
+ "q3": "Second respondent's answer to question 3"
363
+ }
364
+ ]
365
+ ```
366
+
367
+ **2. Navigate to "Analyze Data" Tab**
368
+
369
+ **3. Input Your Data**
370
+
371
+ - Paste responses JSON in the "Survey Responses" field
372
+ - Optionally add questions JSON for better context
373
+ - Use "Load Example" button to see format
374
+
375
+ **4. Run Analysis**
376
+
377
+ Click "🔍 Analyze Data" and wait 30-60 seconds.
378
+
379
+ **5. Review Results**
380
+
381
+ The analysis includes:
382
+
383
+ **Executive Summary**
384
+ - High-level overview of findings
385
+ - Key patterns observed
386
+ - Notable discoveries
387
+ - Response quality assessment
388
+
389
+ **Thematic Analysis**
390
+ - 5-7 main themes identified
391
+ - Description of each theme
392
+ - Prevalence percentages
393
+ - Representative quotes
394
+
395
+ **Sentiment Analysis**
396
+ - Overall sentiment (positive/negative/neutral/mixed)
397
+ - Sentiment distribution breakdown
398
+ - Key emotions detected
399
+ - Intensity assessment
400
+
401
+ **Key Insights**
402
+ - 5-7 actionable insights
403
+ - Specific, evidence-based findings
404
+ - Strategic recommendations
405
+ - Trend observations
406
+
407
+ **Statistics**
408
+ - Total responses analyzed
409
+ - Average response length
410
+ - Completion rates
411
+ - Data quality metrics
412
+
413
+ **6. Download Reports**
414
+
415
+ - JSON file: Full analysis data for further processing
416
+ - Markdown file: Formatted report for presentations
417
+
418
+ ### Analysis Best Practices
419
+
420
+ **Data Preparation:**
421
+
422
+ 1. **Minimum Response Count**
423
+ - Absolute minimum: 10 responses
424
+ - Good results: 20-50 responses
425
+ - Best results: 50+ responses
426
+
427
+ 2. **Response Quality**
428
+ - Encourage detailed, thoughtful responses
429
+ - Filter out spam or very short responses
430
+ - Include diverse perspectives
431
+
432
+ 3. **Data Cleaning**
433
+ - Remove duplicates
434
+ - Handle incomplete responses
435
+ - Fix formatting issues
436
+
437
+ **Interpretation Guidelines:**
438
+
439
+ 1. **Themes**
440
+ - Look for recurring patterns
441
+ - Consider theme prevalence percentages
442
+ - Read example quotes for context
443
+ - Cross-reference with your research questions
444
+
445
+ 2. **Sentiment**
446
+ - Don't over-interpret mixed sentiment
447
+ - Look for sentiment patterns by theme
448
+ - Consider intensity levels
449
+ - Watch for contradictions
450
+
451
+ 3. **Insights**
452
+ - Prioritize insights supported by multiple responses
453
+ - Look for unexpected findings
454
+ - Consider business/research implications
455
+ - Validate with quantitative data when available
456
+
457
+ **Common Pitfalls to Avoid:**
458
+
459
+ ❌ **Cherry-picking**: Don't just highlight what confirms your hypothesis
460
+ ✅ **Balanced reporting**: Include contradictory findings
461
+
462
+ ❌ **Small sample bias**: Don't generalize from <20 responses
463
+ ✅ **Appropriate scope**: Acknowledge sample size limitations
464
+
465
+ ❌ **Over-reliance on AI**: AI assists but doesn't replace human judgment
466
+ ✅ **Critical review**: Validate AI findings with domain expertise
467
+
468
+ ❌ **Ignoring context**: Raw numbers without situational understanding
469
+ ✅ **Contextual analysis**: Consider external factors and timing
470
+
471
+ ### Use Cases
472
+
473
+ **1. Customer Feedback Analysis**
474
+ ```
475
+ Input: 50 responses to "What could we improve?"
476
+ Output:
477
+ - 5 themes (pricing concerns, feature requests, UX issues, etc.)
478
+ - Overall negative sentiment (68%) but constructive tone
479
+ - 7 actionable insights for product roadmap
480
+ Time saved: 4-6 hours of manual coding
481
+ ```
482
+
483
+ **2. Employee Engagement Study**
484
+ ```
485
+ Input: 120 responses across 10 open-ended questions
486
+ Output:
487
+ - Themes: work-life balance, career development, management
488
+ - Mixed sentiment with strong positives and negatives
489
+ - Insights on retention risks and opportunities
490
+ Time saved: 8-12 hours of analysis
491
+ ```
492
+
493
+ **3. User Research Interviews**
494
+ ```
495
+ Input: 25 interview transcripts (formatted as responses)
496
+ Output:
497
+ - Themes: user goals, pain points, feature priorities
498
+ - Positive sentiment on core functionality
499
+ - Insights for next sprint planning
500
+ Time saved: 6-8 hours of manual synthesis
501
+ ```
502
+
503
+ ---
504
+
505
+ ## 💬 Feature Guide: Conversational Research
506
+
507
+ ### Conducting AI-Moderated Interviews
508
+
509
+ **What is Conversational Research?**
510
+
511
+ Unlike static surveys, conversational research creates a dynamic dialogue between an AI moderator and respondents. The AI follows a scripted conversation flow but adapts in real-time by asking follow-up questions based on responses, creating a more natural and engaging interview experience.
512
+
513
+ **When to Use Conversational Research:**
514
+ - 🎤 Exploratory research where you want to probe deeper
515
+ - 💡 User research requiring contextual follow-ups
516
+ - 🔍 Customer discovery with adaptive questioning
517
+ - 📝 Qualitative interviews at scale
518
+ - 🤝 Situations requiring empathetic, human-like interaction
519
+
520
+ ### Designing a Conversation Flow
521
+
522
+ **1. Navigate to "💬 Conversational Research" Tab**
523
+
524
+ Click on the "🎨 Design Flow" sub-tab.
525
+
526
+ **2. Create a New Flow**
527
+
528
+ Enter flow details:
529
+ - **Flow Name**: Descriptive title (e.g., "Product Feedback Interview")
530
+ - **Flow Description**: Purpose and context of the conversation
531
+
532
+ Click "✨ Create New Flow" to start.
533
+
534
+ **3. Add Conversation Steps**
535
+
536
+ For each question/step:
537
+ - **Question/Message**: The scripted question the AI will ask
538
+ - **Step Type**: Choose "Question" or "End"
539
+ - *Question*: Regular conversation step
540
+ - *End*: Final closing message
541
+
542
+ Click "➕ Add Step" to add each node to the flow.
543
+
544
+ **Example Flow Structure:**
545
+ ```
546
+ Step 1 (Question): "Hello! Thank you for taking the time to speak with me.
547
+ What initially attracted you to our product?"
548
+
549
+ Step 2 (Question): "How would you describe your overall experience using
550
+ the product so far?"
551
+
552
+ Step 3 (Question): "What specific features do you find most valuable?"
553
+
554
+ Step 4 (Question): "Have you encountered any challenges or frustrations?"
555
+
556
+ Step 5 (Question): "What improvements would you most like to see?"
557
+
558
+ Step 6 (End): "Thank you for sharing your thoughts! Your feedback is
559
+ incredibly valuable."
560
+ ```
561
+
562
+ **4. Preview Your Flow**
563
+
564
+ The flow preview shows:
565
+ - All conversation steps in order
566
+ - Step types and IDs
567
+ - How the conversation will progress
568
+
569
+ **5. Save Your Flow**
570
+
571
+ Click "💾 Save Flow" to save to a JSON file.
572
+
573
+ **Pro Tip**: Start by clicking "📋 Load Example" to see a complete customer feedback interview template.
574
+
575
+ ### Conducting an Interview
576
+
577
+ **1. Navigate to "🎙️ Conduct Interview" Sub-Tab**
578
+
579
+ **2. Start a Conversation Session**
580
+
581
+ Click "🚀 Start Conversation" to begin.
582
+
583
+ The AI moderator will:
584
+ - Greet the respondent
585
+ - Ask the first question from your flow
586
+ - Wait for a response
587
+
588
+ **3. Respond as the Interviewee**
589
+
590
+ Type your response in the text box and click "Send" (or press Enter).
591
+
592
+ **4. Experience Dynamic Adaptation**
593
+
594
+ The AI moderator intelligently decides whether to:
595
+
596
+ **Ask Scripted Question** (Default):
597
+ - Continues with the next question in your flow
598
+ - Maintains structure and coverage
599
+
600
+ **Ask Dynamic Follow-Up** (Adaptive):
601
+ - Probes deeper into interesting responses
602
+ - Generated based on what you just said
603
+ - Examples: "Tell me more about...", "Can you elaborate on...", "Why do you think..."
604
+
605
+ **Triggers for Follow-Up Questions:**
606
+ - Every 3rd user response (configurable)
607
+ - Responses longer than 5 words
608
+ - Interesting keywords detected:
609
+ - Emotional: "frustrated", "excited", "worried", "confused"
610
+ - Reasoning: "because", "however", "although", "surprisingly"
611
+
612
+ **5. Session Progress**
613
+
614
+ Monitor session status:
615
+ - Active conversation indicator
616
+ - Turn count
617
+ - Current flow position
618
+
619
+ **6. Export the Conversation**
620
+
621
+ When finished, click "📥 Export Conversation" to save:
622
+ - **Transcript**: Readable text format (.txt)
623
+ - **JSON**: Full session data with timestamps
624
+ - **CSV**: Turn-by-turn analysis format
625
+
626
+ ### Best Practices for Conversation Flows
627
+
628
+ **Flow Design:**
629
+
630
+ 1. **Start Broad, Get Specific**
631
+ ```
632
+ Good flow:
633
+ 1. General experience → 2. Specific features → 3. Pain points → 4. Improvements
634
+
635
+ Poor flow:
636
+ 1. Very specific detail → 2. General opinion (order reversed)
637
+ ```
638
+
639
+ 2. **Optimal Flow Length**
640
+ - Short interviews: 4-6 questions
641
+ - Standard interviews: 6-10 questions
642
+ - In-depth interviews: 10-15 questions
643
+ - Note: AI follow-ups extend the conversation naturally
644
+
645
+ 3. **Question Types**
646
+ - Open-ended: "Tell me about...", "Describe your experience..."
647
+ - Focused: "What specific features...", "When did you first..."
648
+ - Reflective: "How did that make you feel?", "What did you learn?"
649
+
650
+ 4. **Professional Tone**
651
+ - Empathetic and non-judgmental
652
+ - Clear and conversational
653
+ - Respectful of respondent's time
654
+ - Genuine curiosity
655
+
656
+ **Conducting Interviews:**
657
+
658
+ 1. **Set Expectations**
659
+ - Tell respondents this is an AI-moderated interview
660
+ - Mention it will ask follow-up questions
661
+ - Encourage detailed responses (5+ words)
662
+
663
+ 2. **Response Quality**
664
+ - Encourage thoughtful, detailed answers
665
+ - Very short responses (<5 words) won't trigger follow-ups
666
+ - Rich responses get more adaptive probing
667
+
668
+ 3. **Managing Length**
669
+ - AI limits follow-ups to avoid fatigue
670
+ - Flow continues even with dynamic questions
671
+ - Respondents can keep answers brief to move faster
672
+
673
+ 4. **Technical Tips**
674
+ - One respondent per session
675
+ - Sessions auto-save conversation history
676
+ - Can't resume abandoned sessions (by design)
677
+ - Export immediately after completion
678
+
679
+ ### Use Cases
680
+
681
+ **1. Customer Discovery Interviews**
682
+ ```
683
+ Scenario: Understanding why users chose your product
684
+ Flow: 5 scripted questions about decision process
685
+ AI Adaptation: Probes on "competitor comparison" mentions
686
+ Result: Rich insights on differentiation factors
687
+ Time: 15-20 minutes per interview
688
+ ```
689
+
690
+ **2. UX Research Sessions**
691
+ ```
692
+ Scenario: Exploring pain points in onboarding flow
693
+ Flow: 8 questions walking through user journey
694
+ AI Adaptation: Asks follow-ups on confusion/frustration
695
+ Result: Detailed understanding of UX issues
696
+ Time: 20-25 minutes per session
697
+ ```
698
+
699
+ **3. Product Feedback at Scale**
700
+ ```
701
+ Scenario: Collecting beta feedback from 50 users
702
+ Flow: 6 standard questions + AI follow-ups
703
+ AI Adaptation: Probes interesting feature requests
704
+ Result: Prioritized roadmap from user insights
705
+ Time: 10-15 minutes × 50 = 8-12 hours total (automated)
706
+ ```
707
+
708
+ **4. Market Research Interviews**
709
+ ```
710
+ Scenario: Understanding buyer preferences
711
+ Flow: 10 questions on needs, alternatives, priorities
712
+ AI Adaptation: Explores "price sensitivity" mentions
713
+ Result: Market positioning insights
714
+ Time: 25-30 minutes per interview
715
+ ```
716
+
717
+ ### Analysis Tips
718
+
719
+ **Reviewing Transcripts:**
720
+ 1. Export all sessions after completion
721
+ 2. Look for recurring themes across conversations
722
+ 3. Note where AI follow-ups uncovered insights
723
+ 4. Compare scripted vs. dynamic question value
724
+
725
+ **Processing Conversations:**
726
+ 1. **Manual Analysis**: Review transcripts for themes
727
+ 2. **Automated Analysis**: Use the "Analyze Data" tab
728
+ - Export conversation turns to CSV
729
+ - Format responses for analysis
730
+ - Run thematic analysis
731
+
732
+ **Key Metrics:**
733
+ - Average conversation length (turns)
734
+ - Follow-up question frequency
735
+ - Response depth (words per turn)
736
+ - Topic coverage across sessions
737
+
738
+ ### Advanced Features
739
+
740
+ **Conversation Summarization** (Coming Soon):
741
+ - AI-generated summary of each conversation
742
+ - Key points extraction
743
+ - Sentiment analysis per session
744
+
745
+ **Flow Branching** (Planned):
746
+ - Conditional logic based on responses
747
+ - Different paths for different respondent types
748
+ - Skip logic for efficiency
749
+
750
+ **Multi-Moderator Styles** (Planned):
751
+ - Empathetic interviewer
752
+ - Business analyst
753
+ - Technical researcher
754
+ - Cultural variations
755
+
756
+ ### Limitations
757
+
758
+ **Current Limitations:**
759
+ - ❌ Linear flows only (no branching yet)
760
+ - ❌ Cannot resume abandoned sessions
761
+ - ❌ One respondent per session
762
+ - ❌ English language optimized (other languages work but less refined)
763
+
764
+ **Best Suited For:**
765
+ - ✅ Qualitative research interviews
766
+ - ✅ Exploratory customer discovery
767
+ - ✅ User research at scale
768
+ - ✅ Standardized but adaptive interviews
769
+
770
+ **Not Ideal For:**
771
+ - ❌ Highly structured surveys (use static surveys instead)
772
+ - ❌ Quantitative data collection
773
+ - ❌ Complex branching logic requirements
774
+ - ❌ Multi-party conversations
775
+
776
+ ---
777
+
778
+ ## 🎓 Complete Workflow Examples
779
+
780
+ ### Example 1: New Product Feature Research
781
+
782
+ **Objective**: Understand if users want a new AI assistant feature
783
+
784
+ **Step 1: Generate Survey** (5 minutes)
785
+ ```
786
+ Outline: "Explore interest in an AI assistant feature for our
787
+ productivity app. Focus on: use cases users envision, concerns
788
+ about AI, willingness to pay, and preferred interaction methods."
789
+
790
+ Settings:
791
+ - Type: Mixed (qualitative + quantitative)
792
+ - Questions: 12
793
+ - Audience: Current users of productivity apps, tech-savvy
794
+ ```
795
+
796
+ **Step 2: Deploy Survey** (You handle this)
797
+ - Export to your survey platform
798
+ - Send to 100 beta users
799
+ - Collect responses over 1 week
800
+
801
+ **Step 3: Translate for Global Test** (10 minutes)
802
+ ```
803
+ Selected languages: Spanish, French, German, Japanese
804
+ Purpose: Test with international user base
805
+ Result: 4 localized versions ready to deploy
806
+ ```
807
+
808
+ **Step 4: Analyze Results** (15 minutes)
809
+ ```
810
+ Input: 78 responses in JSON format
811
+ Analysis reveals:
812
+ - 3 main use cases (writing assistance, data analysis, scheduling)
813
+ - Positive sentiment (72%) but privacy concerns (45% mention)
814
+ - Insights: Users willing to pay $5-10/month, prefer opt-in
815
+ ```
816
+
817
+ **Total Time**: ~30 minutes of work
818
+ **Traditional Time**: 8-12 hours
819
+ **Savings**: ~10 hours
820
+
821
+ ---
822
+
823
+ ### Example 2: Multi-Country Market Research
824
+
825
+ **Objective**: Launch product in 5 new markets, need local insights
826
+
827
+ **Step 1: Generate Core Survey** (5 minutes)
828
+ ```
829
+ Outline: "Market research for launching a sustainable fashion
830
+ brand. Topics: sustainability priorities, price sensitivity,
831
+ preferred materials, shopping habits, brand perception factors."
832
+
833
+ Settings:
834
+ - Type: Qualitative
835
+ - Questions: 15
836
+ - Audience: Environmentally conscious consumers, 25-45
837
+ ```
838
+
839
+ **Step 2: Translate to Target Markets** (15 minutes)
840
+ ```
841
+ Languages: Spanish (Mexico), Portuguese (Brazil), French (France),
842
+ German (Germany), Japanese (Japan)
843
+
844
+ Result: 5 culturally adapted versions
845
+ Quality check: Review by native speakers on team
846
+ ```
847
+
848
+ **Step 3: Deploy and Collect** (You handle this)
849
+ - 50 responses per country
850
+ - 250 total responses
851
+ - 2-week collection period
852
+
853
+ **Step 4: Analyze by Market** (30 minutes)
854
+ ```
855
+ Run analysis separately for each market:
856
+ - Identify market-specific themes
857
+ - Compare sentiment across markets
858
+ - Note cultural differences in priorities
859
+
860
+ Key findings example:
861
+ - Japan: Quality and durability top priority
862
+ - Germany: Certifications and transparency crucial
863
+ - Brazil: Price sensitivity higher, but willing to pay for story
864
+ ```
865
+
866
+ **Total Time**: ~50 minutes
867
+ **Traditional Time**: 20-30 hours (translation + analysis)
868
+ **Cost Savings**: $2000+ in professional services
869
+
870
+ ---
871
+
872
+ ### Example 3: Academic Research Project
873
+
874
+ **Objective**: Study impact of remote work on work-life balance
875
+
876
+ **Step 1: Design Survey** (10 minutes)
877
+ ```
878
+ Outline: "Investigate how remote work affects work-life balance
879
+ among knowledge workers. Explore: boundary management strategies,
880
+ productivity changes, social isolation experiences, family
881
+ dynamics, preference for future work arrangements, and mental
882
+ health impacts."
883
+
884
+ Settings:
885
+ - Type: Qualitative (open-ended for rich data)
886
+ - Questions: 18
887
+ - Audience: Knowledge workers with 1+ year remote experience
888
+ ```
889
+
890
+ **Step 2: Review & Refine** (20 minutes)
891
+ - Review generated questions
892
+ - Ensure alignment with research framework
893
+ - Verify no leading questions
894
+
895
+ **Step 3: Collect Data** (You handle this)
896
+ - Deploy via academic participant pool
897
+ - Collect 150 responses
898
+ - 3-week collection period
899
+
900
+ **Step 4: Comprehensive Analysis** (45 minutes)
901
+ ```
902
+ Input: 150 detailed responses
903
+
904
+ Analysis output:
905
+ - 7 major themes with sub-themes
906
+ - Sentiment patterns by demographic
907
+ - 12 key insights for paper
908
+
909
+ Export: Markdown report for lit review section
910
+ JSON for coding in qualitative software
911
+ ```
912
+
913
+ **Step 5: Follow-up Translation** (Optional)
914
+ ```
915
+ If publishing internationally or presenting at conference:
916
+ Translate survey instrument to show methodology
917
+ Languages: Spanish, French (common in academia)
918
+ ```
919
+
920
+ **Total Time**: ~2 hours
921
+ **Traditional Time**: 15-25 hours of manual thematic coding
922
+ **Quality**: Comparable to manual coding for exploratory research
923
+
924
+ ---
925
+
926
+ ## 💡 Tips for Power Users
927
+
928
+ ### Optimizing for Quality
929
+
930
+ **1. Survey Generation**
931
+ - Iterate on outlines to get better questions
932
+ - Generate multiple versions and combine best questions
933
+ - Use specific examples in outlines for better context
934
+ - Mention your theoretical framework for academic research
935
+
936
+ **2. Translation**
937
+ - Start with common languages to test quality
938
+ - Use back-translation for critical surveys
939
+ - Keep original English version for reference
940
+ - Test with native speakers before full deployment
941
+
942
+ **3. Analysis**
943
+ - Provide questions JSON for better context
944
+ - Clean data before analysis (remove duplicates, spam)
945
+ - Run analysis multiple times for consistency
946
+ - Combine AI insights with manual review
947
+
948
+ ### Optimizing for Cost
949
+
950
+ **Using Free HuggingFace:**
951
+ - Perfect for testing and development
952
+ - Good for small-scale research (<50 responses)
953
+ - Be patient with first request (cold start)
954
+ - Simplify requests for better performance
955
+
956
+ **Using Paid Providers:**
957
+
958
+ | Provider | Best For | Cost Range | Speed |
959
+ |----------|----------|------------|-------|
960
+ | **OpenAI GPT-4o-mini** | Best value | $0.01-0.05/survey | Fast |
961
+ | **OpenAI GPT-4** | Best quality | $0.05-0.15/survey | Fast |
962
+ | **Anthropic Claude** | Complex analysis | $0.02-0.08/survey | Fast |
963
+
964
+ **Cost Control Tips:**
965
+ - Use GPT-4o-mini for generation and translation
966
+ - Use GPT-4 only for complex analysis
967
+ - Batch operations when possible
968
+ - Set up usage alerts in provider dashboards
969
+
970
+ ### Workflow Optimization
971
+
972
+ **Create Templates:**
973
+ Save outlines for common research types:
974
+ - Customer satisfaction surveys
975
+ - Product feedback forms
976
+ - Employee engagement surveys
977
+ - User experience studies
978
+ - Academic research instruments
979
+
980
+ **Batch Processing:**
981
+ - Generate multiple survey versions at once
982
+ - Translate to all needed languages in one go
983
+ - Analyze all demographics separately for comparison
984
+
985
+ **Quality Checkpoints:**
986
+ 1. After generation: Review questions for bias
987
+ 2. After translation: Spot-check with native speakers
988
+ 3. After data collection: Clean data before analysis
989
+ 4. After analysis: Validate insights with domain experts
990
+
991
+ ---
992
+
993
+ ## 🔒 Privacy & Data Security
994
+
995
+ ### What Data is Stored?
996
+
997
+ **By ConversAI:**
998
+ - ❌ No survey data is permanently stored
999
+ - ❌ No responses are saved to disk
1000
+ - ❌ No user information is retained
1001
+ - ✅ Temporary files for downloads only (deleted after download)
1002
+
1003
+ **By LLM Providers:**
1004
+ - Varies by provider (check their policies)
1005
+ - OpenAI: Data not used for training by default
1006
+ - Anthropic: Enterprise plans have data guarantees
1007
+ - HuggingFace: Depends on model provider
1008
+
1009
+ ### Best Practices for Sensitive Research
1010
+
1011
+ **1. Choose Provider Carefully**
1012
+ - For healthcare: Use HIPAA-compliant LLM service
1013
+ - For confidential: Use Anthropic or OpenAI enterprise
1014
+ - For maximum privacy: Self-host open-source models
1015
+
1016
+ **2. Anonymize Data**
1017
+ - Remove identifying information before analysis
1018
+ - Use participant IDs instead of names
1019
+ - Redact sensitive details from responses
1020
+
1021
+ **3. Access Control**
1022
+ - Use private HuggingFace Spaces if needed
1023
+ - Limit team access to credentials
1024
+ - Rotate API keys regularly
1025
+
1026
+ **4. Compliance**
1027
+ - GDPR: Ensure LLM provider is compliant
1028
+ - IRB requirements: Document AI use in protocols
1029
+ - Data retention: Follow your organization's policies
1030
+
1031
+ ---
1032
+
1033
+ ## 📈 Measuring Success
1034
+
1035
+ ### Survey Generation Success Metrics
1036
+
1037
+ ✅ **Quality Indicators:**
1038
+ - Questions are unbiased and clear
1039
+ - Logical flow through survey
1040
+ - Appropriate question types used
1041
+ - All research objectives covered
1042
+
1043
+ ✅ **Efficiency Gains:**
1044
+ - Time to first draft: <5 minutes (vs. hours manually)
1045
+ - Iterations needed: 1-2 (vs. 4-5 manually)
1046
+ - Team review time reduced by 50%+
1047
+
1048
+ ### Translation Success Metrics
1049
+
1050
+ ✅ **Quality Indicators:**
1051
+ - Back-translation matches original meaning
1052
+ - Native speaker approval
1053
+ - Cultural appropriateness confirmed
1054
+ - Response rates comparable across languages
1055
+
1056
+ ✅ **Efficiency Gains:**
1057
+ - Time to translate: Minutes (vs. days/weeks)
1058
+ - Cost: Near-zero (vs. $0.10-0.30 per word)
1059
+ - Speed to market: Immediate (vs. 1-2 weeks)
1060
+
1061
+ ### Analysis Success Metrics
1062
+
1063
+ ✅ **Quality Indicators:**
1064
+ - Themes align with manual coding
1065
+ - Insights lead to actionable decisions
1066
+ - Stakeholders find report valuable
1067
+ - Findings supported by quotes
1068
+
1069
+ ✅ **Efficiency Gains:**
1070
+ - Time to insights: <1 hour (vs. 8-20 hours)
1071
+ - Cost: Minimal (vs. $500-2000 for analyst)
1072
+ - Consistency: High (vs. variable with manual coding)
1073
+
1074
+ ---
1075
+
1076
+ ## 🎯 Use Case Library
1077
+
1078
+ ### Market Research
1079
+ - **New product concept testing**: Generate survey → deploy → analyze feedback
1080
+ - **Brand perception studies**: Multi-language surveys for global brands
1081
+ - **Customer satisfaction tracking**: Quarterly analysis of feedback trends
1082
+ - **Competitive analysis**: Survey design for feature comparison studies
1083
+
1084
+ ### User Experience Research
1085
+ - **Usability study debriefs**: Analyze interview transcripts
1086
+ - **Feature prioritization**: Generate surveys for user voting
1087
+ - **Beta testing feedback**: Quick analysis of bug reports and suggestions
1088
+ - **Accessibility research**: Multi-language surveys for diverse users
1089
+
1090
+ ### Academic Research
1091
+ - **Exploratory studies**: Generate initial survey instruments
1092
+ - **Cross-cultural research**: Translate surveys for international studies
1093
+ - **Qualitative analysis**: Thematic coding of open-ended responses
1094
+ - **Mixed methods**: Combine with quantitative data collection
1095
+
1096
+ ### Human Resources
1097
+ - **Employee engagement**: Annual or pulse surveys
1098
+ - **Exit interviews**: Analysis of leaving employee feedback
1099
+ - **Training needs assessment**: Identify development opportunities
1100
+ - **Culture studies**: Understand organizational dynamics
1101
+
1102
+ ### Product Management
1103
+ - **Feature requests**: Analyze user suggestions
1104
+ - **Beta feedback**: Quick turnaround on pre-release testing
1105
+ - **Roadmap validation**: Survey users on priorities
1106
+ - **Competitor research**: Generate comparison surveys
1107
+
1108
+ ### Healthcare
1109
+ - **Patient satisfaction**: HIPAA-compliant survey generation
1110
+ - **Treatment experience**: Multi-language patient surveys
1111
+ - **Quality improvement**: Analyze patient feedback themes
1112
+ - **Clinical research**: Generate research questionnaires
1113
+
1114
+ ---
1115
+
1116
+ ## 🚧 Limitations & When NOT to Use
1117
+
1118
+ ### Current Limitations
1119
+
1120
+ **Survey Generation:**
1121
+ - ❌ Cannot create complex branching logic
1122
+ - ❌ May need manual refinement for highly specialized topics
1123
+ - ❌ Not a replacement for expert survey design in all cases
1124
+ - ✅ Best for: Standard research surveys, exploratory studies
1125
+
1126
+ **Translation:**
1127
+ - ❌ Not certified/legal translation quality
1128
+ - ❌ May miss subtle cultural nuances in idioms
1129
+ - ❌ Requires native speaker review for publication
1130
+ - ✅ Best for: Research surveys, internal communications
1131
+
1132
+ **Analysis:**
1133
+ - ❌ Not a replacement for rigorous qualitative coding
1134
+ - ❌ May miss domain-specific insights
1135
+ - ❌ Cannot replace human interpretation completely
1136
+ - ✅ Best for: Initial exploration, large-scale feedback, trend identification
1137
+
1138
+ ### When to Use Traditional Methods
1139
+
1140
+ **Use professional survey designers when:**
1141
+ - Regulatory compliance requires certified instruments
1142
+ - High-stakes research with legal implications
1143
+ - Complex adaptive survey logic needed
1144
+ - Validated scales are required
1145
+
1146
+ **Use professional translators when:**
1147
+ - Legal or medical translations needed
1148
+ - Publishing in academic journals
1149
+ - Official government communications
1150
+ - Marketing materials with brand sensitivity
1151
+
1152
+ **Use professional analysts when:**
1153
+ - Publishing peer-reviewed research
1154
+ - Complex coding schemes required
1155
+ - Deep domain expertise needed
1156
+ - Consensus coding is methodology requirement
1157
+
1158
+ ### Best Approach: Hybrid
1159
+
1160
+ **Recommended workflow:**
1161
+ 1. ✅ Use ConversAI for initial draft (fast, cheap)
1162
+ 2. ✅ Expert review and refinement (quality assurance)
1163
+ 3. ✅ Deploy and collect data
1164
+ 4. ✅ ConversAI for preliminary analysis (quick insights)
1165
+ 5. ✅ Deep manual analysis for key findings (rigor)
1166
+
1167
+ ---
1168
+
1169
+ ## 📞 Support & Resources
1170
+
1171
+ ### Getting Help
1172
+
1173
+ **Documentation:**
1174
+ - `USER_GUIDE.md` (this document) - Complete user guide
1175
+ - `QUICK_START_HF_SPACES.md` - Fast deployment
1176
+ - `TROUBLESHOOTING.md` - Common issues and solutions
1177
+ - `README.md` - Technical overview
1178
+
1179
+ **Diagnostics:**
1180
+ - Run `python check_env.py` - Environment checker
1181
+ - Check logs for error messages
1182
+ - Use example data to test functionality
1183
+
1184
+ **Community:**
1185
+ - GitHub Issues - Report bugs and feature requests
1186
+ - HuggingFace Space discussions
1187
+ - Research methods forums
1188
+
1189
+ ### Feedback & Feature Requests
1190
+
1191
+ We'd love to hear from you:
1192
+ - What features would make ConversAI more valuable?
1193
+ - What use cases are we missing?
1194
+ - What pain points can we solve?
1195
+
1196
+ ---
1197
+
1198
+ ## 🎓 Learning Resources
1199
+
1200
+ ### Understanding Qualitative Research
1201
+ - Introduction to thematic analysis
1202
+ - Survey design best practices
1203
+ - Avoiding bias in questions
1204
+ - Cross-cultural research methods
1205
+
1206
+ ### AI & Research Ethics
1207
+ - Using AI in research responsibly
1208
+ - Disclosing AI use in publications
1209
+ - Data privacy considerations
1210
+ - Bias in AI-generated content
1211
+
1212
+ ### Maximizing ConversAI
1213
+ - Video tutorials (coming soon)
1214
+ - Webinar series on research workflows
1215
+ - Case studies from real users
1216
+ - Best practices blog
1217
+
1218
+ ---
1219
+
1220
+ ## 🌟 Success Stories
1221
+
1222
+ ### Story 1: Startup Product Validation
1223
+
1224
+ **Challenge**: Early-stage startup needed to validate product concept across 3 markets in 2 weeks.
1225
+
1226
+ **Solution**:
1227
+ - Generated survey in English (10 questions)
1228
+ - Translated to Spanish and Portuguese
1229
+ - Analyzed 200+ responses in 24 hours
1230
+
1231
+ **Results**:
1232
+ - Launched in correct market first (Brazil, not Mexico as planned)
1233
+ - Saved $3,000 in research costs
1234
+ - Made launch decision 2 weeks faster
1235
+
1236
+ ---
1237
+
1238
+ ### Story 2: University Research Project
1239
+
1240
+ **Challenge**: PhD student analyzing 150 interview transcripts for dissertation.
1241
+
1242
+ **Solution**:
1243
+ - Formatted transcripts as survey responses
1244
+ - Ran thematic analysis
1245
+ - Used insights as starting point for manual coding
1246
+
1247
+ **Results**:
1248
+ - Identified 7 themes in 2 hours vs. estimated 40 hours
1249
+ - Used time savings for deeper literature review
1250
+ - Graduated on schedule
1251
+
1252
+ ---
1253
+
1254
+ ### Story 3: Enterprise Employee Engagement
1255
+
1256
+ **Challenge**: Multinational company with 5,000 employees in 12 countries.
1257
+
1258
+ **Solution**:
1259
+ - Generated engagement survey (20 questions)
1260
+ - Translated to 8 languages
1261
+ - Analyzed responses by region and department
1262
+
1263
+ **Results**:
1264
+ - 40% higher response rate (due to language options)
1265
+ - Identified region-specific retention risks
1266
+ - Informed $500K investment in benefits program
1267
+
1268
+ ---
1269
+
1270
+ ## 🚀 Next Steps
1271
+
1272
+ ### New Users
1273
+ 1. ✅ Start with the "Generate Survey" tab
1274
+ 2. ✅ Use the example outline provided
1275
+ 3. ✅ Review the generated questions
1276
+ 4. ✅ Experiment with different settings
1277
+ 5. ✅ Try the example data in Analysis tab
1278
+
1279
+ ### Regular Users
1280
+ 1. ✅ Create outline templates for common projects
1281
+ 2. ✅ Establish quality review processes
1282
+ 3. ✅ Integrate into research workflow
1283
+ 4. ✅ Share best practices with team
1284
+ 5. ✅ Provide feedback for improvements
1285
+
1286
+ ### Advanced Users
1287
+ 1. ✅ Explore API integration (coming soon)
1288
+ 2. ✅ Customize LLM models for your domain
1289
+ 3. ✅ Build automated research pipelines
1290
+ 4. ✅ Contribute to open source development
1291
+ 5. ✅ Share case studies with community
1292
+
1293
+ ---
1294
+
1295
+ ## 📋 Quick Reference
1296
+
1297
+ ### Common Tasks
1298
+
1299
+ | Task | Location | Time | Tip |
1300
+ |------|----------|------|-----|
1301
+ | Generate survey | Generate tab | 30 sec | Be specific in outline |
1302
+ | Translate survey | Translate tab | 1-2 min | Do all languages at once |
1303
+ | Analyze responses | Analyze tab | 1 min | Min. 10 responses needed |
1304
+ | Download results | Each tab | Instant | JSON for data, MD for reports |
1305
+
1306
+ ### Quality Checklist
1307
+
1308
+ **Before deploying survey:**
1309
+ - [ ] Questions are unbiased and clear
1310
+ - [ ] Appropriate question types used
1311
+ - [ ] Logical flow through survey
1312
+ - [ ] Introduction explains purpose
1313
+ - [ ] Pilot tested with 3-5 people
1314
+
1315
+ **Before deploying translation:**
1316
+ - [ ] Native speaker reviewed
1317
+ - [ ] Cultural appropriateness checked
1318
+ - [ ] Technical terms verified
1319
+ - [ ] Examples make sense in target culture
1320
+
1321
+ **Before presenting analysis:**
1322
+ - [ ] Sufficient responses (20+)
1323
+ - [ ] Themes make sense with data
1324
+ - [ ] Insights are actionable
1325
+ - [ ] Validated with domain knowledge
1326
+ - [ ] Limitations acknowledged
1327
+
1328
+ ---
1329
+
1330
+ **ConversAI** - Transforming qualitative research with AI assistance.
1331
+
1332
+ *Battle the blank page. Reach global audiences. Uncover insights.* 🔬
1333
+
1334
+ ---
1335
+
1336
+ **Version**: 1.0
1337
+ **Last Updated**: 2025
1338
+ **License**: MIT
1339
+ **Support**: See TROUBLESHOOTING.md
app.py CHANGED
@@ -12,13 +12,24 @@ from llm_backend import LLMBackend, LLMProvider
12
  from survey_generator import SurveyGenerator
13
  from survey_translator import SurveyTranslator
14
  from data_analyzer import DataAnalyzer
15
- from export_utils import save_json_file, survey_to_csv, analysis_to_markdown_file
 
 
 
 
 
16
 
17
 
18
  # Global state for current survey
19
  current_survey = None
20
  current_responses = []
21
 
 
 
 
 
 
 
22
 
23
  def initialize_backend():
24
  """Initialize LLM backend based on environment"""
@@ -337,6 +348,196 @@ def load_example_responses():
337
  return json.dumps(example, indent=2)
338
 
339
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  # ===========================
341
  # Gradio Interface
342
  # ===========================
@@ -523,6 +724,202 @@ See the **About** tab for detailed instructions."""
523
  outputs=[responses_input]
524
  )
525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
526
  # ========== ABOUT TAB ==========
527
  with gr.Tab("ℹ️ About"):
528
  gr.Markdown("""
 
12
  from survey_generator import SurveyGenerator
13
  from survey_translator import SurveyTranslator
14
  from data_analyzer import DataAnalyzer
15
+ from export_utils import (save_json_file, survey_to_csv, analysis_to_markdown_file,
16
+ conversation_to_transcript, conversation_to_json, conversation_to_csv,
17
+ flow_to_markdown)
18
+ from conversation_flow import ConversationFlow, ConversationNode, create_example_flow
19
+ from conversation_session import ConversationSession, SessionManager
20
+ from conversation_moderator import ConversationModerator
21
 
22
 
23
  # Global state for current survey
24
  current_survey = None
25
  current_responses = []
26
 
27
+ # Global state for conversational research
28
+ current_flow = None
29
+ session_manager = SessionManager()
30
+ current_session = None
31
+ saved_flows = {}
32
+
33
 
34
  def initialize_backend():
35
  """Initialize LLM backend based on environment"""
 
348
  return json.dumps(example, indent=2)
349
 
350
 
351
+ # ===========================
352
+ # Conversational Research Handlers
353
+ # ===========================
354
+
355
+ def create_new_flow(flow_name: str, flow_description: str):
356
+ """Create a new conversation flow"""
357
+ global current_flow, saved_flows
358
+
359
+ if not flow_name or not flow_name.strip():
360
+ return "❌ Please provide a flow name.", "", None
361
+
362
+ try:
363
+ flow = ConversationFlow(name=flow_name, description=flow_description)
364
+ current_flow = flow
365
+ saved_flows[flow.id] = flow
366
+
367
+ return (
368
+ f"✅ Flow '{flow_name}' created successfully!",
369
+ f"**Flow ID:** {flow.id}\n**Name:** {flow.name}\n**Description:** {flow.description}",
370
+ flow.id
371
+ )
372
+ except Exception as e:
373
+ return f"❌ Error creating flow: {str(e)}", "", None
374
+
375
+
376
+ def load_example_flow():
377
+ """Load an example conversation flow"""
378
+ global current_flow, saved_flows
379
+
380
+ flow = create_example_flow()
381
+ current_flow = flow
382
+ saved_flows[flow.id] = flow
383
+
384
+ return (
385
+ f"✅ Example flow loaded: {flow.name}",
386
+ display_flow(flow),
387
+ flow.id
388
+ )
389
+
390
+
391
+ def add_flow_node(flow_id: str, node_content: str, node_type: str):
392
+ """Add a node to the current flow"""
393
+ global current_flow, saved_flows
394
+
395
+ if not flow_id:
396
+ return "❌ No flow selected.", ""
397
+
398
+ flow = saved_flows.get(flow_id)
399
+ if not flow:
400
+ return "❌ Flow not found.", ""
401
+
402
+ if not node_content or not node_content.strip():
403
+ return "❌ Please provide content for the node.", ""
404
+
405
+ try:
406
+ node = ConversationNode(content=node_content, node_type=node_type.lower())
407
+
408
+ # Link to previous node if exists
409
+ if flow.nodes:
410
+ last_node = flow.nodes[-1]
411
+ last_node.next = node.id
412
+
413
+ flow.add_node(node)
414
+ current_flow = flow
415
+
416
+ return (
417
+ f"✅ Node added successfully! Total nodes: {len(flow.nodes)}",
418
+ display_flow(flow)
419
+ )
420
+ except Exception as e:
421
+ return f"❌ Error adding node: {str(e)}", ""
422
+
423
+
424
+ def display_flow(flow: ConversationFlow) -> str:
425
+ """Display flow as markdown"""
426
+ if not flow or not flow.nodes:
427
+ return "No flow to display"
428
+
429
+ output = f"# {flow.name}\n\n"
430
+ output += f"**Description:** {flow.description}\n\n"
431
+ output += f"**Total Steps:** {len(flow.nodes)}\n\n"
432
+ output += "---\n\n"
433
+
434
+ for i, node in enumerate(flow.nodes, 1):
435
+ output += f"### Step {i}: {node.type.capitalize()}\n\n"
436
+ output += f"{node.content}\n\n"
437
+
438
+ return output
439
+
440
+
441
+ def save_current_flow(flow_id: str):
442
+ """Save the current flow to file"""
443
+ if not flow_id:
444
+ return "❌ No flow selected.", None
445
+
446
+ flow = saved_flows.get(flow_id)
447
+ if not flow:
448
+ return "❌ Flow not found.", None
449
+
450
+ try:
451
+ filepath = save_json_file(flow.to_dict(), "conversation_flow")
452
+ return f"✅ Flow saved to {filepath}", filepath
453
+ except Exception as e:
454
+ return f"❌ Error saving flow: {str(e)}", None
455
+
456
+
457
+ def start_conversation_session(flow_id: str):
458
+ """Start a new conversation session"""
459
+ global current_session, session_manager
460
+
461
+ if not flow_id:
462
+ return [], "❌ Please select a flow first."
463
+
464
+ flow = saved_flows.get(flow_id)
465
+ if not flow:
466
+ return [], "❌ Flow not found."
467
+
468
+ if not llm_backend:
469
+ return [], "❌ LLM backend not initialized."
470
+
471
+ try:
472
+ # Create session
473
+ session = session_manager.create_session(flow_id=flow.id, flow_name=flow.name)
474
+ current_session = session
475
+
476
+ # Create moderator
477
+ moderator = ConversationModerator(llm_backend, flow)
478
+
479
+ # Start conversation
480
+ opening_message = moderator.start_conversation(session)
481
+
482
+ # Return chat history in Gradio format
483
+ return [[None, opening_message]], f"✅ Conversation started! Session ID: {session.id}"
484
+
485
+ except Exception as e:
486
+ return [], f"❌ Error starting conversation: {str(e)}"
487
+
488
+
489
+ def chat_with_moderator(user_message: str, history: List):
490
+ """Handle chat messages with the AI moderator"""
491
+ global current_session
492
+
493
+ if not current_session:
494
+ return history, "❌ No active session. Please start a conversation first."
495
+
496
+ if not llm_backend:
497
+ return history, "❌ LLM backend not initialized."
498
+
499
+ if not user_message or not user_message.strip():
500
+ return history, "❌ Please enter a message."
501
+
502
+ try:
503
+ # Get the flow
504
+ flow = saved_flows.get(current_session.flow_id)
505
+ if not flow:
506
+ return history, "❌ Flow not found."
507
+
508
+ # Create moderator
509
+ moderator = ConversationModerator(llm_backend, flow)
510
+
511
+ # Process user response
512
+ ai_response = moderator.process_user_response(current_session, user_message)
513
+
514
+ # Update history
515
+ history.append([user_message, ai_response])
516
+
517
+ status = f"Session: {current_session.id} | Turns: {current_session.get_turn_count()}"
518
+ if current_session.status == "completed":
519
+ status += " | ✅ Conversation completed"
520
+
521
+ return history, status
522
+
523
+ except Exception as e:
524
+ return history, f"❌ Error: {str(e)}"
525
+
526
+
527
+ def export_conversation():
528
+ """Export the current conversation"""
529
+ global current_session
530
+
531
+ if not current_session:
532
+ return "❌ No active session to export.", None
533
+
534
+ try:
535
+ filepath = conversation_to_transcript(current_session)
536
+ return f"✅ Conversation exported to {filepath}", filepath
537
+ except Exception as e:
538
+ return f"❌ Error exporting conversation: {str(e)}", None
539
+
540
+
541
  # ===========================
542
  # Gradio Interface
543
  # ===========================
 
724
  outputs=[responses_input]
725
  )
726
 
727
+ # ========== CONVERSATIONAL RESEARCH TAB ==========
728
+ with gr.Tab("💬 Conversational Research"):
729
+ gr.Markdown("""
730
+ ## AI-Moderated Conversations
731
+ Design conversation flows and conduct AI-powered qualitative interviews with respondents.
732
+ """)
733
+
734
+ with gr.Tabs():
735
+ # Design Flow Sub-Tab
736
+ with gr.Tab("🎨 Design Flow"):
737
+ gr.Markdown("""
738
+ ### Create Conversation Flows
739
+ Design custom conversation paths for AI-moderated interviews.
740
+ """)
741
+
742
+ with gr.Row():
743
+ with gr.Column(scale=1):
744
+ gr.Markdown("#### Flow Setup")
745
+
746
+ flow_name_input = gr.Textbox(
747
+ label="Flow Name",
748
+ placeholder="e.g., HCP Interview for New Dermatology Product",
749
+ value=""
750
+ )
751
+
752
+ flow_desc_input = gr.Textbox(
753
+ label="Flow Description",
754
+ placeholder="Describe the purpose of this conversation flow...",
755
+ lines=3
756
+ )
757
+
758
+ with gr.Row():
759
+ create_flow_btn = gr.Button("✨ Create New Flow", variant="primary")
760
+ load_example_flow_btn = gr.Button("📋 Load Example", variant="secondary")
761
+
762
+ flow_id_state = gr.State(value="")
763
+
764
+ gr.Markdown("#### Add Steps to Flow")
765
+
766
+ node_content_input = gr.Textbox(
767
+ label="Question/Message",
768
+ placeholder="Enter the question or message for this step...",
769
+ lines=4
770
+ )
771
+
772
+ node_type_input = gr.Radio(
773
+ label="Step Type",
774
+ choices=["Question", "End"],
775
+ value="Question"
776
+ )
777
+
778
+ add_node_btn = gr.Button("➕ Add Step", variant="secondary")
779
+
780
+ save_flow_btn = gr.Button("💾 Save Flow", variant="primary")
781
+
782
+ with gr.Column(scale=1):
783
+ flow_status = gr.Textbox(label="Status", interactive=False)
784
+ flow_display = gr.Markdown(label="Flow Preview", value="No flow created yet")
785
+
786
+ flow_download = gr.File(label="Download Flow JSON", visible=False)
787
+
788
+ # Event handlers for flow design
789
+ create_flow_btn.click(
790
+ fn=create_new_flow,
791
+ inputs=[flow_name_input, flow_desc_input],
792
+ outputs=[flow_status, flow_display, flow_id_state]
793
+ )
794
+
795
+ load_example_flow_btn.click(
796
+ fn=load_example_flow,
797
+ outputs=[flow_status, flow_display, flow_id_state]
798
+ )
799
+
800
+ add_node_btn.click(
801
+ fn=add_flow_node,
802
+ inputs=[flow_id_state, node_content_input, node_type_input],
803
+ outputs=[flow_status, flow_display]
804
+ ).then(
805
+ fn=lambda: "",
806
+ outputs=[node_content_input]
807
+ )
808
+
809
+ save_flow_btn.click(
810
+ fn=save_current_flow,
811
+ inputs=[flow_id_state],
812
+ outputs=[flow_status, flow_download]
813
+ ).then(
814
+ fn=lambda x: gr.File(value=x, visible=True) if x else gr.File(visible=False),
815
+ inputs=[flow_download],
816
+ outputs=[flow_download]
817
+ )
818
+
819
+ # Conduct Interview Sub-Tab
820
+ with gr.Tab("🎙️ Conduct Interview"):
821
+ gr.Markdown("""
822
+ ### AI-Moderated Interview
823
+ Start a conversation session with the AI moderator using your designed flow.
824
+ """)
825
+
826
+ with gr.Row():
827
+ with gr.Column(scale=1):
828
+ conversation_flow_selector = gr.State(value="")
829
+
830
+ gr.Markdown("""
831
+ **Instructions:**
832
+ 1. Design a flow in the 'Design Flow' tab first (or load the example)
833
+ 2. Click 'Start Conversation' to begin
834
+ 3. The AI moderator will ask questions from your flow
835
+ 4. The AI adapts with follow-up questions based on responses
836
+ 5. Export the conversation when finished
837
+ """)
838
+
839
+ with gr.Row():
840
+ start_conversation_btn = gr.Button("🚀 Start Conversation", variant="primary")
841
+ export_conversation_btn = gr.Button("📥 Export Conversation", variant="secondary")
842
+
843
+ conversation_status = gr.Textbox(label="Session Status", interactive=False)
844
+ conversation_download = gr.File(label="Download Transcript", visible=False)
845
+
846
+ with gr.Column(scale=1):
847
+ chatbot = gr.Chatbot(
848
+ label="AI-Moderated Interview",
849
+ height=500
850
+ )
851
+
852
+ msg_input = gr.Textbox(
853
+ label="Your Response",
854
+ placeholder="Type your response here...",
855
+ lines=2
856
+ )
857
+
858
+ with gr.Row():
859
+ submit_btn = gr.Button("Send", variant="primary")
860
+ clear_btn = gr.Button("Clear")
861
+
862
+ # Chat event handlers
863
+ def user_submit(user_message, history):
864
+ """Handle user message submission"""
865
+ if not user_message:
866
+ return history, history, ""
867
+ return history, history + [[user_message, None]], ""
868
+
869
+ def bot_respond(history):
870
+ """Get bot response"""
871
+ if not history or history[-1][1] is not None:
872
+ return history, ""
873
+
874
+ user_msg = history[-1][0]
875
+ updated_history, status = chat_with_moderator(user_msg, history[:-1])
876
+ return updated_history, status
877
+
878
+ # Start conversation
879
+ start_conversation_btn.click(
880
+ fn=lambda: saved_flows[list(saved_flows.keys())[-1]].id if saved_flows else "",
881
+ outputs=[conversation_flow_selector]
882
+ ).then(
883
+ fn=start_conversation_session,
884
+ inputs=[conversation_flow_selector],
885
+ outputs=[chatbot, conversation_status]
886
+ )
887
+
888
+ # Message submission
889
+ msg_input.submit(
890
+ fn=user_submit,
891
+ inputs=[msg_input, chatbot],
892
+ outputs=[chatbot, chatbot, msg_input],
893
+ queue=False
894
+ ).then(
895
+ fn=bot_respond,
896
+ inputs=[chatbot],
897
+ outputs=[chatbot, conversation_status]
898
+ )
899
+
900
+ submit_btn.click(
901
+ fn=user_submit,
902
+ inputs=[msg_input, chatbot],
903
+ outputs=[chatbot, chatbot, msg_input],
904
+ queue=False
905
+ ).then(
906
+ fn=bot_respond,
907
+ inputs=[chatbot],
908
+ outputs=[chatbot, conversation_status]
909
+ )
910
+
911
+ clear_btn.click(lambda: None, None, chatbot, queue=False)
912
+
913
+ # Export conversation
914
+ export_conversation_btn.click(
915
+ fn=export_conversation,
916
+ outputs=[conversation_status, conversation_download]
917
+ ).then(
918
+ fn=lambda x: gr.File(value=x, visible=True) if x else gr.File(visible=False),
919
+ inputs=[conversation_download],
920
+ outputs=[conversation_download]
921
+ )
922
+
923
  # ========== ABOUT TAB ==========
924
  with gr.Tab("ℹ️ About"):
925
  gr.Markdown("""
conversation_flow.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Conversation Flow Management - Design and store conversation paths
3
+ """
4
+ import json
5
+ import uuid
6
+ from typing import Dict, List, Optional
7
+ from datetime import datetime
8
+
9
+
10
+ class ConversationNode:
11
+ """Represents a single node in a conversation flow"""
12
+
13
+ def __init__(self, node_id: str = None, node_type: str = "question",
14
+ content: str = "", next_node: str = None, branches: List[Dict] = None):
15
+ self.id = node_id or str(uuid.uuid4())
16
+ self.type = node_type # "question", "branch", "end"
17
+ self.content = content
18
+ self.next = next_node
19
+ self.branches = branches or [] # For conditional branching
20
+
21
+ def to_dict(self) -> Dict:
22
+ """Convert node to dictionary"""
23
+ return {
24
+ "id": self.id,
25
+ "type": self.type,
26
+ "content": self.content,
27
+ "next": self.next,
28
+ "branches": self.branches
29
+ }
30
+
31
+ @classmethod
32
+ def from_dict(cls, data: Dict) -> 'ConversationNode':
33
+ """Create node from dictionary"""
34
+ return cls(
35
+ node_id=data.get("id"),
36
+ node_type=data.get("type", "question"),
37
+ content=data.get("content", ""),
38
+ next_node=data.get("next"),
39
+ branches=data.get("branches", [])
40
+ )
41
+
42
+
43
+ class ConversationFlow:
44
+ """Manages a complete conversation flow"""
45
+
46
+ def __init__(self, flow_id: str = None, name: str = "Untitled Flow",
47
+ description: str = "", nodes: List[ConversationNode] = None):
48
+ self.id = flow_id or str(uuid.uuid4())
49
+ self.name = name
50
+ self.description = description
51
+ self.nodes = nodes or []
52
+ self.created_at = datetime.now().isoformat()
53
+ self.updated_at = datetime.now().isoformat()
54
+
55
+ def add_node(self, node: ConversationNode, position: int = None):
56
+ """Add a node to the flow"""
57
+ if position is None:
58
+ self.nodes.append(node)
59
+ else:
60
+ self.nodes.insert(position, node)
61
+ self.updated_at = datetime.now().isoformat()
62
+
63
+ def remove_node(self, node_id: str):
64
+ """Remove a node from the flow"""
65
+ self.nodes = [n for n in self.nodes if n.id != node_id]
66
+ self.updated_at = datetime.now().isoformat()
67
+
68
+ def get_node(self, node_id: str) -> Optional[ConversationNode]:
69
+ """Get a node by ID"""
70
+ for node in self.nodes:
71
+ if node.id == node_id:
72
+ return node
73
+ return None
74
+
75
+ def get_start_node(self) -> Optional[ConversationNode]:
76
+ """Get the first node in the flow"""
77
+ return self.nodes[0] if self.nodes else None
78
+
79
+ def reorder_node(self, node_id: str, new_position: int):
80
+ """Move a node to a different position"""
81
+ node = self.get_node(node_id)
82
+ if node:
83
+ self.nodes.remove(node)
84
+ self.nodes.insert(new_position, node)
85
+ self.updated_at = datetime.now().isoformat()
86
+
87
+ def to_dict(self) -> Dict:
88
+ """Convert flow to dictionary"""
89
+ return {
90
+ "id": self.id,
91
+ "name": self.name,
92
+ "description": self.description,
93
+ "nodes": [node.to_dict() for node in self.nodes],
94
+ "created_at": self.created_at,
95
+ "updated_at": self.updated_at
96
+ }
97
+
98
+ @classmethod
99
+ def from_dict(cls, data: Dict) -> 'ConversationFlow':
100
+ """Create flow from dictionary"""
101
+ flow = cls(
102
+ flow_id=data.get("id"),
103
+ name=data.get("name", "Untitled Flow"),
104
+ description=data.get("description", "")
105
+ )
106
+ flow.nodes = [ConversationNode.from_dict(n) for n in data.get("nodes", [])]
107
+ flow.created_at = data.get("created_at", datetime.now().isoformat())
108
+ flow.updated_at = data.get("updated_at", datetime.now().isoformat())
109
+ return flow
110
+
111
+ def save_to_file(self, filepath: str):
112
+ """Save flow to JSON file"""
113
+ with open(filepath, 'w') as f:
114
+ json.dump(self.to_dict(), f, indent=2)
115
+
116
+ @classmethod
117
+ def load_from_file(cls, filepath: str) -> 'ConversationFlow':
118
+ """Load flow from JSON file"""
119
+ with open(filepath, 'r') as f:
120
+ data = json.load(f)
121
+ return cls.from_dict(data)
122
+
123
+ def validate(self) -> tuple[bool, str]:
124
+ """Validate the flow structure"""
125
+ if not self.nodes:
126
+ return False, "Flow must have at least one node"
127
+
128
+ if not self.name or not self.name.strip():
129
+ return False, "Flow must have a name"
130
+
131
+ # Check for orphaned nodes (nodes that can't be reached)
132
+ reachable = set()
133
+ if self.nodes:
134
+ current = self.nodes[0]
135
+ reachable.add(current.id)
136
+
137
+ # Simple validation: check if nodes are in sequence
138
+ for node in self.nodes:
139
+ if not node.content or not node.content.strip():
140
+ return False, f"Node {node.id} has no content"
141
+
142
+ return True, "Flow is valid"
143
+
144
+
145
+ def create_example_flow() -> ConversationFlow:
146
+ """Create an example conversation flow"""
147
+ flow = ConversationFlow(
148
+ name="Customer Feedback Interview",
149
+ description="Structured interview to gather customer feedback on product experience"
150
+ )
151
+
152
+ # Add nodes
153
+ node1 = ConversationNode(
154
+ content="Hello! Thank you for taking the time to speak with me today. I'd like to understand your experience with our product. First, can you tell me what initially attracted you to our product?",
155
+ node_type="question"
156
+ )
157
+
158
+ node2 = ConversationNode(
159
+ content="That's interesting. How would you describe your overall experience using the product so far?",
160
+ node_type="question"
161
+ )
162
+
163
+ node3 = ConversationNode(
164
+ content="What specific features do you find most valuable, and why?",
165
+ node_type="question"
166
+ )
167
+
168
+ node4 = ConversationNode(
169
+ content="Have you encountered any challenges or frustrations while using the product? If so, can you describe them?",
170
+ node_type="question"
171
+ )
172
+
173
+ node5 = ConversationNode(
174
+ content="Based on your experience, what improvements or new features would you most like to see?",
175
+ node_type="question"
176
+ )
177
+
178
+ node6 = ConversationNode(
179
+ content="Thank you so much for sharing your thoughts! Your feedback is incredibly valuable and will help us improve the product. Is there anything else you'd like to add?",
180
+ node_type="end"
181
+ )
182
+
183
+ # Link nodes
184
+ node1.next = node2.id
185
+ node2.next = node3.id
186
+ node3.next = node4.id
187
+ node4.next = node5.id
188
+ node5.next = node6.id
189
+
190
+ flow.add_node(node1)
191
+ flow.add_node(node2)
192
+ flow.add_node(node3)
193
+ flow.add_node(node4)
194
+ flow.add_node(node5)
195
+ flow.add_node(node6)
196
+
197
+ return flow
conversation_moderator.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Conversation Moderator - AI-powered interview moderator
3
+ """
4
+ from typing import Dict, List, Optional, Tuple
5
+ from llm_backend import LLMBackend
6
+ from conversation_flow import ConversationFlow, ConversationNode
7
+ from conversation_session import ConversationSession
8
+
9
+
10
+ class ConversationModerator:
11
+ """
12
+ AI moderator that conducts conversations based on flows.
13
+ Handles scripted questions, dynamic follow-ups, and probing.
14
+ """
15
+
16
+ def __init__(self, llm_backend: LLMBackend, flow: ConversationFlow):
17
+ self.llm = llm_backend
18
+ self.flow = flow
19
+ self.follow_up_threshold = 3 # Ask follow-up every N user responses
20
+
21
+ def start_conversation(self, session: ConversationSession) -> str:
22
+ """
23
+ Start a conversation by asking the first question.
24
+
25
+ Returns:
26
+ The opening message from the AI
27
+ """
28
+ first_node = self.flow.get_start_node()
29
+ if not first_node:
30
+ return "I apologize, but there seems to be an issue with the conversation flow."
31
+
32
+ session.current_node_id = first_node.id
33
+ session.add_turn("ai", first_node.content, node_id=first_node.id)
34
+ return first_node.content
35
+
36
+ def process_user_response(self, session: ConversationSession, user_message: str) -> str:
37
+ """
38
+ Process a user response and generate the next AI message.
39
+
40
+ Args:
41
+ session: Current conversation session
42
+ user_message: The user's message
43
+
44
+ Returns:
45
+ The AI's response
46
+ """
47
+ # Add user message to session
48
+ session.add_turn("user", user_message)
49
+
50
+ # Decide whether to ask scripted question or dynamic follow-up
51
+ if self._should_probe(session, user_message):
52
+ # Generate dynamic follow-up question
53
+ ai_response = self._generate_follow_up(session, user_message)
54
+ session.add_turn("ai", ai_response)
55
+ else:
56
+ # Move to next node in flow
57
+ ai_response = self._get_next_scripted_question(session)
58
+ if ai_response:
59
+ session.add_turn("ai", ai_response, node_id=session.current_node_id)
60
+ else:
61
+ # End of flow
62
+ ai_response = self._generate_closing(session)
63
+ session.add_turn("ai", ai_response)
64
+ session.end_session()
65
+
66
+ return ai_response
67
+
68
+ def _should_probe(self, session: ConversationSession, user_message: str) -> bool:
69
+ """
70
+ Decide if we should probe deeper or continue with scripted questions.
71
+
72
+ Returns:
73
+ True if should ask follow-up, False if should continue flow
74
+ """
75
+ # Don't probe on very short responses
76
+ if len(user_message.split()) < 5:
77
+ return False
78
+
79
+ # Probe every few responses (but not too often)
80
+ user_turns = [t for t in session.conversation_history if t.role == "user"]
81
+ turn_count = len(user_turns)
82
+
83
+ # Probe on turns 2, 5, 8, etc. (every 3 turns, starting after first question)
84
+ if turn_count > 1 and (turn_count - 1) % self.follow_up_threshold == 0:
85
+ return True
86
+
87
+ # Also probe if response contains interesting keywords
88
+ interesting_keywords = [
89
+ "because", "however", "although", "surprisingly", "unfortunately",
90
+ "frustrated", "confused", "excited", "worried", "concerned"
91
+ ]
92
+ if any(keyword in user_message.lower() for keyword in interesting_keywords):
93
+ return True
94
+
95
+ return False
96
+
97
+ def _generate_follow_up(self, session: ConversationSession, user_message: str) -> str:
98
+ """
99
+ Generate a dynamic follow-up question using the LLM.
100
+
101
+ Args:
102
+ session: Current conversation session
103
+ user_message: The user's latest message
104
+
105
+ Returns:
106
+ A follow-up question
107
+ """
108
+ # Create prompt for generating follow-up
109
+ system_prompt = """You are a professional qualitative research interviewer. Your goal is to probe deeper into the respondent's answers to uncover insights.
110
+
111
+ Generate ONE follow-up question that:
112
+ - Explores an interesting point the respondent mentioned
113
+ - Asks for more detail or clarification
114
+ - Uses phrases like "Tell me more about...", "Can you elaborate on...", "What do you mean by...", "Why do you think..."
115
+ - Is empathetic and non-judgmental
116
+ - Is concise (one sentence)
117
+
118
+ Respond ONLY with the follow-up question, nothing else."""
119
+
120
+ user_prompt = f"""The respondent just said: "{user_message}"
121
+
122
+ Generate a single follow-up question to probe deeper into their response."""
123
+
124
+ messages = [
125
+ {"role": "system", "content": system_prompt},
126
+ {"role": "user", "content": user_prompt}
127
+ ]
128
+
129
+ try:
130
+ follow_up = self.llm.generate(messages, max_tokens=100, temperature=0.7)
131
+ # Clean up the response
132
+ follow_up = follow_up.strip().strip('"').strip("'")
133
+ if not follow_up.endswith("?"):
134
+ follow_up += "?"
135
+ return follow_up
136
+ except Exception as e:
137
+ # Fallback to generic follow-up
138
+ return "Can you tell me more about that?"
139
+
140
+ def _get_next_scripted_question(self, session: ConversationSession) -> Optional[str]:
141
+ """
142
+ Get the next scripted question from the flow.
143
+
144
+ Returns:
145
+ The next question, or None if end of flow
146
+ """
147
+ if not session.current_node_id:
148
+ return None
149
+
150
+ current_node = self.flow.get_node(session.current_node_id)
151
+ if not current_node or not current_node.next:
152
+ return None
153
+
154
+ next_node = self.flow.get_node(current_node.next)
155
+ if not next_node:
156
+ return None
157
+
158
+ session.current_node_id = next_node.id
159
+ return next_node.content
160
+
161
+ def _generate_closing(self, session: ConversationSession) -> str:
162
+ """
163
+ Generate a closing message for the conversation.
164
+
165
+ Returns:
166
+ Closing message
167
+ """
168
+ return "Thank you so much for sharing your thoughts with me today. Your insights are incredibly valuable and will help us better understand this topic. Is there anything else you'd like to add before we finish?"
169
+
170
+ def generate_summary(self, session: ConversationSession) -> str:
171
+ """
172
+ Generate a summary of the conversation using the LLM.
173
+
174
+ Args:
175
+ session: The conversation session to summarize
176
+
177
+ Returns:
178
+ A summary of the conversation
179
+ """
180
+ # Get conversation transcript
181
+ transcript_parts = []
182
+ for turn in session.conversation_history:
183
+ speaker = "Moderator" if turn.role == "ai" else "Respondent"
184
+ transcript_parts.append(f"{speaker}: {turn.content}")
185
+
186
+ transcript = "\n".join(transcript_parts)
187
+
188
+ system_prompt = """You are analyzing a qualitative research interview. Generate a concise summary that captures:
189
+ 1. The main topics discussed
190
+ 2. Key insights or themes from the respondent
191
+ 3. Notable quotes or moments
192
+ 4. Overall sentiment
193
+
194
+ Keep the summary to 3-4 paragraphs."""
195
+
196
+ user_prompt = f"""Summarize this interview:
197
+
198
+ {transcript}
199
+
200
+ Provide a professional summary suitable for a research report."""
201
+
202
+ messages = [
203
+ {"role": "system", "content": system_prompt},
204
+ {"role": "user", "content": user_prompt}
205
+ ]
206
+
207
+ try:
208
+ summary = self.llm.generate(messages, max_tokens=500, temperature=0.5)
209
+ return summary.strip()
210
+ except Exception as e:
211
+ return f"Summary generation failed: {str(e)}"
212
+
213
+ def reflect_understanding(self, session: ConversationSession) -> str:
214
+ """
215
+ Periodically reflect back understanding to the respondent.
216
+
217
+ Returns:
218
+ A reflection statement
219
+ """
220
+ recent_turns = [t for t in session.conversation_history if t.role == "user"][-3:]
221
+ if not recent_turns:
222
+ return "Let me make sure I understand you correctly..."
223
+
224
+ recent_content = " ".join([t.content for t in recent_turns])
225
+
226
+ system_prompt = """You are a research interviewer reflecting back what you've heard. Create a brief summary (1-2 sentences) of what the respondent has shared, then ask if you understood correctly.
227
+
228
+ Format: "So if I understand correctly, [summary]. Is that right?" """
229
+
230
+ user_prompt = f"""The respondent recently said: "{recent_content}"
231
+
232
+ Reflect back your understanding and ask for confirmation."""
233
+
234
+ messages = [
235
+ {"role": "system", "content": system_prompt},
236
+ {"role": "user", "content": user_prompt}
237
+ ]
238
+
239
+ try:
240
+ reflection = self.llm.generate(messages, max_tokens=150, temperature=0.5)
241
+ return reflection.strip()
242
+ except Exception as e:
243
+ return "Let me make sure I understand you correctly - can you confirm that I've captured your main points accurately?"
conversation_session.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Conversation Session Management - Track live conversations
3
+ """
4
+ import json
5
+ import uuid
6
+ from typing import Dict, List, Optional
7
+ from datetime import datetime
8
+
9
+
10
+ class ConversationTurn:
11
+ """Represents a single turn in a conversation"""
12
+
13
+ def __init__(self, role: str, content: str, timestamp: str = None,
14
+ node_id: str = None, summary: str = None):
15
+ self.role = role # "ai" or "user"
16
+ self.content = content
17
+ self.timestamp = timestamp or datetime.now().isoformat()
18
+ self.node_id = node_id # Which node in the flow this relates to
19
+ self.summary = summary # AI's summary of this turn
20
+
21
+ def to_dict(self) -> Dict:
22
+ """Convert turn to dictionary"""
23
+ return {
24
+ "role": self.role,
25
+ "content": self.content,
26
+ "timestamp": self.timestamp,
27
+ "node_id": self.node_id,
28
+ "summary": self.summary
29
+ }
30
+
31
+ @classmethod
32
+ def from_dict(cls, data: Dict) -> 'ConversationTurn':
33
+ """Create turn from dictionary"""
34
+ return cls(
35
+ role=data.get("role"),
36
+ content=data.get("content"),
37
+ timestamp=data.get("timestamp"),
38
+ node_id=data.get("node_id"),
39
+ summary=data.get("summary")
40
+ )
41
+
42
+
43
+ class ConversationSession:
44
+ """Manages a live conversation session"""
45
+
46
+ def __init__(self, session_id: str = None, flow_id: str = None,
47
+ respondent_id: str = None, flow_name: str = ""):
48
+ self.id = session_id or str(uuid.uuid4())
49
+ self.flow_id = flow_id
50
+ self.flow_name = flow_name
51
+ self.respondent_id = respondent_id or f"respondent_{uuid.uuid4().hex[:8]}"
52
+ self.conversation_history: List[ConversationTurn] = []
53
+ self.current_node_id: Optional[str] = None
54
+ self.started_at = datetime.now().isoformat()
55
+ self.ended_at: Optional[str] = None
56
+ self.status = "active" # "active", "completed", "abandoned"
57
+ self.metadata = {}
58
+
59
+ def add_turn(self, role: str, content: str, node_id: str = None, summary: str = None):
60
+ """Add a turn to the conversation"""
61
+ turn = ConversationTurn(
62
+ role=role,
63
+ content=content,
64
+ node_id=node_id,
65
+ summary=summary
66
+ )
67
+ self.conversation_history.append(turn)
68
+
69
+ def get_conversation_for_llm(self) -> List[Dict[str, str]]:
70
+ """Get conversation history in format suitable for LLM"""
71
+ messages = []
72
+ for turn in self.conversation_history:
73
+ messages.append({
74
+ "role": "assistant" if turn.role == "ai" else "user",
75
+ "content": turn.content
76
+ })
77
+ return messages
78
+
79
+ def get_last_user_message(self) -> Optional[str]:
80
+ """Get the most recent user message"""
81
+ for turn in reversed(self.conversation_history):
82
+ if turn.role == "user":
83
+ return turn.content
84
+ return None
85
+
86
+ def get_turn_count(self) -> int:
87
+ """Get total number of turns"""
88
+ return len(self.conversation_history)
89
+
90
+ def end_session(self):
91
+ """Mark session as completed"""
92
+ self.status = "completed"
93
+ self.ended_at = datetime.now().isoformat()
94
+
95
+ def abandon_session(self):
96
+ """Mark session as abandoned"""
97
+ self.status = "abandoned"
98
+ self.ended_at = datetime.now().isoformat()
99
+
100
+ def to_dict(self) -> Dict:
101
+ """Convert session to dictionary"""
102
+ return {
103
+ "id": self.id,
104
+ "flow_id": self.flow_id,
105
+ "flow_name": self.flow_name,
106
+ "respondent_id": self.respondent_id,
107
+ "conversation_history": [turn.to_dict() for turn in self.conversation_history],
108
+ "current_node_id": self.current_node_id,
109
+ "started_at": self.started_at,
110
+ "ended_at": self.ended_at,
111
+ "status": self.status,
112
+ "metadata": self.metadata
113
+ }
114
+
115
+ @classmethod
116
+ def from_dict(cls, data: Dict) -> 'ConversationSession':
117
+ """Create session from dictionary"""
118
+ session = cls(
119
+ session_id=data.get("id"),
120
+ flow_id=data.get("flow_id"),
121
+ respondent_id=data.get("respondent_id"),
122
+ flow_name=data.get("flow_name", "")
123
+ )
124
+ session.conversation_history = [
125
+ ConversationTurn.from_dict(t) for t in data.get("conversation_history", [])
126
+ ]
127
+ session.current_node_id = data.get("current_node_id")
128
+ session.started_at = data.get("started_at", datetime.now().isoformat())
129
+ session.ended_at = data.get("ended_at")
130
+ session.status = data.get("status", "active")
131
+ session.metadata = data.get("metadata", {})
132
+ return session
133
+
134
+ def save_to_file(self, filepath: str):
135
+ """Save session to JSON file"""
136
+ with open(filepath, 'w') as f:
137
+ json.dump(self.to_dict(), f, indent=2)
138
+
139
+ @classmethod
140
+ def load_from_file(cls, filepath: str) -> 'ConversationSession':
141
+ """Load session from JSON file"""
142
+ with open(filepath, 'r') as f:
143
+ data = json.load(f)
144
+ return cls.from_dict(data)
145
+
146
+ def get_transcript(self) -> str:
147
+ """Get conversation as readable transcript"""
148
+ lines = []
149
+ lines.append(f"Conversation Session: {self.id}")
150
+ lines.append(f"Flow: {self.flow_name}")
151
+ lines.append(f"Respondent: {self.respondent_id}")
152
+ lines.append(f"Started: {self.started_at}")
153
+ if self.ended_at:
154
+ lines.append(f"Ended: {self.ended_at}")
155
+ lines.append(f"Status: {self.status}")
156
+ lines.append("\n" + "="*60 + "\n")
157
+
158
+ for i, turn in enumerate(self.conversation_history, 1):
159
+ speaker = "AI Moderator" if turn.role == "ai" else "Respondent"
160
+ lines.append(f"[{i}] {speaker} ({turn.timestamp}):")
161
+ lines.append(f"{turn.content}\n")
162
+
163
+ if turn.summary:
164
+ lines.append(f" Summary: {turn.summary}\n")
165
+
166
+ return "\n".join(lines)
167
+
168
+ def get_summary_stats(self) -> Dict:
169
+ """Get summary statistics about the session"""
170
+ user_turns = [t for t in self.conversation_history if t.role == "user"]
171
+ ai_turns = [t for t in self.conversation_history if t.role == "ai"]
172
+
173
+ return {
174
+ "total_turns": len(self.conversation_history),
175
+ "user_turns": len(user_turns),
176
+ "ai_turns": len(ai_turns),
177
+ "avg_user_response_length": sum(len(t.content) for t in user_turns) / max(len(user_turns), 1),
178
+ "duration_minutes": self._calculate_duration_minutes(),
179
+ "status": self.status
180
+ }
181
+
182
+ def _calculate_duration_minutes(self) -> float:
183
+ """Calculate session duration in minutes"""
184
+ if not self.ended_at:
185
+ end_time = datetime.now()
186
+ else:
187
+ end_time = datetime.fromisoformat(self.ended_at)
188
+
189
+ start_time = datetime.fromisoformat(self.started_at)
190
+ duration = (end_time - start_time).total_seconds() / 60
191
+ return round(duration, 2)
192
+
193
+
194
+ class SessionManager:
195
+ """Manages multiple conversation sessions"""
196
+
197
+ def __init__(self):
198
+ self.sessions: Dict[str, ConversationSession] = {}
199
+
200
+ def create_session(self, flow_id: str, flow_name: str = "", respondent_id: str = None) -> ConversationSession:
201
+ """Create a new session"""
202
+ session = ConversationSession(
203
+ flow_id=flow_id,
204
+ flow_name=flow_name,
205
+ respondent_id=respondent_id
206
+ )
207
+ self.sessions[session.id] = session
208
+ return session
209
+
210
+ def get_session(self, session_id: str) -> Optional[ConversationSession]:
211
+ """Get a session by ID"""
212
+ return self.sessions.get(session_id)
213
+
214
+ def get_active_sessions(self) -> List[ConversationSession]:
215
+ """Get all active sessions"""
216
+ return [s for s in self.sessions.values() if s.status == "active"]
217
+
218
+ def get_all_sessions(self) -> List[ConversationSession]:
219
+ """Get all sessions"""
220
+ return list(self.sessions.values())
221
+
222
+ def end_session(self, session_id: str):
223
+ """End a session"""
224
+ session = self.sessions.get(session_id)
225
+ if session:
226
+ session.end_session()
export_utils.py CHANGED
@@ -136,3 +136,108 @@ def create_survey_package(survey_data: Dict) -> Dict[str, str]:
136
  package['csv'] = survey_to_csv(survey_data)
137
 
138
  return package
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  package['csv'] = survey_to_csv(survey_data)
137
 
138
  return package
139
+
140
+
141
+ def conversation_to_transcript(conversation_session) -> str:
142
+ """
143
+ Export conversation session as readable text transcript.
144
+
145
+ Args:
146
+ conversation_session: ConversationSession object
147
+
148
+ Returns:
149
+ Path to transcript file
150
+ """
151
+ transcript = conversation_session.get_transcript()
152
+
153
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
154
+ filename = f"conversation_transcript_{timestamp}.txt"
155
+
156
+ with open(filename, 'w', encoding='utf-8') as f:
157
+ f.write(transcript)
158
+
159
+ return filename
160
+
161
+
162
+ def conversation_to_json(conversation_session) -> str:
163
+ """
164
+ Export conversation session as JSON.
165
+
166
+ Args:
167
+ conversation_session: ConversationSession object
168
+
169
+ Returns:
170
+ Path to JSON file
171
+ """
172
+ return save_json_file(conversation_session.to_dict(), "conversation_session")
173
+
174
+
175
+ def conversation_to_csv(conversation_session) -> str:
176
+ """
177
+ Export conversation turns as CSV.
178
+
179
+ Args:
180
+ conversation_session: ConversationSession object
181
+
182
+ Returns:
183
+ Path to CSV file
184
+ """
185
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
186
+ filename = f"conversation_{timestamp}.csv"
187
+
188
+ with open(filename, 'w', newline='', encoding='utf-8') as f:
189
+ writer = csv.writer(f)
190
+
191
+ # Write header
192
+ writer.writerow(['Turn', 'Speaker', 'Timestamp', 'Content', 'Node ID', 'Summary'])
193
+
194
+ # Write turns
195
+ for i, turn in enumerate(conversation_session.conversation_history, 1):
196
+ speaker = "AI Moderator" if turn.role == "ai" else "Respondent"
197
+ writer.writerow([
198
+ i,
199
+ speaker,
200
+ turn.timestamp,
201
+ turn.content,
202
+ turn.node_id or '',
203
+ turn.summary or ''
204
+ ])
205
+
206
+ return filename
207
+
208
+
209
+ def flow_to_markdown(conversation_flow) -> str:
210
+ """
211
+ Export conversation flow as markdown document.
212
+
213
+ Args:
214
+ conversation_flow: ConversationFlow object
215
+
216
+ Returns:
217
+ Path to markdown file
218
+ """
219
+ lines = []
220
+ lines.append(f"# {conversation_flow.name}\n")
221
+ lines.append(f"**Description:** {conversation_flow.description}\n")
222
+ lines.append(f"**Created:** {conversation_flow.created_at}")
223
+ lines.append(f"**Updated:** {conversation_flow.updated_at}\n")
224
+ lines.append("\n## Conversation Flow\n")
225
+
226
+ for i, node in enumerate(conversation_flow.nodes, 1):
227
+ lines.append(f"### Step {i}: {node.type.capitalize()}\n")
228
+ lines.append(f"**Content:** {node.content}\n")
229
+ if node.next:
230
+ lines.append(f"**Next Node:** {node.next}\n")
231
+ if node.branches:
232
+ lines.append(f"**Branches:** {len(node.branches)}\n")
233
+ lines.append("")
234
+
235
+ content = "\n".join(lines)
236
+
237
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
238
+ filename = f"conversation_flow_{timestamp}.md"
239
+
240
+ with open(filename, 'w', encoding='utf-8') as f:
241
+ f.write(content)
242
+
243
+ return filename