sentiment_insights 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/EXPORT_USAGE.md +325 -0
- data/Gemfile.lock +9 -1
- data/README.md +83 -1
- data/lib/sentiment_insights/export/base_exporter.rb +308 -0
- data/lib/sentiment_insights/export/csv_exporter.rb +261 -0
- data/lib/sentiment_insights/export/excel_exporter.rb +334 -0
- data/lib/sentiment_insights/export/exportable.rb +152 -0
- data/lib/sentiment_insights/export/exporter.rb +169 -0
- data/lib/sentiment_insights/export/json_exporter.rb +183 -0
- data/lib/sentiment_insights/insights/entities.rb +4 -2
- data/lib/sentiment_insights/insights/key_phrases.rb +3 -2
- data/lib/sentiment_insights/insights/sentiment.rb +4 -3
- data/lib/sentiment_insights/version.rb +1 -1
- data/lib/sentiment_insights.rb +1 -0
- data/sentiment_insights.gemspec +3 -0
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74729added1e999a0e6277b89a95fb2ee934103f18df50b8187f6a86d04c833b
|
4
|
+
data.tar.gz: 3be0d99ae0ecc2148110d64bf7030d988e9a03810774d338e1c1ac58d735ed48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 563aecf46e7af1300bb84854f8af8c30eeaa874bf73eb49f18c44c5b2af075084b4fe8eaaf1503b43dad87e48225601f358c99caf658abdad5fd30423d799e22
|
7
|
+
data.tar.gz: 5f017d18b1a447e22399d161f493e3f01784eb917790b846548c0d63aef13f0b8df58101e197c0625c4dbfc209e34e5072a533f41026238468ad6e9fa1bb90ad
|
data/EXPORT_USAGE.md
ADDED
@@ -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.
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sentiment_insights (0.
|
4
|
+
sentiment_insights (0.4.0)
|
5
5
|
aws-sdk-comprehend (>= 1.98.0)
|
6
|
+
rubyXL (~> 3.4)
|
6
7
|
sentimental (~> 1.4.0)
|
7
8
|
|
8
9
|
GEM
|
@@ -27,6 +28,9 @@ GEM
|
|
27
28
|
dotenv (2.8.1)
|
28
29
|
jmespath (1.6.2)
|
29
30
|
logger (1.7.0)
|
31
|
+
nokogiri (1.15.7-arm64-darwin)
|
32
|
+
racc (~> 1.4)
|
33
|
+
racc (1.8.1)
|
30
34
|
rake (13.2.1)
|
31
35
|
rspec (3.13.0)
|
32
36
|
rspec-core (~> 3.13.0)
|
@@ -41,6 +45,10 @@ GEM
|
|
41
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
42
46
|
rspec-support (~> 3.13.0)
|
43
47
|
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)
|
44
52
|
sentimental (1.4.1)
|
45
53
|
|
46
54
|
PLATFORMS
|
data/README.md
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
- [Sentiment Analysis](#sentiment-analysis)
|
13
13
|
- [Key Phrase Extraction](#key-phrase-extraction)
|
14
14
|
- [Entity Extraction](#entity-extraction)
|
15
|
+
- [Export & Output Formats](#export--output-formats)
|
15
16
|
- [Provider Options & Custom Prompts](#provider-options--custom-prompts)
|
16
17
|
- [Full Example](#full-example)
|
17
18
|
- [Contributing](#contributing)
|
@@ -313,6 +314,87 @@ result = insight.extract(
|
|
313
314
|
"the response was copy-paste and didn't address my issue directly.",
|
314
315
|
:segment=>{:age=>"45-54", :region=>"Midwest"}}]}
|
315
316
|
```
|
317
|
+
|
318
|
+
---
|
319
|
+
|
320
|
+
## Export & Output Formats
|
321
|
+
|
322
|
+
SentimentInsights provides flexible export options for all analysis results. Export to CSV, Excel, or JSON formats with advanced filtering and customization.
|
323
|
+
|
324
|
+
### Quick Export Examples
|
325
|
+
|
326
|
+
```ruby
|
327
|
+
result = SentimentInsights::Insights::Sentiment.new.analyze(entries)
|
328
|
+
|
329
|
+
# Direct format methods
|
330
|
+
result.to_csv("analysis.csv") # CSV file
|
331
|
+
result.to_json("analysis.json") # JSON file
|
332
|
+
result.to_excel("analysis.xlsx") # Excel file
|
333
|
+
|
334
|
+
# Auto-detect format from filename
|
335
|
+
result.export("analysis.csv") # Creates CSV
|
336
|
+
result.export("analysis.json") # Creates JSON
|
337
|
+
result.export("analysis.xlsx") # Creates Excel
|
338
|
+
|
339
|
+
# API-friendly formats (no files)
|
340
|
+
api_data = result.to_hash # Structured Hash
|
341
|
+
json_string = result.to_json_string # JSON string
|
342
|
+
```
|
343
|
+
|
344
|
+
### Advanced Export Options
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
# Filtered exports
|
348
|
+
result.export_positive(:csv, "positive_feedback.csv")
|
349
|
+
result.export_negative(:excel, "issues_to_address.xlsx")
|
350
|
+
|
351
|
+
# Fluent interface with filtering
|
352
|
+
result
|
353
|
+
.filter_sentiment(:positive)
|
354
|
+
.filter_segments(age_group: ["18-25", "26-35"])
|
355
|
+
.to_excel("young_positive_feedback.xlsx")
|
356
|
+
|
357
|
+
# Export all formats at once
|
358
|
+
files = result.export_all("comprehensive_analysis")
|
359
|
+
# Returns: { csv: "file.csv", json: "file.json", excel: "file.xlsx" }
|
360
|
+
```
|
361
|
+
|
362
|
+
### CSV Export Structure
|
363
|
+
|
364
|
+
```csv
|
365
|
+
response_id,text,sentiment_label,sentiment_score,segment_age_group,segment_region,timestamp
|
366
|
+
r_1,"I love this product!",positive,0.9,18-25,North,2024-06-28T10:30:00Z
|
367
|
+
|
368
|
+
SUMMARY STATISTICS
|
369
|
+
Total Responses,150
|
370
|
+
Positive Percentage,60.0%
|
371
|
+
Net Sentiment Score,40.0
|
372
|
+
|
373
|
+
SEGMENT ANALYSIS
|
374
|
+
Segment Type,Segment Value,Total Count,Positive %,Net Score
|
375
|
+
Age Group,18-25,75,65.3%,49.3
|
376
|
+
```
|
377
|
+
|
378
|
+
### JSON Export Structure
|
379
|
+
|
380
|
+
```json
|
381
|
+
{
|
382
|
+
"metadata": {
|
383
|
+
"export_timestamp": "2024-06-28T10:30:00Z",
|
384
|
+
"analysis_type": "sentiment",
|
385
|
+
"total_responses": 150,
|
386
|
+
"provider_used": "claude"
|
387
|
+
},
|
388
|
+
"analysis": {
|
389
|
+
"responses": [...],
|
390
|
+
"global_summary": {...},
|
391
|
+
"segment_summary": {...}
|
392
|
+
}
|
393
|
+
}
|
394
|
+
```
|
395
|
+
|
396
|
+
**📋 For complete export documentation, see [EXPORT_USAGE.md](EXPORT_USAGE.md)**
|
397
|
+
|
316
398
|
---
|
317
399
|
|
318
400
|
## Provider Options & Custom Prompts
|
@@ -365,8 +447,8 @@ bundle exec rspec
|
|
365
447
|
- [x] Sentiment Analysis
|
366
448
|
- [x] Key Phrase Extraction
|
367
449
|
- [x] Entity Recognition
|
450
|
+
- [x] Export Functionality (CSV, Excel, JSON)
|
368
451
|
- [ ] Topic Modeling
|
369
|
-
- [ ] CSV/JSON Export Helpers
|
370
452
|
- [ ] Visual Dashboard Add-on
|
371
453
|
|
372
454
|
---
|