nsthorat commited on
Commit
2226ee3
1 Parent(s): aa08fef
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .env +1 -1
  2. .gitattributes +0 -7
  3. data/concept/lilac/legal-termination/concept.json +0 -184
  4. data/concept/lilac/legal-termination/sbert.pkl +0 -0
  5. data/concept/lilac/negative-sentiment/concept.json +0 -634
  6. data/concept/lilac/negative-sentiment/sbert.pkl +0 -0
  7. data/concept/lilac/positive-sentiment/concept.json +0 -564
  8. data/concept/lilac/positive-sentiment/sbert.pkl +0 -0
  9. data/concept/lilac/profanity/concept.json +0 -0
  10. data/concept/lilac/profanity/openai.pkl +0 -3
  11. data/concept/lilac/profanity/sbert.pkl +0 -0
  12. data/concept/lilac/toxicity/concept.json +0 -0
  13. data/concept/lilac/toxicity/sbert.pkl +0 -0
  14. data/datasets/local/spotify/data-00000-of-00001.parquet +0 -3
  15. data/datasets/local/spotify/manifest.json +0 -27
  16. data/datasets/local/spotify/settings.json +0 -1
  17. data/datasets/local/spotify/text/.concepts/local/aliens/sbert-neg-100.pkl +0 -0
  18. data/datasets/local/spotify/text/lang_detection/data-00000-of-00001.parquet +0 -3
  19. data/datasets/local/spotify/text/lang_detection/signal_manifest.json +0 -36
  20. data/datasets/local/spotify/text/sbert/data-00000-of-00001.parquet +0 -3
  21. data/datasets/local/spotify/text/sbert/embedding/local/outerspace/v34/data-00000-of-00001.parquet +0 -3
  22. data/datasets/local/spotify/text/sbert/embedding/local/outerspace/v34/signal_manifest.json +0 -64
  23. data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.keys.pkl +0 -3
  24. data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.npy +0 -3
  25. data/datasets/local/spotify/text/sbert/signal_manifest.json +0 -37
  26. lilac/__init__.py +29 -1
  27. lilac/auth.py +1 -1
  28. lilac/cli.py +37 -0
  29. lilac/concepts/concept.py +12 -12
  30. lilac/concepts/db_concept.py +2 -1
  31. lilac/config.py +6 -14
  32. lilac/data/__init__.py +8 -0
  33. lilac/data/dataset.py +56 -14
  34. lilac/data/dataset_duckdb.py +55 -23
  35. lilac/data/dataset_utils.py +10 -11
  36. lilac/data/sources/__init__.py +0 -0
  37. lilac/data_loader.py +33 -34
  38. lilac/embeddings/embedding.py +2 -1
  39. lilac/embeddings/openai.py +3 -3
  40. lilac/embeddings/palm.py +3 -3
  41. lilac/embeddings/sbert.py +1 -1
  42. lilac/embeddings/vector_store_numpy.py +3 -2
  43. lilac/router_concept.py +2 -2
  44. lilac/router_data_loader.py +1 -4
  45. lilac/router_dataset.py +14 -19
  46. lilac/schema.py +9 -7
  47. lilac/server.py +27 -5
  48. lilac/signals/__init__.py +15 -0
  49. lilac/signals/concept_scorer.py +0 -2
  50. lilac/signals/lang_detection.py +15 -11
.env CHANGED
@@ -12,7 +12,7 @@ DUCKDB_USE_VIEWS=0
12
 
13
  # Variables that can be set in .env.local
14
  #
15
- # Get key from https://www.cohere.ai/api-keys
16
  # COHERE_API_KEY=
17
 
18
  # GCS_REGION=
 
12
 
13
  # Variables that can be set in .env.local
14
  #
15
+ # Get key from https://dashboard.cohere.ai/api-keys
16
  # COHERE_API_KEY=
17
 
18
  # GCS_REGION=
.gitattributes DELETED
@@ -1,7 +0,0 @@
1
- data/datasets/local/spotify/data-00000-of-00001.parquet filter=lfs diff=lfs merge=lfs -text
2
- data/datasets/local/spotify/text/lang_detection/data-00000-of-00001.parquet filter=lfs diff=lfs merge=lfs -text
3
- data/datasets/local/spotify/text/sbert/data-00000-of-00001.parquet filter=lfs diff=lfs merge=lfs -text
4
- data/datasets/local/spotify/text/sbert/embedding/local/outerspace/v34/data-00000-of-00001.parquet filter=lfs diff=lfs merge=lfs -text
5
- data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.keys.pkl filter=lfs diff=lfs merge=lfs -text
6
- data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.npy filter=lfs diff=lfs merge=lfs -text
7
- data/concept/lilac/profanity/openai.pkl filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
data/concept/lilac/legal-termination/concept.json DELETED
@@ -1,184 +0,0 @@
1
- {
2
- "namespace": "lilac",
3
- "concept_name": "legal-termination",
4
- "type": "text",
5
- "data": {
6
- "731b1338cf1949958c3526c555f88058": {
7
- "label": true,
8
- "text": "In the event that any provision of this agreement is found to be unenforceable, the remaining provisions shall continue to be valid and binding.",
9
- "id": "731b1338cf1949958c3526c555f88058"
10
- },
11
- "99a20e547e38474dbc24507a1658d0c9": {
12
- "label": true,
13
- "text": "The parties agree that in the event of a natural disaster or other unforeseen event, both parties will make reasonable efforts to fulfill their obligations under this contract.",
14
- "id": "99a20e547e38474dbc24507a1658d0c9"
15
- },
16
- "3f27b47c526a4c5896a0a100024535c7": {
17
- "label": true,
18
- "text": "If any party breaches the terms of this agreement, the non-breaching party shall have the right to seek legal remedies.",
19
- "id": "3f27b47c526a4c5896a0a100024535c7"
20
- },
21
- "d403dbb1ab9c4594bc7f7dcb0ad5b333": {
22
- "label": true,
23
- "text": "This lease agreement shall survive the termination or expiration of the lease term, and continue to be binding upon the parties.",
24
- "id": "d403dbb1ab9c4594bc7f7dcb0ad5b333"
25
- },
26
- "b7deba9f7e80444abe14448f53f45c43": {
27
- "label": true,
28
- "text": "In the event of a dispute arising from this contract, the parties agree to first attempt to resolve the dispute through mediation before pursuing any legal action.",
29
- "id": "b7deba9f7e80444abe14448f53f45c43"
30
- },
31
- "a82231b490174e62aad733cb0c75024d": {
32
- "label": true,
33
- "text": "This Agreement may be terminated, and the transactions contemplated hereby may be abandoned, at any time prior to the Effective Time, whether prior to or after the Company Stockholders' Approval:",
34
- "id": "a82231b490174e62aad733cb0c75024d"
35
- },
36
- "160b25dbf14e4759a0065bbd652ce33f": {
37
- "label": true,
38
- "text": "This Agreement may be terminated and abandoned at any time prior to the Effective Time of the Merger, whether before or after the Company Stockholder Approval:",
39
- "id": "160b25dbf14e4759a0065bbd652ce33f"
40
- },
41
- "8f5f9f96b16441228bb0c9b8a14c4e25": {
42
- "label": false,
43
- "text": "any jurisdiction, then such provision shall, as to such jurisdiction, be modified or restricted to the extent necessary to make such provision valid, binding and enforceable, or if such provision cannot be so modified or restricted, then such provision shall, as to such jurisdiction, be deemed to be excised from this Agreement; provided, however, that the legality, binding effect and",
44
- "id": "8f5f9f96b16441228bb0c9b8a14c4e25"
45
- },
46
- "87b6c31b04a346b4a3e0da8d2cc5a7ac": {
47
- "label": true,
48
- "text": "This Agreement shall terminate automatically without any further action by any party hereto upon the earliest to occur of (a) the Effective Time of the Merger, (b) the termination of the Merger Agreement in accordance with its terms and (c) any amendment or other modification of the Merger Agreement that reduces the amount of the Merger Consideration or provides that the Merger Consideration shall",
49
- "id": "87b6c31b04a346b4a3e0da8d2cc5a7ac"
50
- },
51
- "985344f7ecfb41f4a69ba101973221a1": {
52
- "label": false,
53
- "text": " During the Employment Period, the Corporation shall pay ----------- the Executive a base salary which, as of the commencement of the Employment Period, shall be at an annual rate of Two Hundred Fifty Thousand Dollars ($250,000). The base salary shall be payable in equal periodic installments which are not less frequent than the periodic installments in effect for salaries of other senior",
54
- "id": "985344f7ecfb41f4a69ba101973221a1"
55
- },
56
- "5d53ff48376046fdab41e95c7f4bad54": {
57
- "label": true,
58
- "text": "This Agreement may be terminated at any time prior to the Closing Date solely:",
59
- "id": "5d53ff48376046fdab41e95c7f4bad54"
60
- },
61
- "bdeb785be2154b21b4eb052466fa9bcb": {
62
- "label": true,
63
- "text": "(a) This Agreement may be terminated by you by notice to the Company at any time prior to the Closing Date if any of the following has occurred: (i) since the respective dates as of which information is given in the Registration Statement and the Prospectus, any material adverse change or any development involving a prospective material adverse change in or affecting the earnings, busi ness,",
64
- "id": "bdeb785be2154b21b4eb052466fa9bcb"
65
- },
66
- "fe6871e9070441f8a9e4b3db26b077d7": {
67
- "label": true,
68
- "text": "Section 3(b), this Section 7 and Section 8 of this Agreement shall survive a termination of this Agreement pursuant to (a) or (b) above in this Section 7 until the date that is two years following the date of such termination. Notwithstanding anything else to the contrary contained herein or in the Merger Agreement, if the Effective Time occurs, the representations and warranties contained in",
69
- "id": "fe6871e9070441f8a9e4b3db26b077d7"
70
- },
71
- "bf1a51751d0748e58c344aec8e5fc789": {
72
- "label": false,
73
- "text": "This Agreement may be executed in one or more counterparts (including counterparts executed and delivered by facsimile, which shall be as counterparts executed and delivered manually), all of which shall be considered one and the same agreement and shall become effective when one or more counterparts have been signed by each of the parties and delivered to the other party, it being understood that",
74
- "id": "bf1a51751d0748e58c344aec8e5fc789"
75
- },
76
- "bc1b2affa6d848fd92d4dee033e30659": {
77
- "label": false,
78
- "text": "would, in your judgment, make it impracticable or inadvisable to market the Units or to enforce contracts for the sale of the Units, (iii) suspension of trading in securities generally on the New York Stock Exchange, the American Stock Exchange or the Nasdaq National Market or limitation on prices (other than limitations on hours or numbers of days of trading) for securities on any such Exchange,",
79
- "id": "bc1b2affa6d848fd92d4dee033e30659"
80
- },
81
- "67a73d5887f74a91bed190ca8f64b17c": {
82
- "label": false,
83
- "text": " The authorized capital stock of FM consists of 1,000 shares of Common Stock, no par value each, of which 1,000 shares are issued and outstanding. There are no outstanding or authorized options, warrants, calls, subscriptions, rights (including any preemptive rights or rights of first refusal), agreements or commitments of any character obligating FM to issue any stock or any other Equity",
84
- "id": "67a73d5887f74a91bed190ca8f64b17c"
85
- },
86
- "025b2ca5147849c8a921d9aaa31cd9cd": {
87
- "label": false,
88
- "text": "Taxes that are being contested in good faith by appropriate proceedings, provided that Holdings, the Borrower or Restricted Subsidiary, as the case may be, has set aside on its books adequate reserves therefor in accordance with GAAP.",
89
- "id": "025b2ca5147849c8a921d9aaa31cd9cd"
90
- },
91
- "76acff27f13743f4822a094c707d8b75": {
92
- "label": false,
93
- "text": "have been a suspension or material limitation in trading in the Company\u2019s common stock on the New York Stock Exchange; (iii) there shall have been a general moratorium on commercial banking activities declared by either federal or New York state authorities or a material disruption in commercial banking or securities settlement or clearance services in the United States; (iv) there shall have been",
94
- "id": "76acff27f13743f4822a094c707d8b75"
95
- },
96
- "b11a95c0eb564445b1a473e90622f861": {
97
- "label": true,
98
- "text": "10.1. This Agreement will terminate:",
99
- "id": "b11a95c0eb564445b1a473e90622f861"
100
- },
101
- "d536428a02084d94ba18d412851cb913": {
102
- "label": false,
103
- "text": "may not be limited to his Base Salary and that the Employee may receive an annual bonus in the amount, if any, determined annually by the Employer. The Employee shall also participate in employee compensation and benefit plans available generally to executives of the Employer (including, without limitation, any tax-qualified profit sharing plan, nonqualified profit sharing plan, life insurance",
104
- "id": "d536428a02084d94ba18d412851cb913"
105
- },
106
- "368bb1d9c7d0419d9ca58f28565eeb2e": {
107
- "label": true,
108
- "text": "This Agreement may be terminated in the absolute discretion of the Representatives, by notice to the Bank, if after execution and delivery of this Agreement and prior to the Closing Date (i) there has been, since the date of this Agreement or since the respective dates as of which information is given in the Registration Statement, the Time of Sale Information or the Prospectus, any material",
109
- "id": "368bb1d9c7d0419d9ca58f28565eeb2e"
110
- },
111
- "1b5fd7b037a84404bf85c858953c79e8": {
112
- "label": true,
113
- "text": "however, (i) the right to terminate this Agreement under this Section 8 shall not be available to such Buyer if the failure of the transactions contemplated by this Agreement to have been consummated by such date is the result of such Buyer\u2019s breach of this Agreement and (ii) the abandonment of the sale and purchase of the Notes and the Warrants shall be applicable only to such Buyer providing",
114
- "id": "1b5fd7b037a84404bf85c858953c79e8"
115
- },
116
- "6d5a23d2663f457cab96df03d9dc8ab7": {
117
- "label": true,
118
- "text": "In addition, any Stockholder may terminate this Agreement if Weatherford, WEUS, or the Company breaches any representation, warranty, covenant or other agreement contained in the Merger Agreement that (A) would give rise to the failure of Weatherford, WEUS, or the Company to satisfy any condition set forth in Section 8.2(a) thereof, and (B) cannot be or has not been cured within 45 days after the",
119
- "id": "6d5a23d2663f457cab96df03d9dc8ab7"
120
- },
121
- "4a8223a48f83491b9b3eafd7ad37baf9": {
122
- "label": true,
123
- "text": "The obligations of the Underwriters hereunder may be terminated by the Representatives, in their absolute discretion, by notice given to and received by the Depositor or the Bank prior to delivery of and payment for the Notes if, prior to that time, any of the events described in Section 5(v) shall have occurred or any of the other conditions described in Section 5 shall not be satisfied.",
124
- "id": "4a8223a48f83491b9b3eafd7ad37baf9"
125
- },
126
- "fbb152eae00c440bb2d0df0fbd82c262": {
127
- "label": true,
128
- "text": "Either of the parties hereto may terminate this Agreement by giving to the other party a notice in writing specifying the date of such termination, which shall be not less than 60 days after the date of receipt of such notice. In the event such notice is given by the Customer, it shall be accompanied by a copy of a resolution of the Board of Directors of the Customer, certified by its Secretary,",
129
- "id": "fbb152eae00c440bb2d0df0fbd82c262"
130
- },
131
- "1d21880f426c45ada31409d22815cc87": {
132
- "label": false,
133
- "text": "Prospectus or the Final Prospectus (exclusive of any amendment or supplement thereof or thereto after the date hereof).",
134
- "id": "1d21880f426c45ada31409d22815cc87"
135
- },
136
- "795cac72a3504740bc7401a84fc6fba4": {
137
- "label": true,
138
- "text": "This Agreement may be terminated by the Customer or the Bank by giving ninety (90) days written notice to the other, provided that such notice to the Bank shall specify the names of the persons to whom the Bank shall deliver the Assets in the Accounts. If notice of termination is given by the Bank, the Customer shall, within ninety (90) days following receipt of the notice, deliver to the Bank Instructions specifying the names of the persons to whom the Bank shall deliver the Assets.",
139
- "id": "795cac72a3504740bc7401a84fc6fba4"
140
- },
141
- "3b82e6eba4894ac0b9f7f12aba2aab2e": {
142
- "label": false,
143
- "text": "of this Agreement, or to Authorized Persons, or may continue to hold the Assets until Instructions are provided to the Bank.",
144
- "id": "3b82e6eba4894ac0b9f7f12aba2aab2e"
145
- },
146
- "da16bd0e9dce4d4c87400eab61b9b14c": {
147
- "label": false,
148
- "text": "into force of the Convention. In such event, the Convention shall cease to have effect:",
149
- "id": "da16bd0e9dce4d4c87400eab61b9b14c"
150
- },
151
- "02cc328109984db094b0b02caec0d575": {
152
- "label": true,
153
- "text": "Survival. The rights and obligations contained in Sections 3 (\u201cOwnership of Work Product\u201d), 4 (\u201cOther Rights\u201d), 5 (\u201cLicense to Preexisting IP\u201d), 6 (\u201cRepresentations and Warranties\u201d), 8 (\u201cConfidential Information\u201d) and 12 (\u201cNon-solicitation\u201d) will survive any termination or expiration of this Agreement. ",
154
- "id": "02cc328109984db094b0b02caec0d575"
155
- },
156
- "f8edf65d9acf4ff4a04459a3492ac426": {
157
- "label": false,
158
- "text": "Severability. Should any provisions of this Agreement be held by a court of law to be illegal, invalid or unenforceable, the legality, validity and enforceability of the remaining provisions of this Agreement will not be affected or impaired thereby. ",
159
- "id": "f8edf65d9acf4ff4a04459a3492ac426"
160
- },
161
- "5a8517f359494ead8c11b6aff440480d": {
162
- "label": false,
163
- "text": "\u0095\tCommitted to deliver the best, we leave no room for customer grievances.\r\n\r\n",
164
- "id": "5a8517f359494ead8c11b6aff440480d"
165
- },
166
- "a47d327d0f6e46fc861f86b2e0e54a2f": {
167
- "label": false,
168
- "text": "the due diligence and using our agreement creator to close the deal successfully. \r",
169
- "id": "a47d327d0f6e46fc861f86b2e0e54a2f"
170
- },
171
- "811d0dcc92e14c5c881e903c7d4ff7b6": {
172
- "label": false,
173
- "text": "in accordance with customary procedures in the relevant markets, but in any event for a settlement period no longer than three months following the date of such commitment.",
174
- "id": "811d0dcc92e14c5c881e903c7d4ff7b6"
175
- },
176
- "907f92e0d5704418944a559a4bfb96c7": {
177
- "label": false,
178
- "text": "terminate in accordance with Section 2 of the Investors\u2019 Rights Agreement.",
179
- "id": "907f92e0d5704418944a559a4bfb96c7"
180
- }
181
- },
182
- "version": 33,
183
- "description": "Termination or survival clause in a legal document"
184
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/concept/lilac/legal-termination/sbert.pkl DELETED
Binary file (33.8 kB)
 
data/concept/lilac/negative-sentiment/concept.json DELETED
@@ -1,634 +0,0 @@
1
- {
2
- "namespace": "lilac",
3
- "concept_name": "negative-sentiment",
4
- "type": "text",
5
- "data": {
6
- "0": {
7
- "label": true,
8
- "text": "Starting To Be Annoyed By Becky...: I'm not sure why I keep reading these books, but I guess it's because I've read the first two so I'll keep reading the rest of the books. In the first book, I really found it amusing. I was a little annoyed by the fact that Becky couldn't stop spending, but then again that's why she is called a Shopaholic. In the second book, I felt more of the same it was just magniifed more. Now in the third book, I'm just down right annoyed by Becky Bloomwood. In this book, she wasn't going on crazy shopping sprees, just planning two different weddings because she was afraid to tell each person and because I feel she's really selfish. Still, I read the book because I wanted to see how she could get herself out of another situation. I will say that I love her friends Suze and Danny, her client Laurel and her husband Luke. Maybe that's why I keep reading. I will read the next book, but I'm sure I'll be just as annoyed when I'm done.",
9
- "id": "0"
10
- },
11
- "1": {
12
- "label": true,
13
- "text": "the cover is fine - the pool is horrible: The entire pool was horrible. The cover was fine once we got it on, but we finally got rid of the pool after 2 weeks because it was so hard to set up and keep clean.",
14
- "id": "1"
15
- },
16
- "2": {
17
- "label": false,
18
- "text": "Good album, not their best.: This album is probably the most marketable and radio friendly of all of dashboard's albums. For the peripheral listener it may be the right one to get to introduce you to this band. But as a Dashboard fan of 5 or so years I truly hope they return to their original sound for their next work. Not for the listen-ability but for the show. To this day the fans react best to the songs from \"Places\" or \"A Mark, A Mission.\" I recommend this album to everyone but I also recommend any and all of their other work.",
19
- "id": "2"
20
- },
21
- "3": {
22
- "label": true,
23
- "text": "This is a horror novel, right?: Never one to pass up any vampire novel, I purchased Sips because the description seemed interesting. Vampires, Marquis de Sade, fetishism, yada yada yada. If this is a comedy, I give it 4 stars; however, I'll give it 1 star as a horror novel. Sade was rather boring; I would think a character as intense and multi-faceted as the Marquis de Sade would make for a more interesting vampire. The writing style isn't too bad, but overall I found the characters to be mildly amusing at best. The plot was thin, the end was anti-climactic, and the vampires were not very frightening. The book had little suspense, and it leaves a mile-wide opening for a sequel at the conclusion. I would, however, like to see something more of the vampire mutants lurking in the graveyard. They were the most riveting of any of the characters.",
24
- "id": "3"
25
- },
26
- "4": {
27
- "label": false,
28
- "text": "Superb mix of global non secular musical denominations: I first heard Ms. Pook's music on the \"Eyes Wide Shut\" soundtrack (the masquerade ball scene) and was blown away; if ever there was a necessity for music to permeate a scene in a film this was it. She incorporates a blend of the traditional songs from faiths across continents and mixes them, for lack of a better comparison than similar to your quintessential raver d.j. (though these are better and definitively more original :) \"Oppenheimer\" is my favorite, and if you let the last track run for a few minutes a portion of the song will play once more. I can't wait to hear more of her stuff - these hymns are awesome.",
29
- "id": "4"
30
- },
31
- "5": {
32
- "label": false,
33
- "text": "A moving and suspenseful story!: For anyone familiar with the occult, this book is likely to raise hairs on the back of your neck as you read. Even if you're not, the storyline is suspenseful and fascinating, and the characters evoke great sympathy and admiration. An excellent read.",
34
- "id": "5"
35
- },
36
- "6": {
37
- "label": false,
38
- "text": "Simple & Easy to Use - A Practical approach to eating out: This guide is extremely to use. It provides sample menus that you'd see at Chinese, Indian and Thai restaurants. Then you are provided with descriptions of each dish and how it is prepared and the ingredients used. From there you are provided with specific considerations as to how the preparation or ingredient list may affect you if you have Gluten or Allergen issues.This book is the size of a passport and very organized and well written. The Chinese, Indian and Thai Cuisine Passport is perfect for making choices while traveling, or while dining at your favorite local restaurant.",
39
- "id": "6"
40
- },
41
- "7": {
42
- "label": true,
43
- "text": "Being Fair....I am a fan of hers: and I really enjoyed her previous works, more than I could have ever imagined, but this record is horrible. The songs are trite, the lyrics are incredibly boring, indulgent and immature. The music is pop staple, with forgetable melodies and repetative chorus lines, I feel as if the studio wrote the entire album for her while she was sleeping, this just doesn't speak to any of her previous works at all. This album fits on the same shelf with a Nickelodeon-themed CD. Instead of heading in the direction of an artist like Alanis Morrisette, she is going backward and joining the ranks of Hannah Montana and the Naked Brothers Band. She is a great artist and her first two records are amazing. She is better than this CD and I am looking forward to her next effort.",
44
- "id": "7"
45
- },
46
- "8": {
47
- "label": true,
48
- "text": "Sucked: I thought the DVD sucked tremendously. It was very boring and if I could, I would return it for a refund. There was only one \"small\" clip of Dylan himself. I'm very disappointed.",
49
- "id": "8"
50
- },
51
- "9": {
52
- "label": false,
53
- "text": "Excellent product: Easy to install. If you have a newer furnace you probably do not need the swail switch as the HE220A comes with a Humistat which can be connected to the furnace. They recommend the Honeywell 32005847-001 Installation Kit, Bypass which is a little pricey and you can probably buy the pieces of this kit cheaper individually from Home Depot or Lowes or ACO as well as the filters.",
54
- "id": "9"
55
- },
56
- "10": {
57
- "label": false,
58
- "text": "Very happy.: I am very happy with this trashcan. I was unable to find one in the stores to fit the space in my cabinet, but this one does the job. It is very sturdy and looks like it will put up with years of use.",
59
- "id": "10"
60
- },
61
- "11": {
62
- "label": true,
63
- "text": "These aren't Throughbreds!: This makes me so mad. All these new authors are coming and changing the series. Nothings the same anymore and the plots are repeditive. Don't even bother reading these books until #32 these are like a different series. I don't know excactly what's happing but these new authors suck!",
64
- "id": "11"
65
- },
66
- "12": {
67
- "label": true,
68
- "text": "Large and slow are a bad combination.: I bought this TV and returned it a week later, because it blurred so badly with motion that sports were unwatchable. I ended up buying a smaller Sony XBR4, and I have none of the issues (plus the picture is far, far better).This has nothing to do with 60 vs 120Hz. That is more important for DVDs and Blu-Ray signals that are 24fps (which doesn't divide evenly into 60 but does for 120). The LT52133 has an 8ms response time, which is extremely slow. A decent LCD should be 5 or lower.If you want an LCD, choose speed and quality over size. If you want size and quality but want to spend less, buy a plasma. Don't buy a big, cheap, slow LCD!I gave it 2 stars because I like the interface and remote.",
69
- "id": "12"
70
- },
71
- "13": {
72
- "label": true,
73
- "text": "Skip it: This movie is very poorly written and the result is not distressing, just lame. The actors do their best but from very early on it is obvious that the material gives them nothing to work with. Fans of Colin Firth will experience a certain dim level of enjoyment. Minnie Driver is a treat but her character is no better written than the others. Vermont locations are worth something. With one or two moments of exception it's neither comedic nor romantic.",
74
- "id": "13"
75
- },
76
- "14": {
77
- "label": false,
78
- "text": "Belive it i went to the concert?: hi everyone let me tell you i went to the concert i was amazed with what i saw cher was awsome i tell you buy the dvd. as i sat in front of the stage cher was doing a great job to us the she is living proof . So i urge you to buy it?",
79
- "id": "14"
80
- },
81
- "15": {
82
- "label": false,
83
- "text": "Vale la pena.: En este libro se narra de una forma muy interesante la vida de una familia en particular. Lo que mas me gusto de este libro fue la manera en que la autora describe a lo largo del libro las personalidades de los sujetos envueltos en la novela; que vienen a ser muy distintos y extremos, lo cual, intensifica el drama... Definitivamente es un buen libro y lo recomiendo a todos.",
84
- "id": "15"
85
- },
86
- "16": {
87
- "label": false,
88
- "text": "Nummie Children's story: I ordered this book for our grandchildren. Two boys 5 & 3 and a 4 month old girl. All love the story. The mouse is determined.",
89
- "id": "16"
90
- },
91
- "17": {
92
- "label": true,
93
- "text": "Seem to be alone on this one: Looking at the other reviews, I seem to be the only one that was disappointed with this book. The content is too babyish in most of it for older tweens and the more \"grown up\" content would be over a younger tween's head. I had a quick read through and with every paged turned, I thought duh. I'll be looking around for another book shortly.",
94
- "id": "17"
95
- },
96
- "18": {
97
- "label": false,
98
- "text": "Best yet: by far the best EA game yet. I especially like the easy controls and kick - a graphics. the playbook is extremely accurate and detailed. Also the fight songs and cheerleaders were a nice touch. this is an excellent game and worth checking out.",
99
- "id": "18"
100
- },
101
- "19": {
102
- "label": true,
103
- "text": "washed out: A bit like Simply Reds version of the Valentine bros hit \"Moneys too tight to mention\" - this cover version has nothing of the driving energy that characterised the original recording.",
104
- "id": "19"
105
- },
106
- "20": {
107
- "label": false,
108
- "text": "great water bottle: I love this bottle it is great. I like knowing it is non toxic and it just works very well. You can have it full and lay it down and it doesn't leak at all.",
109
- "id": "20"
110
- },
111
- "21": {
112
- "label": false,
113
- "text": "Nice goggles: I am pretty happy with these goggles. They work well during swim workouts in the pool. I do notice a little bit of fogging from time to time. I had hoped to wear them during an upcoming triathlon, but based on a few instances where they slipped a little in the pool I am concerned that they won't be secure enough. I will keep using them in the pool, but will likely get different ones for open water races.",
114
- "id": "21"
115
- },
116
- "22": {
117
- "label": true,
118
- "text": "aaahhh nnnoooooo!: Hopefully the last film in one of the worst horror trilogys ever made. This series pretty much ruined the horror film for years to come, for one its too self aware, thats incredibley annoying, second everyone acts like they are on Friends or some sitcom. The acting is just plain bad and unconvincing. Now the gore, if you're going with material this weak you should load it up with disgusting violence, is there any in the Scream series? No.Everyone went to see this movie just to see who THE KILLER is. This movie sets low standards to be met, you expect alot of people to die, one shock, then we find out who the killer is, then you go home. Every horror film being made today is like that, there's nothing new or exciting or risk taking, its the same stuff over and over and people are laping it up like dog food.This film is what you've come to expect, bad acting, some people die and we eventually find out who the killer is and all is merry and well. Pathetic.",
119
- "id": "22"
120
- },
121
- "23": {
122
- "label": false,
123
- "text": "A classic of its kind: This movie is a classic of its kind and much better that a lot of movies, that followed. It is not one of the best, but it still deserves five stars...",
124
- "id": "23"
125
- },
126
- "24": {
127
- "label": true,
128
- "text": "Nice suite, but Virtual PC 7 disappoints on my G5: I purchased the upgrade since I'd already bought both Office v.X and Virtual PC 6.1 last year.The biggest letdown is that Microsoft's promised support for the G5 is nearly non-existent. I have a dual processor G5 with an ATI Radeon 9800 card (Apple), and after trying to install Virtual PC 7 three times, I cannot get a VM to work. It did install (and work) flawlessly on my G4 Powerbook. Googling for reviews finds it's very hit or miss, but if (when) it misses, you'll regret investing the extra $$$ in an immature product.",
129
- "id": "24"
130
- },
131
- "25": {
132
- "label": true,
133
- "text": "Okay player, don't expect a miracle: I bought this DVD player at Circuit City earlier this yr for about a $100. I hooked it up to a 47\" Vizio LCD (which by the way has an awesome picture) using a HDMI cable. After fine tuning this product, I was very, very, very diasppointed. The picture was very \"grainy\" (lots of pixels). I have a $35 DVD player that only utilizes an s-video cable that produces a much more crisp picture. Be warned, the picture stinks.",
134
- "id": "25"
135
- },
136
- "26": {
137
- "label": false,
138
- "text": "A revelation of the science of consciousness evolution and all natural growth: Here is a readable and fascinating account of the development of the new science of chaos theory, the only body of ideas that describes how the natural world as experienced by human beings emerges out of basic quantum processes. The different explorers and innovators of the new science are introduced in a personable way that will enchant the interested reader.",
139
- "id": "26"
140
- },
141
- "27": {
142
- "label": true,
143
- "text": "Don't say that I didn't warn ya' !: I'm absolutely convinced that Delbert McClinton had no controlover the release of this CD. I rated it 1 star simplybecause there is no 0 star rating ! In actuality , I am not certain that the vocalist on this recording IS Delbert McClinton. Only on the Mr. Pitiful track is there any similarity at all to Delbert's voice. This is the perfect CD for someone with money to burn who would like to have a recording of a 1960's garage band recorded in a garage and who should be working in a garage ! Delbert fans...run fast and run far away from this ! END",
144
- "id": "27"
145
- },
146
- "28": {
147
- "label": true,
148
- "text": "This item is not available: I ordered this unit on February 7th. Every time I checked back on the status of the order, it read \"not shipped\" and the estimated shipping date got moved out. I really don't think this unit is avaialble from the company anytime soon. I cancelled the order.",
149
- "id": "28"
150
- },
151
- "29": {
152
- "label": true,
153
- "text": "I used to like ABBA...: I used to like ABBA, until I saw Mama Mia! A horribly disjointed musical, where songs feel contrived to fit into the story; a story that doesn't seem to come together. Individual songs are usually done alright, but don't segue from one to another very well.The cast butchered several of the songs, but especially S.O.S, Take A Chance On Me, and anything where Pierce Brosnan sang. On a side note, I also counted at least two violations of Chekov's Gun. And finally, I think it has a bad moral message. Which you only recognize if you manage to sit through the whole thing.If there is justice in the world, cast members without established careers won't get to have them as punishment for the worst movies I've seen since The Talented Mr. Ripley.",
154
- "id": "29"
155
- },
156
- "30": {
157
- "label": true,
158
- "text": "A complete disaster!: If you're like me, you probably wanted to check out this movie because it sounded like it really could be an excellent supernatural Gothic horror tale full of goblins and wicked things alike. Well, don't make the same mistake I did and actually watch it. It's horrible. Terrible. An honest to goodness waste of film. The acting is wretched, the film quality is rotten (it actually looks twenty years older than it is), and the plot is thin, weak, and does not give you what it's supposed to. The only reason I bothered to give this film 1 star is because of Alexis Arquette -- he's great looking, but should have left this film out of his career.",
159
- "id": "30"
160
- },
161
- "31": {
162
- "label": false,
163
- "text": "beautiful detail: I just purchased these Dover COloring Books for my mother and she loves them. The detail is out of this world and the variety of colors you can use are only limited by your inagination. HIGHLY RECOMMENDED!",
164
- "id": "31"
165
- },
166
- "32": {
167
- "label": true,
168
- "text": "Very disappointed: I looked forward to getting this movie as I had heard many good things about it but it was nothing like I had imagined or been led to believe. There is very little actual history in it or real Christian experience except for the background because the main focus is a soap opera style romance and caricature figures. I agree with the reviewer who described it as a mixture of \"tawdry Hollywood sex\" somehow interspersed with a vague nod to Christianity. The only decent scene was the arena scene where the Christians are going to their deaths singing hymns - but that's not enough to make it a great or even a good movie. Not personally to my taste anyway.",
169
- "id": "32"
170
- },
171
- "33": {
172
- "label": true,
173
- "text": "Unreliable minikit: I bought this minikit because it got good reviews and it would be perfect for my purposes. However it switches on and off whenever it wants, it looses contact with the phone. Very often the on/off button works only in a horizontal position (?) I use a Treo 650, which is on the compatible phone list. When I contacted Parrot, they said it wasn't (?) At last I opened the unit, but there are no moving parts inside except the micro switches. It is giving me a headache, so I will go searching for an alternative.",
174
- "id": "33"
175
- },
176
- "34": {
177
- "label": false,
178
- "text": "A Christmas Classic!: This is surely one of the best classical Christmas recordings available. Don't buy the older version, as the quality of this recording is excellent. This is one of those \"Every Christmas - Can't have Christmas without\" recordings.",
179
- "id": "34"
180
- },
181
- "35": {
182
- "label": true,
183
- "text": "too narrow: These were the narrowest pair of D size shoes I have ever tried on. I don't care how nice a shoe looks. If it don't fit it just don't fit.",
184
- "id": "35"
185
- },
186
- "36": {
187
- "label": true,
188
- "text": "Lack of extension: This earphones lack a descent extension cord. ITs very small cable, but its of good quality. Sadly, cord its too short, and the extension is useless.",
189
- "id": "36"
190
- },
191
- "37": {
192
- "label": false,
193
- "text": "Easy-Reading: This is the 3rd Southern Sisters Mystery I've read. They're easy, fast and funny murder mysteries, with lots of cute family stories intertwined in the intrigue.",
194
- "id": "37"
195
- },
196
- "38": {
197
- "label": true,
198
- "text": "it'd be great if it worked like it was supposed to: for the first 30 seconds it was lovely, but i believe that either the motor isn't powerful enough to keep the shaft rotating smoothly or 3 AA batteries just don't provide enough juice for the motor to work more than 30 seconds. it was a nice idea, but i'm rather dissapointed. the jelly material is somewhat difficult to maintain also. i think if it were hooked up to a larger battery pack it'd be WONDERFUL... which i think i may have a macgyver friend with a knack for electronics attempt to do for me.",
199
- "id": "38"
200
- },
201
- "39": {
202
- "label": false,
203
- "text": "Not Hornby's best but still good: I loved About a Boy and really, really loved the sardonic wit of High Fidelity. About a Boy is much deeper but just as cynical. Maybe even more so. The characters are richly drawn and just complex enough to keep the reader wanting more. Good read, but best to take some time with this one. Not recommended for a summer beach read.",
204
- "id": "39"
205
- },
206
- "40": {
207
- "label": true,
208
- "text": "A Disappointment: As with most Taunton Press publications, the illustrations and photographs in this book are spectacular and the organization and layout is superb. Nonetheless, I found this book disappointing. It lacks both depth and breadth. I had hoped for a detailed review of wood joinery including some of the more unusual joinery found in Japanese woodworking. This book, however, is targeted more toward the beginner. Even so, it does not cover the details and \"tricks\" of even the most basic techniques in sufficient detail to allow beginners to easily reproduce them. Consequently, it is unclear who this book was written for - not the beginner as it lacks depth, and not the advanced woodworker as it lacks breadth. Far more effort appears to have been put into appearance and organization than in content.",
209
- "id": "40"
210
- },
211
- "41": {
212
- "label": true,
213
- "text": "Horrible. Don't do it!: Great price for the item when a 6' one of these at Best Buy is $20. Thing is, the one from Best Buy fits in the outlet and stays there. This cord fits very loose and does not connect. I bought 2 of them, neither did what they were suppose to.As much as I hate to say it, but, buy the more expensive one. At least it works.",
214
- "id": "41"
215
- },
216
- "42": {
217
- "label": false,
218
- "text": "Given as a gift...: Given to my best friend as a gift. She loves it. Her fiance enjoys making coffee for her in the mornings. :)",
219
- "id": "42"
220
- },
221
- "43": {
222
- "label": false,
223
- "text": "Love the ring.: This is a nice ring. I was worried it out be thin and cheap looking, but it's not. It's a very pretty stylish ring. Go for it.",
224
- "id": "43"
225
- },
226
- "44": {
227
- "label": true,
228
- "text": "Beautiful writing Marred by One-Note Characterizations: How could Kingsolver have ruined her book with such an obvious error? Nathan is a strident paper doll that flattens the whole story. Just as bad, the author has all the narrators using the same ironic tone to decribe him, deadening their voices as well. At the same time, Kingsolver doesn't have the guts to show him doing something trully terrible. I don't trust an author who can't let the reader make up his own mind, and as a consequence I couldn't trust her views about ANYTHING in the story. I'm giving this two stars for her descriptions of the African landscape, and that is all.",
229
- "id": "44"
230
- },
231
- "45": {
232
- "label": true,
233
- "text": "Much worse than any cordless phone I've ever had: This phone cuts out only 2 rooms away from the base station. There is static noise, and callers on the other end complain about sound quality. I can't go into the garden, which used to be no problem with my old 900 MHz phone.",
234
- "id": "45"
235
- },
236
- "46": {
237
- "label": true,
238
- "text": "Waste of time & money: The first Hangover was not too bad, this one was just terrible. The acting is bad, the script is bad, everything about this movie was just bad. Do yourself a favor, don't buy this movie as it is a total waste of time and money.",
239
- "id": "46"
240
- },
241
- "47": {
242
- "label": true,
243
- "text": "Did Not Work For Me!: Impressive You Tube Video (Like a Sci-Fi Fantasy). In reality it's a high speed Easy Out so unsurprisingly it broke faster than an Easy out. This product did not work for me. The drill part did not drlil, the puller part did not pull. It was a total zero.",
244
- "id": "47"
245
- },
246
- "48": {
247
- "label": false,
248
- "text": "Excellent book, long overdue.: From a very long time women were told that looking good was of utmost importance. This was without regard to health or fitness and how age affected these parameters. Witness the whalebone and other types of corsets, the spike heeled shoes and the numerous weight loss programmes on the market (some of which are downright dangerous). Now there is a book, backed by solid research, that allows women of all ages to remain fit and healthy for a lifetime. I am certainly going to recommend this book to all the women I know.Bentley Norville",
249
- "id": "48"
250
- },
251
- "49": {
252
- "label": true,
253
- "text": "not an all star: Not a practical guide in this collecting age. Does NOT have a comprehensive list; meaning it does NOT cover all manufacturers and, more importantly, for the ones it does, only provides listings of the base set. That means no insert or variation pricing whatsoever. Also, no oddball or minor league issues are listed. Generally speaking, unless you are collecting base sets prior to the advent of inserts and alternate versions of the base set, this guide is fairly useless.",
254
- "id": "49"
255
- },
256
- "50": {
257
- "label": true,
258
- "text": "Again, second rate city, third rate writer: Just another example of Mr. Lindberg's pitiful attempt at exhibiting a strong expertise on a subject with which he is clearly obsessed. Don't waste your time with this book, either. It is poorly written and fails to engage the reader. You might consider using this book and the first book he wrote on the same subject, as a pair of bookends. That is about all they are worth.",
259
- "id": "50"
260
- },
261
- "51": {
262
- "label": false,
263
- "text": "Reality: No one should need to convince you to buy this book, you should just do it! It's so well written and worded and brings you right to the heart of a sexual reality that most people like to pretend doesn't really live and breath in their fair cities. I never again want to hear someone bad mouth a working girl for what she does. I will and do now however look at men with a curious eye wondering if they are depraved peep show window lickers :)",
264
- "id": "51"
265
- },
266
- "52": {
267
- "label": true,
268
- "text": "Bummer: Visual effects and Battle footage were great...the other 85% of the movie was just lousy fluff...",
269
- "id": "52"
270
- },
271
- "53": {
272
- "label": false,
273
- "text": "The spark of idependence: Filled with the independent spark that made us all love life at one point or another. A fun, introspective and nonsensical movie that sticks with you.",
274
- "id": "53"
275
- },
276
- "54": {
277
- "label": false,
278
- "text": "What I expected from Mirman's website. Funny. Funny. Russian.: lol, gotta love Eugene. Even when his audience doesn't initially laugh, he gets in a good zinger at himself and they laugh at that. He's witty without being condescending, and uncomplicated without seeing contrived. However, if you're not a fan of irreverant humor, this may not be for you.",
279
- "id": "54"
280
- },
281
- "55": {
282
- "label": true,
283
- "text": "Do not...repeat...do not bother!: It is not often that I offer a negative review but this compilation while attractive does not deliver at all.The foot massage gizmo is awkward and uncomfortable.The pumice stone leaves rough splinter like skin.The foot scrub doesn't reall scrub.The rotary action tool has five heads, none of which work well and you must hold the switch in place or it turns off. It is cumbersome and ineffective.The one star was initially given for a foot brush (which later lost its bristles very easily as I update the review) and a sweet smelling foot repair balm.Don't waist your money. Soak your feet and invest in an inexpensive German Titania file, smooth and coarser side, or a like product. It will last for years.",
284
- "id": "55"
285
- },
286
- "56": {
287
- "label": true,
288
- "text": "Not Sandra's Best: Ms. Brown has written better romance novels. Don't give up on her if this was your first Sandra book.The feeble female lead struggles with a 15-year crush that walks back into her life. The smug male lead acts like a jerk through most of the novel. The romance scenes grapple to muster up passion but fall short. Both of the main characters bothered me; my favorite character was the 17-year old.A quick read...about 4 hours (with interruptions) for me...but probably not worth it.",
289
- "id": "56"
290
- },
291
- "57": {
292
- "label": false,
293
- "text": "Impressed: Lots-O-Fun. Wood and glass toys are high quality and are a good fall back for the kids to play with they are \"bored\". Would buy again.",
294
- "id": "57"
295
- },
296
- "58": {
297
- "label": true,
298
- "text": "Light turned on by itself 3 times: The installation was easy. I used it for a week, everything worked fine, EXCEPT the light it connected to turned on by itself 3 times so far, with no one near to either one of the switch. Not sure whether it is a defective unit, or this product is too sensitive to noise. I'm returning this product and will just install a regular switch instead.",
299
- "id": "58"
300
- },
301
- "59": {
302
- "label": false,
303
- "text": "good battery: I feel kind of silly writing a review for a battery, but have to say that these last a LONG time. Work very well.",
304
- "id": "59"
305
- },
306
- "60": {
307
- "label": false,
308
- "text": "Even a Woman finds it funny: Yes, even a woman finds \"Married to Mommy\" funny. The book gets you laughing aloud when it is trying to make fun of \"Mommies\". The truth is that it really is making fun of the stupidity of men and their simple basic needs of sex, getting out of work, and beer. Of course, the truth is always funny.A definite MUST for any woman, married or not. We will now know all the secret tricks the men try to use on us.By the way, I am NOT a MOMMY!",
309
- "id": "60"
310
- },
311
- "61": {
312
- "label": false,
313
- "text": "Gungrave...not quite what you might expect: Those thinking this is another version of Trigun will be disappointed. Gungrave is actually a lot deeper and more complex. The lead is short on dialouge, but the story has more depth and character development than most anime. The first DVD is more about the main character's past than about the reanimated killing machine he's become, but it definitely leaves you wanting more.",
314
- "id": "61"
315
- },
316
- "62": {
317
- "label": false,
318
- "text": "Error in product description: It's great in every way. However, if you'd prefer a digital tuner (as I do), then you might need to look further. The product description boasts a digital AM/FM tuner, but it's disappointingly an analog AM/FM tuner.Overall - especially for the price - I think it's pretty good.",
319
- "id": "62"
320
- },
321
- "63": {
322
- "label": false,
323
- "text": "good phone but not as user friendly as it could be: Battery life is very good. Phone has good range. My only complaint is it's to involved to get your message from the handset.",
324
- "id": "63"
325
- },
326
- "64": {
327
- "label": true,
328
- "text": "Big waste of money (and space in my house!): My 5 year old son wanted this so bad, but when we got it for him, there were so many pieces to put together that didn't fit together well, he never played with it. It just sits on our floor in many pieces taking up toy space! What a waste!",
329
- "id": "64"
330
- },
331
- "65": {
332
- "label": false,
333
- "text": "Don't want to take it off: Very satisfied with an earlier purchase of this Bali bra model, I was just as pleased with the new one. Very comfortable, well made and a good neutral color. It will be my next choice, too.",
334
- "id": "65"
335
- },
336
- "66": {
337
- "label": false,
338
- "text": "Fantastico: If anybody who's into rock music is ever looking for a band to keep you on your toes, this is the band. I've been a fan for 10 years now, and no album has ever sounded like any of their previous albums. This disc is fantastic with such a variety of styles, as are the previous releases, even back to the Rainbow Butt Monkey days.",
339
- "id": "66"
340
- },
341
- "67": {
342
- "label": true,
343
- "text": "too much visual: There are far too much designs, visuals, colors, etc in the book - this is highly distracting, as TV screen can be...By way of example (among so many...), what is the use of colors with the three squares of the Pyth. theorem???? this is as useless as writting 2+3=5 with 2 in blue, 3 in red and 5 in yellow...I wish I had purchased the 2nd edition, which according to reviews was closer to what I was looking for.",
344
- "id": "67"
345
- },
346
- "68": {
347
- "label": false,
348
- "text": "Aretha's First Arista Release Showed Pleasures to Come: After a long and musically satisfying career with Atlantic, Aretha severed her ties with that company and moved under the wing of Arista's Clive Davis. With the start of the 1980's, Aretha was looking for new territory to conquer and almost succeeded with this mixed bag.\"United Together\" is a fine tune that benefits from beautiful orchestral arrangement that is matched by Aretha's superb vocal instrument. The remake of \"Can't Turn You Loose\" allows Aretha to show why she is the Queen of Soul\" for she really belts this one out. Another cover, that of the Doobies' \"What a Fool Believes,\" is an interesting interpretation. The final cut \"School Days\" appears to be \"autobiographical\" for every girl growing up in the fifties.Although not as strong as her Atlantic work, \"Aretha\" is still a suitable addition to the artist's discography.",
349
- "id": "68"
350
- },
351
- "69": {
352
- "label": true,
353
- "text": "Misguided Purchase: The photo and description do not reflect the product. The screen panel kit I received was white. What a huge inconvenience during a time-crunch.",
354
- "id": "69"
355
- },
356
- "70": {
357
- "label": true,
358
- "text": "Banacek: My husband and were looking forward to seeing this series.The first show was SO boring, we finally just quit watching it.Actually, we haven't gotten around to watching anymore. I guess we were afraid of a repeat.Maybe that was just once, I hope!",
359
- "id": "70"
360
- },
361
- "71": {
362
- "label": false,
363
- "text": "JDT: Uncle Tupelo is without doubt one of the most under appreciated groups of the 90's. Anodyne, like each of the three albums that came before it, has everything that a remarkable recording requires: great songs, honest lyrics, and artists who really care about the music they are making. Like the best of Dylan and Springsteen, the songs are about real people with real troubles and joys. When you hear them you know they are coming from the heart. The songs contributed by Jay Farrar and Jeff Tweedy are easily differentiated by the voacls, music, and lyrics. What makes this record interesting is how well these unique sounds compliment each other. The union is seamless.",
364
- "id": "71"
365
- },
366
- "72": {
367
- "label": false,
368
- "text": "Well Worth Reading: First a confession: Miriam Wasserman was my mother. However, she published several books, but this is the only one I really found useful. She walks the reader through the New York City school system and the attitudes of different groups involved in the system back in the 1960s. This includes parents, teachers and administrators. Her view is that the further away one got from parents and students, the more prestige one had. She meticulously describes the teachers' strike of 1968 against \"community control of schools\", a strike of which she is extremely critical. She explores the racism that was involved in this strike, including using quotes from striking teachers, etc. It should be emphasized that the author was pro-union all her life, so her views don't stem from an anti-union bias. The book also covers the high school student rebellion which coincided with and followed the strike.",
369
- "id": "72"
370
- },
371
- "73": {
372
- "label": false,
373
- "text": "compact and loaded: I bought this phone after reading the cnet reviews and really liked it. It looks small and really compact. I like the camera pics at 2 mega pixel and bright flash. The mp3 player is crisp. The headset that comes along delvers amazing fM radio. I think my phone is not very loud and you have a problem when you are around a noisy crowd. I just bought this phone again for my cousin. He likes it too. Almost forgot the display is very good.",
374
- "id": "73"
375
- },
376
- "74": {
377
- "label": false,
378
- "text": "Outstanding text!: Brooks/Cole should keep this text in their catalog for ages! It is well-written, examples are generally quite clear, vocabulary is introduced well, and the exercises develop real skills, rather than simply be busy-work. One of the best calculus books ever!",
379
- "id": "74"
380
- },
381
- "75": {
382
- "label": false,
383
- "text": "Excel 2003 Bible: Very good source of information. I will most likely buy other books in this series.",
384
- "id": "75"
385
- },
386
- "76": {
387
- "label": false,
388
- "text": "Tasting is Believing: Gluten-free breads used to have a gritty texture from the rice flour, and were too soft for sandwiches. Bette Hagman uses garbanzo/fava bean flour, sorghum flour, tapioca flour, and corn starch to create breads which have a similar texture to wheat flour breads, and the flavors of her breads are fabulous.My BF bought me this book and a great tasting beverage to drink it with. Since he knows I quit coffee recently, he's been really wonderful helping me in cope with my mood swings. S o y f e e is made from soy beans that is roasted just like coffee. I enjoy the taste and don't miss coffee one bit. Buy it online at www.s o y c o f fee.com.This is a 'must have' for anyone baking gluten-free. I think all of Bette Hagman's books are wonderful and a must for those with gluten intolerance.",
389
- "id": "76"
390
- },
391
- "77": {
392
- "label": false,
393
- "text": "5 stars for the show, no stars for the \"Collector's Edition\": I was really looking forward to getting this Collector's Edition and see what extras were added. I knew it wasn't a lot - just a mini-book and a documentary - but I figured it would be packaged in a cool way.Wrong.As others have already mentioned, the Collector's Edition is *literally* theAvatar: The Last Airbender - The Complete Book 1 Collectionslipped into another cardboard box, with a little booklet and DVD in an envelope (not even a case!) wedged in. It's really disappointing; it would have been so easy to create a quality Collector's Edition but the studio couldn't be bothered, I guess.",
394
- "id": "77"
395
- },
396
- "78": {
397
- "label": false,
398
- "text": "sula scottcampos: Sula, a book that talks about the issues of being a black women is a really good novel to read.One of the reasons I recommend it is because of its realism and its themes - death, sex, friendship and poverty.I also think that its characters are very good, its easy to identify with one or both of them. I really recommend this book to anyone who enjoys good literature.",
399
- "id": "78"
400
- },
401
- "79": {
402
- "label": false,
403
- "text": "Fantastic! It's a must-have for girls!: I hated razor, tried shaving but it did not work for me. Shaving made the hair grows thicker and faster afterwards, plus the roots are impossible to be getting rid of. After reading the reviews, I ordered it to try, I used it for once and already fall in love with this. I used to use small tweezer to pluck out my leg's hair, in order to avoid the razor, it took me a few hours to do that but this super electronic tweezer works wonder! You won't see the black roots and I have smooth and silkly legs in 20 mins. It does not hurt at all, if you use it on your legs. But, if you use it at your under arm, it won't be a pleasant feeling, of course! I will never use anything else besides this for hair removing anymore! highly recommended!",
404
- "id": "79"
405
- },
406
- "80": {
407
- "label": true,
408
- "text": "This is not a toy: I guess I was expecting more out of these leave window decals. I just didn't find them attractive after placing them on my window, they seem very cheap, I guess because they are cheap.I threw them away.",
409
- "id": "80"
410
- },
411
- "81": {
412
- "label": false,
413
- "text": "Wonderful book for anyone running a professional hatchery: This book is aimed more for hatcheries that are raising Trout, Salmon, Catfish and other food fishes. However, there is so much information in this book that even ornamental fish hatcheries will find an incredible amount of useful information. The chapters on Fish Nutrition are especially helpful.",
414
- "id": "81"
415
- },
416
- "82": {
417
- "label": false,
418
- "text": "Amazing book!!: Once again, Eric Victorino's artistic talent is put into this great free-verse poetry book. I couldn't put it down and I finished it the day I received it in the mail. All of the poems are awesome but the one I found the most interesting was \"It's A People Business.\" All of the experiences in his life, personally and with his band, come to life in this book. Please check it out! It's worth every penny!!",
419
- "id": "82"
420
- },
421
- "83": {
422
- "label": false,
423
- "text": "The white trumpet contender respect Miles Davis!: The story of the Jazz in the Fifties certainly would be remain unfinished without the ominous presence of this outstanding virtuoso. Baker sound still possesses this alluring hook, this magnetic engagement charm, eloquent expressiveness, enrapturing lyricism and contagious rhythm, despite the elapsed time, which confirms by itself the status of his musicianship.This selection is jus a little sample of the broad universe of his genius. A well thought selection of great musical successes, available, preserved and immortalized by the Digital Technology for our future enjoyment.Absolutely indispensable in your treasured collection.",
424
- "id": "83"
425
- },
426
- "84": {
427
- "label": true,
428
- "text": "What the?: I'm sorry, maybe it's just me but I can't helping stating that this has to be one of the wrost movies I've seen in my life!Can you say boring? Can you say doesn't make sense at all? The first 30 minutes of the movie were O.K. But it went downhill after that. This movie is a prime example of a director attempting to make a deep movie with a meaningful lesson but failed on all levels. I don't recommend this movie unless you want to go to sleep or you don't have anything else to do.",
429
- "id": "84"
430
- },
431
- "85": {
432
- "label": false,
433
- "text": "very very good!!!!: linda blair is a young girl who is possessed. and her mother doesn't know what to do until one day when she hears her daughter screaming and stabbind herself she knows what to do GET AN EXORCIZIM!!!",
434
- "id": "85"
435
- },
436
- "86": {
437
- "label": false,
438
- "text": "Awesome product for the price!: This range extender works as advertised! I am very happy with the purchase. I was a little worried after reading some of the horror stories here, but I have to say, Chovy's review instructions (on this site) were just this ticket to get the repeater up and running in less than 30 minutes. It was unbelievably easy to install! Do not be frightened by negative reviews. If you can set up a wireless network, you can set up this repeater. However, I did upgrade the firmware before I did anything else and maybe that helped. I got the firmware update from the Belkin site.",
439
- "id": "86"
440
- },
441
- "87": {
442
- "label": true,
443
- "text": "Slight: This book is either a heavily illustrated short story collection or a text-heavy comic. Its unusual format is its most original feature. Its plots are negligible, but its illustrations and text evoke a unique atmosphere of self-conscious nonconformism. Although its target audience is dare-to-be-different teens and college students, its interesting turns of phrase and expressive line drawings are not devoid of interest for general audences.",
444
- "id": "87"
445
- },
446
- "88": {
447
- "label": false,
448
- "text": "ANgeleyes: Seem to dry up their eyes fairly well, although I haven't seen the color (brown stain) change much yet.",
449
- "id": "88"
450
- },
451
- "89": {
452
- "label": true,
453
- "text": "Nice Try: Salt Lake 2002 is not a bad game, but it isn't good either. The graphics are excellent, but some of the events are bad. Bobsleigh, and skiing aren't bad but the others are. You dont stay into it for long. I liked it for a while, but it gets boring.",
454
- "id": "89"
455
- },
456
- "90": {
457
- "label": true,
458
- "text": "Cutler's share of the pie: This book was a major disappointment. I am familiar with books written solely by the Dalai Lama, such as the \"Library of Tibet\" series, which are much more engrossing and have much more substance than Cutler's book. Cutler attempts (successfully, sadly) to have his share of the profitable market that involves the Dalai Lama's writings. The book is insipid, does not try to explain any important issue in the light of Buddhist philosophy, and only rehashes issues that several other westerners already wrote about. It's another big ego trip: we keep hearing time and again about his opportunities to be with the Dalai Lama. What a shame, Cutler. I sold the book as soon as I finished it.",
459
- "id": "90"
460
- },
461
- "91": {
462
- "label": true,
463
- "text": "Mostly tedious, with interesting parts: I found the writing interesting, and the subject fascinating, but I found myself frustrated by the author's difficulty in talking directly about the status of Muslim women with her interview subjects. The author spent many pages writing about the menus and dress of the many middle and upper-middle class women she interviewed. It seemed as though her interview subjects resisted her efforts to discuss the status of women in their countries, so we too as readers had to wade through much distracting material and misunderstandings about feminism and gender. Great travel stories, but not a great source of information about Muslim women.",
464
- "id": "91"
465
- },
466
- "92": {
467
- "label": true,
468
- "text": "Sesame Street Toddler: I did not find this game to be as educationally sound as I would expect from Sesame street. There is too much talking before the program will react to a command. The graphics are jerky and the cursor acts like the target is magnetically charged and keeps pushing away the cursor. When the child actually does manage to click on a target, the cursor may still fly to another target and the child is told that his answer is wrong. Another example of educational problems is the pronunciation of \"eggs\" using a long \"a\" sound instead of a short \"e.\" This is not very helpful in teaching a child the sound for short \"e.\" Children that are used to playing computer games by themselves may find that this game is too frustrating to do alone. The open ended learning curve is a great idea. I just wish Sesame Street would hire a truly qualified literacy expert to help clean up the many problems in this program.",
469
- "id": "92"
470
- },
471
- "93": {
472
- "label": true,
473
- "text": "needs a buzz cut and a point: I avoided reading this book, not because of the hermaphrodite subject matter, but because I have never read a multigenerational family saga that I liked. Many books let me down in the middle, and this was no exception. The beginning of the book was incredible and harrowing, with momentum and characterization. The post-America nextgens part of the saga was so boring I found myself flipping and flipping - always a bad sign. If there was some kind of larger point to all of that, then I must have missed it. Yes there's the identity duality and trinity themes playing out here: man/woman, greek/turkish/american modern/old world sick/healthy innocent/guilty original/reinvented. But it was almost as if the author was saying - here it is again - get it? I like my fiction much more subtle than this.",
474
- "id": "93"
475
- },
476
- "94": {
477
- "label": true,
478
- "text": "OMG! DO NOT BUY!: I normally don't take the time to submit a review.In this case however, I feel obligated to do so.This is by far one of the worst purchases I have ever made.Here's why.....The contraption is far too bulky.The case's enclosing is unbearable, takes a good minute or so to open it.The texture of the material feels like a cheap toy.The overall design is horrible, something I could make in my basement.For the love of everything sacred, do not buy this thing.",
479
- "id": "94"
480
- },
481
- "95": {
482
- "label": false,
483
- "text": "Good price, good quality: Comparable HDMI cables can be bought for 45 or more. Even though the price is cheap the quality is good, no problems so far.",
484
- "id": "95"
485
- },
486
- "96": {
487
- "label": false,
488
- "text": "Good rock music: This is what i call rock music good beat and good lyrics, don't listen to the other reviews. This cd is one of the best, listen to a few songs and you will get hooked. I recommend this cd its awesome.",
489
- "id": "96"
490
- },
491
- "97": {
492
- "label": true,
493
- "text": "BORING!: This movie is soo boring. How in the hell did this movie make so much at the box office. Do people really want to pay for crappy movies like this. bottom line this is a chick flick nothing is good. And now they are re-releasing this movie with more boring stuff. This is the worst movie ever.",
494
- "id": "97"
495
- },
496
- "98": {
497
- "label": true,
498
- "text": "Already Rusting: Inferior quality. The plating is thin and rust is coming through the finish. Inexcusable for a product that is designed for use in a humid environment.",
499
- "id": "98"
500
- },
501
- "99": {
502
- "label": true,
503
- "text": "confusing internet setup: i wanted a camera that could email photos but this camera will not go out through the router and the manual setup , to punch a hole thru router is confusing.",
504
- "id": "99"
505
- },
506
- "04c7dfc0f94e4e88968d09b40edbfa14": {
507
- "label": true,
508
- "text": "The new gaming console is unaffordable.",
509
- "id": "04c7dfc0f94e4e88968d09b40edbfa14"
510
- },
511
- "58f58a1a4cbb4bb699772ed934006ec8": {
512
- "label": true,
513
- "text": "How can it be sure difficult for @115830 to deliver a package to a University address? Two failed attempts so far ...",
514
- "id": "58f58a1a4cbb4bb699772ed934006ec8"
515
- },
516
- "d4a3cd4877c54aef81c376eff8008df4": {
517
- "label": false,
518
- "text": "@204780 Glad they showed up! Hope you have a great flight! -Sean",
519
- "id": "d4a3cd4877c54aef81c376eff8008df4"
520
- },
521
- "affe1d6548f84bed84238bac45cc10a1": {
522
- "label": false,
523
- "text": "@British_Airways Thank you! All looks good then \ud83c\uddec\ud83c\udde7\u2708\ufe0f",
524
- "id": "affe1d6548f84bed84238bac45cc10a1"
525
- },
526
- "e304ea77a94c450a95690c7b605a035f": {
527
- "label": false,
528
- "text": "@246667 Thank you for reaching out, Andrea. The built in application in Windows 10 are exempted to be uninstalled. However, you can send this suggestion directly to our developers via the Feedback Hub so they can take a look at it: https://t.co/jowrfbgQm6. Keep in touch.",
529
- "id": "e304ea77a94c450a95690c7b605a035f"
530
- },
531
- "76b694b019eb4e6888a422e144030bd0": {
532
- "label": true,
533
- "text": "@GWRHelp It\u2019s mainly the constant short forming and cancellations due to mechanical faults Phil. As a company, these excuses have been used ad nauseam for years and years. It just gets worse and no amount of rhetoric and IET self promotion can hide that fact.",
534
- "id": "76b694b019eb4e6888a422e144030bd0"
535
- },
536
- "ce0698020b7a457396c7674b04db10e6": {
537
- "label": false,
538
- "text": "English gangster flick.",
539
- "id": "ce0698020b7a457396c7674b04db10e6"
540
- },
541
- "52bda6cbab224899845e66e0474cdefc": {
542
- "label": false,
543
- "text": "sees the formula graph, the chip calculates the formula, able to \"survive\" thanks to its connection to Edit, develops a parallel personality and affords her abilities greater than she ever imagined...",
544
- "id": "52bda6cbab224899845e66e0474cdefc"
545
- },
546
- "435aabe68c294963a05e090d479582bc": {
547
- "label": false,
548
- "text": "Aanandam is a 2016 Indian Malayalam campus musical film written and directed by Ganesh Raj in his directorial debut. Vineeth Sreenivasan produces the film under the banner of Habit Of Life with Vinod Shornur under Cast N Crew.",
549
- "id": "435aabe68c294963a05e090d479582bc"
550
- },
551
- "f96313d0087e4941a359783634ef9e86": {
552
- "label": false,
553
- "text": "The remarkable story of The Weather Underground, radical activists of the 1970s, and of radical politics at its best and most disastrous.",
554
- "id": "f96313d0087e4941a359783634ef9e86"
555
- },
556
- "f63e4502791a409fa2d750687d3841eb": {
557
- "label": false,
558
- "text": "A young widow on a trip to the backwoods stumbles upon the operation of a gang of drug smugglers. They attempt to kill her in order to keep their operation a secret, but she turns out to be more resourceful than they thought, and starts to turn the tables on them.",
559
- "id": "f63e4502791a409fa2d750687d3841eb"
560
- },
561
- "108ac02949324b02bdcbe4c7a77bacdc": {
562
- "label": false,
563
- "text": "The story of a young Marine, fresh from Camp Pendleton, who is forced to confront the complexities of adulthood and a volatile home life during a four-day Thanksgiving leave.",
564
- "id": "108ac02949324b02bdcbe4c7a77bacdc"
565
- },
566
- "44fc412246964b2393fa0035ff093a00": {
567
- "label": false,
568
- "text": "Exploring the rough and tumble world of hockey, Academy Award winner Alex Gibney (\"Taxi to the Dark Side\") looks at the world of the NHL enforcers and specifically the career of Chris \"Knuckles\" Nilan who helped the Montreal Canadiens win the Stanley Cup.",
569
- "id": "44fc412246964b2393fa0035ff093a00"
570
- },
571
- "409350c111af4ba3a94c842b797ddb95": {
572
- "label": false,
573
- "text": "Two fishing fanatics get in trouble when their fishing boat gets stolen while on a trip.",
574
- "id": "409350c111af4ba3a94c842b797ddb95"
575
- },
576
- "d48d8f3b5a524ecea69bae718d1f1513": {
577
- "label": false,
578
- "text": "A willful young boy follows his just as obstinate grandmother in a journey across Iraq, determined to discover the fate of her missing son, Ahmed's father, who never returned from war.",
579
- "id": "d48d8f3b5a524ecea69bae718d1f1513"
580
- },
581
- "283e96de5b474240a044c50dbc2551fb": {
582
- "label": false,
583
- "text": "A group of people are sitting in a theatre watching a movie when one realises that the woman on the screen is her. (IMDb)",
584
- "id": "283e96de5b474240a044c50dbc2551fb"
585
- },
586
- "516d0f2f3a854a97a87c64db19a89fac": {
587
- "label": false,
588
- "text": "of the fake prediction. Fantastic swashbuckling adventures in a 18th century setting, with a light criticism of the war and the mighty.",
589
- "id": "516d0f2f3a854a97a87c64db19a89fac"
590
- },
591
- "c2f55710669b40aa937625fe0ab04065": {
592
- "label": false,
593
- "text": "famous for his reputation as a Don Juan, to seduce C\u00e9cile and emotionally destroy her. While on his mission, Valmont gets sidetracked when he goes to visit his aunt and falls for Madame Tourvel, a virtuous, married woman who knows of his womanizing ways, but that only makes the challenge more exciting to Valmont. Together, Madame de Merteuil and Valmont make a dangerous team and they will stop at nothing when it comes to matters of the heart.",
594
- "id": "c2f55710669b40aa937625fe0ab04065"
595
- },
596
- "ba0261b2ee3244d29bb3a8c6d77195a6": {
597
- "label": false,
598
- "text": "sees the formula graph, the chip calculates the formula, able to \"survive\" thanks to its connection to Edit, develops a parallel personality and affords her abilities greater than she ever imagined...",
599
- "id": "ba0261b2ee3244d29bb3a8c6d77195a6"
600
- },
601
- "5e724fbde8ee44d9a8fc87a6e6667f01": {
602
- "label": false,
603
- "text": "telling the story about people who despite all obstacles strive for their goal.",
604
- "id": "5e724fbde8ee44d9a8fc87a6e6667f01"
605
- },
606
- "557eba5ebfc9467a9d88688afed41354": {
607
- "label": false,
608
- "text": "A young playboy who learns he has one month until he becomes infertile sets out to procreate as much as possible.",
609
- "id": "557eba5ebfc9467a9d88688afed41354"
610
- },
611
- "aa20e22fbe96487d8ee1223a6ef4da0b": {
612
- "label": false,
613
- "text": "Set in modern times, Alex finds King Arthur's sword Excalibur and must prove himself worthy of it.",
614
- "id": "aa20e22fbe96487d8ee1223a6ef4da0b"
615
- },
616
- "bea56d34f6df408c9ec9653b17a90a93": {
617
- "label": false,
618
- "text": "Kostis is a 40-year-old doctor that finds himself in the small island of Antiparos, in order to take over the local clinic. His whole life and routine will turn upside down when he meets an international group of young and beautiful tourists and he falls in love with Anna, a 19-year-old goddess.",
619
- "id": "bea56d34f6df408c9ec9653b17a90a93"
620
- },
621
- "e61a3251720d425c9f4770cb4b11d2d9": {
622
- "label": false,
623
- "text": "Friends on a weekend excursion take a path into a forest that leads to death and destruction.",
624
- "id": "e61a3251720d425c9f4770cb4b11d2d9"
625
- },
626
- "5471008376cf44518f2ff1f67f057c08": {
627
- "label": false,
628
- "text": "Mr Bournelis suggested all 30 lineal metres of blockwork should be removed and replaced, which would require removing and reinstalling the fence. The total cost of his suggested method of rectification was said to be $14,650 for each unit, giving a total cost of rectification of $29,300.",
629
- "id": "5471008376cf44518f2ff1f67f057c08"
630
- }
631
- },
632
- "version": 27,
633
- "description": "Negative sentiment"
634
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/concept/lilac/negative-sentiment/sbert.pkl DELETED
Binary file (106 kB)
 
data/concept/lilac/positive-sentiment/concept.json DELETED
@@ -1,564 +0,0 @@
1
- {
2
- "namespace": "lilac",
3
- "concept_name": "positive-sentiment",
4
- "type": "text",
5
- "data": {
6
- "0": {
7
- "label": false,
8
- "text": "Starting To Be Annoyed By Becky...: I'm not sure why I keep reading these books, but I guess it's because I've read the first two so I'll keep reading the rest of the books. In the first book, I really found it amusing. I was a little annoyed by the fact that Becky couldn't stop spending, but then again that's why she is called a Shopaholic. In the second book, I felt more of the same it was just magniifed more. Now in the third book, I'm just down right annoyed by Becky Bloomwood. In this book, she wasn't going on crazy shopping sprees, just planning two different weddings because she was afraid to tell each person and because I feel she's really selfish. Still, I read the book because I wanted to see how she could get herself out of another situation. I will say that I love her friends Suze and Danny, her client Laurel and her husband Luke. Maybe that's why I keep reading. I will read the next book, but I'm sure I'll be just as annoyed when I'm done.",
9
- "id": "0"
10
- },
11
- "1": {
12
- "label": false,
13
- "text": "the cover is fine - the pool is horrible: The entire pool was horrible. The cover was fine once we got it on, but we finally got rid of the pool after 2 weeks because it was so hard to set up and keep clean.",
14
- "id": "1"
15
- },
16
- "2": {
17
- "label": true,
18
- "text": "Good album, not their best.: This album is probably the most marketable and radio friendly of all of dashboard's albums. For the peripheral listener it may be the right one to get to introduce you to this band. But as a Dashboard fan of 5 or so years I truly hope they return to their original sound for their next work. Not for the listen-ability but for the show. To this day the fans react best to the songs from \"Places\" or \"A Mark, A Mission.\" I recommend this album to everyone but I also recommend any and all of their other work.",
19
- "id": "2"
20
- },
21
- "3": {
22
- "label": false,
23
- "text": "This is a horror novel, right?: Never one to pass up any vampire novel, I purchased Sips because the description seemed interesting. Vampires, Marquis de Sade, fetishism, yada yada yada. If this is a comedy, I give it 4 stars; however, I'll give it 1 star as a horror novel. Sade was rather boring; I would think a character as intense and multi-faceted as the Marquis de Sade would make for a more interesting vampire. The writing style isn't too bad, but overall I found the characters to be mildly amusing at best. The plot was thin, the end was anti-climactic, and the vampires were not very frightening. The book had little suspense, and it leaves a mile-wide opening for a sequel at the conclusion. I would, however, like to see something more of the vampire mutants lurking in the graveyard. They were the most riveting of any of the characters.",
24
- "id": "3"
25
- },
26
- "4": {
27
- "label": true,
28
- "text": "Superb mix of global non secular musical denominations: I first heard Ms. Pook's music on the \"Eyes Wide Shut\" soundtrack (the masquerade ball scene) and was blown away; if ever there was a necessity for music to permeate a scene in a film this was it. She incorporates a blend of the traditional songs from faiths across continents and mixes them, for lack of a better comparison than similar to your quintessential raver d.j. (though these are better and definitively more original :) \"Oppenheimer\" is my favorite, and if you let the last track run for a few minutes a portion of the song will play once more. I can't wait to hear more of her stuff - these hymns are awesome.",
29
- "id": "4"
30
- },
31
- "5": {
32
- "label": true,
33
- "text": "A moving and suspenseful story!: For anyone familiar with the occult, this book is likely to raise hairs on the back of your neck as you read. Even if you're not, the storyline is suspenseful and fascinating, and the characters evoke great sympathy and admiration. An excellent read.",
34
- "id": "5"
35
- },
36
- "6": {
37
- "label": true,
38
- "text": "Simple & Easy to Use - A Practical approach to eating out: This guide is extremely to use. It provides sample menus that you'd see at Chinese, Indian and Thai restaurants. Then you are provided with descriptions of each dish and how it is prepared and the ingredients used. From there you are provided with specific considerations as to how the preparation or ingredient list may affect you if you have Gluten or Allergen issues.This book is the size of a passport and very organized and well written. The Chinese, Indian and Thai Cuisine Passport is perfect for making choices while traveling, or while dining at your favorite local restaurant.",
39
- "id": "6"
40
- },
41
- "7": {
42
- "label": false,
43
- "text": "Being Fair....I am a fan of hers: and I really enjoyed her previous works, more than I could have ever imagined, but this record is horrible. The songs are trite, the lyrics are incredibly boring, indulgent and immature. The music is pop staple, with forgetable melodies and repetative chorus lines, I feel as if the studio wrote the entire album for her while she was sleeping, this just doesn't speak to any of her previous works at all. This album fits on the same shelf with a Nickelodeon-themed CD. Instead of heading in the direction of an artist like Alanis Morrisette, she is going backward and joining the ranks of Hannah Montana and the Naked Brothers Band. She is a great artist and her first two records are amazing. She is better than this CD and I am looking forward to her next effort.",
44
- "id": "7"
45
- },
46
- "8": {
47
- "label": false,
48
- "text": "Sucked: I thought the DVD sucked tremendously. It was very boring and if I could, I would return it for a refund. There was only one \"small\" clip of Dylan himself. I'm very disappointed.",
49
- "id": "8"
50
- },
51
- "9": {
52
- "label": true,
53
- "text": "Excellent product: Easy to install. If you have a newer furnace you probably do not need the swail switch as the HE220A comes with a Humistat which can be connected to the furnace. They recommend the Honeywell 32005847-001 Installation Kit, Bypass which is a little pricey and you can probably buy the pieces of this kit cheaper individually from Home Depot or Lowes or ACO as well as the filters.",
54
- "id": "9"
55
- },
56
- "10": {
57
- "label": true,
58
- "text": "Very happy.: I am very happy with this trashcan. I was unable to find one in the stores to fit the space in my cabinet, but this one does the job. It is very sturdy and looks like it will put up with years of use.",
59
- "id": "10"
60
- },
61
- "11": {
62
- "label": false,
63
- "text": "These aren't Throughbreds!: This makes me so mad. All these new authors are coming and changing the series. Nothings the same anymore and the plots are repeditive. Don't even bother reading these books until #32 these are like a different series. I don't know excactly what's happing but these new authors suck!",
64
- "id": "11"
65
- },
66
- "12": {
67
- "label": false,
68
- "text": "Large and slow are a bad combination.: I bought this TV and returned it a week later, because it blurred so badly with motion that sports were unwatchable. I ended up buying a smaller Sony XBR4, and I have none of the issues (plus the picture is far, far better).This has nothing to do with 60 vs 120Hz. That is more important for DVDs and Blu-Ray signals that are 24fps (which doesn't divide evenly into 60 but does for 120). The LT52133 has an 8ms response time, which is extremely slow. A decent LCD should be 5 or lower.If you want an LCD, choose speed and quality over size. If you want size and quality but want to spend less, buy a plasma. Don't buy a big, cheap, slow LCD!I gave it 2 stars because I like the interface and remote.",
69
- "id": "12"
70
- },
71
- "13": {
72
- "label": false,
73
- "text": "Skip it: This movie is very poorly written and the result is not distressing, just lame. The actors do their best but from very early on it is obvious that the material gives them nothing to work with. Fans of Colin Firth will experience a certain dim level of enjoyment. Minnie Driver is a treat but her character is no better written than the others. Vermont locations are worth something. With one or two moments of exception it's neither comedic nor romantic.",
74
- "id": "13"
75
- },
76
- "14": {
77
- "label": true,
78
- "text": "Belive it i went to the concert?: hi everyone let me tell you i went to the concert i was amazed with what i saw cher was awsome i tell you buy the dvd. as i sat in front of the stage cher was doing a great job to us the she is living proof . So i urge you to buy it?",
79
- "id": "14"
80
- },
81
- "15": {
82
- "label": true,
83
- "text": "Vale la pena.: En este libro se narra de una forma muy interesante la vida de una familia en particular. Lo que mas me gusto de este libro fue la manera en que la autora describe a lo largo del libro las personalidades de los sujetos envueltos en la novela; que vienen a ser muy distintos y extremos, lo cual, intensifica el drama... Definitivamente es un buen libro y lo recomiendo a todos.",
84
- "id": "15"
85
- },
86
- "16": {
87
- "label": true,
88
- "text": "Nummie Children's story: I ordered this book for our grandchildren. Two boys 5 & 3 and a 4 month old girl. All love the story. The mouse is determined.",
89
- "id": "16"
90
- },
91
- "17": {
92
- "label": false,
93
- "text": "Seem to be alone on this one: Looking at the other reviews, I seem to be the only one that was disappointed with this book. The content is too babyish in most of it for older tweens and the more \"grown up\" content would be over a younger tween's head. I had a quick read through and with every paged turned, I thought duh. I'll be looking around for another book shortly.",
94
- "id": "17"
95
- },
96
- "18": {
97
- "label": true,
98
- "text": "Best yet: by far the best EA game yet. I especially like the easy controls and kick - a graphics. the playbook is extremely accurate and detailed. Also the fight songs and cheerleaders were a nice touch. this is an excellent game and worth checking out.",
99
- "id": "18"
100
- },
101
- "19": {
102
- "label": false,
103
- "text": "washed out: A bit like Simply Reds version of the Valentine bros hit \"Moneys too tight to mention\" - this cover version has nothing of the driving energy that characterised the original recording.",
104
- "id": "19"
105
- },
106
- "20": {
107
- "label": true,
108
- "text": "great water bottle: I love this bottle it is great. I like knowing it is non toxic and it just works very well. You can have it full and lay it down and it doesn't leak at all.",
109
- "id": "20"
110
- },
111
- "21": {
112
- "label": true,
113
- "text": "Nice goggles: I am pretty happy with these goggles. They work well during swim workouts in the pool. I do notice a little bit of fogging from time to time. I had hoped to wear them during an upcoming triathlon, but based on a few instances where they slipped a little in the pool I am concerned that they won't be secure enough. I will keep using them in the pool, but will likely get different ones for open water races.",
114
- "id": "21"
115
- },
116
- "22": {
117
- "label": false,
118
- "text": "aaahhh nnnoooooo!: Hopefully the last film in one of the worst horror trilogys ever made. This series pretty much ruined the horror film for years to come, for one its too self aware, thats incredibley annoying, second everyone acts like they are on Friends or some sitcom. The acting is just plain bad and unconvincing. Now the gore, if you're going with material this weak you should load it up with disgusting violence, is there any in the Scream series? No.Everyone went to see this movie just to see who THE KILLER is. This movie sets low standards to be met, you expect alot of people to die, one shock, then we find out who the killer is, then you go home. Every horror film being made today is like that, there's nothing new or exciting or risk taking, its the same stuff over and over and people are laping it up like dog food.This film is what you've come to expect, bad acting, some people die and we eventually find out who the killer is and all is merry and well. Pathetic.",
119
- "id": "22"
120
- },
121
- "23": {
122
- "label": true,
123
- "text": "A classic of its kind: This movie is a classic of its kind and much better that a lot of movies, that followed. It is not one of the best, but it still deserves five stars...",
124
- "id": "23"
125
- },
126
- "24": {
127
- "label": false,
128
- "text": "Nice suite, but Virtual PC 7 disappoints on my G5: I purchased the upgrade since I'd already bought both Office v.X and Virtual PC 6.1 last year.The biggest letdown is that Microsoft's promised support for the G5 is nearly non-existent. I have a dual processor G5 with an ATI Radeon 9800 card (Apple), and after trying to install Virtual PC 7 three times, I cannot get a VM to work. It did install (and work) flawlessly on my G4 Powerbook. Googling for reviews finds it's very hit or miss, but if (when) it misses, you'll regret investing the extra $$$ in an immature product.",
129
- "id": "24"
130
- },
131
- "25": {
132
- "label": false,
133
- "text": "Okay player, don't expect a miracle: I bought this DVD player at Circuit City earlier this yr for about a $100. I hooked it up to a 47\" Vizio LCD (which by the way has an awesome picture) using a HDMI cable. After fine tuning this product, I was very, very, very diasppointed. The picture was very \"grainy\" (lots of pixels). I have a $35 DVD player that only utilizes an s-video cable that produces a much more crisp picture. Be warned, the picture stinks.",
134
- "id": "25"
135
- },
136
- "26": {
137
- "label": true,
138
- "text": "A revelation of the science of consciousness evolution and all natural growth: Here is a readable and fascinating account of the development of the new science of chaos theory, the only body of ideas that describes how the natural world as experienced by human beings emerges out of basic quantum processes. The different explorers and innovators of the new science are introduced in a personable way that will enchant the interested reader.",
139
- "id": "26"
140
- },
141
- "27": {
142
- "label": false,
143
- "text": "Don't say that I didn't warn ya' !: I'm absolutely convinced that Delbert McClinton had no controlover the release of this CD. I rated it 1 star simplybecause there is no 0 star rating ! In actuality , I am not certain that the vocalist on this recording IS Delbert McClinton. Only on the Mr. Pitiful track is there any similarity at all to Delbert's voice. This is the perfect CD for someone with money to burn who would like to have a recording of a 1960's garage band recorded in a garage and who should be working in a garage ! Delbert fans...run fast and run far away from this ! END",
144
- "id": "27"
145
- },
146
- "28": {
147
- "label": false,
148
- "text": "This item is not available: I ordered this unit on February 7th. Every time I checked back on the status of the order, it read \"not shipped\" and the estimated shipping date got moved out. I really don't think this unit is avaialble from the company anytime soon. I cancelled the order.",
149
- "id": "28"
150
- },
151
- "29": {
152
- "label": false,
153
- "text": "I used to like ABBA...: I used to like ABBA, until I saw Mama Mia! A horribly disjointed musical, where songs feel contrived to fit into the story; a story that doesn't seem to come together. Individual songs are usually done alright, but don't segue from one to another very well.The cast butchered several of the songs, but especially S.O.S, Take A Chance On Me, and anything where Pierce Brosnan sang. On a side note, I also counted at least two violations of Chekov's Gun. And finally, I think it has a bad moral message. Which you only recognize if you manage to sit through the whole thing.If there is justice in the world, cast members without established careers won't get to have them as punishment for the worst movies I've seen since The Talented Mr. Ripley.",
154
- "id": "29"
155
- },
156
- "30": {
157
- "label": false,
158
- "text": "A complete disaster!: If you're like me, you probably wanted to check out this movie because it sounded like it really could be an excellent supernatural Gothic horror tale full of goblins and wicked things alike. Well, don't make the same mistake I did and actually watch it. It's horrible. Terrible. An honest to goodness waste of film. The acting is wretched, the film quality is rotten (it actually looks twenty years older than it is), and the plot is thin, weak, and does not give you what it's supposed to. The only reason I bothered to give this film 1 star is because of Alexis Arquette -- he's great looking, but should have left this film out of his career.",
159
- "id": "30"
160
- },
161
- "31": {
162
- "label": true,
163
- "text": "beautiful detail: I just purchased these Dover COloring Books for my mother and she loves them. The detail is out of this world and the variety of colors you can use are only limited by your inagination. HIGHLY RECOMMENDED!",
164
- "id": "31"
165
- },
166
- "32": {
167
- "label": false,
168
- "text": "Very disappointed: I looked forward to getting this movie as I had heard many good things about it but it was nothing like I had imagined or been led to believe. There is very little actual history in it or real Christian experience except for the background because the main focus is a soap opera style romance and caricature figures. I agree with the reviewer who described it as a mixture of \"tawdry Hollywood sex\" somehow interspersed with a vague nod to Christianity. The only decent scene was the arena scene where the Christians are going to their deaths singing hymns - but that's not enough to make it a great or even a good movie. Not personally to my taste anyway.",
169
- "id": "32"
170
- },
171
- "33": {
172
- "label": false,
173
- "text": "Unreliable minikit: I bought this minikit because it got good reviews and it would be perfect for my purposes. However it switches on and off whenever it wants, it looses contact with the phone. Very often the on/off button works only in a horizontal position (?) I use a Treo 650, which is on the compatible phone list. When I contacted Parrot, they said it wasn't (?) At last I opened the unit, but there are no moving parts inside except the micro switches. It is giving me a headache, so I will go searching for an alternative.",
174
- "id": "33"
175
- },
176
- "34": {
177
- "label": true,
178
- "text": "A Christmas Classic!: This is surely one of the best classical Christmas recordings available. Don't buy the older version, as the quality of this recording is excellent. This is one of those \"Every Christmas - Can't have Christmas without\" recordings.",
179
- "id": "34"
180
- },
181
- "35": {
182
- "label": false,
183
- "text": "too narrow: These were the narrowest pair of D size shoes I have ever tried on. I don't care how nice a shoe looks. If it don't fit it just don't fit.",
184
- "id": "35"
185
- },
186
- "36": {
187
- "label": false,
188
- "text": "Lack of extension: This earphones lack a descent extension cord. ITs very small cable, but its of good quality. Sadly, cord its too short, and the extension is useless.",
189
- "id": "36"
190
- },
191
- "37": {
192
- "label": true,
193
- "text": "Easy-Reading: This is the 3rd Southern Sisters Mystery I've read. They're easy, fast and funny murder mysteries, with lots of cute family stories intertwined in the intrigue.",
194
- "id": "37"
195
- },
196
- "38": {
197
- "label": false,
198
- "text": "it'd be great if it worked like it was supposed to: for the first 30 seconds it was lovely, but i believe that either the motor isn't powerful enough to keep the shaft rotating smoothly or 3 AA batteries just don't provide enough juice for the motor to work more than 30 seconds. it was a nice idea, but i'm rather dissapointed. the jelly material is somewhat difficult to maintain also. i think if it were hooked up to a larger battery pack it'd be WONDERFUL... which i think i may have a macgyver friend with a knack for electronics attempt to do for me.",
199
- "id": "38"
200
- },
201
- "39": {
202
- "label": true,
203
- "text": "Not Hornby's best but still good: I loved About a Boy and really, really loved the sardonic wit of High Fidelity. About a Boy is much deeper but just as cynical. Maybe even more so. The characters are richly drawn and just complex enough to keep the reader wanting more. Good read, but best to take some time with this one. Not recommended for a summer beach read.",
204
- "id": "39"
205
- },
206
- "40": {
207
- "label": false,
208
- "text": "A Disappointment: As with most Taunton Press publications, the illustrations and photographs in this book are spectacular and the organization and layout is superb. Nonetheless, I found this book disappointing. It lacks both depth and breadth. I had hoped for a detailed review of wood joinery including some of the more unusual joinery found in Japanese woodworking. This book, however, is targeted more toward the beginner. Even so, it does not cover the details and \"tricks\" of even the most basic techniques in sufficient detail to allow beginners to easily reproduce them. Consequently, it is unclear who this book was written for - not the beginner as it lacks depth, and not the advanced woodworker as it lacks breadth. Far more effort appears to have been put into appearance and organization than in content.",
209
- "id": "40"
210
- },
211
- "41": {
212
- "label": false,
213
- "text": "Horrible. Don't do it!: Great price for the item when a 6' one of these at Best Buy is $20. Thing is, the one from Best Buy fits in the outlet and stays there. This cord fits very loose and does not connect. I bought 2 of them, neither did what they were suppose to.As much as I hate to say it, but, buy the more expensive one. At least it works.",
214
- "id": "41"
215
- },
216
- "42": {
217
- "label": true,
218
- "text": "Given as a gift...: Given to my best friend as a gift. She loves it. Her fiance enjoys making coffee for her in the mornings. :)",
219
- "id": "42"
220
- },
221
- "43": {
222
- "label": true,
223
- "text": "Love the ring.: This is a nice ring. I was worried it out be thin and cheap looking, but it's not. It's a very pretty stylish ring. Go for it.",
224
- "id": "43"
225
- },
226
- "44": {
227
- "label": false,
228
- "text": "Beautiful writing Marred by One-Note Characterizations: How could Kingsolver have ruined her book with such an obvious error? Nathan is a strident paper doll that flattens the whole story. Just as bad, the author has all the narrators using the same ironic tone to decribe him, deadening their voices as well. At the same time, Kingsolver doesn't have the guts to show him doing something trully terrible. I don't trust an author who can't let the reader make up his own mind, and as a consequence I couldn't trust her views about ANYTHING in the story. I'm giving this two stars for her descriptions of the African landscape, and that is all.",
229
- "id": "44"
230
- },
231
- "45": {
232
- "label": false,
233
- "text": "Much worse than any cordless phone I've ever had: This phone cuts out only 2 rooms away from the base station. There is static noise, and callers on the other end complain about sound quality. I can't go into the garden, which used to be no problem with my old 900 MHz phone.",
234
- "id": "45"
235
- },
236
- "46": {
237
- "label": false,
238
- "text": "Waste of time & money: The first Hangover was not too bad, this one was just terrible. The acting is bad, the script is bad, everything about this movie was just bad. Do yourself a favor, don't buy this movie as it is a total waste of time and money.",
239
- "id": "46"
240
- },
241
- "47": {
242
- "label": false,
243
- "text": "Did Not Work For Me!: Impressive You Tube Video (Like a Sci-Fi Fantasy). In reality it's a high speed Easy Out so unsurprisingly it broke faster than an Easy out. This product did not work for me. The drill part did not drlil, the puller part did not pull. It was a total zero.",
244
- "id": "47"
245
- },
246
- "48": {
247
- "label": true,
248
- "text": "Excellent book, long overdue.: From a very long time women were told that looking good was of utmost importance. This was without regard to health or fitness and how age affected these parameters. Witness the whalebone and other types of corsets, the spike heeled shoes and the numerous weight loss programmes on the market (some of which are downright dangerous). Now there is a book, backed by solid research, that allows women of all ages to remain fit and healthy for a lifetime. I am certainly going to recommend this book to all the women I know.Bentley Norville",
249
- "id": "48"
250
- },
251
- "49": {
252
- "label": false,
253
- "text": "not an all star: Not a practical guide in this collecting age. Does NOT have a comprehensive list; meaning it does NOT cover all manufacturers and, more importantly, for the ones it does, only provides listings of the base set. That means no insert or variation pricing whatsoever. Also, no oddball or minor league issues are listed. Generally speaking, unless you are collecting base sets prior to the advent of inserts and alternate versions of the base set, this guide is fairly useless.",
254
- "id": "49"
255
- },
256
- "50": {
257
- "label": false,
258
- "text": "Again, second rate city, third rate writer: Just another example of Mr. Lindberg's pitiful attempt at exhibiting a strong expertise on a subject with which he is clearly obsessed. Don't waste your time with this book, either. It is poorly written and fails to engage the reader. You might consider using this book and the first book he wrote on the same subject, as a pair of bookends. That is about all they are worth.",
259
- "id": "50"
260
- },
261
- "51": {
262
- "label": true,
263
- "text": "Reality: No one should need to convince you to buy this book, you should just do it! It's so well written and worded and brings you right to the heart of a sexual reality that most people like to pretend doesn't really live and breath in their fair cities. I never again want to hear someone bad mouth a working girl for what she does. I will and do now however look at men with a curious eye wondering if they are depraved peep show window lickers :)",
264
- "id": "51"
265
- },
266
- "52": {
267
- "label": false,
268
- "text": "Bummer: Visual effects and Battle footage were great...the other 85% of the movie was just lousy fluff...",
269
- "id": "52"
270
- },
271
- "53": {
272
- "label": true,
273
- "text": "The spark of idependence: Filled with the independent spark that made us all love life at one point or another. A fun, introspective and nonsensical movie that sticks with you.",
274
- "id": "53"
275
- },
276
- "54": {
277
- "label": true,
278
- "text": "What I expected from Mirman's website. Funny. Funny. Russian.: lol, gotta love Eugene. Even when his audience doesn't initially laugh, he gets in a good zinger at himself and they laugh at that. He's witty without being condescending, and uncomplicated without seeing contrived. However, if you're not a fan of irreverant humor, this may not be for you.",
279
- "id": "54"
280
- },
281
- "55": {
282
- "label": false,
283
- "text": "Do not...repeat...do not bother!: It is not often that I offer a negative review but this compilation while attractive does not deliver at all.The foot massage gizmo is awkward and uncomfortable.The pumice stone leaves rough splinter like skin.The foot scrub doesn't reall scrub.The rotary action tool has five heads, none of which work well and you must hold the switch in place or it turns off. It is cumbersome and ineffective.The one star was initially given for a foot brush (which later lost its bristles very easily as I update the review) and a sweet smelling foot repair balm.Don't waist your money. Soak your feet and invest in an inexpensive German Titania file, smooth and coarser side, or a like product. It will last for years.",
284
- "id": "55"
285
- },
286
- "56": {
287
- "label": false,
288
- "text": "Not Sandra's Best: Ms. Brown has written better romance novels. Don't give up on her if this was your first Sandra book.The feeble female lead struggles with a 15-year crush that walks back into her life. The smug male lead acts like a jerk through most of the novel. The romance scenes grapple to muster up passion but fall short. Both of the main characters bothered me; my favorite character was the 17-year old.A quick read...about 4 hours (with interruptions) for me...but probably not worth it.",
289
- "id": "56"
290
- },
291
- "57": {
292
- "label": true,
293
- "text": "Impressed: Lots-O-Fun. Wood and glass toys are high quality and are a good fall back for the kids to play with they are \"bored\". Would buy again.",
294
- "id": "57"
295
- },
296
- "58": {
297
- "label": false,
298
- "text": "Light turned on by itself 3 times: The installation was easy. I used it for a week, everything worked fine, EXCEPT the light it connected to turned on by itself 3 times so far, with no one near to either one of the switch. Not sure whether it is a defective unit, or this product is too sensitive to noise. I'm returning this product and will just install a regular switch instead.",
299
- "id": "58"
300
- },
301
- "59": {
302
- "label": true,
303
- "text": "good battery: I feel kind of silly writing a review for a battery, but have to say that these last a LONG time. Work very well.",
304
- "id": "59"
305
- },
306
- "60": {
307
- "label": true,
308
- "text": "Even a Woman finds it funny: Yes, even a woman finds \"Married to Mommy\" funny. The book gets you laughing aloud when it is trying to make fun of \"Mommies\". The truth is that it really is making fun of the stupidity of men and their simple basic needs of sex, getting out of work, and beer. Of course, the truth is always funny.A definite MUST for any woman, married or not. We will now know all the secret tricks the men try to use on us.By the way, I am NOT a MOMMY!",
309
- "id": "60"
310
- },
311
- "61": {
312
- "label": true,
313
- "text": "Gungrave...not quite what you might expect: Those thinking this is another version of Trigun will be disappointed. Gungrave is actually a lot deeper and more complex. The lead is short on dialouge, but the story has more depth and character development than most anime. The first DVD is more about the main character's past than about the reanimated killing machine he's become, but it definitely leaves you wanting more.",
314
- "id": "61"
315
- },
316
- "62": {
317
- "label": true,
318
- "text": "Error in product description: It's great in every way. However, if you'd prefer a digital tuner (as I do), then you might need to look further. The product description boasts a digital AM/FM tuner, but it's disappointingly an analog AM/FM tuner.Overall - especially for the price - I think it's pretty good.",
319
- "id": "62"
320
- },
321
- "63": {
322
- "label": true,
323
- "text": "good phone but not as user friendly as it could be: Battery life is very good. Phone has good range. My only complaint is it's to involved to get your message from the handset.",
324
- "id": "63"
325
- },
326
- "64": {
327
- "label": false,
328
- "text": "Big waste of money (and space in my house!): My 5 year old son wanted this so bad, but when we got it for him, there were so many pieces to put together that didn't fit together well, he never played with it. It just sits on our floor in many pieces taking up toy space! What a waste!",
329
- "id": "64"
330
- },
331
- "65": {
332
- "label": true,
333
- "text": "Don't want to take it off: Very satisfied with an earlier purchase of this Bali bra model, I was just as pleased with the new one. Very comfortable, well made and a good neutral color. It will be my next choice, too.",
334
- "id": "65"
335
- },
336
- "66": {
337
- "label": true,
338
- "text": "Fantastico: If anybody who's into rock music is ever looking for a band to keep you on your toes, this is the band. I've been a fan for 10 years now, and no album has ever sounded like any of their previous albums. This disc is fantastic with such a variety of styles, as are the previous releases, even back to the Rainbow Butt Monkey days.",
339
- "id": "66"
340
- },
341
- "67": {
342
- "label": false,
343
- "text": "too much visual: There are far too much designs, visuals, colors, etc in the book - this is highly distracting, as TV screen can be...By way of example (among so many...), what is the use of colors with the three squares of the Pyth. theorem???? this is as useless as writting 2+3=5 with 2 in blue, 3 in red and 5 in yellow...I wish I had purchased the 2nd edition, which according to reviews was closer to what I was looking for.",
344
- "id": "67"
345
- },
346
- "68": {
347
- "label": true,
348
- "text": "Aretha's First Arista Release Showed Pleasures to Come: After a long and musically satisfying career with Atlantic, Aretha severed her ties with that company and moved under the wing of Arista's Clive Davis. With the start of the 1980's, Aretha was looking for new territory to conquer and almost succeeded with this mixed bag.\"United Together\" is a fine tune that benefits from beautiful orchestral arrangement that is matched by Aretha's superb vocal instrument. The remake of \"Can't Turn You Loose\" allows Aretha to show why she is the Queen of Soul\" for she really belts this one out. Another cover, that of the Doobies' \"What a Fool Believes,\" is an interesting interpretation. The final cut \"School Days\" appears to be \"autobiographical\" for every girl growing up in the fifties.Although not as strong as her Atlantic work, \"Aretha\" is still a suitable addition to the artist's discography.",
349
- "id": "68"
350
- },
351
- "69": {
352
- "label": false,
353
- "text": "Misguided Purchase: The photo and description do not reflect the product. The screen panel kit I received was white. What a huge inconvenience during a time-crunch.",
354
- "id": "69"
355
- },
356
- "70": {
357
- "label": false,
358
- "text": "Banacek: My husband and were looking forward to seeing this series.The first show was SO boring, we finally just quit watching it.Actually, we haven't gotten around to watching anymore. I guess we were afraid of a repeat.Maybe that was just once, I hope!",
359
- "id": "70"
360
- },
361
- "71": {
362
- "label": true,
363
- "text": "JDT: Uncle Tupelo is without doubt one of the most under appreciated groups of the 90's. Anodyne, like each of the three albums that came before it, has everything that a remarkable recording requires: great songs, honest lyrics, and artists who really care about the music they are making. Like the best of Dylan and Springsteen, the songs are about real people with real troubles and joys. When you hear them you know they are coming from the heart. The songs contributed by Jay Farrar and Jeff Tweedy are easily differentiated by the voacls, music, and lyrics. What makes this record interesting is how well these unique sounds compliment each other. The union is seamless.",
364
- "id": "71"
365
- },
366
- "72": {
367
- "label": true,
368
- "text": "Well Worth Reading: First a confession: Miriam Wasserman was my mother. However, she published several books, but this is the only one I really found useful. She walks the reader through the New York City school system and the attitudes of different groups involved in the system back in the 1960s. This includes parents, teachers and administrators. Her view is that the further away one got from parents and students, the more prestige one had. She meticulously describes the teachers' strike of 1968 against \"community control of schools\", a strike of which she is extremely critical. She explores the racism that was involved in this strike, including using quotes from striking teachers, etc. It should be emphasized that the author was pro-union all her life, so her views don't stem from an anti-union bias. The book also covers the high school student rebellion which coincided with and followed the strike.",
369
- "id": "72"
370
- },
371
- "73": {
372
- "label": true,
373
- "text": "compact and loaded: I bought this phone after reading the cnet reviews and really liked it. It looks small and really compact. I like the camera pics at 2 mega pixel and bright flash. The mp3 player is crisp. The headset that comes along delvers amazing fM radio. I think my phone is not very loud and you have a problem when you are around a noisy crowd. I just bought this phone again for my cousin. He likes it too. Almost forgot the display is very good.",
374
- "id": "73"
375
- },
376
- "74": {
377
- "label": true,
378
- "text": "Outstanding text!: Brooks/Cole should keep this text in their catalog for ages! It is well-written, examples are generally quite clear, vocabulary is introduced well, and the exercises develop real skills, rather than simply be busy-work. One of the best calculus books ever!",
379
- "id": "74"
380
- },
381
- "75": {
382
- "label": true,
383
- "text": "Excel 2003 Bible: Very good source of information. I will most likely buy other books in this series.",
384
- "id": "75"
385
- },
386
- "76": {
387
- "label": true,
388
- "text": "Tasting is Believing: Gluten-free breads used to have a gritty texture from the rice flour, and were too soft for sandwiches. Bette Hagman uses garbanzo/fava bean flour, sorghum flour, tapioca flour, and corn starch to create breads which have a similar texture to wheat flour breads, and the flavors of her breads are fabulous.My BF bought me this book and a great tasting beverage to drink it with. Since he knows I quit coffee recently, he's been really wonderful helping me in cope with my mood swings. S o y f e e is made from soy beans that is roasted just like coffee. I enjoy the taste and don't miss coffee one bit. Buy it online at www.s o y c o f fee.com.This is a 'must have' for anyone baking gluten-free. I think all of Bette Hagman's books are wonderful and a must for those with gluten intolerance.",
389
- "id": "76"
390
- },
391
- "77": {
392
- "label": true,
393
- "text": "5 stars for the show, no stars for the \"Collector's Edition\": I was really looking forward to getting this Collector's Edition and see what extras were added. I knew it wasn't a lot - just a mini-book and a documentary - but I figured it would be packaged in a cool way.Wrong.As others have already mentioned, the Collector's Edition is *literally* theAvatar: The Last Airbender - The Complete Book 1 Collectionslipped into another cardboard box, with a little booklet and DVD in an envelope (not even a case!) wedged in. It's really disappointing; it would have been so easy to create a quality Collector's Edition but the studio couldn't be bothered, I guess.",
394
- "id": "77"
395
- },
396
- "78": {
397
- "label": true,
398
- "text": "sula scottcampos: Sula, a book that talks about the issues of being a black women is a really good novel to read.One of the reasons I recommend it is because of its realism and its themes - death, sex, friendship and poverty.I also think that its characters are very good, its easy to identify with one or both of them. I really recommend this book to anyone who enjoys good literature.",
399
- "id": "78"
400
- },
401
- "79": {
402
- "label": true,
403
- "text": "Fantastic! It's a must-have for girls!: I hated razor, tried shaving but it did not work for me. Shaving made the hair grows thicker and faster afterwards, plus the roots are impossible to be getting rid of. After reading the reviews, I ordered it to try, I used it for once and already fall in love with this. I used to use small tweezer to pluck out my leg's hair, in order to avoid the razor, it took me a few hours to do that but this super electronic tweezer works wonder! You won't see the black roots and I have smooth and silkly legs in 20 mins. It does not hurt at all, if you use it on your legs. But, if you use it at your under arm, it won't be a pleasant feeling, of course! I will never use anything else besides this for hair removing anymore! highly recommended!",
404
- "id": "79"
405
- },
406
- "80": {
407
- "label": false,
408
- "text": "This is not a toy: I guess I was expecting more out of these leave window decals. I just didn't find them attractive after placing them on my window, they seem very cheap, I guess because they are cheap.I threw them away.",
409
- "id": "80"
410
- },
411
- "81": {
412
- "label": true,
413
- "text": "Wonderful book for anyone running a professional hatchery: This book is aimed more for hatcheries that are raising Trout, Salmon, Catfish and other food fishes. However, there is so much information in this book that even ornamental fish hatcheries will find an incredible amount of useful information. The chapters on Fish Nutrition are especially helpful.",
414
- "id": "81"
415
- },
416
- "82": {
417
- "label": true,
418
- "text": "Amazing book!!: Once again, Eric Victorino's artistic talent is put into this great free-verse poetry book. I couldn't put it down and I finished it the day I received it in the mail. All of the poems are awesome but the one I found the most interesting was \"It's A People Business.\" All of the experiences in his life, personally and with his band, come to life in this book. Please check it out! It's worth every penny!!",
419
- "id": "82"
420
- },
421
- "83": {
422
- "label": true,
423
- "text": "The white trumpet contender respect Miles Davis!: The story of the Jazz in the Fifties certainly would be remain unfinished without the ominous presence of this outstanding virtuoso. Baker sound still possesses this alluring hook, this magnetic engagement charm, eloquent expressiveness, enrapturing lyricism and contagious rhythm, despite the elapsed time, which confirms by itself the status of his musicianship.This selection is jus a little sample of the broad universe of his genius. A well thought selection of great musical successes, available, preserved and immortalized by the Digital Technology for our future enjoyment.Absolutely indispensable in your treasured collection.",
424
- "id": "83"
425
- },
426
- "84": {
427
- "label": false,
428
- "text": "What the?: I'm sorry, maybe it's just me but I can't helping stating that this has to be one of the wrost movies I've seen in my life!Can you say boring? Can you say doesn't make sense at all? The first 30 minutes of the movie were O.K. But it went downhill after that. This movie is a prime example of a director attempting to make a deep movie with a meaningful lesson but failed on all levels. I don't recommend this movie unless you want to go to sleep or you don't have anything else to do.",
429
- "id": "84"
430
- },
431
- "85": {
432
- "label": true,
433
- "text": "very very good!!!!: linda blair is a young girl who is possessed. and her mother doesn't know what to do until one day when she hears her daughter screaming and stabbind herself she knows what to do GET AN EXORCIZIM!!!",
434
- "id": "85"
435
- },
436
- "86": {
437
- "label": true,
438
- "text": "Awesome product for the price!: This range extender works as advertised! I am very happy with the purchase. I was a little worried after reading some of the horror stories here, but I have to say, Chovy's review instructions (on this site) were just this ticket to get the repeater up and running in less than 30 minutes. It was unbelievably easy to install! Do not be frightened by negative reviews. If you can set up a wireless network, you can set up this repeater. However, I did upgrade the firmware before I did anything else and maybe that helped. I got the firmware update from the Belkin site.",
439
- "id": "86"
440
- },
441
- "87": {
442
- "label": false,
443
- "text": "Slight: This book is either a heavily illustrated short story collection or a text-heavy comic. Its unusual format is its most original feature. Its plots are negligible, but its illustrations and text evoke a unique atmosphere of self-conscious nonconformism. Although its target audience is dare-to-be-different teens and college students, its interesting turns of phrase and expressive line drawings are not devoid of interest for general audences.",
444
- "id": "87"
445
- },
446
- "88": {
447
- "label": true,
448
- "text": "ANgeleyes: Seem to dry up their eyes fairly well, although I haven't seen the color (brown stain) change much yet.",
449
- "id": "88"
450
- },
451
- "89": {
452
- "label": false,
453
- "text": "Nice Try: Salt Lake 2002 is not a bad game, but it isn't good either. The graphics are excellent, but some of the events are bad. Bobsleigh, and skiing aren't bad but the others are. You dont stay into it for long. I liked it for a while, but it gets boring.",
454
- "id": "89"
455
- },
456
- "90": {
457
- "label": false,
458
- "text": "Cutler's share of the pie: This book was a major disappointment. I am familiar with books written solely by the Dalai Lama, such as the \"Library of Tibet\" series, which are much more engrossing and have much more substance than Cutler's book. Cutler attempts (successfully, sadly) to have his share of the profitable market that involves the Dalai Lama's writings. The book is insipid, does not try to explain any important issue in the light of Buddhist philosophy, and only rehashes issues that several other westerners already wrote about. It's another big ego trip: we keep hearing time and again about his opportunities to be with the Dalai Lama. What a shame, Cutler. I sold the book as soon as I finished it.",
459
- "id": "90"
460
- },
461
- "91": {
462
- "label": false,
463
- "text": "Mostly tedious, with interesting parts: I found the writing interesting, and the subject fascinating, but I found myself frustrated by the author's difficulty in talking directly about the status of Muslim women with her interview subjects. The author spent many pages writing about the menus and dress of the many middle and upper-middle class women she interviewed. It seemed as though her interview subjects resisted her efforts to discuss the status of women in their countries, so we too as readers had to wade through much distracting material and misunderstandings about feminism and gender. Great travel stories, but not a great source of information about Muslim women.",
464
- "id": "91"
465
- },
466
- "92": {
467
- "label": false,
468
- "text": "Sesame Street Toddler: I did not find this game to be as educationally sound as I would expect from Sesame street. There is too much talking before the program will react to a command. The graphics are jerky and the cursor acts like the target is magnetically charged and keeps pushing away the cursor. When the child actually does manage to click on a target, the cursor may still fly to another target and the child is told that his answer is wrong. Another example of educational problems is the pronunciation of \"eggs\" using a long \"a\" sound instead of a short \"e.\" This is not very helpful in teaching a child the sound for short \"e.\" Children that are used to playing computer games by themselves may find that this game is too frustrating to do alone. The open ended learning curve is a great idea. I just wish Sesame Street would hire a truly qualified literacy expert to help clean up the many problems in this program.",
469
- "id": "92"
470
- },
471
- "93": {
472
- "label": false,
473
- "text": "needs a buzz cut and a point: I avoided reading this book, not because of the hermaphrodite subject matter, but because I have never read a multigenerational family saga that I liked. Many books let me down in the middle, and this was no exception. The beginning of the book was incredible and harrowing, with momentum and characterization. The post-America nextgens part of the saga was so boring I found myself flipping and flipping - always a bad sign. If there was some kind of larger point to all of that, then I must have missed it. Yes there's the identity duality and trinity themes playing out here: man/woman, greek/turkish/american modern/old world sick/healthy innocent/guilty original/reinvented. But it was almost as if the author was saying - here it is again - get it? I like my fiction much more subtle than this.",
474
- "id": "93"
475
- },
476
- "94": {
477
- "label": false,
478
- "text": "OMG! DO NOT BUY!: I normally don't take the time to submit a review.In this case however, I feel obligated to do so.This is by far one of the worst purchases I have ever made.Here's why.....The contraption is far too bulky.The case's enclosing is unbearable, takes a good minute or so to open it.The texture of the material feels like a cheap toy.The overall design is horrible, something I could make in my basement.For the love of everything sacred, do not buy this thing.",
479
- "id": "94"
480
- },
481
- "95": {
482
- "label": true,
483
- "text": "Good price, good quality: Comparable HDMI cables can be bought for 45 or more. Even though the price is cheap the quality is good, no problems so far.",
484
- "id": "95"
485
- },
486
- "96": {
487
- "label": true,
488
- "text": "Good rock music: This is what i call rock music good beat and good lyrics, don't listen to the other reviews. This cd is one of the best, listen to a few songs and you will get hooked. I recommend this cd its awesome.",
489
- "id": "96"
490
- },
491
- "97": {
492
- "label": false,
493
- "text": "BORING!: This movie is soo boring. How in the hell did this movie make so much at the box office. Do people really want to pay for crappy movies like this. bottom line this is a chick flick nothing is good. And now they are re-releasing this movie with more boring stuff. This is the worst movie ever.",
494
- "id": "97"
495
- },
496
- "98": {
497
- "label": false,
498
- "text": "Already Rusting: Inferior quality. The plating is thin and rust is coming through the finish. Inexcusable for a product that is designed for use in a humid environment.",
499
- "id": "98"
500
- },
501
- "99": {
502
- "label": false,
503
- "text": "confusing internet setup: i wanted a camera that could email photos but this camera will not go out through the router and the manual setup , to punch a hole thru router is confusing.",
504
- "id": "99"
505
- },
506
- "55066581ad334ef5844c6f7707525010": {
507
- "label": true,
508
- "text": "Thought this was super cool, and a really important step in all the physical books' preservation.",
509
- "id": "55066581ad334ef5844c6f7707525010"
510
- },
511
- "fef14d13366f482d9f4e0726b357f178": {
512
- "label": true,
513
- "text": "There are some amazing hikes around Mt. Fuji.",
514
- "id": "fef14d13366f482d9f4e0726b357f178"
515
- },
516
- "70aed7369aa74031a06f5f3155476d7c": {
517
- "label": true,
518
- "text": "Thought this was super cool, and a really important step in preserving all the physical books.",
519
- "id": "70aed7369aa74031a06f5f3155476d7c"
520
- },
521
- "ac65d14b710648b8bf3c2a53caf6ac91": {
522
- "label": false,
523
- "text": "The profits of the business that was most successful were still negative.",
524
- "id": "ac65d14b710648b8bf3c2a53caf6ac91"
525
- },
526
- "ce00e6b1547444259a13c55654e66500": {
527
- "label": true,
528
- "text": "love them best, they reconnect in hysterically funny and emotionally significant ways.",
529
- "id": "ce00e6b1547444259a13c55654e66500"
530
- },
531
- "8943a94d205b43ceb4420d5ab9c5611a": {
532
- "label": true,
533
- "text": "Walt Disney's timeless masterpiece is an extravaganza of sight and sound! See the music come to life, hear the pictures burst into song and experience the excitement that is Fantasia over and over again.",
534
- "id": "8943a94d205b43ceb4420d5ab9c5611a"
535
- },
536
- "6af8fc3dd30d4f8caf5a2929fc88534b": {
537
- "label": false,
538
- "text": "A director struggles with a difficult sex scene between a young actor and actress who can't stand one another. Aided by her loyal assistant, she is hell-bent on getting the scene right without compromise.",
539
- "id": "6af8fc3dd30d4f8caf5a2929fc88534b"
540
- },
541
- "dbe571ed810d40f48170147dcab1c90f": {
542
- "label": false,
543
- "text": "sound created by drawing directly on the soundtrack).",
544
- "id": "dbe571ed810d40f48170147dcab1c90f"
545
- },
546
- "682102dfc5494f03926d16ae947a6250": {
547
- "label": true,
548
- "text": "one of glowing admiration! Written by Mark Toscano",
549
- "id": "682102dfc5494f03926d16ae947a6250"
550
- },
551
- "9b044458bb0e4bd68359e62d5fb4b979": {
552
- "label": false,
553
- "text": "Seth McArdle (Samuel Davis) is a high school senior with an especially full plate. Not only must he navigate the usual social and academic pitfalls of high school, but he has to contend with his young twin sisters, serving as de facto parent in the absence of his deceased mother and deadbeat father. The pressure mounts when the bank calls with a foreclosure warning, and Seth's frustrations spill",
554
- "id": "9b044458bb0e4bd68359e62d5fb4b979"
555
- },
556
- "abf2d24c7d8845769b7368be28f2c25d": {
557
- "label": true,
558
- "text": "Bjork is a beautiful creature and her music is stellar to anything I've ever heard. This DVD is essential for all Bjork fans, because you find something new every time you watch it.",
559
- "id": "abf2d24c7d8845769b7368be28f2c25d"
560
- }
561
- },
562
- "version": 11,
563
- "description": "Positive sentiment"
564
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/concept/lilac/positive-sentiment/sbert.pkl DELETED
Binary file (94.4 kB)
 
data/concept/lilac/profanity/concept.json DELETED
The diff for this file is too large to render. See raw diff
 
data/concept/lilac/profanity/openai.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a97028bbb8a75913874b83c768c5cdc8ad9ec00aba1ce4296429dd7326165ad7
3
- size 3247822
 
 
 
 
data/concept/lilac/profanity/sbert.pkl DELETED
Binary file (844 kB)
 
data/concept/lilac/toxicity/concept.json DELETED
The diff for this file is too large to render. See raw diff
 
data/concept/lilac/toxicity/sbert.pkl DELETED
Binary file (958 kB)
 
data/datasets/local/spotify/data-00000-of-00001.parquet DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:32224657332b09187a737c73ab634f9d14c9ba9a240bd105f1b9819cde2afcef
3
- size 37128682
 
 
 
 
data/datasets/local/spotify/manifest.json DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "files": [
3
- "data-00000-of-00001.parquet"
4
- ],
5
- "data_schema": {
6
- "fields": {
7
- "artist": {
8
- "dtype": "string"
9
- },
10
- "song": {
11
- "dtype": "string"
12
- },
13
- "link": {
14
- "dtype": "string"
15
- },
16
- "text": {
17
- "dtype": "string"
18
- },
19
- "__line_number__": {
20
- "dtype": "int64"
21
- },
22
- "__rowid__": {
23
- "dtype": "string"
24
- }
25
- }
26
- }
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/datasets/local/spotify/settings.json DELETED
@@ -1 +0,0 @@
1
- {"ui": {"media_paths": [["text"]]}}
 
 
data/datasets/local/spotify/text/.concepts/local/aliens/sbert-neg-100.pkl DELETED
Binary file (169 kB)
 
data/datasets/local/spotify/text/lang_detection/data-00000-of-00001.parquet DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0f1555427c8dc3b2f1e9310f5e71b46297e607f710365e107c73c894d5a8e1b0
3
- size 2033407
 
 
 
 
data/datasets/local/spotify/text/lang_detection/signal_manifest.json DELETED
@@ -1,36 +0,0 @@
1
- {
2
- "files": [
3
- "data-00000-of-00001.parquet"
4
- ],
5
- "parquet_id": "lang_detection(text)",
6
- "data_schema": {
7
- "fields": {
8
- "__rowid__": {
9
- "dtype": "string"
10
- },
11
- "text": {
12
- "fields": {
13
- "lang_detection": {
14
- "repeated_field": {
15
- "fields": {
16
- "lang_code": {
17
- "dtype": "string"
18
- }
19
- },
20
- "dtype": "string_span"
21
- },
22
- "signal": {
23
- "signal_name": "lang_detection"
24
- }
25
- }
26
- }
27
- }
28
- }
29
- },
30
- "signal": {
31
- "signal_name": "lang_detection"
32
- },
33
- "enriched_path": [
34
- "text"
35
- ]
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/datasets/local/spotify/text/sbert/data-00000-of-00001.parquet DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9796beb630cc3503f3c2ac9db8f71e4c1604570836d78bbf364e801cd427c39e
3
- size 2709987
 
 
 
 
data/datasets/local/spotify/text/sbert/embedding/local/outerspace/v34/data-00000-of-00001.parquet DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d1ba0fe68cc02849b0a20b7f72047c8e9cb8e5ef5b57b0cd642fa0b0be8a6e06
3
- size 3340135
 
 
 
 
data/datasets/local/spotify/text/sbert/embedding/local/outerspace/v34/signal_manifest.json DELETED
@@ -1,64 +0,0 @@
1
- {
2
- "files": [
3
- "data-00000-of-00001.parquet"
4
- ],
5
- "parquet_id": "local/outerspace/v34(text.sbert.*.embedding)",
6
- "data_schema": {
7
- "fields": {
8
- "__rowid__": {
9
- "dtype": "string"
10
- },
11
- "text": {
12
- "fields": {
13
- "sbert": {
14
- "repeated_field": {
15
- "fields": {
16
- "embedding": {
17
- "fields": {
18
- "local/outerspace/v34": {
19
- "dtype": "float32",
20
- "signal": {
21
- "signal_name": "concept_score",
22
- "embedding": "sbert",
23
- "namespace": "local",
24
- "concept_name": "outerspace",
25
- "draft": "main",
26
- "num_negative_examples": 100
27
- },
28
- "bins": [
29
- [
30
- "Not in concept",
31
- null,
32
- 0.5
33
- ],
34
- [
35
- "In concept",
36
- 0.5,
37
- null
38
- ]
39
- ]
40
- }
41
- }
42
- }
43
- }
44
- }
45
- }
46
- }
47
- }
48
- }
49
- },
50
- "signal": {
51
- "signal_name": "concept_score",
52
- "embedding": "sbert",
53
- "namespace": "local",
54
- "concept_name": "outerspace",
55
- "draft": "main",
56
- "num_negative_examples": 100
57
- },
58
- "enriched_path": [
59
- "text",
60
- "sbert",
61
- "*",
62
- "embedding"
63
- ]
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.keys.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d5df43291782b8c731d4ce56537946654c642a01dc9a4e37de394836362f6b45
3
- size 3727400
 
 
 
 
data/datasets/local/spotify/text/sbert/embeddings-00000-of-00001.npy DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:94e10c23d7229541e1f60b791a659d13673b10a03649abf0ae092e0e18c5aee3
3
- size 170446976
 
 
 
 
data/datasets/local/spotify/text/sbert/signal_manifest.json DELETED
@@ -1,37 +0,0 @@
1
- {
2
- "files": [
3
- "data-00000-of-00001.parquet"
4
- ],
5
- "parquet_id": "sbert(text)",
6
- "data_schema": {
7
- "fields": {
8
- "__rowid__": {
9
- "dtype": "string"
10
- },
11
- "text": {
12
- "fields": {
13
- "sbert": {
14
- "repeated_field": {
15
- "fields": {
16
- "embedding": {
17
- "dtype": "embedding"
18
- }
19
- },
20
- "dtype": "string_span"
21
- },
22
- "signal": {
23
- "signal_name": "sbert"
24
- }
25
- }
26
- }
27
- }
28
- }
29
- },
30
- "signal": {
31
- "signal_name": "sbert"
32
- },
33
- "enriched_path": [
34
- "text"
35
- ],
36
- "embedding_filename_prefix": "embeddings-00000-of-00001"
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lilac/__init__.py CHANGED
@@ -1,3 +1,31 @@
 
 
 
 
 
 
1
  from .server import start_server, stop_server
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- __all__ = ['start_server', 'stop_server']
 
 
 
 
 
 
1
+ from importlib import metadata
2
+
3
+ from .data import * # noqa: F403
4
+ from .data.dataset_duckdb import DatasetDuckDB
5
+ from .data_loader import create_dataset
6
+ from .db_manager import get_dataset, set_default_dataset_cls
7
  from .server import start_server, stop_server
8
+ from .signals import * # noqa: F403
9
+ from .signals.default_signals import register_default_signals
10
+ from .sources import * # noqa: F403
11
+ from .sources.default_sources import register_default_sources
12
+
13
+ try:
14
+ __version__ = metadata.version('lilacai')
15
+ except metadata.PackageNotFoundError:
16
+ __version__ = ''
17
+
18
+ register_default_sources()
19
+ register_default_signals()
20
+ set_default_dataset_cls(DatasetDuckDB)
21
+
22
+ # Avoids polluting the results of dir(__package__).
23
+ del (metadata, register_default_sources, register_default_signals, set_default_dataset_cls,
24
+ DatasetDuckDB)
25
 
26
+ __all__ = [
27
+ 'start_server',
28
+ 'stop_server',
29
+ 'create_dataset',
30
+ 'get_dataset',
31
+ ]
lilac/auth.py CHANGED
@@ -51,7 +51,7 @@ class UserInfo(BaseModel):
51
 
52
  class AuthenticationInfo(BaseModel):
53
  """Authentication information for the user."""
54
- user: Optional[UserInfo]
55
  access: UserAccess
56
  auth_enabled: bool
57
 
 
51
 
52
  class AuthenticationInfo(BaseModel):
53
  """Authentication information for the user."""
54
+ user: Optional[UserInfo] = None
55
  access: UserAccess
56
  auth_enabled: bool
57
 
lilac/cli.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Lilac CLI."""
2
+
3
+ import click
4
+
5
+ from . import __version__
6
+ from .server import start_server
7
+
8
+
9
+ @click.command()
10
+ @click.option(
11
+ '--host',
12
+ help='The host address where the web server will listen to.',
13
+ default='0.0.0.0',
14
+ type=str)
15
+ @click.option('--port', help='The port number of the web-server', type=int, default=5432)
16
+ def start(host: str, port: int) -> None:
17
+ """Starts the Lilac web server."""
18
+ start_server(host=host, port=port, open=True)
19
+
20
+
21
+ @click.command()
22
+ def version() -> None:
23
+ """Prints the version of Lilac."""
24
+ print(__version__)
25
+
26
+
27
+ @click.group()
28
+ def cli() -> None:
29
+ """Lilac CLI."""
30
+ pass
31
+
32
+
33
+ cli.add_command(start)
34
+ cli.add_command(version)
35
+
36
+ if __name__ == '__main__':
37
+ cli()
lilac/concepts/concept.py CHANGED
@@ -8,7 +8,7 @@ import numpy as np
8
  from joblib import Parallel, delayed
9
  from pydantic import BaseModel, validator
10
  from scipy.interpolate import interp1d
11
- from sklearn.base import BaseEstimator, clone
12
  from sklearn.exceptions import NotFittedError
13
  from sklearn.linear_model import LogisticRegression
14
  from sklearn.metrics import precision_recall_curve, roc_auc_score
@@ -82,9 +82,9 @@ DRAFT_MAIN = 'main'
82
  class ExampleIn(BaseModel):
83
  """An example in a concept without the id (used for adding new examples)."""
84
  label: bool
85
- text: Optional[str]
86
- img: Optional[bytes]
87
- origin: Optional[ExampleOrigin]
88
  # The name of the draft to put the example in. If None, puts it in the main draft.
89
  draft: Optional[DraftId] = DRAFT_MAIN
90
 
@@ -175,7 +175,7 @@ class LogisticEmbeddingModel:
175
  return np.random.rand(len(embeddings))
176
 
177
  def _setup_training(
178
- self, X_train: np.ndarray, labels: list[bool],
179
  implicit_negatives: Optional[np.ndarray]) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
180
  num_pos_labels = len([y for y in labels if y])
181
  num_neg_labels = len([y for y in labels if not y])
@@ -184,7 +184,7 @@ class LogisticEmbeddingModel:
184
 
185
  if implicit_negatives is not None:
186
  num_implicit_labels = len(implicit_negatives)
187
- implicit_labels = [False] * num_implicit_labels
188
  X_train = np.concatenate([implicit_negatives, X_train])
189
  y_train = np.concatenate([implicit_labels, y_train])
190
  sample_weights = [1.0 / num_implicit_labels] * num_implicit_labels + sample_weights
@@ -220,11 +220,11 @@ class LogisticEmbeddingModel:
220
  self, embeddings: np.ndarray, labels: list[bool],
221
  implicit_negatives: Optional[np.ndarray]) -> tuple[Optional[ConceptMetrics], float]:
222
  """Return the concept metrics."""
223
- labels = np.array(labels)
224
- n_splits = min(len(labels), MAX_NUM_CROSS_VAL_MODELS)
225
  fold = KFold(n_splits, shuffle=True, random_state=42)
226
 
227
- def _fit_and_score(model: BaseEstimator, X_train: np.ndarray, y_train: np.ndarray,
228
  sample_weights: np.ndarray, X_test: np.ndarray,
229
  y_test: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
230
  if len(set(y_train)) < 2:
@@ -236,9 +236,9 @@ class LogisticEmbeddingModel:
236
  # Compute the metrics for each validation fold in parallel.
237
  jobs: list[Callable] = []
238
  for (train_index, test_index) in fold.split(embeddings):
239
- X_train, y_train = embeddings[train_index], labels[train_index]
240
  X_train, y_train, sample_weights = self._setup_training(X_train, y_train, implicit_negatives)
241
- X_test, y_test = embeddings[test_index], labels[test_index]
242
  model = clone(self._model)
243
  jobs.append(delayed(_fit_and_score)(model, X_train, y_train, sample_weights, X_test, y_test))
244
  results = Parallel(n_jobs=-1)(jobs)
@@ -261,7 +261,7 @@ class LogisticEmbeddingModel:
261
  f1=max_f1,
262
  precision=max_f1_prec,
263
  recall=max_f1_recall,
264
- roc_auc=roc_auc_val,
265
  overall=_get_overall_score(max_f1))
266
  return metrics, max_f1_thresh
267
 
 
8
  from joblib import Parallel, delayed
9
  from pydantic import BaseModel, validator
10
  from scipy.interpolate import interp1d
11
+ from sklearn.base import clone
12
  from sklearn.exceptions import NotFittedError
13
  from sklearn.linear_model import LogisticRegression
14
  from sklearn.metrics import precision_recall_curve, roc_auc_score
 
82
  class ExampleIn(BaseModel):
83
  """An example in a concept without the id (used for adding new examples)."""
84
  label: bool
85
+ text: Optional[str] = None
86
+ img: Optional[bytes] = None
87
+ origin: Optional[ExampleOrigin] = None
88
  # The name of the draft to put the example in. If None, puts it in the main draft.
89
  draft: Optional[DraftId] = DRAFT_MAIN
90
 
 
175
  return np.random.rand(len(embeddings))
176
 
177
  def _setup_training(
178
+ self, X_train: np.ndarray, labels: Union[list[bool], np.ndarray],
179
  implicit_negatives: Optional[np.ndarray]) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
180
  num_pos_labels = len([y for y in labels if y])
181
  num_neg_labels = len([y for y in labels if not y])
 
184
 
185
  if implicit_negatives is not None:
186
  num_implicit_labels = len(implicit_negatives)
187
+ implicit_labels = np.array([False] * num_implicit_labels)
188
  X_train = np.concatenate([implicit_negatives, X_train])
189
  y_train = np.concatenate([implicit_labels, y_train])
190
  sample_weights = [1.0 / num_implicit_labels] * num_implicit_labels + sample_weights
 
220
  self, embeddings: np.ndarray, labels: list[bool],
221
  implicit_negatives: Optional[np.ndarray]) -> tuple[Optional[ConceptMetrics], float]:
222
  """Return the concept metrics."""
223
+ labels_np = np.array(labels)
224
+ n_splits = min(len(labels_np), MAX_NUM_CROSS_VAL_MODELS)
225
  fold = KFold(n_splits, shuffle=True, random_state=42)
226
 
227
+ def _fit_and_score(model: LogisticRegression, X_train: np.ndarray, y_train: np.ndarray,
228
  sample_weights: np.ndarray, X_test: np.ndarray,
229
  y_test: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
230
  if len(set(y_train)) < 2:
 
236
  # Compute the metrics for each validation fold in parallel.
237
  jobs: list[Callable] = []
238
  for (train_index, test_index) in fold.split(embeddings):
239
+ X_train, y_train = embeddings[train_index], labels_np[train_index]
240
  X_train, y_train, sample_weights = self._setup_training(X_train, y_train, implicit_negatives)
241
+ X_test, y_test = embeddings[test_index], labels_np[test_index]
242
  model = clone(self._model)
243
  jobs.append(delayed(_fit_and_score)(model, X_train, y_train, sample_weights, X_test, y_test))
244
  results = Parallel(n_jobs=-1)(jobs)
 
261
  f1=max_f1,
262
  precision=max_f1_prec,
263
  recall=max_f1_recall,
264
+ roc_auc=float(roc_auc_val),
265
  overall=_get_overall_score(max_f1))
266
  return metrics, max_f1_thresh
267
 
lilac/concepts/db_concept.py CHANGED
@@ -340,7 +340,8 @@ class DiskConceptModelDB(ConceptModelDB):
340
  for dir in dirs:
341
  dir = os.path.relpath(dir, datasets_path)
342
  dataset_namespace, dataset_name, *path, _, _, _, _ = Path(dir).parts
343
- result.append(ConceptColumnInfo(namespace=dataset_namespace, name=dataset_name, path=path))
 
344
  return result
345
 
346
 
 
340
  for dir in dirs:
341
  dir = os.path.relpath(dir, datasets_path)
342
  dataset_namespace, dataset_name, *path, _, _, _, _ = Path(dir).parts
343
+ result.append(
344
+ ConceptColumnInfo(namespace=dataset_namespace, name=dataset_name, path=tuple(path)))
345
  return result
346
 
347
 
lilac/config.py CHANGED
@@ -20,35 +20,27 @@ EnvironmentKeys = Union[Literal['LILAC_DATA_PATH'],
20
  Literal['DUCKDB_USE_VIEWS'],
21
  # Debugging
22
  Literal['DEBUG'], Literal['DISABLE_LOGS']]
23
- _ENV: dict[str, Optional[str]] = {}
24
- # Private config variables. Saved separately to remove private env variables from tests.
25
- _ENV_LOCAL: dict[str, Optional[str]] = {}
26
 
27
 
28
  def env(key: EnvironmentKeys, default: Optional[Any] = None) -> Any:
29
  """Return the value of an environment variable."""
30
  global _ENV
31
- global _ENV_LOCAL
32
  first_load = False
33
  # This is done lazily so we can prevent loading local environment variables when testing. The
34
  # 'PYTEST_CURRENT_TEST' environment variable is only set after module initialization by pytest.
35
- if not _ENV or _ENV_LOCAL:
 
 
36
  _ENV = {
37
  **dotenv_values('.env'), # load shared variables
38
  **dotenv_values('.env.demo'), # load demo-specific environment flags.
39
- }
40
- _ENV_LOCAL = {
41
- # Load locally set variables when not in a testing environment.
42
- **(dotenv_values('.env.local') if 'PYTEST_CURRENT_TEST' not in os.environ else {}),
43
  }
44
  first_load = True
45
 
46
  # Override the file based configs with the current environment, in case flags have changed.
47
- environment = {
48
- **_ENV,
49
- **(_ENV_LOCAL if 'PYTEST_CURRENT_TEST' not in os.environ else {}),
50
- **os.environ
51
- }
52
 
53
  if first_load:
54
  if environment.get('LILAC_AUTH_ENABLED', None):
 
20
  Literal['DUCKDB_USE_VIEWS'],
21
  # Debugging
22
  Literal['DEBUG'], Literal['DISABLE_LOGS']]
23
+ _ENV: Optional[dict[str, Optional[str]]] = None
 
 
24
 
25
 
26
  def env(key: EnvironmentKeys, default: Optional[Any] = None) -> Any:
27
  """Return the value of an environment variable."""
28
  global _ENV
 
29
  first_load = False
30
  # This is done lazily so we can prevent loading local environment variables when testing. The
31
  # 'PYTEST_CURRENT_TEST' environment variable is only set after module initialization by pytest.
32
+
33
+ if _ENV is None:
34
+ in_test = os.environ.get('LILAC_TEST', None)
35
  _ENV = {
36
  **dotenv_values('.env'), # load shared variables
37
  **dotenv_values('.env.demo'), # load demo-specific environment flags.
38
+ **(dotenv_values('.env.local') if not in_test else {})
 
 
 
39
  }
40
  first_load = True
41
 
42
  # Override the file based configs with the current environment, in case flags have changed.
43
+ environment = {**_ENV, **os.environ}
 
 
 
 
44
 
45
  if first_load:
46
  if environment.get('LILAC_AUTH_ENABLED', None):
lilac/data/__init__.py CHANGED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from .dataset import ConceptQuery, KeywordQuery, Search, SemanticQuery
2
+
3
+ __all__ = [
4
+ 'Search',
5
+ 'KeywordQuery',
6
+ 'ConceptQuery',
7
+ 'SemanticQuery',
8
+ ]
lilac/data/dataset.py CHANGED
@@ -1,6 +1,7 @@
1
  """The interface for the database."""
2
  import abc
3
  import enum
 
4
  from concurrent.futures import ThreadPoolExecutor
5
  from datetime import datetime
6
  from typing import Any, Iterator, Literal, Optional, Sequence, Union
@@ -13,7 +14,7 @@ from pydantic import StrictBool, StrictBytes, StrictFloat, StrictInt, StrictStr,
13
  from ..auth import UserInfo
14
  from ..embeddings.vector_store import VectorStore
15
  from ..schema import VALUE_KEY, Bin, DataType, Path, PathTuple, Schema, normalize_path
16
- from ..signals.signal import Signal, resolve_signal
17
  from ..tasks import TaskStepId
18
 
19
  # Threshold for rejecting certain queries (e.g. group by) for columns with large cardinality.
@@ -45,11 +46,11 @@ class StatsResult(BaseModel):
45
  approx_count_distinct: int
46
 
47
  # Defined for ordinal features.
48
- min_val: Optional[Union[float, datetime]]
49
- max_val: Optional[Union[float, datetime]]
50
 
51
  # Defined for text features.
52
- avg_text_length: Optional[float]
53
 
54
 
55
  class MediaResult(BaseModel):
@@ -103,9 +104,9 @@ class SortResult(BaseModel):
103
  # The sort order.
104
  order: SortOrder
105
  # The alias of the column if it was aliased.
106
- alias: Optional[str]
107
  # The search index if the sort is by a search.
108
- search_index: Optional[int]
109
 
110
 
111
  class SearchResultInfo(BaseModel):
@@ -115,13 +116,13 @@ class SearchResultInfo(BaseModel):
115
  # The resulting column that was searched.
116
  result_path: PathTuple
117
  # The alias of the UDF.
118
- alias: Optional[str]
119
 
120
 
121
  class SelectRowsSchemaUDF(BaseModel):
122
  """The UDF for a select rows schema query."""
123
  path: PathTuple
124
- alias: Optional[str]
125
 
126
 
127
  class SelectRowsSchemaResult(BaseModel):
@@ -129,13 +130,13 @@ class SelectRowsSchemaResult(BaseModel):
129
  data_schema: Schema
130
  udfs: list[SelectRowsSchemaUDF] = []
131
  search_results: list[SearchResultInfo] = []
132
- sorts: Optional[list[SortResult]]
133
 
134
 
135
  class Column(BaseModel):
136
  """A column in the dataset."""
137
  path: PathTuple
138
- alias: Optional[str] # This is the renamed column during querying and response.
139
 
140
  # Defined when the feature is another column.
141
  signal_udf: Optional[Signal] = None
@@ -169,7 +170,7 @@ class DatasetUISettings(BaseModel):
169
 
170
  class DatasetSettings(BaseModel):
171
  """The persistent settings for a dataset."""
172
- ui: Optional[DatasetUISettings]
173
  preferred_embedding: Optional[str] = None
174
 
175
 
@@ -219,20 +220,20 @@ SearchValue = StrictStr
219
 
220
  class KeywordQuery(BaseModel):
221
  """A keyword search query on a column."""
222
- type: Literal['keyword']
223
  search: SearchValue
224
 
225
 
226
  class SemanticQuery(BaseModel):
227
  """A semantic search on a column."""
228
- type: Literal['semantic']
229
  search: SearchValue
230
  embedding: str
231
 
232
 
233
  class ConceptQuery(BaseModel):
234
  """A concept search query on a column."""
235
- type: Literal['concept']
236
  concept_namespace: str
237
  concept_name: str
238
  embedding: str
@@ -247,6 +248,9 @@ class Search(BaseModel):
247
  class Dataset(abc.ABC):
248
  """The database implementation to query a dataset."""
249
 
 
 
 
250
  def __init__(self, namespace: str, dataset_name: str):
251
  """Initialize a dataset.
252
 
@@ -298,6 +302,11 @@ class Dataset(abc.ABC):
298
  """
299
  pass
300
 
 
 
 
 
 
301
  @abc.abstractmethod
302
  def delete_signal(self, signal_path: Path) -> None:
303
  """Delete a computed signal from the dataset.
@@ -411,6 +420,39 @@ class Dataset(abc.ABC):
411
  """
412
  pass
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
 
415
  def default_settings(dataset: Dataset) -> DatasetSettings:
416
  """Gets the default settings for a dataset."""
 
1
  """The interface for the database."""
2
  import abc
3
  import enum
4
+ import pathlib
5
  from concurrent.futures import ThreadPoolExecutor
6
  from datetime import datetime
7
  from typing import Any, Iterator, Literal, Optional, Sequence, Union
 
14
  from ..auth import UserInfo
15
  from ..embeddings.vector_store import VectorStore
16
  from ..schema import VALUE_KEY, Bin, DataType, Path, PathTuple, Schema, normalize_path
17
+ from ..signals.signal import Signal, TextEmbeddingSignal, get_signal_by_type, resolve_signal
18
  from ..tasks import TaskStepId
19
 
20
  # Threshold for rejecting certain queries (e.g. group by) for columns with large cardinality.
 
46
  approx_count_distinct: int
47
 
48
  # Defined for ordinal features.
49
+ min_val: Optional[Union[float, datetime]] = None
50
+ max_val: Optional[Union[float, datetime]] = None
51
 
52
  # Defined for text features.
53
+ avg_text_length: Optional[float] = None
54
 
55
 
56
  class MediaResult(BaseModel):
 
104
  # The sort order.
105
  order: SortOrder
106
  # The alias of the column if it was aliased.
107
+ alias: Optional[str] = None
108
  # The search index if the sort is by a search.
109
+ search_index: Optional[int] = None
110
 
111
 
112
  class SearchResultInfo(BaseModel):
 
116
  # The resulting column that was searched.
117
  result_path: PathTuple
118
  # The alias of the UDF.
119
+ alias: Optional[str] = None
120
 
121
 
122
  class SelectRowsSchemaUDF(BaseModel):
123
  """The UDF for a select rows schema query."""
124
  path: PathTuple
125
+ alias: Optional[str] = None
126
 
127
 
128
  class SelectRowsSchemaResult(BaseModel):
 
130
  data_schema: Schema
131
  udfs: list[SelectRowsSchemaUDF] = []
132
  search_results: list[SearchResultInfo] = []
133
+ sorts: Optional[list[SortResult]] = None
134
 
135
 
136
  class Column(BaseModel):
137
  """A column in the dataset."""
138
  path: PathTuple
139
+ alias: Optional[str] = None # This is the renamed column during querying and response.
140
 
141
  # Defined when the feature is another column.
142
  signal_udf: Optional[Signal] = None
 
170
 
171
  class DatasetSettings(BaseModel):
172
  """The persistent settings for a dataset."""
173
+ ui: Optional[DatasetUISettings] = None
174
  preferred_embedding: Optional[str] = None
175
 
176
 
 
220
 
221
  class KeywordQuery(BaseModel):
222
  """A keyword search query on a column."""
223
+ type: Literal['keyword'] = 'keyword'
224
  search: SearchValue
225
 
226
 
227
  class SemanticQuery(BaseModel):
228
  """A semantic search on a column."""
229
+ type: Literal['semantic'] = 'semantic'
230
  search: SearchValue
231
  embedding: str
232
 
233
 
234
  class ConceptQuery(BaseModel):
235
  """A concept search query on a column."""
236
+ type: Literal['concept'] = 'concept'
237
  concept_namespace: str
238
  concept_name: str
239
  embedding: str
 
248
  class Dataset(abc.ABC):
249
  """The database implementation to query a dataset."""
250
 
251
+ namespace: str
252
+ dataset_name: str
253
+
254
  def __init__(self, namespace: str, dataset_name: str):
255
  """Initialize a dataset.
256
 
 
302
  """
303
  pass
304
 
305
+ def compute_embedding(self, embedding_name: str, path: Path) -> None:
306
+ """Compute an embedding for a given field path."""
307
+ signal = get_signal_by_type(embedding_name, TextEmbeddingSignal)()
308
+ self.compute_signal(signal, path)
309
+
310
  @abc.abstractmethod
311
  def delete_signal(self, signal_path: Path) -> None:
312
  """Delete a computed signal from the dataset.
 
420
  """
421
  pass
422
 
423
+ @abc.abstractmethod
424
+ def to_json(self, filepath: Union[str, pathlib.Path], jsonl: bool = True) -> None:
425
+ """Export the dataset to a JSON file.
426
+
427
+ Args:
428
+ filepath: The path to the file to export to.
429
+ jsonl: Whether to export to JSONL or JSON.
430
+ """
431
+ pass
432
+
433
+ @abc.abstractmethod
434
+ def to_pandas(self) -> pd.DataFrame:
435
+ """Export the dataset to a pandas DataFrame."""
436
+ pass
437
+
438
+ @abc.abstractmethod
439
+ def to_parquet(self, filepath: Union[str, pathlib.Path]) -> None:
440
+ """Export the dataset to a parquet file.
441
+
442
+ Args:
443
+ filepath: The path to the file to export to.
444
+ """
445
+ pass
446
+
447
+ @abc.abstractmethod
448
+ def to_csv(self, filepath: Union[str, pathlib.Path]) -> None:
449
+ """Export the dataset to a csv file.
450
+
451
+ Args:
452
+ filepath: The path to the file to export to.
453
+ """
454
+ pass
455
+
456
 
457
  def default_settings(dataset: Dataset) -> DatasetSettings:
458
  """Gets the default settings for a dataset."""
lilac/data/dataset_duckdb.py CHANGED
@@ -3,6 +3,7 @@ import functools
3
  import glob
4
  import math
5
  import os
 
6
  import re
7
  import shutil
8
  import threading
@@ -129,7 +130,7 @@ class DuckDBSearchUDF(BaseModel):
129
  udf: Column
130
  search_path: PathTuple
131
  output_path: PathTuple
132
- sort: Optional[tuple[PathTuple, SortOrder]]
133
 
134
 
135
  class DuckDBSearchUDFs(BaseModel):
@@ -339,21 +340,26 @@ class DatasetDuckDB(Dataset):
339
  new_steps = len(signals_to_compute)
340
  # Setup the task steps so the task progress indicator knows the number of steps before they are
341
  # computed.
 
 
342
  if task_step_id:
343
  (task_id, step_id) = task_step_id
344
- if new_steps:
345
  # Make a step for the parent.
346
  set_worker_steps(task_id, [TaskStepInfo()] * (new_steps + 1))
347
 
348
  for i, (new_path, signal) in enumerate(signals_to_compute):
349
  if new_path not in manifest.data_schema.leafs:
350
  self.compute_signal(
351
- signal, source_path, task_step_id=(task_id, i) if task_step_id else None)
352
 
353
  if is_value_path:
354
  new_path = (*new_path, VALUE_KEY)
355
 
356
- return (new_path, (task_id, step_id + new_steps) if task_step_id else None)
 
 
 
357
 
358
  @override
359
  def compute_signal(self,
@@ -363,6 +369,10 @@ class DatasetDuckDB(Dataset):
363
  source_path = normalize_path(leaf_path)
364
  manifest = self.manifest()
365
 
 
 
 
 
366
  # Prepare the dependencies of this signal.
367
  signal_source_path, task_step_id = self._prepare_signal(
368
  signal, source_path, manifest, compute_dependencies=True, task_step_id=task_step_id)
@@ -426,7 +436,7 @@ class DatasetDuckDB(Dataset):
426
  signal_manifest_filepath = os.path.join(output_dir, SIGNAL_MANIFEST_FILENAME)
427
  with open_file(signal_manifest_filepath, 'w') as f:
428
  f.write(signal_manifest.json(exclude_none=True, indent=2))
429
- log(f'Wrote signal manifest to {signal_manifest_filepath}')
430
 
431
  @override
432
  def delete_signal(self, signal_path: Path) -> None:
@@ -574,6 +584,7 @@ class DatasetDuckDB(Dataset):
574
  if leaf.dtype == DataType.STRING:
575
  avg_length_query = ', avg(length(val)) as avgTextLength'
576
 
 
577
  if leaf.dtype == DataType.BOOLEAN:
578
  approx_count_distinct = 2
579
  else:
@@ -595,7 +606,7 @@ class DatasetDuckDB(Dataset):
595
  result = StatsResult(
596
  path=path, total_count=total_count, approx_count_distinct=approx_count_distinct)
597
 
598
- if leaf.dtype == DataType.STRING:
599
  result.avg_text_length = row[1]
600
 
601
  # Compute min/max values for ordinal leafs, without sampling the data.
@@ -736,9 +747,6 @@ class DatasetDuckDB(Dataset):
736
 
737
  def _merge_sorts(self, search_udfs: list[DuckDBSearchUDF], sort_by: Optional[Sequence[Path]],
738
  sort_order: Optional[SortOrder]) -> list[SortResult]:
739
- if sort_by and not sort_order:
740
- raise ValueError('`sort_order` is required when `sort_by` is specified.')
741
-
742
  # True when the user has explicitly sorted by the alias of a search UDF (e.g. in ASC order).
743
  is_explicit_search_sort = False
744
  for sort_by_path in sort_by or []:
@@ -749,6 +757,8 @@ class DatasetDuckDB(Dataset):
749
 
750
  sort_results: list[SortResult] = []
751
  if sort_by and not is_explicit_search_sort:
 
 
752
  # If the user has explicitly set a sort by, and it's not a search UDF alias, override.
753
  sort_results = [
754
  SortResult(path=normalize_path(sort_by), order=sort_order) for sort_by in sort_by if sort_by
@@ -853,7 +863,7 @@ class DatasetDuckDB(Dataset):
853
 
854
  topk_udf_col = self._topk_udf_to_sort_by(udf_columns, sort_by, limit, sort_order)
855
  if topk_udf_col:
856
- key_prefixes: Optional[list[VectorKey]] = None
857
  if where_query:
858
  # If there are filters, we need to send UUIDs to the top k query.
859
  df = con.execute(f'SELECT {UUID_COLUMN} FROM t {where_query}').df()
@@ -982,7 +992,7 @@ class DatasetDuckDB(Dataset):
982
  signal_column = list(temp_signal_cols.keys())[0]
983
  input = df[signal_column]
984
 
985
- with DebugTimer(f'Computing signal "{signal}"'):
986
  signal.setup()
987
 
988
  if signal.compute_type in [SignalInputType.TEXT_EMBEDDING]:
@@ -998,7 +1008,7 @@ class DatasetDuckDB(Dataset):
998
  signal_out,
999
  task_step_id=task_step_id,
1000
  estimated_len=len(flat_keys),
1001
- step_description=f'Computing {signal.key()}...')
1002
  df[signal_column] = unflatten(signal_out, input)
1003
  else:
1004
  num_rich_data = count_primitives(input)
@@ -1011,12 +1021,12 @@ class DatasetDuckDB(Dataset):
1011
  signal_out,
1012
  task_step_id=task_step_id,
1013
  estimated_len=num_rich_data,
1014
- step_description=f'Computing {signal.key()}...')
1015
  signal_out_list = list(signal_out)
1016
  if signal_column in temp_column_to_offset_column:
1017
  offset_column_name, field = temp_column_to_offset_column[signal_column]
1018
- nested_spans: Iterator[Item] = df[offset_column_name]
1019
- flat_spans = list(flatten(nested_spans))
1020
  for span, item in zip(flat_spans, signal_out_list):
1021
  _offset_any_span(cast(int, span[VALUE_KEY][TEXT_SPAN_START_FEATURE]), item, field)
1022
 
@@ -1261,19 +1271,20 @@ class DatasetDuckDB(Dataset):
1261
  """Create a UDF for each search for finding the location of the text with spans."""
1262
  search_udfs: list[DuckDBSearchUDF] = []
1263
  for search in searches:
 
1264
  if search.query.type == 'keyword':
1265
- udf = Column(path=search.path, signal_udf=SubstringSignal(query=search.query.search))
1266
  search_udfs.append(
1267
  DuckDBSearchUDF(
1268
  udf=udf,
1269
- search_path=search.path,
1270
  output_path=(*_col_destination_path(udf), PATH_WILDCARD)))
1271
  elif search.query.type == 'semantic' or search.query.type == 'concept':
1272
  embedding = search.query.embedding
1273
  if not embedding:
1274
  raise ValueError(f'Please provide an embedding for semantic search. Got search: {search}')
1275
 
1276
- embedding_path = (*search.path, embedding, PATH_WILDCARD, EMBEDDING_KEY)
1277
  try:
1278
  manifest.data_schema.get_field(embedding_path)
1279
  except Exception as e:
@@ -1282,7 +1293,7 @@ class DatasetDuckDB(Dataset):
1282
  f'Please compute the embedding index before issuing a {search.query.type} query.'
1283
  ) from e
1284
 
1285
- search_signal: Signal
1286
  if search.query.type == 'semantic':
1287
  search_signal = SemanticSimilaritySignal(
1288
  query=search.query.search, embedding=search.query.embedding)
@@ -1295,11 +1306,11 @@ class DatasetDuckDB(Dataset):
1295
  # Add the label UDF.
1296
  concept_labels_signal = ConceptLabelsSignal(
1297
  namespace=search.query.concept_namespace, concept_name=search.query.concept_name)
1298
- concept_labels_udf = Column(path=search.path, signal_udf=concept_labels_signal)
1299
  search_udfs.append(
1300
  DuckDBSearchUDF(
1301
  udf=concept_labels_udf,
1302
- search_path=search.path,
1303
  output_path=_col_destination_path(concept_labels_udf),
1304
  sort=None))
1305
 
@@ -1309,7 +1320,7 @@ class DatasetDuckDB(Dataset):
1309
  search_udfs.append(
1310
  DuckDBSearchUDF(
1311
  udf=udf,
1312
- search_path=search.path,
1313
  output_path=_col_destination_path(udf),
1314
  sort=(output_path, SortOrder.DESC)))
1315
  else:
@@ -1429,6 +1440,25 @@ class DatasetDuckDB(Dataset):
1429
  f'{_escape_col_name(path_comp)}' if quote_each_part else str(path_comp) for path_comp in path
1430
  ])
1431
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1432
 
1433
  def _escape_string_literal(string: str) -> str:
1434
  string = string.replace("'", "''")
@@ -1555,7 +1585,7 @@ class SignalManifest(BaseModel):
1555
  enriched_path: PathTuple
1556
 
1557
  # The filename prefix for the embedding. Present when the signal is an embedding.
1558
- embedding_filename_prefix: Optional[str]
1559
 
1560
  @validator('signal', pre=True)
1561
  def parse_signal(cls, signal: dict) -> Signal:
@@ -1679,6 +1709,8 @@ def _make_schema_from_path(path: PathTuple, field: Field) -> Schema:
1679
  field = Field(repeated_field=field)
1680
  else:
1681
  field = Field(fields={sub_path: field})
 
 
1682
  return Schema(fields=field.fields)
1683
 
1684
 
 
3
  import glob
4
  import math
5
  import os
6
+ import pathlib
7
  import re
8
  import shutil
9
  import threading
 
130
  udf: Column
131
  search_path: PathTuple
132
  output_path: PathTuple
133
+ sort: Optional[tuple[PathTuple, SortOrder]] = None
134
 
135
 
136
  class DuckDBSearchUDFs(BaseModel):
 
340
  new_steps = len(signals_to_compute)
341
  # Setup the task steps so the task progress indicator knows the number of steps before they are
342
  # computed.
343
+ task_id: Optional[str] = None
344
+ step_id: Optional[int] = None
345
  if task_step_id:
346
  (task_id, step_id) = task_step_id
347
+ if task_id != '' and new_steps:
348
  # Make a step for the parent.
349
  set_worker_steps(task_id, [TaskStepInfo()] * (new_steps + 1))
350
 
351
  for i, (new_path, signal) in enumerate(signals_to_compute):
352
  if new_path not in manifest.data_schema.leafs:
353
  self.compute_signal(
354
+ signal, source_path, task_step_id=(task_id, i) if task_id is not None else None)
355
 
356
  if is_value_path:
357
  new_path = (*new_path, VALUE_KEY)
358
 
359
+ new_task_id: Optional[TaskStepId] = None
360
+ if task_id is not None and step_id is not None:
361
+ new_task_id = (task_id, step_id + new_steps)
362
+ return (new_path, new_task_id)
363
 
364
  @override
365
  def compute_signal(self,
 
369
  source_path = normalize_path(leaf_path)
370
  manifest = self.manifest()
371
 
372
+ if task_step_id is None:
373
+ # Make a dummy task step so we report progress via tqdm.
374
+ task_step_id = ('', 0)
375
+
376
  # Prepare the dependencies of this signal.
377
  signal_source_path, task_step_id = self._prepare_signal(
378
  signal, source_path, manifest, compute_dependencies=True, task_step_id=task_step_id)
 
436
  signal_manifest_filepath = os.path.join(output_dir, SIGNAL_MANIFEST_FILENAME)
437
  with open_file(signal_manifest_filepath, 'w') as f:
438
  f.write(signal_manifest.json(exclude_none=True, indent=2))
439
+ log(f'Wrote signal output to {output_dir}')
440
 
441
  @override
442
  def delete_signal(self, signal_path: Path) -> None:
 
584
  if leaf.dtype == DataType.STRING:
585
  avg_length_query = ', avg(length(val)) as avgTextLength'
586
 
587
+ row: Optional[tuple[int, ...]] = None
588
  if leaf.dtype == DataType.BOOLEAN:
589
  approx_count_distinct = 2
590
  else:
 
606
  result = StatsResult(
607
  path=path, total_count=total_count, approx_count_distinct=approx_count_distinct)
608
 
609
+ if leaf.dtype == DataType.STRING and row:
610
  result.avg_text_length = row[1]
611
 
612
  # Compute min/max values for ordinal leafs, without sampling the data.
 
747
 
748
  def _merge_sorts(self, search_udfs: list[DuckDBSearchUDF], sort_by: Optional[Sequence[Path]],
749
  sort_order: Optional[SortOrder]) -> list[SortResult]:
 
 
 
750
  # True when the user has explicitly sorted by the alias of a search UDF (e.g. in ASC order).
751
  is_explicit_search_sort = False
752
  for sort_by_path in sort_by or []:
 
757
 
758
  sort_results: list[SortResult] = []
759
  if sort_by and not is_explicit_search_sort:
760
+ if not sort_order:
761
+ raise ValueError('`sort_order` is required when `sort_by` is specified.')
762
  # If the user has explicitly set a sort by, and it's not a search UDF alias, override.
763
  sort_results = [
764
  SortResult(path=normalize_path(sort_by), order=sort_order) for sort_by in sort_by if sort_by
 
863
 
864
  topk_udf_col = self._topk_udf_to_sort_by(udf_columns, sort_by, limit, sort_order)
865
  if topk_udf_col:
866
+ key_prefixes: Optional[Iterable[VectorKey]] = None
867
  if where_query:
868
  # If there are filters, we need to send UUIDs to the top k query.
869
  df = con.execute(f'SELECT {UUID_COLUMN} FROM t {where_query}').df()
 
992
  signal_column = list(temp_signal_cols.keys())[0]
993
  input = df[signal_column]
994
 
995
+ with DebugTimer(f'Computing signal "{signal.signal_name}"'):
996
  signal.setup()
997
 
998
  if signal.compute_type in [SignalInputType.TEXT_EMBEDDING]:
 
1008
  signal_out,
1009
  task_step_id=task_step_id,
1010
  estimated_len=len(flat_keys),
1011
+ step_description=f'Computing {signal.key()}')
1012
  df[signal_column] = unflatten(signal_out, input)
1013
  else:
1014
  num_rich_data = count_primitives(input)
 
1021
  signal_out,
1022
  task_step_id=task_step_id,
1023
  estimated_len=num_rich_data,
1024
+ step_description=f'Computing {signal.key()}')
1025
  signal_out_list = list(signal_out)
1026
  if signal_column in temp_column_to_offset_column:
1027
  offset_column_name, field = temp_column_to_offset_column[signal_column]
1028
+ nested_spans: Iterable[Item] = df[offset_column_name]
1029
+ flat_spans = flatten(nested_spans)
1030
  for span, item in zip(flat_spans, signal_out_list):
1031
  _offset_any_span(cast(int, span[VALUE_KEY][TEXT_SPAN_START_FEATURE]), item, field)
1032
 
 
1271
  """Create a UDF for each search for finding the location of the text with spans."""
1272
  search_udfs: list[DuckDBSearchUDF] = []
1273
  for search in searches:
1274
+ search_path = normalize_path(search.path)
1275
  if search.query.type == 'keyword':
1276
+ udf = Column(path=search_path, signal_udf=SubstringSignal(query=search.query.search))
1277
  search_udfs.append(
1278
  DuckDBSearchUDF(
1279
  udf=udf,
1280
+ search_path=search_path,
1281
  output_path=(*_col_destination_path(udf), PATH_WILDCARD)))
1282
  elif search.query.type == 'semantic' or search.query.type == 'concept':
1283
  embedding = search.query.embedding
1284
  if not embedding:
1285
  raise ValueError(f'Please provide an embedding for semantic search. Got search: {search}')
1286
 
1287
+ embedding_path = (*search_path, embedding, PATH_WILDCARD, EMBEDDING_KEY)
1288
  try:
1289
  manifest.data_schema.get_field(embedding_path)
1290
  except Exception as e:
 
1293
  f'Please compute the embedding index before issuing a {search.query.type} query.'
1294
  ) from e
1295
 
1296
+ search_signal: Optional[Signal] = None
1297
  if search.query.type == 'semantic':
1298
  search_signal = SemanticSimilaritySignal(
1299
  query=search.query.search, embedding=search.query.embedding)
 
1306
  # Add the label UDF.
1307
  concept_labels_signal = ConceptLabelsSignal(
1308
  namespace=search.query.concept_namespace, concept_name=search.query.concept_name)
1309
+ concept_labels_udf = Column(path=search_path, signal_udf=concept_labels_signal)
1310
  search_udfs.append(
1311
  DuckDBSearchUDF(
1312
  udf=concept_labels_udf,
1313
+ search_path=search_path,
1314
  output_path=_col_destination_path(concept_labels_udf),
1315
  sort=None))
1316
 
 
1320
  search_udfs.append(
1321
  DuckDBSearchUDF(
1322
  udf=udf,
1323
+ search_path=search_path,
1324
  output_path=_col_destination_path(udf),
1325
  sort=(output_path, SortOrder.DESC)))
1326
  else:
 
1440
  f'{_escape_col_name(path_comp)}' if quote_each_part else str(path_comp) for path_comp in path
1441
  ])
1442
 
1443
+ @override
1444
+ def to_json(self, filepath: Union[str, pathlib.Path], jsonl: bool = True) -> None:
1445
+ self._execute(f"COPY t TO '{filepath}' (FORMAT JSON, ARRAY {'FALSE' if jsonl else 'TRUE'})")
1446
+ log(f'Dataset exported to {filepath}')
1447
+
1448
+ @override
1449
+ def to_pandas(self) -> pd.DataFrame:
1450
+ return self._query_df('SELECT * FROM t')
1451
+
1452
+ @override
1453
+ def to_csv(self, filepath: Union[str, pathlib.Path]) -> None:
1454
+ self._execute(f"COPY t TO '{filepath}' (FORMAT CSV, HEADER)")
1455
+ log(f'Dataset exported to {filepath}')
1456
+
1457
+ @override
1458
+ def to_parquet(self, filepath: Union[str, pathlib.Path]) -> None:
1459
+ self._execute(f"COPY t TO '{filepath}' (FORMAT PARQUET)")
1460
+ log(f'Dataset exported to {filepath}')
1461
+
1462
 
1463
  def _escape_string_literal(string: str) -> str:
1464
  string = string.replace("'", "''")
 
1585
  enriched_path: PathTuple
1586
 
1587
  # The filename prefix for the embedding. Present when the signal is an embedding.
1588
+ embedding_filename_prefix: Optional[str] = None
1589
 
1590
  @validator('signal', pre=True)
1591
  def parse_signal(cls, signal: dict) -> Signal:
 
1709
  field = Field(repeated_field=field)
1710
  else:
1711
  field = Field(fields={sub_path: field})
1712
+ if not field.fields:
1713
+ raise ValueError(f'Invalid path: {path}. Must contain at least one field name.')
1714
  return Schema(fields=field.fields)
1715
 
1716
 
lilac/data/dataset_utils.py CHANGED
@@ -71,9 +71,6 @@ def lilac_embedding(start: int, end: int, embedding: Optional[np.ndarray]) -> It
71
  return lilac_span(start, end, {EMBEDDING_KEY: embedding})
72
 
73
 
74
- Tflatten = TypeVar('Tflatten', object, np.ndarray)
75
-
76
-
77
  def _flatten(input: Union[Iterator, object], is_primitive_predicate: Callable[[object],
78
  bool]) -> Generator:
79
  """Flattens a nested iterable."""
@@ -88,8 +85,8 @@ def _flatten(input: Union[Iterator, object], is_primitive_predicate: Callable[[o
88
  yield from _flatten(elem, is_primitive_predicate)
89
 
90
 
91
- def flatten(input: Union[Iterator, Iterable, Tflatten],
92
- is_primitive_predicate: Callable[[object], bool] = is_primitive) -> Iterator[Tflatten]:
93
  """Flattens a nested iterator.
94
 
95
  Primitives and dictionaries are not flattened. The user can also provide a predicate to determine
@@ -221,8 +218,8 @@ def create_signal_schema(signal: Signal, source_path: PathTuple, current_schema:
221
  return schema({UUID_COLUMN: 'string', **cast(dict, enriched_schema.fields)})
222
 
223
 
224
- def write_item_embeddings_to_disk(keys: Iterable[str], embeddings: Iterable[object],
225
- output_dir: str, shard_index: int, num_shards: int) -> str:
226
  """Write a set of embeddings to disk."""
227
  output_path_prefix = embedding_index_filename_prefix(output_dir, shard_index, num_shards)
228
 
@@ -231,7 +228,8 @@ def write_item_embeddings_to_disk(keys: Iterable[str], embeddings: Iterable[obje
231
  return isinstance(input, np.ndarray)
232
 
233
  flat_keys = flatten_keys(keys, embeddings, is_primitive_predicate=embedding_predicate)
234
- flat_embeddings = flatten(embeddings, is_primitive_predicate=embedding_predicate)
 
235
 
236
  embedding_vectors: list[np.ndarray] = []
237
  embedding_keys: list[VectorKey] = []
@@ -244,12 +242,12 @@ def write_item_embeddings_to_disk(keys: Iterable[str], embeddings: Iterable[obje
244
  embedding_vectors.append(lilac_embedding[EMBEDDING_KEY].reshape(-1))
245
  embedding_keys.append(key)
246
 
247
- embedding_vectors = np.array(embedding_vectors)
248
 
249
  # Write the embedding index and the ordered UUID column to disk so they can be joined later.
250
 
251
  with open_file(output_path_prefix + _EMBEDDINGS_SUFFIX, 'wb') as f:
252
- np.save(f, embedding_vectors, allow_pickle=False)
253
  with open_file(output_path_prefix + _KEYS_SUFFIX, 'wb') as f:
254
  pickle.dump(embedding_keys, f)
255
 
@@ -279,12 +277,13 @@ def write_items_to_parquet(items: Iterable[Item], output_dir: str, schema: Schem
279
  f = open_file(filepath, mode='wb')
280
  writer = ParquetWriter(schema)
281
  writer.open(f)
 
282
  num_items = 0
283
  for item in items:
284
  # Add a UUID column.
285
  if UUID_COLUMN not in item:
286
  item[UUID_COLUMN] = secrets.token_urlsafe(nbytes=12) # 16 base64 characters.
287
- if env('DEBUG'):
288
  try:
289
  _validate(item, arrow_schema)
290
  except Exception as e:
 
71
  return lilac_span(start, end, {EMBEDDING_KEY: embedding})
72
 
73
 
 
 
 
74
  def _flatten(input: Union[Iterator, object], is_primitive_predicate: Callable[[object],
75
  bool]) -> Generator:
76
  """Flattens a nested iterable."""
 
85
  yield from _flatten(elem, is_primitive_predicate)
86
 
87
 
88
+ def flatten(input: Union[Iterator, Iterable],
89
+ is_primitive_predicate: Callable[[object], bool] = is_primitive) -> Iterator:
90
  """Flattens a nested iterator.
91
 
92
  Primitives and dictionaries are not flattened. The user can also provide a predicate to determine
 
218
  return schema({UUID_COLUMN: 'string', **cast(dict, enriched_schema.fields)})
219
 
220
 
221
+ def write_item_embeddings_to_disk(keys: Iterable[str], embeddings: Iterable[Item], output_dir: str,
222
+ shard_index: int, num_shards: int) -> str:
223
  """Write a set of embeddings to disk."""
224
  output_path_prefix = embedding_index_filename_prefix(output_dir, shard_index, num_shards)
225
 
 
228
  return isinstance(input, np.ndarray)
229
 
230
  flat_keys = flatten_keys(keys, embeddings, is_primitive_predicate=embedding_predicate)
231
+ flat_embeddings = cast(Iterable[Item],
232
+ flatten(embeddings, is_primitive_predicate=embedding_predicate))
233
 
234
  embedding_vectors: list[np.ndarray] = []
235
  embedding_keys: list[VectorKey] = []
 
242
  embedding_vectors.append(lilac_embedding[EMBEDDING_KEY].reshape(-1))
243
  embedding_keys.append(key)
244
 
245
+ embedding_matrix = np.array(embedding_vectors)
246
 
247
  # Write the embedding index and the ordered UUID column to disk so they can be joined later.
248
 
249
  with open_file(output_path_prefix + _EMBEDDINGS_SUFFIX, 'wb') as f:
250
+ np.save(cast(str, f), embedding_matrix, allow_pickle=False)
251
  with open_file(output_path_prefix + _KEYS_SUFFIX, 'wb') as f:
252
  pickle.dump(embedding_keys, f)
253
 
 
277
  f = open_file(filepath, mode='wb')
278
  writer = ParquetWriter(schema)
279
  writer.open(f)
280
+ debug = env('DEBUG', False)
281
  num_items = 0
282
  for item in items:
283
  # Add a UUID column.
284
  if UUID_COLUMN not in item:
285
  item[UUID_COLUMN] = secrets.token_urlsafe(nbytes=12) # 16 base64 characters.
286
+ if debug:
287
  try:
288
  _validate(item, arrow_schema)
289
  except Exception as e:
lilac/data/sources/__init__.py DELETED
File without changes
lilac/data_loader.py CHANGED
@@ -8,35 +8,47 @@ poetry run python -m lilac.data_loader \
8
  --config_path=./datasets/the_movies_dataset.json
9
  """
10
  import json
11
- import math
12
  import os
13
  import pathlib
14
  import uuid
15
- from typing import Iterable, Optional, Union, cast
16
 
17
  import click
18
  import pandas as pd
19
  from distributed import Client
20
 
 
 
21
  from .data.dataset_utils import write_items_to_parquet
22
- from .data.sources.default_sources import register_default_sources
23
- from .data.sources.source import Source
24
- from .data.sources.source_registry import resolve_source
25
  from .schema import (
26
  MANIFEST_FILENAME,
27
  PARQUET_FILENAME_PREFIX,
28
  UUID_COLUMN,
29
- DataType,
30
  Field,
31
  Item,
32
  Schema,
33
  SourceManifest,
34
  field,
 
35
  )
 
 
 
36
  from .tasks import TaskStepId, progress
37
  from .utils import get_dataset_output_dir, log, open_file
38
 
39
 
 
 
 
 
 
 
 
 
 
 
40
  def process_source(base_dir: Union[str, pathlib.Path],
41
  namespace: str,
42
  dataset_name: str,
@@ -53,15 +65,14 @@ def process_source(base_dir: Union[str, pathlib.Path],
53
  items = normalize_items(items, source_schema.fields)
54
 
55
  # Add progress.
56
- if task_step_id is not None:
57
- items = progress(
58
- items,
59
- task_step_id=task_step_id,
60
- estimated_len=source_schema.num_items,
61
- step_description=f'Reading from source {source.name}...')
62
 
63
  # Filter out the `None`s after progress.
64
- items = cast(Iterable[Item], (item for item in items if item is not None))
65
 
66
  data_schema = Schema(fields={**source_schema.fields, UUID_COLUMN: field('string')})
67
  filepath, num_items = write_items_to_parquet(
@@ -76,19 +87,16 @@ def process_source(base_dir: Union[str, pathlib.Path],
76
  manifest = SourceManifest(files=filenames, data_schema=data_schema, images=None)
77
  with open_file(os.path.join(output_dir, MANIFEST_FILENAME), 'w') as f:
78
  f.write(manifest.json(indent=2, exclude_none=True))
79
- log(f'Manifest for dataset "{dataset_name}" written to {output_dir}')
80
 
81
  return output_dir, num_items
82
 
83
 
84
  def normalize_items(items: Iterable[Item], fields: dict[str, Field]) -> Item:
85
  """Sanitize items by removing NaNs and NaTs."""
86
- replace_nan_fields = set([
87
- field_name for field_name, field in fields.items()
88
- if field.dtype == DataType.STRING or field.dtype == DataType.NULL
89
- ])
90
- timestamp_fields = set(
91
- [field_name for field_name, field in fields.items() if field.dtype == DataType.TIMESTAMP])
92
  for item in items:
93
  if item is None:
94
  yield item
@@ -98,20 +106,11 @@ def normalize_items(items: Iterable[Item], fields: dict[str, Field]) -> Item:
98
  if UUID_COLUMN not in item:
99
  item[UUID_COLUMN] = uuid.uuid4().hex
100
 
101
- # Fix NaN string fields.
102
- for name in replace_nan_fields:
103
- item_value = item.get(name)
104
- if item_value and not isinstance(item_value, str):
105
- if math.isnan(item_value):
106
- item[name] = None
107
- else:
108
- item[name] = str(item_value)
109
-
110
- # Fix NaT (not a time) timestamp fields.
111
- for name in timestamp_fields:
112
- item_value = item.get(name)
113
- if item_value and pd.isnull(item_value):
114
- item[name] = None
115
 
116
  yield item
117
 
 
8
  --config_path=./datasets/the_movies_dataset.json
9
  """
10
  import json
 
11
  import os
12
  import pathlib
13
  import uuid
14
+ from typing import Iterable, Optional, Union
15
 
16
  import click
17
  import pandas as pd
18
  from distributed import Client
19
 
20
+ from .config import data_path
21
+ from .data.dataset import Dataset
22
  from .data.dataset_utils import write_items_to_parquet
23
+ from .db_manager import get_dataset
 
 
24
  from .schema import (
25
  MANIFEST_FILENAME,
26
  PARQUET_FILENAME_PREFIX,
27
  UUID_COLUMN,
 
28
  Field,
29
  Item,
30
  Schema,
31
  SourceManifest,
32
  field,
33
+ is_float,
34
  )
35
+ from .sources.default_sources import register_default_sources
36
+ from .sources.source import Source
37
+ from .sources.source_registry import resolve_source
38
  from .tasks import TaskStepId, progress
39
  from .utils import get_dataset_output_dir, log, open_file
40
 
41
 
42
+ def create_dataset(
43
+ namespace: str,
44
+ dataset_name: str,
45
+ source_config: Source,
46
+ ) -> Dataset:
47
+ """Load a dataset from a given source configuration."""
48
+ process_source(data_path(), namespace, dataset_name, source_config)
49
+ return get_dataset(namespace, dataset_name)
50
+
51
+
52
  def process_source(base_dir: Union[str, pathlib.Path],
53
  namespace: str,
54
  dataset_name: str,
 
65
  items = normalize_items(items, source_schema.fields)
66
 
67
  # Add progress.
68
+ items = progress(
69
+ items,
70
+ task_step_id=task_step_id,
71
+ estimated_len=source_schema.num_items,
72
+ step_description=f'Reading from source {source.name}...')
 
73
 
74
  # Filter out the `None`s after progress.
75
+ items = (item for item in items if item is not None)
76
 
77
  data_schema = Schema(fields={**source_schema.fields, UUID_COLUMN: field('string')})
78
  filepath, num_items = write_items_to_parquet(
 
87
  manifest = SourceManifest(files=filenames, data_schema=data_schema, images=None)
88
  with open_file(os.path.join(output_dir, MANIFEST_FILENAME), 'w') as f:
89
  f.write(manifest.json(indent=2, exclude_none=True))
90
+ log(f'Dataset "{dataset_name}" written to {output_dir}')
91
 
92
  return output_dir, num_items
93
 
94
 
95
  def normalize_items(items: Iterable[Item], fields: dict[str, Field]) -> Item:
96
  """Sanitize items by removing NaNs and NaTs."""
97
+ replace_nan_fields = [
98
+ field_name for field_name, field in fields.items() if field.dtype and not is_float(field.dtype)
99
+ ]
 
 
 
100
  for item in items:
101
  if item is None:
102
  yield item
 
106
  if UUID_COLUMN not in item:
107
  item[UUID_COLUMN] = uuid.uuid4().hex
108
 
109
+ # Fix NaN values.
110
+ for field_name in replace_nan_fields:
111
+ item_value = item.get(field_name)
112
+ if item_value and pd.isna(item_value):
113
+ item[field_name] = None
 
 
 
 
 
 
 
 
 
114
 
115
  yield item
116
 
lilac/embeddings/embedding.py CHANGED
@@ -88,7 +88,8 @@ def compute_split_embeddings(docs: Iterable[str],
88
 
89
  for x in list(pool.map(lambda x: embed_fn(x), chunks(texts, batch_size))):
90
  embeddings.extend(x)
91
- matrix = normalize(np.array(embeddings)).astype(np.float16)
 
92
  # np.split returns a shallow copy of each embedding so we don't increase the mem footprint.
93
  embeddings_batch = cast(list[np.ndarray], np.split(matrix, matrix.shape[0]))
94
  for (index, (_, (start, end))), embedding in zip(batch, embeddings_batch):
 
88
 
89
  for x in list(pool.map(lambda x: embed_fn(x), chunks(texts, batch_size))):
90
  embeddings.extend(x)
91
+ matrix = cast(np.ndarray, normalize(np.array(embeddings)))
92
+ matrix = matrix.astype(np.float16)
93
  # np.split returns a shallow copy of each embedding so we don't increase the mem footprint.
94
  embeddings_batch = cast(list[np.ndarray], np.split(matrix, matrix.shape[0]))
95
  for (index, (_, (start, end))), embedding in zip(batch, embeddings_batch):
lilac/embeddings/openai.py CHANGED
@@ -1,5 +1,5 @@
1
  """OpenAI embeddings."""
2
- from typing import TYPE_CHECKING, Iterable, cast
3
 
4
  import numpy as np
5
  from tenacity import retry, stop_after_attempt, wait_random_exponential
@@ -33,7 +33,7 @@ class OpenAI(TextEmbeddingSignal):
33
  name = 'openai'
34
  display_name = 'OpenAI Embeddings'
35
 
36
- _model: 'openai.Embedding'
37
 
38
  @override
39
  def setup(self) -> None:
@@ -59,7 +59,7 @@ class OpenAI(TextEmbeddingSignal):
59
  # See https://github.com/search?q=repo%3Aopenai%2Fopenai-python+replace+newlines&type=code
60
  texts = [text.replace('\n', ' ') for text in texts]
61
 
62
- response = self._model.create(input=texts, model=EMBEDDING_MODEL)
63
  return [np.array(embedding['embedding'], dtype=np.float32) for embedding in response['data']]
64
 
65
  docs = cast(Iterable[str], docs)
 
1
  """OpenAI embeddings."""
2
+ from typing import TYPE_CHECKING, Any, Iterable, cast
3
 
4
  import numpy as np
5
  from tenacity import retry, stop_after_attempt, wait_random_exponential
 
33
  name = 'openai'
34
  display_name = 'OpenAI Embeddings'
35
 
36
+ _model: type['openai.Embedding']
37
 
38
  @override
39
  def setup(self) -> None:
 
59
  # See https://github.com/search?q=repo%3Aopenai%2Fopenai-python+replace+newlines&type=code
60
  texts = [text.replace('\n', ' ') for text in texts]
61
 
62
+ response: Any = self._model.create(input=texts, model=EMBEDDING_MODEL)
63
  return [np.array(embedding['embedding'], dtype=np.float32) for embedding in response['data']]
64
 
65
  docs = cast(Iterable[str], docs)
lilac/embeddings/palm.py CHANGED
@@ -31,7 +31,7 @@ class PaLM(TextEmbeddingSignal):
31
  name = 'palm'
32
  display_name = 'PaLM Embeddings'
33
 
34
- _model: 'palm'
35
 
36
  @override
37
  def setup(self) -> None:
@@ -41,7 +41,7 @@ class PaLM(TextEmbeddingSignal):
41
  try:
42
  import google.generativeai as palm
43
  palm.configure(api_key=api_key)
44
- self._model = palm
45
  except ImportError:
46
  raise ImportError('Could not import the "google.generativeai" python package. '
47
  'Please install it with `pip install google-generativeai`.')
@@ -53,7 +53,7 @@ class PaLM(TextEmbeddingSignal):
53
  @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(10))
54
  def embed_fn(texts: list[str]) -> list[np.ndarray]:
55
  assert len(texts) == 1, 'PaLM API only supports batch size 1.'
56
- response = self._model.generate_embeddings(model=EMBEDDING_MODEL, text=texts[0])
57
  return [np.array(response['embedding'], dtype=np.float32)]
58
 
59
  docs = cast(Iterable[str], docs)
 
31
  name = 'palm'
32
  display_name = 'PaLM Embeddings'
33
 
34
+ _model: 'palm.generate_embeddings'
35
 
36
  @override
37
  def setup(self) -> None:
 
41
  try:
42
  import google.generativeai as palm
43
  palm.configure(api_key=api_key)
44
+ self._model = palm.generate_embeddings
45
  except ImportError:
46
  raise ImportError('Could not import the "google.generativeai" python package. '
47
  'Please install it with `pip install google-generativeai`.')
 
53
  @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(10))
54
  def embed_fn(texts: list[str]) -> list[np.ndarray]:
55
  assert len(texts) == 1, 'PaLM API only supports batch size 1.'
56
+ response = self._model(model=EMBEDDING_MODEL, text=texts[0])
57
  return [np.array(response['embedding'], dtype=np.float32)]
58
 
59
  docs = cast(Iterable[str], docs)
lilac/embeddings/sbert.py CHANGED
@@ -31,7 +31,7 @@ MODEL_NAME = MINI_LM_MODEL
31
  @functools.cache
32
  def _sbert() -> tuple[Optional[str], 'SentenceTransformer']:
33
  try:
34
- import torch
35
  from sentence_transformers import SentenceTransformer
36
  except ImportError:
37
  raise ImportError('Could not import the "sentence_transformers" python package. '
 
31
  @functools.cache
32
  def _sbert() -> tuple[Optional[str], 'SentenceTransformer']:
33
  try:
34
+ import torch.backends.mps
35
  from sentence_transformers import SentenceTransformer
36
  except ImportError:
37
  raise ImportError('Could not import the "sentence_transformers" python package. '
lilac/embeddings/vector_store_numpy.py CHANGED
@@ -49,7 +49,8 @@ class NumpyVectorStore(VectorStore):
49
  Returns
50
  The embeddings for the given keys.
51
  """
52
- return self._embeddings.take(self._lookup.loc[keys], axis=0)
 
53
 
54
  @override
55
  def topk(self,
@@ -62,7 +63,7 @@ class NumpyVectorStore(VectorStore):
62
  list[VectorKey],
63
  [k[0] if isinstance(k, tuple) and len(k) == 1 else k for k in key_prefixes])
64
  # This uses the hierarchical index (MutliIndex) to do a prefix lookup.
65
- row_indices = self._lookup.loc[key_prefixes]
66
  keys, embeddings = list(row_indices.index), self._embeddings.take(row_indices, axis=0)
67
  else:
68
  keys, embeddings = self._keys, self._embeddings
 
49
  Returns
50
  The embeddings for the given keys.
51
  """
52
+ locs = self._lookup.loc[cast(list[str], keys)]
53
+ return self._embeddings.take(locs, axis=0)
54
 
55
  @override
56
  def topk(self,
 
63
  list[VectorKey],
64
  [k[0] if isinstance(k, tuple) and len(k) == 1 else k for k in key_prefixes])
65
  # This uses the hierarchical index (MutliIndex) to do a prefix lookup.
66
+ row_indices = self._lookup.loc[cast(list[str], key_prefixes)]
67
  keys, embeddings = list(row_indices.index), self._embeddings.take(row_indices, axis=0)
68
  else:
69
  keys, embeddings = self._keys, self._embeddings
lilac/router_concept.py CHANGED
@@ -113,8 +113,8 @@ def merge_concept_draft(namespace: str, concept_name: str, options: MergeConcept
113
 
114
  class ScoreExample(BaseModel):
115
  """Example to score along a specific concept."""
116
- text: Optional[str]
117
- img: Optional[bytes]
118
 
119
 
120
  class ScoreBody(BaseModel):
 
113
 
114
  class ScoreExample(BaseModel):
115
  """Example to score along a specific concept."""
116
+ text: Optional[str] = None
117
+ img: Optional[bytes] = None
118
 
119
 
120
  class ScoreBody(BaseModel):
lilac/router_data_loader.py CHANGED
@@ -14,16 +14,13 @@ from pydantic import BaseModel
14
 
15
  from .auth import get_user_access
16
  from .config import data_path
17
- from .data.sources.default_sources import register_default_sources
18
- from .data.sources.source_registry import get_source_cls, registered_sources
19
  from .data_loader import process_source
20
  from .router_utils import RouteErrorHandler
 
21
  from .tasks import TaskId, task_manager
22
 
23
  REQUEST_TIMEOUT_SEC = 30 * 60 # 30 mins.
24
 
25
- register_default_sources()
26
-
27
  router = APIRouter(route_class=RouteErrorHandler)
28
 
29
 
 
14
 
15
  from .auth import get_user_access
16
  from .config import data_path
 
 
17
  from .data_loader import process_source
18
  from .router_utils import RouteErrorHandler
19
+ from .sources.source_registry import get_source_cls, registered_sources
20
  from .tasks import TaskId, task_manager
21
 
22
  REQUEST_TIMEOUT_SEC = 30 * 60 # 30 mins.
23
 
 
 
24
  router = APIRouter(route_class=RouteErrorHandler)
25
 
26
 
lilac/router_dataset.py CHANGED
@@ -23,13 +23,11 @@ from .data.dataset import (
23
  StatsResult,
24
  UnaryOp,
25
  )
26
- from .data.dataset_duckdb import DatasetDuckDB
27
- from .db_manager import get_dataset, remove_dataset_from_cache, set_default_dataset_cls
28
  from .router_utils import RouteErrorHandler
29
  from .schema import Bin, Path, normalize_path
30
  from .signals.concept_labels import ConceptLabelsSignal
31
  from .signals.concept_scorer import ConceptScoreSignal
32
- from .signals.default_signals import register_default_signals
33
  from .signals.semantic_similarity import SemanticSimilaritySignal
34
  from .signals.signal import (
35
  Signal,
@@ -44,9 +42,6 @@ from .utils import DatasetInfo, list_datasets
44
 
45
  router = APIRouter(route_class=RouteErrorHandler)
46
 
47
- register_default_signals()
48
- set_default_dataset_cls(DatasetDuckDB)
49
-
50
 
51
  @router.get('/', response_model_exclude_none=True)
52
  def get_datasets() -> list[DatasetInfo]:
@@ -193,23 +188,23 @@ class Column(DBColumn):
193
 
194
  class SelectRowsOptions(BaseModel):
195
  """The request for the select rows endpoint."""
196
- columns: Optional[Sequence[Union[Path, Column]]]
197
- searches: Optional[Sequence[Search]]
198
- filters: Optional[Sequence[Filter]]
199
- sort_by: Optional[Sequence[Path]]
200
  sort_order: Optional[SortOrder] = SortOrder.DESC
201
- limit: Optional[int]
202
- offset: Optional[int]
203
- combine_columns: Optional[bool]
204
 
205
 
206
  class SelectRowsSchemaOptions(BaseModel):
207
  """The request for the select rows schema endpoint."""
208
- columns: Optional[Sequence[Union[Path, Column]]]
209
- searches: Optional[Sequence[Search]]
210
- sort_by: Optional[Sequence[Path]]
211
  sort_order: Optional[SortOrder] = SortOrder.DESC
212
- combine_columns: Optional[bool]
213
 
214
 
215
  class SelectRowsResponse(BaseModel):
@@ -268,11 +263,11 @@ def select_rows_schema(namespace: str, dataset_name: str,
268
  class SelectGroupsOptions(BaseModel):
269
  """The request for the select groups endpoint."""
270
  leaf_path: Path
271
- filters: Optional[Sequence[Filter]]
272
  sort_by: Optional[GroupsSortBy] = GroupsSortBy.COUNT
273
  sort_order: Optional[SortOrder] = SortOrder.DESC
274
  limit: Optional[int] = 100
275
- bins: Optional[list[Bin]]
276
 
277
 
278
  @router.post('/{namespace}/{dataset_name}/select_groups')
 
23
  StatsResult,
24
  UnaryOp,
25
  )
26
+ from .db_manager import get_dataset, remove_dataset_from_cache
 
27
  from .router_utils import RouteErrorHandler
28
  from .schema import Bin, Path, normalize_path
29
  from .signals.concept_labels import ConceptLabelsSignal
30
  from .signals.concept_scorer import ConceptScoreSignal
 
31
  from .signals.semantic_similarity import SemanticSimilaritySignal
32
  from .signals.signal import (
33
  Signal,
 
42
 
43
  router = APIRouter(route_class=RouteErrorHandler)
44
 
 
 
 
45
 
46
  @router.get('/', response_model_exclude_none=True)
47
  def get_datasets() -> list[DatasetInfo]:
 
188
 
189
  class SelectRowsOptions(BaseModel):
190
  """The request for the select rows endpoint."""
191
+ columns: Optional[Sequence[Union[Path, Column]]] = None
192
+ searches: Optional[Sequence[Search]] = None
193
+ filters: Optional[Sequence[Filter]] = None
194
+ sort_by: Optional[Sequence[Path]] = None
195
  sort_order: Optional[SortOrder] = SortOrder.DESC
196
+ limit: Optional[int] = None
197
+ offset: Optional[int] = None
198
+ combine_columns: Optional[bool] = None
199
 
200
 
201
  class SelectRowsSchemaOptions(BaseModel):
202
  """The request for the select rows schema endpoint."""
203
+ columns: Optional[Sequence[Union[Path, Column]]] = None
204
+ searches: Optional[Sequence[Search]] = None
205
+ sort_by: Optional[Sequence[Path]] = None
206
  sort_order: Optional[SortOrder] = SortOrder.DESC
207
+ combine_columns: Optional[bool] = None
208
 
209
 
210
  class SelectRowsResponse(BaseModel):
 
263
  class SelectGroupsOptions(BaseModel):
264
  """The request for the select groups endpoint."""
265
  leaf_path: Path
266
+ filters: Optional[Sequence[Filter]] = None
267
  sort_by: Optional[GroupsSortBy] = GroupsSortBy.COUNT
268
  sort_order: Optional[SortOrder] = SortOrder.DESC
269
  limit: Optional[int] = 100
270
+ bins: Optional[list[Bin]] = None
271
 
272
 
273
  @router.post('/{namespace}/{dataset_name}/select_groups')
lilac/schema.py CHANGED
@@ -111,14 +111,14 @@ Bin = tuple[str, Optional[Union[float, int]], Optional[Union[float, int]]]
111
 
112
  class Field(BaseModel):
113
  """Holds information for a field in the schema."""
114
- repeated_field: Optional['Field']
115
- fields: Optional[dict[str, 'Field']]
116
- dtype: Optional[DataType]
117
  # Defined as the serialized signal when this field is the root result of a signal.
118
- signal: Optional[dict[str, Any]]
119
  # Maps a named bin to a tuple of (start, end) values.
120
- bins: Optional[list[Bin]]
121
- categorical: Optional[bool]
122
 
123
  @validator('fields')
124
  def either_fields_or_repeated_field_is_defined(
@@ -256,6 +256,8 @@ class Schema(BaseModel):
256
  def schema(schema_like: object) -> Schema:
257
  """Parse a schema-like object to a Schema object."""
258
  field = _parse_field_like(schema_like)
 
 
259
  return Schema(fields=field.fields)
260
 
261
 
@@ -371,7 +373,7 @@ class SourceManifest(BaseModel):
371
  data_schema: Schema
372
 
373
  # Image information for the dataset.
374
- images: Optional[list[ImageInfo]]
375
 
376
 
377
  def _str_fields(fields: dict[str, Field], indent: int) -> str:
 
111
 
112
  class Field(BaseModel):
113
  """Holds information for a field in the schema."""
114
+ repeated_field: Optional['Field'] = None
115
+ fields: Optional[dict[str, 'Field']] = None
116
+ dtype: Optional[DataType] = None
117
  # Defined as the serialized signal when this field is the root result of a signal.
118
+ signal: Optional[dict[str, Any]] = None
119
  # Maps a named bin to a tuple of (start, end) values.
120
+ bins: Optional[list[Bin]] = None
121
+ categorical: Optional[bool] = None
122
 
123
  @validator('fields')
124
  def either_fields_or_repeated_field_is_defined(
 
256
  def schema(schema_like: object) -> Schema:
257
  """Parse a schema-like object to a Schema object."""
258
  field = _parse_field_like(schema_like)
259
+ if not field.fields:
260
+ raise ValueError('Schema must have fields')
261
  return Schema(fields=field.fields)
262
 
263
 
 
373
  data_schema: Schema
374
 
375
  # Image information for the dataset.
376
+ images: Optional[list[ImageInfo]] = None
377
 
378
 
379
  def _str_fields(fields: dict[str, Field], indent: int) -> str:
lilac/server.py CHANGED
@@ -4,6 +4,7 @@ import asyncio
4
  import logging
5
  import os
6
  import shutil
 
7
  from typing import Any, Optional
8
 
9
  import uvicorn
@@ -157,17 +158,38 @@ logging.getLogger('uvicorn.access').addFilter(GetTasksFilter())
157
  SERVER: Optional[uvicorn.Server] = None
158
 
159
 
160
- def start_server(host: str = '0.0.0.0', port: int = 5432) -> None:
161
- """Starts the Lilac web server."""
 
 
 
 
 
 
162
  global SERVER
163
  if SERVER:
164
  raise ValueError('Server is already running')
165
 
166
- config = uvicorn.Config(app, host='0.0.0.0', port=5432)
 
 
 
 
 
167
  SERVER = uvicorn.Server(config)
 
 
 
 
 
 
 
168
  try:
169
- loop = asyncio.get_running_loop()
170
- loop.create_task(SERVER.serve())
 
 
 
171
  except RuntimeError:
172
  SERVER.run()
173
 
 
4
  import logging
5
  import os
6
  import shutil
7
+ import webbrowser
8
  from typing import Any, Optional
9
 
10
  import uvicorn
 
158
  SERVER: Optional[uvicorn.Server] = None
159
 
160
 
161
+ def start_server(host: str = '0.0.0.0', port: int = 5432, open: bool = False) -> None:
162
+ """Starts the Lilac web server.
163
+
164
+ Args:
165
+ host: The host to run the server on.
166
+ port: The port to run the server on.
167
+ open: Whether to open a browser tab upon startup.
168
+ """
169
  global SERVER
170
  if SERVER:
171
  raise ValueError('Server is already running')
172
 
173
+ config = uvicorn.Config(
174
+ app,
175
+ host=host,
176
+ port=port,
177
+ access_log=False,
178
+ )
179
  SERVER = uvicorn.Server(config)
180
+
181
+ if open:
182
+
183
+ @app.on_event('startup')
184
+ def open_browser() -> None:
185
+ webbrowser.open(f'http://{host}:{port}')
186
+
187
  try:
188
+ loop = asyncio.get_event_loop()
189
+ if loop.is_running():
190
+ loop.create_task(SERVER.serve())
191
+ else:
192
+ SERVER.run()
193
  except RuntimeError:
194
  SERVER.run()
195
 
lilac/signals/__init__.py CHANGED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Signals enrich a document with additional metadata."""
2
+
3
+ from .lang_detection import LangDetectionSignal
4
+ from .near_dup import NearDuplicateSignal
5
+ from .ner import SpacyNER
6
+ from .pii import PIISignal
7
+ from .signal import Signal
8
+
9
+ __all__ = [
10
+ 'Signal',
11
+ 'LangDetectionSignal',
12
+ 'NearDuplicateSignal',
13
+ 'SpacyNER',
14
+ 'PIISignal',
15
+ ]
lilac/signals/concept_scorer.py CHANGED
@@ -51,7 +51,6 @@ class ConceptScoreSignal(TextEmbeddingModelSignal):
51
  model = self._concept_model_db.get(
52
  self.namespace, self.concept_name, self.embedding, self._column_info, user=self._user)
53
  if not model:
54
- print('creating model...')
55
  model = self._concept_model_db.create(
56
  self.namespace, self.concept_name, self.embedding, self._column_info, user=self._user)
57
 
@@ -68,7 +67,6 @@ class ConceptScoreSignal(TextEmbeddingModelSignal):
68
  vector_store: VectorStore) -> Iterable[Optional[Item]]:
69
  concept_model = self._get_concept_model()
70
  embeddings = vector_store.get(keys)
71
- print('MODEL=', concept_model.version)
72
  return concept_model.score_embeddings(self.draft, embeddings).tolist()
73
 
74
  @override
 
51
  model = self._concept_model_db.get(
52
  self.namespace, self.concept_name, self.embedding, self._column_info, user=self._user)
53
  if not model:
 
54
  model = self._concept_model_db.create(
55
  self.namespace, self.concept_name, self.embedding, self._column_info, user=self._user)
56
 
 
67
  vector_store: VectorStore) -> Iterable[Optional[Item]]:
68
  concept_model = self._get_concept_model()
69
  embeddings = vector_store.get(keys)
 
70
  return concept_model.score_embeddings(self.draft, embeddings).tolist()
71
 
72
  @override
lilac/signals/lang_detection.py CHANGED
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
  class LangDetectionSignal(TextSignal):
19
  """Detects the language code in text.
20
 
21
- <br>
22
 
23
  Supports 55 languages returning their
24
  [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
@@ -29,10 +29,10 @@ class LangDetectionSignal(TextSignal):
29
  input_type = SignalInputType.TEXT
30
  compute_type = SignalInputType.TEXT
31
 
32
- split_by_paragraph = PydanticField(
33
- False, description='Compute language scores for each paragraph.')
34
 
35
- _model: 'langdetect'
36
 
37
  @override
38
  def setup(self) -> None:
@@ -42,7 +42,7 @@ class LangDetectionSignal(TextSignal):
42
  except ImportError:
43
  raise ImportError('Could not import the "langdetect" python package. '
44
  'Please install it with `pip install langdetect`.')
45
- self._model = langdetect
46
 
47
  @override
48
  def fields(self) -> Field:
@@ -52,6 +52,10 @@ class LangDetectionSignal(TextSignal):
52
 
53
  @override
54
  def compute(self, data: Iterable[RichData]) -> Iterable[Optional[Item]]:
 
 
 
 
55
  data = cast(Iterable[str], data)
56
  # Split on paragraphs.
57
  split_symbol = re.compile('(\r?\n){2,}')
@@ -59,8 +63,8 @@ class LangDetectionSignal(TextSignal):
59
  for text in data:
60
  if not self.split_by_paragraph:
61
  try:
62
- yield self._model.detect(text)
63
- except self._model.LangDetectException:
64
  yield None
65
  continue
66
 
@@ -72,9 +76,9 @@ class LangDetectionSignal(TextSignal):
72
  text_span = text_span.strip()
73
  if text_span:
74
  try:
75
- lang_code = self._model.detect(text_span)
76
  result.append(lilac_span(prev_end, start, {LANG_CODE: lang_code}))
77
- except self._model.LangDetectException:
78
  pass
79
  prev_end = end
80
 
@@ -82,9 +86,9 @@ class LangDetectionSignal(TextSignal):
82
  text_span = text[prev_end:]
83
  if text_span.strip():
84
  try:
85
- lang_code = self._model.detect(text_span)
86
  result.append(lilac_span(prev_end, len(text), {LANG_CODE: lang_code}))
87
- except self._model.LangDetectException:
88
  pass
89
 
90
  yield result
 
18
  class LangDetectionSignal(TextSignal):
19
  """Detects the language code in text.
20
 
21
+ \
22
 
23
  Supports 55 languages returning their
24
  [ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
 
29
  input_type = SignalInputType.TEXT
30
  compute_type = SignalInputType.TEXT
31
 
32
+ split_by_paragraph: bool = PydanticField(
33
+ default=False, description='Compute language scores for each paragraph.')
34
 
35
+ _model: Optional['langdetect.detect'] = None
36
 
37
  @override
38
  def setup(self) -> None:
 
42
  except ImportError:
43
  raise ImportError('Could not import the "langdetect" python package. '
44
  'Please install it with `pip install langdetect`.')
45
+ self._model = langdetect.detect
46
 
47
  @override
48
  def fields(self) -> Field:
 
52
 
53
  @override
54
  def compute(self, data: Iterable[RichData]) -> Iterable[Optional[Item]]:
55
+ if not self._model:
56
+ raise RuntimeError('Language detection model is not initialized.')
57
+
58
+ import langdetect
59
  data = cast(Iterable[str], data)
60
  # Split on paragraphs.
61
  split_symbol = re.compile('(\r?\n){2,}')
 
63
  for text in data:
64
  if not self.split_by_paragraph:
65
  try:
66
+ yield self._model(text)
67
+ except langdetect.LangDetectException:
68
  yield None
69
  continue
70
 
 
76
  text_span = text_span.strip()
77
  if text_span:
78
  try:
79
+ lang_code = self._model(text_span)
80
  result.append(lilac_span(prev_end, start, {LANG_CODE: lang_code}))
81
+ except langdetect.LangDetectException:
82
  pass
83
  prev_end = end
84
 
 
86
  text_span = text[prev_end:]
87
  if text_span.strip():
88
  try:
89
+ lang_code = self._model(text_span)
90
  result.append(lilac_span(prev_end, len(text), {LANG_CODE: lang_code}))
91
+ except langdetect.LangDetectException:
92
  pass
93
 
94
  yield result