Skip to content

Commit ade81d8

Browse files
authored
Merge pull request #4 from mathrailsAI/feature/export-results
Add comprehensive export functionality with CSV, Excel, and JSON support
2 parents 5be5999 + 1efc53e commit ade81d8

17 files changed

+2349
-10
lines changed

EXPORT_USAGE.md

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
# SentimentInsights Export Feature Guide
2+
3+
The SentimentInsights gem now includes comprehensive export functionality for all analysis results. Export your sentiment analysis, entity extraction, and key phrase results to CSV and Excel formats with advanced filtering and customization options.
4+
5+
## 🚀 Quick Start
6+
7+
```ruby
8+
# Run your analysis as usual
9+
result = SentimentInsights::Insights::Sentiment.new.analyze(entries)
10+
11+
# Export to CSV (simplest usage)
12+
result.to_csv("my_analysis.csv")
13+
14+
# Export to Excel
15+
result.to_excel("my_analysis.xlsx")
16+
17+
# Auto-detect format from filename
18+
result.export("my_analysis.csv") # Creates CSV
19+
result.export("my_analysis.xlsx") # Creates Excel
20+
```
21+
22+
## 📊 CSV Export Structure
23+
24+
### Sentiment Analysis CSV
25+
```csv
26+
response_id,text,sentiment_label,sentiment_score,segment_age_group,segment_region,timestamp
27+
r_1,"I love this product!",positive,0.9,18-25,North,2024-06-28T10:30:00Z
28+
r_2,"Service was terrible",negative,-0.8,26-35,South,2024-06-28T10:31:00Z
29+
30+
SUMMARY STATISTICS
31+
Total Responses,150
32+
Positive Count,90
33+
Positive Percentage,60.0%
34+
Net Sentiment Score,40.0
35+
36+
SEGMENT ANALYSIS
37+
Segment Type,Segment Value,Total Count,Positive %,Neutral %,Negative %,Net Score
38+
Age Group,18-25,75,65.3%,18.7%,16.0%,49.3
39+
Age Group,26-35,45,53.3%,22.2%,24.4%,28.9
40+
```
41+
42+
### Entity Extraction CSV
43+
```csv
44+
response_id,text,entities_found,segment_age_group,segment_region,timestamp
45+
r_1,"Apple released iPhone",apple:ORGANIZATION,iphone:PRODUCT,18-25,North,2024-06-28T10:30:00Z
46+
47+
SUMMARY STATISTICS
48+
Total Unique Entities,25
49+
Organizations Mentioned,8
50+
Most Mentioned Entity,apple (5 times)
51+
52+
ENTITY DETAILS
53+
Entity,Type,Total Mentions,Response IDs,Segment Distribution
54+
apple,ORGANIZATION,5,"r_1,r_3,r_7",age_group_18-25:3,age_group_26-35:2
55+
```
56+
57+
### Key Phrases CSV
58+
```csv
59+
response_id,text,sentiment,sentiment_score,key_phrases_found,segment_age_group,timestamp
60+
r_1,"Great customer service!",positive,0.8,"customer service,great experience",18-25,2024-06-28T10:30:00Z
61+
62+
PHRASE DETAILS
63+
Phrase,Total Mentions,Response IDs,Sentiment Distribution,Segment Distribution
64+
customer service,8,"r_1,r_4,r_7",positive:5,neutral:2,negative:1,age_group_18-25:4
65+
```
66+
67+
## 🎛️ Advanced Export Options
68+
69+
### Basic Configuration
70+
```ruby
71+
# Export with custom options
72+
result.to_csv("analysis.csv", {
73+
include_summary: true, # Include summary statistics
74+
include_segments: true, # Include segment analysis
75+
include_timestamp: true, # Add timestamp column
76+
timestamp_format: "%Y-%m-%d %H:%M:%S"
77+
})
78+
79+
# Skip summary and segments (responses only)
80+
result.to_csv("responses_only.csv", {
81+
include_summary: false,
82+
include_segments: false
83+
})
84+
```
85+
86+
### Dynamic Segment Handling
87+
The export system automatically detects and flattens all segment structures:
88+
89+
```ruby
90+
entries = [
91+
{
92+
answer: "Great product!",
93+
segment: {
94+
demographics: { age: "25-34", income: "high" },
95+
location: { country: "USA", state: "CA" },
96+
simple_field: "value"
97+
}
98+
}
99+
]
100+
101+
result = analyzer.analyze(entries)
102+
result.to_csv("complex_segments.csv")
103+
104+
# CSV headers will be:
105+
# response_id,text,sentiment_label,sentiment_score,
106+
# segment_demographics_age,segment_demographics_income,
107+
# segment_location_country,segment_location_state,
108+
# segment_simple_field,timestamp
109+
```
110+
111+
## 🔍 Filtering and Custom Exports
112+
113+
### Fluent Interface
114+
```ruby
115+
# Method chaining for custom exports
116+
result
117+
.responses_only # Skip summary sections
118+
.filter_sentiment(:positive) # Only positive responses
119+
.filter_segments(age_group: ["18-25", "26-35"]) # Specific age groups
120+
.to_csv("young_positive_feedback.csv")
121+
```
122+
123+
### Quick Filter Methods
124+
```ruby
125+
# Export only positive responses
126+
result.export_positive(:csv, "positive_feedback.csv")
127+
128+
# Export only negative responses
129+
result.export_negative(:excel, "issues_to_address.xlsx")
130+
131+
# Export specific segments
132+
result.export_by_segment(:age_group, ["18-25"], :csv, "young_users.csv")
133+
result.export_by_segment(:region, ["North", "South"], :excel, "regional_analysis.xlsx")
134+
```
135+
136+
### Advanced Filtering
137+
```ruby
138+
# Complex filter combinations
139+
result.exporter({
140+
filter: {
141+
sentiment: [:positive, :neutral], # Exclude negative
142+
segments: {
143+
age_group: ["18-25", "26-35"],
144+
region: ["North", "West"]
145+
}
146+
},
147+
include_summary: false
148+
}).to_csv("filtered_analysis.csv")
149+
```
150+
151+
## 📈 Excel Export Features
152+
153+
Excel exports include multiple worksheets:
154+
155+
1. **Responses** - Individual response data
156+
2. **Summary** - Statistical summaries
157+
3. **Segment Analysis** - Breakdown by segments
158+
4. **Entity Details** - Entity-specific analysis (entities only)
159+
5. **Phrase Details** - Phrase-specific analysis (key phrases only)
160+
161+
```ruby
162+
# Basic Excel export
163+
result.to_excel("comprehensive_report.xlsx")
164+
165+
# Excel with custom options
166+
result.to_excel("detailed_report.xlsx", {
167+
include_summary: true,
168+
include_segments: true
169+
})
170+
```
171+
172+
## 🚀 Batch Export
173+
174+
Export to multiple formats at once:
175+
176+
```ruby
177+
# Export to both CSV and Excel
178+
files = result.export_all("quarterly_analysis")
179+
# Returns: { csv: "quarterly_analysis.csv", excel: "quarterly_analysis.xlsx" }
180+
181+
files.each do |format, filename|
182+
puts "#{format.upcase} exported to: #{filename}"
183+
end
184+
```
185+
186+
## 🔧 Advanced Usage with Exporter Class
187+
188+
For maximum control, use the Exporter class directly:
189+
190+
```ruby
191+
exporter = result.exporter({
192+
include_summary: true,
193+
include_segments: true,
194+
filter: { sentiment: [:positive] }
195+
})
196+
197+
# Multiple export operations
198+
csv_file = exporter.to_csv("positive_analysis.csv")
199+
excel_file = exporter.to_excel("positive_analysis.xlsx")
200+
201+
# Specialized exports
202+
summary_only = exporter.to_csv_summary_only("summary.csv")
203+
responses_only = exporter.to_csv_responses_only("responses.csv")
204+
```
205+
206+
## 🎯 Use Cases
207+
208+
### Customer Feedback Analysis
209+
```ruby
210+
feedback = analyzer.analyze(customer_responses)
211+
212+
# Export all feedback
213+
feedback.export_all("customer_feedback_analysis")
214+
215+
# Export issues that need attention
216+
feedback.export_negative(:excel, "issues_to_resolve.xlsx")
217+
218+
# Export by customer segment
219+
feedback.export_by_segment(:customer_tier, ["premium", "enterprise"], :csv, "premium_feedback.csv")
220+
```
221+
222+
### Survey Response Processing
223+
```ruby
224+
survey_results = analyzer.analyze(survey_responses)
225+
226+
# Comprehensive report for stakeholders
227+
survey_results.to_excel("survey_report.xlsx", {
228+
include_summary: true,
229+
include_segments: true
230+
})
231+
232+
# Quick CSV for data team
233+
survey_results
234+
.responses_only
235+
.to_csv("raw_survey_data.csv")
236+
```
237+
238+
### Regional Analysis
239+
```ruby
240+
regional_analysis = analyzer.analyze(regional_data)
241+
242+
# Export by region
243+
%w[North South East West].each do |region|
244+
regional_analysis.export_by_segment(:region, region, :csv, "#{region.downcase}_analysis.csv")
245+
end
246+
```
247+
248+
## 📋 File Naming
249+
250+
Auto-generated filenames include timestamps:
251+
- `sentiment_analysis_20240628_103045.csv`
252+
- `entities_analysis_20240628_103045.xlsx`
253+
- `key_phrases_analysis_20240628_103045.csv`
254+
255+
## 🛠️ Installation Requirements
256+
257+
Add to your Gemfile:
258+
```ruby
259+
gem 'sentiment_insights', '~> 0.3.0'
260+
gem 'rubyXL', '~> 3.4' # For Excel export support
261+
```
262+
263+
## 🔍 Error Handling
264+
265+
```ruby
266+
begin
267+
result.to_excel("report.xlsx")
268+
rescue => e
269+
puts "Excel export failed: #{e.message}"
270+
# Fallback to CSV
271+
result.to_csv("report.csv")
272+
end
273+
```
274+
275+
## 🎉 Integration Examples
276+
277+
### Rails Controller
278+
```ruby
279+
class AnalyticsController < ApplicationController
280+
def export_feedback
281+
entries = FeedbackResponse.includes(:customer).map do |response|
282+
{
283+
answer: response.comment,
284+
segment: {
285+
customer_tier: response.customer.tier,
286+
region: response.customer.region,
287+
product: response.product_name
288+
}
289+
}
290+
end
291+
292+
result = SentimentInsights::Insights::Sentiment.new.analyze(entries)
293+
294+
filename = result.to_excel("feedback_analysis_#{Date.current}.xlsx")
295+
296+
send_file filename,
297+
filename: "customer_feedback_analysis.xlsx",
298+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
299+
end
300+
end
301+
```
302+
303+
### Background Job
304+
```ruby
305+
class AnalysisExportJob < ApplicationJob
306+
def perform(survey_id, email)
307+
survey = Survey.find(survey_id)
308+
entries = survey.responses.map { |r| { answer: r.text, segment: r.metadata } }
309+
310+
result = SentimentInsights::Insights::Sentiment.new.analyze(entries)
311+
files = result.export_all("survey_#{survey_id}_analysis")
312+
313+
AnalysisMailer.send_results(email, files).deliver_now
314+
end
315+
end
316+
```
317+
318+
## 🚀 Performance Tips
319+
320+
1. **Use filtering** to reduce export size for large datasets
321+
2. **Skip unnecessary sections** with `responses_only` for faster exports
322+
3. **Batch processing** - split large datasets before analysis
323+
4. **Background jobs** for large exports in web applications
324+
325+
The export system is designed to handle dynamic segment structures, large datasets, and provides maximum flexibility for different use cases while maintaining excellent performance.

Gemfile.lock

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PATH
22
remote: .
33
specs:
4-
sentiment_insights (0.2.0)
4+
sentiment_insights (0.4.0)
55
aws-sdk-comprehend (>= 1.98.0)
6+
rubyXL (~> 3.4)
67
sentimental (~> 1.4.0)
78

89
GEM
@@ -27,6 +28,9 @@ GEM
2728
dotenv (2.8.1)
2829
jmespath (1.6.2)
2930
logger (1.7.0)
31+
nokogiri (1.15.7-arm64-darwin)
32+
racc (~> 1.4)
33+
racc (1.8.1)
3034
rake (13.2.1)
3135
rspec (3.13.0)
3236
rspec-core (~> 3.13.0)
@@ -41,6 +45,10 @@ GEM
4145
diff-lcs (>= 1.2.0, < 2.0)
4246
rspec-support (~> 3.13.0)
4347
rspec-support (3.13.2)
48+
rubyXL (3.4.33)
49+
nokogiri (>= 1.10.8)
50+
rubyzip (>= 1.3.0)
51+
rubyzip (2.4.1)
4452
sentimental (1.4.1)
4553

4654
PLATFORMS

0 commit comments

Comments
 (0)