laidline-pipecat 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- laidline_pipecat-1.0.0/.gitignore +2 -0
- laidline_pipecat-1.0.0/LICENSE +341 -0
- laidline_pipecat-1.0.0/PKG-INFO +82 -0
- laidline_pipecat-1.0.0/README.md +61 -0
- laidline_pipecat-1.0.0/laidline_pipecat/__init__.py +8 -0
- laidline_pipecat-1.0.0/laidline_pipecat/processor.py +150 -0
- laidline_pipecat-1.0.0/laidline_pipecat/py.typed +0 -0
- laidline_pipecat-1.0.0/pyproject.toml +34 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
Laidline Source-Available Licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Harrison Bootes, licensed exclusively to Laidline LLC.
|
|
4
|
+
|
|
5
|
+
Acceptance
|
|
6
|
+
|
|
7
|
+
By using the Software, You agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
You are not required to accept these terms in order to receive a copy of the
|
|
10
|
+
Software, and Detection and Verification applies to everyone, whether or not
|
|
11
|
+
they accept these terms. However, nothing other than these terms grants You
|
|
12
|
+
permission to use, copy, distribute, make available, or prepare derivative works
|
|
13
|
+
of the Software beyond what the law allows without the Licensor's permission,
|
|
14
|
+
and You indicate Your acceptance of these terms by doing any of those things.
|
|
15
|
+
|
|
16
|
+
Copyright Licence
|
|
17
|
+
|
|
18
|
+
The Licensor grants You a non-exclusive, worldwide, non-sublicensable,
|
|
19
|
+
non-transferable licence to use, copy, distribute, make available, and prepare
|
|
20
|
+
derivative works of the Software, in each case subject to the limitations and
|
|
21
|
+
conditions below. Within the Allowance the licence is royalty-free. The Software
|
|
22
|
+
is licensed, not sold.
|
|
23
|
+
|
|
24
|
+
Detection and Verification
|
|
25
|
+
|
|
26
|
+
Anyone may use the Software to detect, decode and verify marks, signatures,
|
|
27
|
+
certificates and evidence produced with the Software, and to run the
|
|
28
|
+
verification script it places in evidence exports, free of charge, for
|
|
29
|
+
themselves or for others. This right applies in every licence state, whether or
|
|
30
|
+
not the user has registered, is within the Allowance or holds a Laidline
|
|
31
|
+
Licence, and it does not end when any licence under these terms ends. Nothing in
|
|
32
|
+
these terms, including the limitations below, may be read as restricting it.
|
|
33
|
+
|
|
34
|
+
This right does not extend to embedding a watermark in content or attaching a
|
|
35
|
+
signed manifest to content; those acts are Marking and remain subject to the
|
|
36
|
+
Marking Allowance and the Limitations. A service that offers detection and
|
|
37
|
+
verification together with Marking is within this right only as to the detection
|
|
38
|
+
and verification.
|
|
39
|
+
|
|
40
|
+
Marking Allowance
|
|
41
|
+
|
|
42
|
+
You may use the Software to Mark content without charge up to the Allowance. The
|
|
43
|
+
Allowance is the number of Credits per calendar month (UTC) that the Licensor
|
|
44
|
+
publishes for that month. It is one Allowance per month for You together with
|
|
45
|
+
every member of Your Company that uses the Software, not one Allowance for each
|
|
46
|
+
evidence log, installation or entity: the Credits of all Marking by those users,
|
|
47
|
+
in every evidence log, count towards that one Allowance. The Software counts
|
|
48
|
+
Credits per evidence log; that is a technical limit, not a grant of a separate
|
|
49
|
+
Allowance for each log. Credits are computed, from the facts the Software
|
|
50
|
+
records in Your evidence log, by the weight table in force for that month, which
|
|
51
|
+
the Licensor signs and identifies by version. The weight table in force for a
|
|
52
|
+
month is the newest signed weight table the Licensor has published whose
|
|
53
|
+
effective_from date is at or before the start of that month, whether or not Your
|
|
54
|
+
installation holds it; the Software applies the newest table Your installation
|
|
55
|
+
holds, so its figures can differ from the Credits under these terms until Your
|
|
56
|
+
installation receives the published table. The Licensor may change the Allowance
|
|
57
|
+
or the weights only (a) to add a medium or Marking method that the previous
|
|
58
|
+
table lacks, (b) to reflect a change in its measured cost of serving a medium,
|
|
59
|
+
stated in the notice, or (c) to correct an error that the notice identifies by
|
|
60
|
+
row, with the measurement that shows it. It makes a change by publishing a new
|
|
61
|
+
signed weight table in a release and on its website, with a notice stating the
|
|
62
|
+
reason. A table that raises any weight or lowers the Allowance applies only from
|
|
63
|
+
a month that begins at least 30 days after its publication, and the Licensor
|
|
64
|
+
also emails the notice to registered users when it publishes the table. A table
|
|
65
|
+
that raises no weight and does not lower the Allowance applies from the first
|
|
66
|
+
day of the month after its publication, without that wait. A change never
|
|
67
|
+
applies to a month already begun or past. If You do not accept a change, You may
|
|
68
|
+
stop Marking at no cost.
|
|
69
|
+
|
|
70
|
+
Marking above the Allowance in a calendar month is licensed only on one
|
|
71
|
+
condition, which limits the scope of that permission and is not a promise: that
|
|
72
|
+
before 23:59:59 UTC on the last day of the following calendar month the Licensor
|
|
73
|
+
has issued to You or Your Company a Laidline Licence other than a Legal-Process
|
|
74
|
+
Licence whose coverage includes that month. The condition applies separately to
|
|
75
|
+
each calendar month. If it is met, that Marking is licensed from the start. If
|
|
76
|
+
it is not met, Marking in that month is unlicensed from the first Credit above
|
|
77
|
+
the Allowance, and the Licensor has the remedies available for unlicensed Use;
|
|
78
|
+
that Marking can become licensed later only by the late issue of a Laidline
|
|
79
|
+
Licence under Termination (a). The condition does not by itself end Your other
|
|
80
|
+
licences; a notice under Termination governs when they end. Where a Laidline
|
|
81
|
+
Licence already applies to the month, Marking above its grant is settled as its
|
|
82
|
+
Customer Agreement provides.
|
|
83
|
+
|
|
84
|
+
Above the Allowance the Software behaves as follows, by design and not as a
|
|
85
|
+
failure. Every mark is still watermarked, signed, logged, checkpointed and
|
|
86
|
+
timestamped exactly as before, and mark and proxy responses do not change.
|
|
87
|
+
Unless a paid Laidline Licence is current or in its grace period, new marks
|
|
88
|
+
carry the shared pool key and a trial issuer number instead of a private key and
|
|
89
|
+
a registered issuer number. Without a Laidline Licence that unlocks the month,
|
|
90
|
+
an evidence export still produces the complete signed bundle, but the compliance
|
|
91
|
+
paperwork (the filled-in compliance texts, the licence clause and the packaged
|
|
92
|
+
robustness and phantom figures) is withheld and the bundle's summary opens with
|
|
93
|
+
an unlicensed-use notice. In every case the raw evidence log, checkpoints and
|
|
94
|
+
certificates stay on Your systems, readable and copyable with any tool; the
|
|
95
|
+
Software does not delete, encrypt or lock them.
|
|
96
|
+
|
|
97
|
+
Limitations
|
|
98
|
+
|
|
99
|
+
You may not provide the Software to third parties as a hosted or managed
|
|
100
|
+
service, where the service provides users with access to any substantial set of
|
|
101
|
+
the features or functionality of the Software.
|
|
102
|
+
|
|
103
|
+
You may not use the Software, or any derivative work of it, for a Competing Use.
|
|
104
|
+
|
|
105
|
+
Using the Software to Mark, sign and record the outputs of Your own products and
|
|
106
|
+
services, including outputs You deliver to Your customers, is neither a hosted
|
|
107
|
+
or managed service nor a Competing Use.
|
|
108
|
+
|
|
109
|
+
Marking, signing or recording the outputs of third parties' own generators as a
|
|
110
|
+
service to those third parties is a Competing Use unless a Laidline Licence that
|
|
111
|
+
includes the tenant-reports feature applies. You may let a contractor use the
|
|
112
|
+
Software on Your behalf, for Your own outputs; You remain responsible for its
|
|
113
|
+
compliance.
|
|
114
|
+
|
|
115
|
+
You may not move, change, disable, or circumvent the Licence Key Functionality
|
|
116
|
+
in the Software, and You may not remove or obscure any functionality in the
|
|
117
|
+
Software that is protected by the licence key. The Licence Key Functionality
|
|
118
|
+
includes the Meter, the meter block in evidence entries, the Licence-State
|
|
119
|
+
Surfaces and the Payload-Key Switch. You may not re-enable by other means any
|
|
120
|
+
functionality that the licence key protects. Any such change ends Your Licences
|
|
121
|
+
under Termination. This paragraph does not restrict detection and verification,
|
|
122
|
+
writing Your own compliance documents, reading, copying, verifying or exporting
|
|
123
|
+
Your own records, or correcting an error that stops the Software working as
|
|
124
|
+
documented, to the extent the law gives You that right and only as far as
|
|
125
|
+
necessary to correct it.
|
|
126
|
+
|
|
127
|
+
You may have rights under the law that these terms cannot limit, including the
|
|
128
|
+
rights to make a back-up copy of the Software, to observe, study and test its
|
|
129
|
+
functioning, and to decompile it for interoperability to the extent the law
|
|
130
|
+
allows. These terms do not limit them.
|
|
131
|
+
|
|
132
|
+
You may not alter, remove, or obscure any licensing, copyright, or other notices
|
|
133
|
+
of the Licensor in the Software. Any use of the Licensor's Trademarks is subject
|
|
134
|
+
to applicable law.
|
|
135
|
+
|
|
136
|
+
Benchmarks
|
|
137
|
+
|
|
138
|
+
If You are a Competitor, You may not disclose to any third party any benchmark,
|
|
139
|
+
comparison or performance data about the Software without the Licensor's prior
|
|
140
|
+
written permission.
|
|
141
|
+
|
|
142
|
+
If You are not a Competitor, You may benchmark the Software, and You may publish
|
|
143
|
+
or otherwise disclose the results only if (a) the disclosure names the Software
|
|
144
|
+
version, the configuration, the decoder mode, the data and the published run of
|
|
145
|
+
the benchmark harness used, so that the result can be replicated, and (b) You
|
|
146
|
+
grant the Licensor, to the extent You are entitled to grant it, the right to
|
|
147
|
+
benchmark Your products and services and to publish the results on the same
|
|
148
|
+
terms, irrespective of any restriction on benchmarks in the terms of Your
|
|
149
|
+
products and services. Disclosing results grants that right.
|
|
150
|
+
|
|
151
|
+
Nothing in this section restricts acts the law allows despite a contrary term,
|
|
152
|
+
or disclosure to a court or public authority. The first paragraph does not cover
|
|
153
|
+
testing by public authorities, research institutions or independent experts not
|
|
154
|
+
paid by a Competitor.
|
|
155
|
+
|
|
156
|
+
Patents
|
|
157
|
+
|
|
158
|
+
The Licensor grants You a licence, under any patent claims the Licensor can
|
|
159
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
160
|
+
sale, import and have imported the Software, in each case subject to the
|
|
161
|
+
limitations and conditions in this licence. This licence does not cover any
|
|
162
|
+
patent claims that You cause to be infringed by modifications or additions to
|
|
163
|
+
the Software. If You or Your Company make any written claim that the Software
|
|
164
|
+
infringes or contributes to infringement of any patent, Your patent licence for
|
|
165
|
+
the Software granted under these terms ends immediately. If Your Company makes
|
|
166
|
+
such a claim, Your patent licence ends immediately for work on behalf of Your
|
|
167
|
+
Company.
|
|
168
|
+
|
|
169
|
+
Notices
|
|
170
|
+
|
|
171
|
+
You must ensure that anyone who gets a copy of any part of the Software from You
|
|
172
|
+
also gets a copy of these terms.
|
|
173
|
+
|
|
174
|
+
If You modify the Software, You must include in any modified copies of the
|
|
175
|
+
Software prominent notices stating that You have modified the Software.
|
|
176
|
+
|
|
177
|
+
Third-party components distributed with the Software keep their own licences,
|
|
178
|
+
listed in docs/licences.md; these terms do not apply to them.
|
|
179
|
+
|
|
180
|
+
Your Records
|
|
181
|
+
|
|
182
|
+
As between You and the Licensor, the evidence logs, checkpoints and
|
|
183
|
+
certificates, the signing and payload keys You generate, and the media You
|
|
184
|
+
create or process with the Software are Yours. The Software does not send them
|
|
185
|
+
to the Licensor, and these terms give the Licensor no right to them.
|
|
186
|
+
Registration and the usage report, if You use them, send only what the
|
|
187
|
+
Software's documentation lists, which includes no media, evidence entries or
|
|
188
|
+
private keys.
|
|
189
|
+
|
|
190
|
+
Nothing in these terms restricts You from reading, copying, verifying or
|
|
191
|
+
exporting Your own raw evidence log, checkpoints and certificates, with the
|
|
192
|
+
Software or any other tool, during or after Your Licences. The compliance
|
|
193
|
+
paperwork that the Software withholds above the Allowance is text and figures
|
|
194
|
+
written by the Licensor, into which the Software merges facts from Your own
|
|
195
|
+
evidence log; those facts stay in Your log, readable and copyable, and
|
|
196
|
+
withholding the paperwork withholds none of Your data.
|
|
197
|
+
|
|
198
|
+
Your records are available to You in every licence state for any legal or
|
|
199
|
+
regulatory proceeding. If You receive a lawful order for them, the Licensor's
|
|
200
|
+
published legal-process policy describes how to obtain, free and on presentation
|
|
201
|
+
of the order, a Legal-Process Licence unlocking the compliance paperwork for the
|
|
202
|
+
months demanded.
|
|
203
|
+
|
|
204
|
+
Issuer Numbers
|
|
205
|
+
|
|
206
|
+
Trial issuer numbers, which the Software draws at random, are not registered
|
|
207
|
+
with the Licensor, carry no claim about who made a mark, and may be held by more
|
|
208
|
+
than one user at the same time. Registered issuer numbers are allocated only
|
|
209
|
+
under a Customer Agreement.
|
|
210
|
+
|
|
211
|
+
Compliance Texts
|
|
212
|
+
|
|
213
|
+
The compliance texts that the Software places in evidence exports are templates
|
|
214
|
+
written by the Licensor. They are not legal advice and do not establish that You
|
|
215
|
+
comply with any law. You remain the provider responsible for Your own
|
|
216
|
+
compliance, including any duty to mark content, disclose it or keep records.
|
|
217
|
+
|
|
218
|
+
No Other Rights
|
|
219
|
+
|
|
220
|
+
These terms do not imply any licences other than those expressly granted in
|
|
221
|
+
these terms.
|
|
222
|
+
|
|
223
|
+
Termination
|
|
224
|
+
|
|
225
|
+
Use of the Software in violation of these terms is not licensed. Your Licences
|
|
226
|
+
end only after You receive a written notice of the violation from the Licensor,
|
|
227
|
+
as follows.
|
|
228
|
+
|
|
229
|
+
(a) A notice about Marking above the Allowance names each calendar month
|
|
230
|
+
concerned and the Credits above the Allowance in it. Your Licences end at
|
|
231
|
+
23:59:59 UTC on the 30th day after You receive the notice, unless by then the
|
|
232
|
+
Licensor has issued to You or Your Company a Laidline Licence other than a
|
|
233
|
+
Legal-Process Licence whose coverage includes every month the notice names. In
|
|
234
|
+
that case nothing ends, and the Marking in those months is licensed from the
|
|
235
|
+
start.
|
|
236
|
+
|
|
237
|
+
(b) For any other violation, Your Licences end at 23:59:59 UTC on the 30th day
|
|
238
|
+
after You receive the notice, unless by then You have ceased the violation and,
|
|
239
|
+
where the notice asks, confirmed in writing that You have done so.
|
|
240
|
+
|
|
241
|
+
You receive a notice when it reaches the email address of Your registration, if
|
|
242
|
+
You have registered, or otherwise any address through which You offer the
|
|
243
|
+
Software or Marked content to the public. A notice sent by email is treated as
|
|
244
|
+
received on the next business day after it is sent, unless it bounces.
|
|
245
|
+
|
|
246
|
+
Termination never affects the right under Detection and Verification or Your
|
|
247
|
+
rights under Your Records.
|
|
248
|
+
|
|
249
|
+
No Liability
|
|
250
|
+
|
|
251
|
+
AS FAR AS THE LAW ALLOWS, THE SOFTWARE COMES "AS IS" AND "WITH ALL FAULTS",
|
|
252
|
+
WITHOUT ANY WARRANTY OR CONDITION, EXPRESS OR IMPLIED. THE LICENSOR DISCLAIMS
|
|
253
|
+
ALL IMPLIED WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, ANY
|
|
254
|
+
IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE AND ANY IMPLIED WARRANTY OF
|
|
255
|
+
TITLE OR NON-INFRINGEMENT. THE LICENSOR WILL NOT BE LIABLE TO YOU FOR ANY
|
|
256
|
+
DAMAGES ARISING OUT OF THESE TERMS OR THE USE OR NATURE OF THE SOFTWARE, UNDER
|
|
257
|
+
ANY KIND OF LEGAL CLAIM.
|
|
258
|
+
|
|
259
|
+
NOTHING IN THESE TERMS EXCLUDES OR LIMITS LIABILITY FOR FRAUD, FRAUDULENT
|
|
260
|
+
MISREPRESENTATION OR FRAUDULENT CONCEALMENT, FOR INTENTIONAL ACTS, WILFUL
|
|
261
|
+
MISCONDUCT OR GROSS NEGLIGENCE, FOR INJURY TO LIFE, BODY OR HEALTH TO THE EXTENT
|
|
262
|
+
THE LAW DOES NOT ALLOW ITS EXCLUSION, OR FOR ANY OTHER LIABILITY THAT THE LAW
|
|
263
|
+
DOES NOT ALLOW TO BE EXCLUDED OR LIMITED. NOTHING IN THESE TERMS LIMITS ANY
|
|
264
|
+
RIGHT THAT CANNOT BE LIMITED UNDER APPLICABLE LAW, INCLUDING ANY RIGHT UNDER THE
|
|
265
|
+
FLORIDA DECEPTIVE AND UNFAIR TRADE PRACTICES ACT.
|
|
266
|
+
|
|
267
|
+
Governing Law
|
|
268
|
+
|
|
269
|
+
These terms, and any dispute or claim arising out of or in connection with them
|
|
270
|
+
or the Software (including non-contractual disputes or claims), are governed by
|
|
271
|
+
the laws of the State of Florida, United States of America, without regard to
|
|
272
|
+
its conflict-of-laws rules, and the United Nations Convention on Contracts for
|
|
273
|
+
the International Sale of Goods (1980) does not apply. The state and federal
|
|
274
|
+
courts located in Florida, and within Florida the courts of the county of
|
|
275
|
+
Laidline's principal office, have exclusive jurisdiction over any such dispute
|
|
276
|
+
or claim, as far as the law allows the parties to agree on it. If You are a
|
|
277
|
+
consumer, nothing in this clause limits Your right to bring proceedings in the
|
|
278
|
+
courts of the place where You are domiciled or habitually resident, or in the
|
|
279
|
+
courts located in Florida, and the Licensor may bring proceedings against You
|
|
280
|
+
only in the former. This clause also does not deprive You of the protection of
|
|
281
|
+
any provision of the law of Your habitual residence (or, for a business,
|
|
282
|
+
establishment) that cannot be excluded by agreement.
|
|
283
|
+
|
|
284
|
+
Definitions
|
|
285
|
+
|
|
286
|
+
The Licensor (also called Laidline) is Laidline LLC, a Florida limited liability
|
|
287
|
+
company, which holds an exclusive licence of the copyright in the Software from
|
|
288
|
+
its author, with the right to grant licences, and the Software is the software
|
|
289
|
+
the Licensor makes available under these terms, including any portion of it.
|
|
290
|
+
|
|
291
|
+
You refers to the individual or entity agreeing to these terms.
|
|
292
|
+
|
|
293
|
+
Your Company is any legal entity, sole proprietorship, or other kind of
|
|
294
|
+
organization that You work for, plus all organizations that have Control over,
|
|
295
|
+
are under the Control of, or are under common Control with that organization.
|
|
296
|
+
Control means ownership of substantially all the assets of an entity, or the
|
|
297
|
+
power to direct its management and policies by vote, contract, or otherwise.
|
|
298
|
+
Control can be direct or indirect.
|
|
299
|
+
|
|
300
|
+
Your Licences are all the licences granted to You for the Software under these
|
|
301
|
+
terms.
|
|
302
|
+
|
|
303
|
+
Use means anything You do with the Software requiring one of Your Licences.
|
|
304
|
+
|
|
305
|
+
Trademark means trademarks, service marks, and similar rights.
|
|
306
|
+
|
|
307
|
+
To Mark content is to use the Software to embed a watermark in it or to attach a
|
|
308
|
+
signed manifest to it.
|
|
309
|
+
|
|
310
|
+
A Laidline Licence is a licence file that the Licensor signs and issues for the
|
|
311
|
+
Software under a Customer Agreement or under the Licensor's published
|
|
312
|
+
legal-process policy. A Legal-Process Licence is a Laidline Licence issued under
|
|
313
|
+
that policy: it unlocks export and the compliance paperwork for the months a
|
|
314
|
+
lawful order demands, and it licenses no Marking. A Customer Agreement is a
|
|
315
|
+
separate agreement between You and the Licensor under which the Licensor issues
|
|
316
|
+
Laidline Licences and registered issuer numbers.
|
|
317
|
+
|
|
318
|
+
The Licence Key Functionality is the functionality in the Software that reads,
|
|
319
|
+
verifies or applies Laidline Licences, issuer certificates and signed weight
|
|
320
|
+
tables, or that counts Credits. The Meter is the functionality that records and
|
|
321
|
+
counts Credits. The Licence-State Surfaces are the licence state and usage
|
|
322
|
+
figures the Software reports in its status commands, logs, metrics, response
|
|
323
|
+
headers and evidence exports, including the unlicensed-use notice and the
|
|
324
|
+
export's licence block. The Payload-Key Switch is the Software's choice of
|
|
325
|
+
payload key and issuer number for each new mark, and the evidence event it
|
|
326
|
+
records when that choice changes.
|
|
327
|
+
|
|
328
|
+
A Competing Use is making available to others, commercially or free of charge, a
|
|
329
|
+
product or service that (a) substitutes for the Software; (b) substitutes for
|
|
330
|
+
any other product or service the Licensor offers using the Software that exists
|
|
331
|
+
when the Licensor makes the Software available; or (c) offers the same or
|
|
332
|
+
substantially similar marking, watermarking, signing or detection of
|
|
333
|
+
AI-generated content as the Software. Products and services compete even when
|
|
334
|
+
they work through different interfaces or on different platforms, or are free of
|
|
335
|
+
charge; one marketed as a practical substitute for the Software competes.
|
|
336
|
+
Detecting and verifying marks made with the Software, as Detection and
|
|
337
|
+
Verification permits, is never a Competing Use.
|
|
338
|
+
|
|
339
|
+
A Competitor is anyone who offers, or has publicly announced that it will offer,
|
|
340
|
+
a Competing Use or a hosted or managed service built from the Software. If You
|
|
341
|
+
are a Competitor, so is Your Company.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: laidline-pipecat
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Pipecat `FrameProcessor` placed after TTS; marks TTS audio frames with streaming AudioSeal; one evidence entry per utterance.
|
|
5
|
+
Project-URL: Homepage, https://laidline.com
|
|
6
|
+
Project-URL: Documentation, https://laidline.com/docs/quickstart
|
|
7
|
+
Project-URL: Changelog, https://laidline.com/docs/changelog
|
|
8
|
+
Author: Laidline LLC
|
|
9
|
+
License-Expression: LicenseRef-Laidline-Source-Available
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai-act,c2pa,pipecat,provenance,voice,watermark
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Multimedia
|
|
16
|
+
Classifier: Topic :: Security :: Cryptography
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: laidline[audio]<2,>=1.0
|
|
19
|
+
Requires-Dist: pipecat-ai<2,>=1.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# laidline-pipecat
|
|
23
|
+
|
|
24
|
+
A Pipecat `FrameProcessor` that sits right after the TTS service. It marks every TTS audio frame with streaming AudioSeal and writes one Laidline evidence entry per utterance.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install laidline-pipecat # pulls laidline[audio] and pipecat-ai>=1.12,<2
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from laidline import MarkContext, Marker
|
|
32
|
+
from laidline_pipecat import LaidlineTTSProcessor
|
|
33
|
+
|
|
34
|
+
marker = Marker.from_config("laidline.yaml") # in-process: keys, models and evidence stay on your host
|
|
35
|
+
pipeline = Pipeline(
|
|
36
|
+
[
|
|
37
|
+
transport.input(),
|
|
38
|
+
stt,
|
|
39
|
+
context_aggregator.user(),
|
|
40
|
+
llm,
|
|
41
|
+
tts,
|
|
42
|
+
LaidlineTTSProcessor(marker, ctx=MarkContext(route="pipecat:support-bot", tenant="acme")),
|
|
43
|
+
transport.output(),
|
|
44
|
+
context_aggregator.assistant(),
|
|
45
|
+
]
|
|
46
|
+
)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## What it does
|
|
50
|
+
|
|
51
|
+
- Each downstream `TTSAudioRawFrame` is replaced by a copy carrying the marked PCM. The copy keeps the same length, rate, channels, `pts`, `transport_destination`, `context_id` and metadata. Every other frame passes through unchanged.
|
|
52
|
+
- `TTSStartedFrame` opens an utterance. `TTSStoppedFrame`, `InterruptionFrame`, `EndFrame`, `CancelFrame` and processor cleanup close it. Closing writes one `marked` evidence entry with `modality: audio`, `watermark.streaming: true`, the payload and issuer id, the duration, your `ctx`, and the TTS `context_id` under `extra.context_id`. An utterance that changes sample rate part-way gets one entry per format.
|
|
53
|
+
- It needs an in-process `Marker` with `watermark.audio.enabled: true`. A `MarkClient` raises `TypeError`, because the streaming path has no HTTP form. A Marker with audio watermarking disabled raises `ValueError`.
|
|
54
|
+
- A marking failure raises out of `process_frame`. Pipecat reports it as an error and does not push the unmarked frame.
|
|
55
|
+
- The embedder is AudioSeal's streaming card (`watermark.audio.stream_kind: block`, the only kind).
|
|
56
|
+
|
|
57
|
+
## What it does not do
|
|
58
|
+
|
|
59
|
+
- Audio below 16 kHz (an 8 kHz phone bot) is not marked: it passes through unchanged and the entry says `watermark: null`, `watermark_skipped:rate_below_16k`. The streaming mark does not survive below 16 kHz.
|
|
60
|
+
- A stream carries no C2PA manifest (`c2pa: null`, warning `manifest_skipped:streaming`). The watermark and the evidence entry are the provenance for live audio.
|
|
61
|
+
- For a recording you store, sign the file itself with `marker.mark_audio(..., fmt="wav" | "flac" | "mp3" | "m4a")`. This embeds a manifest and adds the batch mark. Laidline's `/v1/audio/speech` proxy in streaming mode stores a signed twin of a response only when `watermark.audio.store_signed_twin` is enabled and only for a stream that completed.
|
|
62
|
+
|
|
63
|
+
## Survival
|
|
64
|
+
|
|
65
|
+
Measured 2026-09-27 on LibriSpeech test-clean, 500 speech clips. The detection threshold is 0.39, which gave a 0.75 % false-positive rate. Figures are the share of clips on which the streaming-mode mark (the one this plugin embeds) is still detected:
|
|
66
|
+
|
|
67
|
+
| Transform | Streaming mode |
|
|
68
|
+
|---|---|
|
|
69
|
+
| Opus 24 kbps | 100 % |
|
|
70
|
+
| Opus 48 kbps | 100 % |
|
|
71
|
+
| MP3 64 kbps | 100 % |
|
|
72
|
+
| AAC 64 kbps | 100 % |
|
|
73
|
+
| G.711 mu-law | 0 % |
|
|
74
|
+
| 8 kHz resampling | 0 % |
|
|
75
|
+
| EnCodec 6 kbps | 100 % detected, 0 % exact issuer |
|
|
76
|
+
| Mimi | 0 % |
|
|
77
|
+
|
|
78
|
+
The streaming mark survives an offline Opus transcode at 24 and 48 kbps (100 percent on 500 LibriSpeech clips); no WebRTC session, packet loss or jitter was tested. **It does not survive a simulated phone leg** (G.711 codec simulation). The streaming mark was not run over a real call. For phone deployments, provenance comes from the evidence entry and from C2PA on stored recordings, not from the watermark. For comparison, the batch (non-streaming) mark that `mark_audio` embeds survives simulated G.711 and 8 kHz at 100 %, and a real call with the batch mark: 99 % (100 Twilio number-to-number calls recorded at the callee, G.711 8 kHz, carrier routing unconfirmed and possibly on-net, measured 2026-09-27).
|
|
79
|
+
|
|
80
|
+
Mean embed SNR is 17.4 dB (5th percentile 8.7 dB), which is audible on some voices. Listen to your own voices before you ship.
|
|
81
|
+
|
|
82
|
+
The full numbers and method are in [the benchmarks page](https://laidline.com/docs/benchmarks) ("Audio robustness"), and what was tested, and how, in [https://laidline.com/docs/integrations/pipecat](https://laidline.com/docs/integrations/pipecat). Streaming sessions, detection and the operating threshold are in [https://laidline.com/docs/integrations/audio](https://laidline.com/docs/integrations/audio).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# laidline-pipecat
|
|
2
|
+
|
|
3
|
+
A Pipecat `FrameProcessor` that sits right after the TTS service. It marks every TTS audio frame with streaming AudioSeal and writes one Laidline evidence entry per utterance.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install laidline-pipecat # pulls laidline[audio] and pipecat-ai>=1.12,<2
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from laidline import MarkContext, Marker
|
|
11
|
+
from laidline_pipecat import LaidlineTTSProcessor
|
|
12
|
+
|
|
13
|
+
marker = Marker.from_config("laidline.yaml") # in-process: keys, models and evidence stay on your host
|
|
14
|
+
pipeline = Pipeline(
|
|
15
|
+
[
|
|
16
|
+
transport.input(),
|
|
17
|
+
stt,
|
|
18
|
+
context_aggregator.user(),
|
|
19
|
+
llm,
|
|
20
|
+
tts,
|
|
21
|
+
LaidlineTTSProcessor(marker, ctx=MarkContext(route="pipecat:support-bot", tenant="acme")),
|
|
22
|
+
transport.output(),
|
|
23
|
+
context_aggregator.assistant(),
|
|
24
|
+
]
|
|
25
|
+
)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What it does
|
|
29
|
+
|
|
30
|
+
- Each downstream `TTSAudioRawFrame` is replaced by a copy carrying the marked PCM. The copy keeps the same length, rate, channels, `pts`, `transport_destination`, `context_id` and metadata. Every other frame passes through unchanged.
|
|
31
|
+
- `TTSStartedFrame` opens an utterance. `TTSStoppedFrame`, `InterruptionFrame`, `EndFrame`, `CancelFrame` and processor cleanup close it. Closing writes one `marked` evidence entry with `modality: audio`, `watermark.streaming: true`, the payload and issuer id, the duration, your `ctx`, and the TTS `context_id` under `extra.context_id`. An utterance that changes sample rate part-way gets one entry per format.
|
|
32
|
+
- It needs an in-process `Marker` with `watermark.audio.enabled: true`. A `MarkClient` raises `TypeError`, because the streaming path has no HTTP form. A Marker with audio watermarking disabled raises `ValueError`.
|
|
33
|
+
- A marking failure raises out of `process_frame`. Pipecat reports it as an error and does not push the unmarked frame.
|
|
34
|
+
- The embedder is AudioSeal's streaming card (`watermark.audio.stream_kind: block`, the only kind).
|
|
35
|
+
|
|
36
|
+
## What it does not do
|
|
37
|
+
|
|
38
|
+
- Audio below 16 kHz (an 8 kHz phone bot) is not marked: it passes through unchanged and the entry says `watermark: null`, `watermark_skipped:rate_below_16k`. The streaming mark does not survive below 16 kHz.
|
|
39
|
+
- A stream carries no C2PA manifest (`c2pa: null`, warning `manifest_skipped:streaming`). The watermark and the evidence entry are the provenance for live audio.
|
|
40
|
+
- For a recording you store, sign the file itself with `marker.mark_audio(..., fmt="wav" | "flac" | "mp3" | "m4a")`. This embeds a manifest and adds the batch mark. Laidline's `/v1/audio/speech` proxy in streaming mode stores a signed twin of a response only when `watermark.audio.store_signed_twin` is enabled and only for a stream that completed.
|
|
41
|
+
|
|
42
|
+
## Survival
|
|
43
|
+
|
|
44
|
+
Measured 2026-09-27 on LibriSpeech test-clean, 500 speech clips. The detection threshold is 0.39, which gave a 0.75 % false-positive rate. Figures are the share of clips on which the streaming-mode mark (the one this plugin embeds) is still detected:
|
|
45
|
+
|
|
46
|
+
| Transform | Streaming mode |
|
|
47
|
+
|---|---|
|
|
48
|
+
| Opus 24 kbps | 100 % |
|
|
49
|
+
| Opus 48 kbps | 100 % |
|
|
50
|
+
| MP3 64 kbps | 100 % |
|
|
51
|
+
| AAC 64 kbps | 100 % |
|
|
52
|
+
| G.711 mu-law | 0 % |
|
|
53
|
+
| 8 kHz resampling | 0 % |
|
|
54
|
+
| EnCodec 6 kbps | 100 % detected, 0 % exact issuer |
|
|
55
|
+
| Mimi | 0 % |
|
|
56
|
+
|
|
57
|
+
The streaming mark survives an offline Opus transcode at 24 and 48 kbps (100 percent on 500 LibriSpeech clips); no WebRTC session, packet loss or jitter was tested. **It does not survive a simulated phone leg** (G.711 codec simulation). The streaming mark was not run over a real call. For phone deployments, provenance comes from the evidence entry and from C2PA on stored recordings, not from the watermark. For comparison, the batch (non-streaming) mark that `mark_audio` embeds survives simulated G.711 and 8 kHz at 100 %, and a real call with the batch mark: 99 % (100 Twilio number-to-number calls recorded at the callee, G.711 8 kHz, carrier routing unconfirmed and possibly on-net, measured 2026-09-27).
|
|
58
|
+
|
|
59
|
+
Mean embed SNR is 17.4 dB (5th percentile 8.7 dB), which is audible on some voices. Listen to your own voices before you ship.
|
|
60
|
+
|
|
61
|
+
The full numbers and method are in [the benchmarks page](https://laidline.com/docs/benchmarks) ("Audio robustness"), and what was tested, and how, in [https://laidline.com/docs/integrations/pipecat](https://laidline.com/docs/integrations/pipecat). Streaming sessions, detection and the operating threshold are in [https://laidline.com/docs/integrations/audio](https://laidline.com/docs/integrations/audio).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Pipecat ``FrameProcessor`` placed after TTS: marks every TTS audio frame with streaming AudioSeal and writes one
|
|
2
|
+
evidence entry per utterance. See ``LaidlineTTSProcessor``."""
|
|
3
|
+
|
|
4
|
+
from laidline_pipecat.processor import LaidlineTTSProcessor
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
|
|
8
|
+
__all__ = ["LaidlineTTSProcessor", "__version__"]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""``LaidlineTTSProcessor``: a Pipecat ``FrameProcessor`` placed right after the TTS service. Every downstream
|
|
2
|
+
``TTSAudioRawFrame`` is replaced by a copy of the same frame carrying AudioSeal-marked PCM (``pts``,
|
|
3
|
+
``transport_destination``, ``context_id`` and metadata kept). ``TTSStartedFrame`` opens an utterance;
|
|
4
|
+
``TTSStoppedFrame``, ``InterruptionFrame``, ``EndFrame``, ``CancelFrame`` and ``cleanup`` close it and write its one
|
|
5
|
+
evidence entry (``modality: audio``, ``watermark.streaming: true``, ``c2pa: null``: a stream carries no manifest).
|
|
6
|
+
Every frame is pushed on; nothing but the audio bytes changes.
|
|
7
|
+
|
|
8
|
+
Needs an in-process ``Marker`` with ``watermark.audio.enabled`` (the streaming path has no HTTP form). A marking
|
|
9
|
+
failure raises out of ``process_frame``: Pipecat reports it as an error and the unmarked frame is not pushed."""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import copy
|
|
15
|
+
import dataclasses
|
|
16
|
+
import logging
|
|
17
|
+
import threading
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from laidline import MarkContext, Marker
|
|
21
|
+
from laidline.core.api import AudioStreamSession, MarkClient
|
|
22
|
+
from pipecat.frames.frames import (
|
|
23
|
+
CancelFrame,
|
|
24
|
+
EndFrame,
|
|
25
|
+
Frame,
|
|
26
|
+
InterruptionFrame,
|
|
27
|
+
TTSAudioRawFrame,
|
|
28
|
+
TTSStartedFrame,
|
|
29
|
+
TTSStoppedFrame,
|
|
30
|
+
)
|
|
31
|
+
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
|
32
|
+
|
|
33
|
+
log = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
_CLOSING = (TTSStoppedFrame, InterruptionFrame, EndFrame, CancelFrame)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class LaidlineTTSProcessor(FrameProcessor):
|
|
39
|
+
"""Watermark TTS audio in a Pipecat pipeline: ``[..., tts, LaidlineTTSProcessor(marker), transport.output()]``.
|
|
40
|
+
|
|
41
|
+
``ctx`` is copied into every utterance's evidence entry (default route ``pipecat:tts``); the utterance's TTS
|
|
42
|
+
``context_id`` is added under ``extra.context_id``. Other keyword arguments go to ``FrameProcessor``."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, marker: Marker, *, ctx: MarkContext | None = None, **kwargs: Any) -> None:
|
|
45
|
+
if isinstance(marker, MarkClient) or not isinstance(marker, Marker):
|
|
46
|
+
raise TypeError("LaidlineTTSProcessor needs an in-process Marker (a MarkClient cannot mark a stream)")
|
|
47
|
+
if marker.audio_wm is None:
|
|
48
|
+
raise ValueError("watermark.audio.enabled is false in this Marker's configuration")
|
|
49
|
+
super().__init__(**kwargs)
|
|
50
|
+
self._marker = marker
|
|
51
|
+
self._ctx = ctx or MarkContext(route="pipecat:tts")
|
|
52
|
+
self._session: AudioStreamSession | None = None
|
|
53
|
+
self._context_id: str | None = None
|
|
54
|
+
# System frames (interruption, cancel) run on Pipecat's input task while an audio frame may be mid-``process``
|
|
55
|
+
# in a worker thread on the process task; the lock keeps ``close`` from racing that call.
|
|
56
|
+
self._lock = threading.Lock()
|
|
57
|
+
self._closing: set[asyncio.Future[str | None]] = set()
|
|
58
|
+
|
|
59
|
+
async def process_frame(self, frame: Frame, direction: FrameDirection) -> None:
|
|
60
|
+
await super().process_frame(frame, direction)
|
|
61
|
+
if isinstance(frame, TTSStartedFrame):
|
|
62
|
+
await self._finish(relay=True)
|
|
63
|
+
self._context_id = frame.context_id
|
|
64
|
+
elif isinstance(frame, TTSAudioRawFrame) and direction == FrameDirection.DOWNSTREAM:
|
|
65
|
+
frame = await self._mark(frame)
|
|
66
|
+
elif isinstance(frame, _CLOSING):
|
|
67
|
+
# an utterance that ends relays what a keyed stream held back; an interruption or a cancel discards it
|
|
68
|
+
await self._finish(relay=isinstance(frame, (TTSStoppedFrame, EndFrame)))
|
|
69
|
+
self._context_id = None
|
|
70
|
+
await self.push_frame(frame, direction)
|
|
71
|
+
|
|
72
|
+
async def cleanup(self) -> None:
|
|
73
|
+
"""Close the open utterance, then wait for every close still running, including those whose caller a
|
|
74
|
+
barge-in cancelled, so no evidence write is left behind when the pipeline stops."""
|
|
75
|
+
await super().cleanup() # type: ignore[no-untyped-call] # unannotated in pipecat 1.12
|
|
76
|
+
await self._finish()
|
|
77
|
+
if self._closing:
|
|
78
|
+
await asyncio.gather(*self._closing, return_exceptions=True) # failures are logged by _closed
|
|
79
|
+
|
|
80
|
+
async def _mark(self, frame: TTSAudioRawFrame) -> TTSAudioRawFrame:
|
|
81
|
+
marked = None
|
|
82
|
+
while marked is None: # None: an interruption closed the session under this frame; mark it in a new one
|
|
83
|
+
marked = await asyncio.to_thread(self._process, await self._session_for(frame), frame.audio)
|
|
84
|
+
out = copy.copy(frame) # same id, pts, destination, context_id: only the samples change
|
|
85
|
+
out.metadata = dict(frame.metadata)
|
|
86
|
+
out.audio = marked
|
|
87
|
+
out.num_frames = len(marked) // (2 * frame.num_channels)
|
|
88
|
+
return out
|
|
89
|
+
|
|
90
|
+
async def _session_for(self, frame: TTSAudioRawFrame) -> AudioStreamSession:
|
|
91
|
+
s = self._session
|
|
92
|
+
if s is not None and s.rate == frame.sample_rate and s.channels == frame.num_channels:
|
|
93
|
+
return s
|
|
94
|
+
await self._finish(relay=True) # none open, or the format changed mid-utterance: one entry per format
|
|
95
|
+
context_id = frame.context_id or self._context_id
|
|
96
|
+
extra = {**self._ctx.extra, **({"context_id": context_id} if context_id else {})}
|
|
97
|
+
ctx = dataclasses.replace(self._ctx, extra=extra)
|
|
98
|
+
# off the loop: the first session loads the streaming generator (a download on a cold cache)
|
|
99
|
+
s = await asyncio.to_thread(
|
|
100
|
+
self._marker.audio_stream, ctx, sample_rate=frame.sample_rate, channels=frame.num_channels
|
|
101
|
+
)
|
|
102
|
+
self._session = s
|
|
103
|
+
return s
|
|
104
|
+
|
|
105
|
+
def _process(self, s: AudioStreamSession, pcm16: bytes) -> bytes | None:
|
|
106
|
+
with self._lock:
|
|
107
|
+
return None if s.closed else s.process(pcm16)
|
|
108
|
+
|
|
109
|
+
def _close(self, s: AudioStreamSession) -> str | None:
|
|
110
|
+
with self._lock:
|
|
111
|
+
# an utterance that ended was flushed first; an interrupted one pushed no tail, so none is counted
|
|
112
|
+
return s.close(discard_tail=True).entry_hash
|
|
113
|
+
|
|
114
|
+
def _flush(self, s: AudioStreamSession) -> bytes:
|
|
115
|
+
with self._lock:
|
|
116
|
+
return b"" if s.closed else s.flush()
|
|
117
|
+
|
|
118
|
+
async def _finish(self, relay: bool = False) -> None:
|
|
119
|
+
s, self._session = self._session, None
|
|
120
|
+
if s is None:
|
|
121
|
+
return
|
|
122
|
+
try:
|
|
123
|
+
if relay and s.keyed: # only a keyed stream holds frames back
|
|
124
|
+
# a keyed stream holds its lookahead and last hop back; push them, marked, as one
|
|
125
|
+
# more audio frame before the frame that ends the utterance
|
|
126
|
+
tail = await asyncio.to_thread(self._flush, s)
|
|
127
|
+
if tail:
|
|
128
|
+
out = TTSAudioRawFrame(
|
|
129
|
+
audio=tail, sample_rate=s.rate, num_channels=s.channels, context_id=self._context_id
|
|
130
|
+
)
|
|
131
|
+
await self.push_frame(out, FrameDirection.DOWNSTREAM)
|
|
132
|
+
finally: # the session is already detached: a failed or cancelled relay must not leave it unclosed
|
|
133
|
+
# shielded: a barge-in cancels the task awaiting this, and a close still queued in the executor would be
|
|
134
|
+
# dropped with it, leaving marked audio with no entry. ``_closing`` holds the task until it is done.
|
|
135
|
+
task = asyncio.ensure_future(asyncio.to_thread(self._close, s))
|
|
136
|
+
self._closing.add(task)
|
|
137
|
+
task.add_done_callback(lambda t: self._closed(t, s.asset_id))
|
|
138
|
+
entry_hash = await asyncio.shield(task)
|
|
139
|
+
log.info("laidline: utterance %s marked (%d frames), evidence %s", s.asset_id, s.frames, entry_hash)
|
|
140
|
+
|
|
141
|
+
def _closed(self, task: asyncio.Future[str | None], asset_id: str) -> None:
|
|
142
|
+
"""Done callback of a shielded close: forget it and log a failure, which nobody may be awaiting any more (a
|
|
143
|
+
barge-in cancelled the caller)."""
|
|
144
|
+
self._closing.discard(task)
|
|
145
|
+
if task.cancelled():
|
|
146
|
+
log.error("laidline: close of utterance %s was cancelled; its evidence was not written", asset_id)
|
|
147
|
+
elif (e := task.exception()) is not None:
|
|
148
|
+
log.error(
|
|
149
|
+
"laidline: utterance %s: evidence was not written: %s: %s", asset_id, type(e).__name__, str(e)[:200]
|
|
150
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "laidline-pipecat"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Pipecat `FrameProcessor` placed after TTS; marks TTS audio frames with streaming AudioSeal; one evidence entry per utterance."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
authors = [{name = "Laidline LLC"}]
|
|
8
|
+
license = "LicenseRef-Laidline-Source-Available"
|
|
9
|
+
license-files = ["LICENSE"]
|
|
10
|
+
keywords = ["ai-act", "c2pa", "pipecat", "provenance", "voice", "watermark"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 5 - Production/Stable",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
|
+
"Topic :: Multimedia",
|
|
15
|
+
"Topic :: Security :: Cryptography",
|
|
16
|
+
"Operating System :: OS Independent",
|
|
17
|
+
]
|
|
18
|
+
dependencies = ["laidline[audio]>=1.0,<2", "pipecat-ai>=1.12,<2"]
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
Homepage = "https://laidline.com"
|
|
22
|
+
Documentation = "https://laidline.com/docs/quickstart"
|
|
23
|
+
Changelog = "https://laidline.com/docs/changelog"
|
|
24
|
+
|
|
25
|
+
[build-system]
|
|
26
|
+
requires = ["hatchling"]
|
|
27
|
+
build-backend = "hatchling.build"
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.targets.sdist]
|
|
30
|
+
# the tests and the repository's ignore file stay in the repository
|
|
31
|
+
exclude = ["/tests", "/.gitignore", "**/__pycache__"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["laidline_pipecat"]
|